Search code examples
network-programmingoperating-systemnic

What are NIC MMIO regions used for?


I'm confusing about the usage of NIC (Network interface card) MMIO regions.

For example, this is the information of a NIC on my computer

03:02.1 Ethernet controller: Intel Corporation 82546EB Gigabit Ethernet Controller (Copper) (rev 03)
    Subsystem: Intel Corporation PRO/1000 MT Dual Port Server Adapter
    Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
    Status: Cap+ 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
    Latency: 64 (63750ns min), Cache Line Size: 64 bytes
    Interrupt: pin B routed to IRQ 19
    Region 0: Memory at e1b00000 (64-bit, non-prefetchable) [size=128K]
    Region 2: Memory at e1a40000 (64-bit, non-prefetchable) [size=256K]
    Region 4: I/O ports at 2000 [size=64]
    Expansion ROM at e1a00000 [disabled] [size=256K]
    Capabilities: <access denied>
    Kernel driver in use: e1000
    Kernel modules: e1000

I can see that it has 2 MMIO regions.

At first I think that these 2 regions are used for receiving and sending packets, one is the RX buffer and another is the TX buffer, but after doing some test, I think that I was wrong.

So, what actually these MMIO regions are used for? And if they not the TX and RX buffers, where are these buffers?

Thanks.


Solution

  • These are memory base address registers (BARs). Here is an OSDev explanation for the concept. Memory BARs usage is device-dependent and might be a subject for a separate talk. For instance, a PCI device may have a small BAR to provide access to whatever registers it has. Also, certain parts of device RAM may be exposed by means of larger BARs.

    Your question is about NIC, so, indeed, one of the BARs in your example is a base HW address where NIC registers reside. e1000 driver can query the address during PCI resource allocation step (it's a long talk, but, all in all, a suitable address resides in hw_addr field of struct e1000_hw). And, during its operation, e1000 may read from some registers or write to them using the mentioned address + some offset. You can find offsets for different registers defined in the corresponding header. For instance, when the driver needs to manage, say, Tx ring, it may query/update its head or tail using the proper registers. For example, you may take a look at how the driver writes zeroes there.

    You also asked about Rx and Tx buffers location. It's not quite clear whether you mean data buffers. If so, I'm afraid, lspci may not be helpful since actually packet data is received and transmitted using host memory buffers and DMA (direct memory access) technique. For instance, if the driver wants to transmit a packet, it obtains the physical address of the buffer where the packet is stored (host memory) and prepares a so-called descriptor by setting the packet buffer address in it. The descriptor is then pushed to the device. As soon as the NIC gets the descriptor, it will initiate a DMA transaction, i.e. it will place a memory access request directly on the host memory and eventually it will read in the contents of the buffer to be transmitted.

    So, I hope you find my short answer to be at least a little bit useful. And, of course, you may learn more from the driver source and some HW-related documents.