EZBS PicoCOM1 PHY patch

Aus Verteilte Systeme - Wiki
Wechseln zu: Navigation, Suche

(Work in progress!)

Hintergrund

Die Ethernet-Phy(sical Layer)-Schnittstelle ("die PHY") der PicoCOM1 ist ein Teridian 78Q2123.

Der Ethernet Link Layer ist auf dem Mikrocontroller Atmel AT91SAM9260 implementiert. Unter Elinos wird der macb-Kerneltreiber verwendet, leider nur mit generischer PHY-Unterstützung.

Problem

Mit Default-Setup durch den generischen PHY-Treiber erfolgt der Aufbau eines Links nicht reproduzierbaren Verzögerungen unterworfen. Die Probleme ließen sich mit beliebigen Gegenstellen (Cisco-Switches, Netgear-Hubs, Ethernet-NICs) nachvollziehen; oft ist auch nach Stunden noch kein Link zwischen den Partnern ausgehandelt.

Lösungsansätze

Ursachen für die Probleme, einen Link auszuhandeln, konnten trotz diverser Vermutungen noch nicht eindeutig bestimmt werden. Abhilfe schafft das Abschalten der Autonegotiation und Festlegen der Parameter der Teridian-PHY auf 100 MBit, Full Duplex. Dieser Baustein besitzt 24 16 bit breite Steuer- und Statusregister.

In der PHY muss dafür Register MR0 mit dem Wert 0x2100 beschrieben werden. Bits: 12=0 (ANEGEN) verhindert Autonegotiation, 13=1 (SPEEDSL) setzt 100Base-TX und 8=1 (DUPLEX) Full-Duplex-Modus. Die restlichen Bits sind hier bewusst auf 0 gesetzt, der Wert wird ohne weitere Maskierung direkt in das Register übernommen.

Zum Ansprechen der Register ist die PHY über ein MDIO-Interface an den ARM-Controller angeschlossen, der die Kommunikation auf das interne Register EMAC_MAN ("Phy Maintenance Register") im Ethernet-Subsystem abbildet, Adresse 0xFFFC4034. Die MDIO-Bus-ID der PHY ist 1 (später in den Codebeispielen zu sehen).

Über EMAC_MAN-Zugriffe lassen sich einzelne Schreib- und Lesebefehle an die PHY absetzen. Das Register-Layout ist im Prozessorhandbuch (Kapitel 35.5.12) mit den erforderlichen Default-Werten beschrieben.


Via Bootmonitor

Bootvorgang (bei Countdown) mit beliebiger Taste anhalten, Prompt erscheint. help mii erläutert die mii-Kommandos, die die PHY-Kommunikation komfortabel abstrahieren.

Setzen von 100TX/FDX, zu beachten ist die Bus-ID 1 der PHY auf dem PicoCOM1 (Parameter: read/write, Bus-ID Registernummer, Wert):

mii write 1 0 2100


Um die PHY-Initialisierung bei jedem Bootvorgang durchzuführen, kann die Variable bootcmd um diesen Befehl erweitert werden:

setenv bootcmd "mii write 1 0 2100 ; nboot 0x21000000 0 0x100000 ; bootm 0x21000000"

Anschließend mit

saveenv 

abspeichern, sonst gehen die Variableninhalte beim Reset wieder verloren!

Problem hierbei: Funktioniert nur, bis der Kerneltreiber seinerseits die PHY neu initialisiert; in diesem Moment geht der Link wieder verloren und es wird erneut eine (selten erfolgreiche) Autonegotiation versucht. Eine nützliche bzw. notwendige Maßnahme ist die Initialisierung auf Bootloader-Ebene jedoch, wenn der Kernel via tftp geladen werden soll.

Anmerkung: ist der Kernel wie oben angenommen im Flash-ROM abgelegt, ist ein Ethernet-Link während des Bootstrappings nur für Debugging-Zwecke vom Bootloader-Prompt erforderlich.


Via ioctl

Ist der Kernel soweit gebootet, dass aus dem Userspace z.B. von durch init gestartete Prozesse ioctl()-Aufrufe abgesetzt werden können, bietet sich diese Variante an, um die PHY zu beeinflussen. Der macb-Kerneltreiber unterstützt die ioctl-Kommandos SIOCGMIIREG (Get/Lesen) und SIOCSMIIREG (Set/Schreiben), um Befehle an die PHY durchzureichen bzw. Register zu schreiben/zu lesen.

