This is an old revision of the document!

Table of Contents

Week 2

Day 1

Git commit: 318ca039b7381e67e04f92447d9b2a211fe9541a

Today was about reorganizing parts of what I've written so far and taking some time to analyze things and try to see the big picture. Also, I did some debugging in the Linux driver (insert printks, make modules, make modules_install, modprobe -r pcnet32, modprobe pcnet32) and found out that even that one takes an unneeded branch at one point and tries to modify some registers that aren't available on older chips. Since the datasheets say that accessing inexistent registers might summon some nasty demons, I avoided this in my code. It could be that those accesses do some undocumented stuff, but for now I'll keep this in mind and see how things turn out when the driver is all done.

Other than that, I'm all set up for tackling the transmit and receive parts, which I'll start tomorrow.

Day 2

Git commit: 04d57225b1c06fa6c37f7565ed9b2977580a29e0

As I suspected, the transmit and receive were easier than the NIC's setup. I managed to implement both of them today, following the r8169 driver source code.

Transmit works by first giving you an struct io_buffer. It is the transmit routine's responsibility to fill the current available descriptor's fields with the iobuf's parameters (length, start address). Then you have to change the descriptor's ownership to 1 to signal that it now contains valid information and the NIC should send the data that it describes. After this, the routine forces the NIC to send any new valid descriptors by setting the TDMD (Transmit Demand) bit. I suppose it works without this setting since the datasheet mentions that there is a poll-time counter that eventually elapses. In the end, all you have to do is make sure that the circular descriptor buffer is handled, by advancing the cursor and increasing the number of descriptors in use.

The .poll routine has to check first if there are any new received frames or if some frames have finished being transmitted by the NIC.

  • The transmitted frames now have the OWN bit from the descriptor set to 0 thus signalling that the NIC is done with their processing. To cleanup the buffer, it uses the netdev_tx_complete() routine, resets the descriptor, advances the tail of the circular buffer and decreases the total used descriptor count.
  • The received packets have a similar fate. One of the differences is the fact that you have to see if there weren't any errors in the frame's receival such as a CRC, framing or overflow errors. If there is such an error, the frame is discarded using netdev_rx_err. If there was no error first use iob_put to adjust the iobuffer's length if required and finally send the frame to the upper layers using netdev_rx. Since the buffer is out of our hands now the driver is free to remove any references it might have had to it and clear the descriptor, plus advance the cursor. As a result, the driver has to allocate new buffers for all the descriptors that were valid and which got their frames sent to the upper layers. This is the final thing the driver has to do.

After all this was done, I tested the driver on my VMWare setup, and after fixing some bugs I managed to get it working. In the end, I've booted a DSL using my driver :) Yay.

In the next few days I'll spend some time cleaning up the code and rearranging stuff.

QR Code
QR Code soc:2010:andreif:journal:week2 (generated for current page)