RTL8169

Aus Lowlevel
Wechseln zu:Navigation, Suche

Der RTL8169 ist neben dem RTL8139 ein weiterer Netzwerkchip der Firma Realtek. Er kann Daten im Bereich von 10/100/1000 Megabits pro Sekunde übertragen. Der Chip RTL8168 ist als PCI-Express-Version nahezu identisch anzusteuern.

Initialisierung

PCI

Die Karte unterstützt die PCI-Funktionen Fast Back-to-Back Transactions sowie Memory Write and Invalidate. Diese können im PCI-Command-Register aktiviert werden. Die RTL8168 kann Message Signaled Interrupts (MSI) unterstützen. Die entsprechenden Informationen stehen dann in der PCI-Capabilities-Liste.

IO/MMIO

RTL8168 und RTL8169 unterstützen MMIO. Die Basisadresse kann über die PCI-BARs ausgelesen werden. Sollten mehrere MMIO-BARs angegeben sein, ist die erste zu nutzen. Im Folgenden wird die Karte über IO-Ports angesteuert, für eine Ansteuerung über MMIO kann analog vorgegangen werden.

Die Offsets der im Folgenden verwendeten Register sind wie folgt definiert: <c>

  1. define RTL8168_IDR0 0x00 // Mac address
  2. define RTL8168_TXDESC 0x20 // Tx descriptors (32bit)
  3. define RTL8168_RXDESC 0xE4 // Tx descriptors (32bit)
  4. define RTL8168_CHIPCMD 0x37 // Command register
  5. define RTL8168_TPPOLL 0x38 // Transmit Priority Polling
  6. define RTL8168_INTRMASK 0x3C // Interrupt mask
  7. define RTL8168_INTRSTATUS 0x3E // Interrupt status
  8. define RTL8168_TXCONFIG 0x40 // Tx config
  9. define RTL8168_RXCONFIG 0x44 // Rx config
  10. define RTL8168_RPS 0xDA // Max Receive Packet Size
  11. define RTL8168_ETTHR 0xEC // Early transmit threshold

</c>

MAC-Adresse herausfinden

Die 6 Bytes lange MAC-Adresse des Geräts kann aus den ersten 6 Registern (ausgehend von der o.g. Basisadresse) ausgelesen werden:

<c>char mac_addr[6]; for(int i = 0; i < 6; ++i) {

   mac_addr[i] = inb(port_base + RTL8168_IDR0 + i); // Funktion zum Einlesen eines Bytes vom angegebenen Port

} </c>

Reset

Durch das Setzen von Bit 8 im Command-Register (0x37) wird ein Reset der Karte ausgelöst. Der Abschluss des Vorgangs wird von der Karte mit dem Löschen dieses Bits quittiert.

Transfer-Deskriptoren

Sende- und Empfangsdeskriptoren sind wie folgt definiert: <c> typedef struct {

   uint32_t command;  // command/status dword
   uint32_t vlan;
   uint32_t low_buf;  // low 32-bits of physical buffer address
   uint32_t high_buf; // high 32-bits of physical buffer address

} __attribute__((packed)) RTL8168_Desc; </c>

Die Deskriptoren sind an 256-Bytes-Grenzen auszurichten und bilden einen Ring, dessen Ende durch das Setzen von Bit 30 des command-Felds indiziert wird. In dieses Feld werden außerdem die Länge des Puffers (Bits 0-15) so wie das OWN-Bit (Bit 31) geschrieben. Die Sende- bzw. Empfangspuffer können maximal 64 KiB groß sein (allerdings kann die Karte höchstens 16 KiB große Pakete empfangen), ihre physische Adresse wird in low_buf und high_buf gespeichert. Die Puffer sind an 8-Bytes-Grenzen auszurichten.

Die Karte verfügt über drei Ringe von je maximal 1024 Deskriptoren, einen Empfangsring, einen Sendering mit normaler und einen Sendering mit hoher Priorität (letzterer ist analog zum normalen Sendering anzusteuern; im Folgenden wird nur auf den normalen Sendering eingegangen).

Konfiguration

Dieser Beispielcode konfiguriert die Karte für das Senden und Empfangen von Paketen. Hierbei wird die Karte in den sog. "promiscuous mode" gesetzt, in dem alle Pakete akzeptiert werden, auch solche, die nicht an das Gerät gerichtet sind. Weiterhin werden Interrupts aktiviert. <c> outl(port_base + RTL8168_RXCONFIG, 0x0000E70F); // RxConfig = Rx FIFO threshold: no; Max DMA burst size: unbeschränkt; Promiscuous mode outb(port_base + RTL8168_CHIPCMD, 0x04); // Aktiviere Tx, bevor TxConfig gesetzt wird outl(port_base + RTL8168_TXCONFIG, 0x03000700); // TxConfig = InterFrameGap time: normal, Max DMA burst size: unbeschränkt outw(port_base + RTL8168_RPS, 0x1FFF); // Maximale Größe empfangener Pakete (hier: 8 KiB) outb(port_base + RTL8168_ETTHR, 0x3F); // Early transmit threshold: Keine vorzeitige Übertragung

outl(port_base + RTL8168_TXDESC, paging_getPhysAddr(rAdapter->Tx_Descriptors)); // Adresse des ersten Tx-Descriptors (normale Priorität) outl(port_base + RTL8168_RXDESC, paging_getPhysAddr(rAdapter->Rx_Descriptors)); // Adresse des ersten Rx-Descriptors

outw(port_base + RTL8168_INTRMASK, 0xC3FF); // Aktiviere alle Interrupts outb(port_base + RTL8168_CHIPCMD, 0x0C); // Aktivere Senden und Empfangen </c>

Senden

Um ein Paket zu senden, sind zunächst die Parameter im command-Feld des Sendedeskriptors zu setzen. Hierbei sind das OWN-Bit, Bits 28 und 29 zu setzen und die Länge des Pakets in Bits 0-15 zu schreiben. Durch das Schreiben von Bit 6 in das Transmit-Priority-Polling-Register wird der Karte das Vorliegen eines zu sendenen Pakets mitgeteilt.

RTL8168 und RTL8169 können, um die CPU zu entlasten, die Prüfsummen der wichtigsten Protokolle selbst berechnen. Um diese Funktion zu verwenden, ist das Prüfsummenfeld im Protokollheader zu löschen und stattdessen das entsprechende Bit im command-Feld des Sendedeskriptors zu setzen. Unterstützt werden IPv4 (Bit 18), UDP (Bit 17) und TCP (Bit 16). Neuere Varianten dieser Netzwerkkarte beherrschen auch IPv6.

Empfangen

Ist bei einem Interrupt Bit 0 des Interrupt-Statusregisters gesetzt, hat die Karte ein Paket empfangen. Es ist nun durch den Ring der Empfangsdeskriptoren zu iterieren und nach Deskriptoren zu suchen, deren OWN-Bit gelöscht ist. Die Länge des empfangenen Pakets steht in Bits 0-15 des command-Felds. Nach Nutzung der empfangenen Daten ist der Deskriptor wieder in den Ursprungszustand (OWN-Bit gesetzt, Länge des Puffers in Bits 0-15 des command-Felds) zu versetzen.

Weblinks