Minimalistisches Beispiel, um einen Wert zu lesen:

#include <sys/ioctl.h>
#include <net/if.h>  
#include <linux/mii.h>
#include <linux/sockios.h>

void main(void)
{
  struct ifreq ifr;
  memset(&ifr, 0, sizeof(ifr));
  strcpy(ifr.ifr_name, "eth0"); 
  struct mii_ioctl_data* mii = (struct mii_ioctl_data*)(&ifr.ifr_data);
  mii->phy_id = 1; // ID der PHY
  mii->reg_num = 18; // Registernummer, z.B. 18 fuer Diagnostic
  mii->val_in = 0; // wird für SIOCSMIIREG (schreiben) verwendet
  mii->val_out = 0;

  int fd = socket(AF_INET, SOCK_DGRAM, 0); // beliebiger INET-Socket
  int err = ioctl(fd, SIOCGMIIREG, &ifr); // SIOCGMIIREG = read
  printf("PHY register 23: 0x%04x\n", mii->val_out);
}


Via Kerneltreiber-Patch

Um einen Elinos-Kernel mit einem Patch zu versehen, muss nur ein Elinos-Projekt gecloned werden, um dort Schattenkopien der geänderten Kernelquelldateien im kernelsrc/-Unterverzeichnis anzulegen. Der Dateibaum unterhalb kernelsrc/ verdrängt als Overlay während des Elinos-Buildprozesses (make boot) gleichnamige Quelldateien aus dem Kernel-Grundquellen bzw. den Elinos- oder BSP-Overlay-Quellebenen.

Zum Patchen des macb-Treibers genügt es also, in einem Elinos-Projekt die Dateien kernelsrc/drivers/net/macb[.c|.h] als Kopien der Originalquellen anzulegen und anzupassen. Das mit make boot erzeugte Kernelimage boot/pImage enthält dann den Patch. Anschließend das Kernelimage unter neuem Namen in /tftpboot kopieren und /etc/bootptab anpassen und killall -HUP bootpd.

Innerhalb macb.c kann z.B. macb_mdio_write() verwendet werden, um auf PHY-Register zuzugreifen:

macb_mdio_write(&bp->mii_bus, 1, 0, 0x2100);

Diese Initialisierung auf 100TX/FDX kann in macb_open() am Ende eingefügt werden.

Testen im Bootmonitor: PHY von Hand patchen, Kernel via tftp laden (wird in RAM ab Adresse 0x21000000 geladen) und von dort booten.

mii write 1 0 2100
dhcp
bootm 0x21000000

Zum Vergleich der übliche Bootvorgang, bei dem zunächst das im Flash-ROM abgelegte Kernelimage ins RAM kopiert wird:

nboot 0x21000000 0 0x100000
bootm 0x21000000

Status

Kernelpatch ist momentan als Lösung favorisiert. Bootmonitor-Patch funktioniert reproduzierbar und führt zu kurzfristigem Zustandekommen des Links, Patch auf Kernel-Ebene läuft manchmal in ein Timeout, nach dem ein automatisch re-open() des macb-Treibers erfolgt, bei dem schließlich ein Link zustande kommt.

Das bootcmd wurde auf den PicoCOM1-Targets für den Ablauf PHY-Fixup/Kernel via tftp laden/Kernel booten angepasst:

mii write 1 0 2100
sleep 4
dhcp
bootm 0x21000000

Die sleep-Zeile musste eingefügt werden, weil das dhcp-Kommando Autonegotiation aktiviert, wenn kein Link besteht. Durch die eingefügte Pause kann sich der Link etablieren, bevor die dhcp-Zeile ausgeführt wird, vier Sekunden ist nach ersten Beobachtungen ein brauchbarer Kompromiss zwischen Bootverzögerung und ausreichender Zeitspanne für den Linkaufbau.

Auf den zugeordneten Host-PCs liegt das Kernelimage mit o.g. Patch unter /tftpboot/arm_26_pImage_macb und wird von /etc/bootptab bei BOOTP Anfrage des Targes angeboten. Der entsprechende bootptab-Eintrag:

arm_targetpico:\
       :hd=/tftpboot:\
       :rp=/tftpboot/nfsroot_arm26:\
       :ht=ether:\
       :ha=00055101a399:\
       :hn:\
       :ip=arm_targetpico:\
       :sa=ezbs09.ezbs.fh-wiesbaden.de:bf=arm_26_pImage_macb: