AMD PCNET: Difference between revisions

Jump to navigation Jump to search
m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
m (fix a small typo)
m (Bot: Replace deprecated source tag with syntaxhighlight)
Line 12:
In the PCI configuration space, the card has vendor ID 0x1022 and device ID 0x2000. A separate similar device (PCnet-PCI III and clones) has device ID 0x2001 and is programmed similarly.
 
The first task of the driver should be to enable the IO ports and bus mastering ability of the device in PCI configuration space. This is done by setting bits 0 and 2 of the control register, e.g. <sourcesyntaxhighlight lang="c">uint32_t conf = pciConfigReadDWord(bus, slot, func, offset);
conf &= 0xffff0000; // preserve status register, clear config register
conf |= 0x5; // set bits 0 and 2
pciConfigWriteDWord(bus, slot, func, offset, conf);</sourcesyntaxhighlight>
 
You will then want to read the IO base address of the first BAR from configuration space. We will assume this has the value io_base.
Line 46:
|}
 
In addition, the card requires different length data accesses to the registers depending on the setting of DWIO: if DWIO=0, then offsets 0x0 through 0xf are read as single bytes, all others read/written as 16-bit words; if DWIO=1, then all registers (including 0x0 through 0xf) are read/written as 32-bit double words (and with accesses aligned on 32-bit boundaries). We can write functions to access the registers:<sourcesyntaxhighlight lang="c">void writeRAP32(uint32_t val)
{
outd(io_base + 0x14, val);
Line 78:
writeRAP16(csr_no);
outw(io_base + 0x10, val);
}</sourcesyntaxhighlight>
and similar functions for BCRs.
 
Unfortunately it is difficult to determine the current state of DWIO (and therefore know which state the card is in when the driver initializes) as the only way of reporting it is to read BCR18 bit 7, which in turn requires knowledge of the BDP, which requires knowledge of DWIO etc. Fortunately, following a reset (either hard or soft), the card is in a known state with DWIO=0 (16-bit access). Normally, therefore, when your driver takes control of the card, it would expect to assume it is in 16-bit mode. However, it may be the case that firmware or a boot-loader has already initialized the card into 32-bit mode, which you didn't know about. You should, therefore, reset the card when your driver takes control. This is accomplished by a read of the reset register:<sourcesyntaxhighlight lang="c">ind(io_base + 0x18);
inw(io_base + 0x14);</sourcesyntaxhighlight>Note this snippet reads first from the 32-bit reset register: if the card is in 32-bit mode this will trigger a reset, if in 16-bit mode it will simply read garbage without affecting the card. It then reads from the 16-bit reset register: if the card was initially in 32-bit mode, it has since been reset and will now be reset again, otherwise it will reset for the first time.
 
You should now wait 1 microsecond for the reset to complete (using your OSs timing functions).
 
Then, if desired, you can program the card into 32-bit mode (the rest of this article assumes this, but you can easily substitute read/writeCSR32 with read/writeCSR16 if you like). To do this, we simply need to perform a 32 bit write of 0 to the RDP. After reset, RAP points to CSR0, so we are effectively writing 0 to CSR0. This will not cause any harm as we completely reprogram CSR0 later anyway.<sourcesyntaxhighlight lang="c">outd(io_base + 0x10, 0);</sourcesyntaxhighlight>
 
=== Interrupt handling ===
Line 94:
=== SWSTYLE ===
 
We now need to set the value of SWSTYLE to 2. After reset, it defaults to 0 representing 16-bit legacy compatibility mode. We want the card to be able to access all of the first 4 GiB of (physical) memory for its buffers, so need to set it to 32-bit mode.<sourcesyntaxhighlight lang="c">uint32_t csr58 = readCSR32(58);
csr58 &= 0xFF00; // SWSTYLE is 8 bits (7:0)
csr58 |= 2;
writeCSR32(58, csr58);</sourcesyntaxhighlight>
 
=== ASEL ===
 
The card has both 10/100baseT and coaxial outputs. It has functionality to automatically select whichever is attached which is normally enabled by default. This snippet simply ensures this functionality is enabled by setting the ASEL bit in BCR2 just in case firmware has altered this for some reason.<sourcesyntaxhighlight lang="c">uint32_t bcr2 = readBCR32(2);
bcr2 |= 0x2;
writeBCR32(2, bcr2);</sourcesyntaxhighlight>
 
=== Ring buffers ===
Line 239:
Sending packets involves simply writing the packet details to the next available transmit buffer, then flipping the ownership for the particular ring buffer entry to the card. The card regularly scans all the transmit buffers looking for one it hasn't sent, and then will transmit those it finds.
 
For example:<sourcesyntaxhighlight lang="c">int sendPacket(void *packet, size_t len, uint8_t *dest)
{
// the next available descriptor entry index is in tx_buffer_ptr
Line 278:
// update the next transmit pointer
tx_buffer_ptr = nextTxIdx(tx_buffer_ptr);
}</sourcesyntaxhighlight>
 
== Handling interrupts and receiving packets ==
Line 286:
Note that interrupts can come from many sources (other than new packets). If a new packet has been signaled then CSR0 bit 10 will be set. There are other bits in CSR0 than can be set (depending on how you set up interrupt masks in CSR3) and additionally other bits in CSR4 that can signal interrupts (although these are usually masked out on reset). After you have properly handled an interrupt, you will need to write a 1 back to the appropriate bit in CSR0 or CSR4 before sending EOI to you interrupt controller (or the interrupt will continue to be signaled). Bitwise OR CSR0 with 0x7F00 and bitwise OR CSR4 with 0x022A will reset all interrupts. Remember to preserve bit 6 in CSR0 and bit 11 in CSR4.
 
Once a receive packet interrupt has been received, you need to loop through the receive descriptor entries (starting at rx_buffer_ptr) handling each packet until you find an entry which the driver doesn't own, then stop. e.g. <sourcesyntaxhighlight lang="c">void handleReceiveInterrupt()
{
while(driverOwns(rdes, rx_buffer_ptr))
Line 315:
 
// don't forget to send EOI
}</sourcesyntaxhighlight>
 
== Important Registers ==
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu