972
edits
[unchecked revision] | [unchecked revision] |
m (Bot: Replace deprecated source tag with syntaxhighlight) |
|||
(21 intermediate revisions by 14 users not shown) | |||
Line 1:
'''Programming Guide for the RTL8169(S)-32/64 Network Interface Chipsets'''
The RTL8169 is Realtek's next generation of high-performance network cards. This particular chipset is designed to operate at 10/100/1000 Mbps speeds.
== Identification ==
The basic interface for the RTL8169 series is common in several Realtek network cards. This applies to the following noncomprehensive list of PCI Vendor and Device IDs from FreeBSD's re driver:
* 10ec:8161
* 10ec:8168
* 10ec:8169
* 1259:c107
* 1737:1032
* 16ec:0116
== Basic Startup ==
Line 9 ⟶ 16:
=== Get the MAC Address ===
First
ex:
<syntaxhighlight lang="c">
char i;
for (i = 0; i < 6; i++)
{▼
}
</syntaxhighlight>
=== Reset the Chip ===
It is necessary to reset the RTL8169 to put the registers in a known default state, as well as begin powering up the chip. We need to send the reset command to Chip Command register at offset 0x37. The reset bit is at offset 0x10,
ex:
<syntaxhighlight lang="c">
outportb(ioaddr + 0x37, 0x10); /*set the Reset bit (0x10) to the Command Register (0x37)*/
while(inportb(ioaddr + 0x37) & 0x10)
;/*setting a timeout could be useful if the card is problematic*/
</syntaxhighlight>
== Setting up the Rx Descriptors ==
One of the new features introduced with this new-gen chip is that it is completely
Rx Descriptors are used to tell the NIC where to put packets once
====Descriptor format====
▲Rx Descriptors are used to tell the NIC where to put packets once recieved. Because this is an asyncronous operation, we must setup the descriptors before we enable the reception of packets so that the NIC knows where to put things. A major function of descriptors is to tell the NIC which descriptors are owned by the OS (host) and which ones are owned by the NIC. If the descriptor is owned by the NIC, the NIC can then read it and use it for the next packet it recieves, if not, it either skips over it or sends a RDU (Rx Descriptor Unavailable) interrupt and halts all further Rx operations. Because there can be multiple descriptors used, there is also a EOR (End of Rx descriptor Ring) bit used when the NIC has reached the end of the descriptors and needs to loop back to the beginning of the descriptors. There is one more big 'gotcha' with all of this, the beginning of the descriptor arrays must be aligned on a 256-byte boundary.
{| {{wikitable}}
! Offset
! Name
! Description
|-
| dword 0 || Flags || 31 bit=OWN (if set, card own this descriptor) 30 bit=EOR (last descriptor in list)
|-
| dword 1 || VLAN || Unused
|-
| dword 2 || Pointer to buffer low 32 bits ||
|-
| dword 3 || Pointer to buffer high 32 bits ||
|-
|}
====Code example====
<syntaxhighlight lang="c">
struct Descriptor {
▲ {
};
Line 44 ⟶ 74:
{
/* rx_buffer_len is the size (in bytes) that is reserved for incoming packets */
unsigned int OWN = 0x80000000, EOR = 0x40000000; /*
int i;
for(i = 0; i < num_of_rx_descriptors; i++) /* num_of_rx_descriptors can be up to 1024 */
{
if(i == (num_of_rx_descriptors - 1)) /*
else
/* VLAN adjustments are not part of this guide at the moment - leave as zeros for normal operation */
Rx_Descriptors[i].low_buf = (unsigned int)&packet_buffer_address; /*
/*
}
}
</syntaxhighlight>
== Configuring RxConfig and TxConfig ==
Line 66 ⟶ 97:
eg:
<syntaxhighlight lang="c">
outportl(ioaddr + 0x40, 0x03000700); /* IFG: normal, MXDMA: unlimited */
</syntaxhighlight>
=== RxConfig ===
The
eg:
<syntaxhighlight lang="c">
outportl(ioaddr + 0x44, 0x0000E70F) /* RXFTH: unlimited, MXDMA: unlimited, AAP: set (promisc. mode set) */
</syntaxhighlight>
== Max Packet Sizes ==
=== Max Transmit Packet Size ===
The MTPS register is located at offset 0xEC and is used for setting the maximum packet size that can be transmitted from the RTL8169. The
eg:
<syntaxhighlight lang="c">
outportb(ioaddr + 0xEC, 0x3B); /*
</syntaxhighlight>
=== Receive Packet Maximum Size ===
The RMS register is located at offset 0xDA and is used for setting the maximum packet size that can be
eg:
<syntaxhighlight lang="c">
outportw(ioaddr + 0xDA, 0x1FFF); /*
</syntaxhighlight>
== Full Reset Example ==
This is a barebones example of how to reset the RTL8169 without anything like auto-negotiation (explained later) or (G)MII interactions.
eg:
<syntaxhighlight lang="c">
struct Descriptor
{
};
/**
* Note that this assumes 16*1024=16KB (4 pages) of physical memory at 1MB and 2MB is identity mapped to
* the same linear address range
*/
struct Descriptor *Rx_Descriptors = (struct Descriptor *)0x100000; /* 1MB Base Address of Rx Descriptors */
struct Descriptor *Tx_Descriptors = (struct Descriptor *)0x200000; /* 2MB Base Address of Tx Descriptors */
Line 111 ⟶ 152:
for(i = 0; i < num_of_rx_descriptors; i++) /* num_of_rx_descriptors can be up to 1024 */
{
if(i == (num_of_rx_descriptors - 1)) /*
else
Rx_Descriptors[i].low_buf = (unsigned int)&packet_buffer_address; /* this is where the packet data will go */▼
/** packet_buffer_address is the *physical* address for the buffer */
/* if you are programming for a 64-bit OS, put the high memory location in the 'high_buf' descriptor area */▼
▲ Rx_Descriptors[i].low_buf = (unsigned int)&packet_buffer_address;
Rx_Descriptors[i].high_buf = 0;
▲ /*
}
}
Line 125 ⟶ 169:
unsigned char mac_address[6];
outportb(ioaddr + 0x37, 0x10); /*
while(inportb(ioaddr + 0x37) & 0x10){} /*
for (i = 0; i < 6; i++)
setup_rx_descriptors();
outportb(ioaddr + 0x50, 0xC0); /*
outportl(ioaddr + 0x44, 0x0000E70F); /* RxConfig = RXFTH: unlimited, MXDMA: unlimited, AAP: set (promisc. mode set) */
outportb(ioaddr + 0x37, 0x04); /* Enable Tx in the Command register, required before setting TxConfig */
outportl(ioaddr + 0x40, 0x03000700); /* TxConfig = IFG: normal, MXDMA: unlimited */
outportw(ioaddr + 0xDA, 0x1FFF); /*
outportb(ioaddr + 0xEC, 0x3B); /* max tx packet size */
/* offset 0x20 == Transmit Descriptor Start Address Register
offset 0xE4 == Receive Descriptor Start Address Register
outportl(ioaddr + 0x20, (unsigned long)&Tx_Descriptors[0]; /* tell the NIC where the first Tx descriptor is */▼
Again, these are *physical* addresses. This code assumes physical==linear, this is
outportl(ioaddr + 0xE4, (unsigned long)&Rx_Descriptors[0]; /* tell the NIC where the first Rx descriptor is */▼
typically not the case in real world kernels
▲ */
▲ outportl(ioaddr + 0x20, (unsigned long)&Tx_Descriptors[0]; /*
▲ outportl(ioaddr + 0xE4, (unsigned long)&Rx_Descriptors[0]; /*
outportb(ioaddr + 0x37, 0x0C); /*
outportb(ioaddr + 0x50, 0x00); /*
}
</syntaxhighlight>
== External Links ==
* http://
[[Category:Network
[[Category:Standards]]
|