RTL8169: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
No edit summary
No edit summary
Line 54: Line 54:
}
}
}
}

== Configuring RxConfig and TxConfig ==
=== (Un)locking Registers ===
In order to use some critical registers, we must 'unlock' them to alter their states and then 'lock' them after we are done to prevent accidental alterations to those registers during operation. The 9346CR register is at offset 0x50 and is used as a key to those critical registers. In order to 'unlock' them, we must set the card in "Config register write enable" mode. This is done by setting both the EEM (operating mode) bits. Once that has been done, it is then ok to finish setting up the card. Once configuration is done and the OS begins proceeding as normal, the EEM bits should be set low to set the card in "normal" mode and lock the config registers.


== External Links ==
== External Links ==

Revision as of 18:18, 15 July 2008

This page is a stub.
You can help the wiki by accurately adding more contents to it.

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.

Basic Startup

Get the MAC Address

First thing's first, we need to get the NIC's physical MAC address. Normally we should go through the EEPROM to access the MAC address, but in this case we will take a shortcut and obtain the address from the MAC0-6 registers. The MAC registers start at offset 0x00 and should be accessed in 8-bit segments.

ex:

char i;
for (i = 0; i < 6; i++)
{mac_address[i] = inportb(ioaddr + i);} /*ioaddr is the base address obtainable from the PCI device configuration space.*/ 

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, therefor we need to do an 'outportb' using those offsets to tell the chip to begin the resetting process. Once we have sent that command, it will take some time for the chip to complete the operation, and because it is altering registers we should stop all further writes/reads to registers until it has completed. The reset bit in the Command Register will self-clear once the operation is finished, that's what we should check for before proceeding setting up the chip.

ex:

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*/

Setting up the Rx Descriptors

One of the new features introduced with this new-gen chip is that it is completely desriptor-based. The chip supports up to 3 unique descriptor sets with 1024 desriptors available per set; 1024 for recieving packets, 1024 for normal transmission, and 1024 for high-priority transmission packets. It is not required to use all of the descriptors per set, or even use all three sets. Each descriptor is 16-bytes wide and contains a 64-bit buffer address (to store data for transmission or to tell the reception process where to dump the data) and Command double-word.

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.

eg:

struct Descriptor
{
    unsigned int command, 
                 vlan,
                 low_buf,
                 high_buf; 
};
struct Descriptor *Rx_Descriptors = (struct Descriptor *)0x100000; /* 1MB Base Address of Rx Descriptors */
void setup_rx_descriptors()
{
    /* rx_buffer_len is the size (in bytes) that is reserved for incoming packets */
    unsigned int OWN = 0x80000000, EOR = 0x40000000; /* bit offsets */
    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)) /* last descriptor? if so, set the EOR bit */
        {Rx_Descriptors[i].command = (OWN | EOR | (rx_buffer_len & 0x3FFF));}
        else
        {Rx_Descriptors[i].command = (OWN | (rx_buffer_len & 0x3FFF));}
        Rx_Descriptors[i].low_buf = (unsigned int)&packet_buffer_address; /* this is where the packet data will go */
        /* if you are programming for a 64-bit OS, put the high memory location in the 'high_buf' descriptor area */
    }
}

Configuring RxConfig and TxConfig

(Un)locking Registers

In order to use some critical registers, we must 'unlock' them to alter their states and then 'lock' them after we are done to prevent accidental alterations to those registers during operation. The 9346CR register is at offset 0x50 and is used as a key to those critical registers. In order to 'unlock' them, we must set the card in "Config register write enable" mode. This is done by setting both the EEM (operating mode) bits. Once that has been done, it is then ok to finish setting up the card. Once configuration is done and the OS begins proceeding as normal, the EEM bits should be set low to set the card in "normal" mode and lock the config registers.

External Links