Receiving packets on the i219-V

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Janworks
Posts: 3
Joined: Tue Sep 25, 2018 9:36 am
Location: Germany

Receiving packets on the i219-V

Post by Janworks »

Hello,

I am currently working on a driver for the i219-V network card. While there unfortunately is little documentation on its software interface, I was able to figure out most of its functionality using old manuals and Intel's official e1000e driver; after understanding the relation between the PCH and PHY things are quite similar to older e1000 cards. At this point my driver is able to transmit packets on real hardware, as I successfully tested with a hand-crafted ARP packet and Wireshark.

Unfortunately, receiving does not work. I already tried debugging that problem by printing the configuration and status registers; but from my point of view, the respective flags seem to be correct. The various statistics registers did not change, even when I was sure that the card *must* have received a packet (e.g. when getting the ARP response). Manually examing the receive descriptor ring did not show anything, too. Right now it looks like the PHY never receives packets, either because there is some misconfiguration on a very low level or the packet filtering is not properly initialized.

I've already checked with the e1000e driver, but it implements very many features and thus makes it easy to miss something important. Intel's driver seems to be doing a full hardware reset on startup; but since transmitting works already, I hope to avoid this.

I put the working parts of my code into a Wiki article draft; I will be happy to turn it into a full Wiki article, since digging through the documentation took me a lot of time.

The receiving code looks like this:

Code: Select all

// Allocate receive data buffer
uint64_t rxBufferMemPhy;
rxBufferMem = heap_alloc_contiguous(RX_DESC_COUNT * RX_BUFFER_SIZE, VM_R | VM_W, &rxBufferMemPhy);
if(!rxBufferMem)
    panic("Could not allocate i219 receive data buffer.");

// Allocate and initialize receive descriptor buffer
uint64_t rxDescriptorsPhy;
rxDescriptors = heap_alloc_contiguous(RX_DESC_COUNT * sizeof(rx_desc_t), VM_R | VM_W, &rxDescriptorsPhy);
if(!rxDescriptors)
    panic("Could not allocate i219 receive descriptor buffer.");
for(int i = 0; i < RX_DESC_COUNT; ++i)
{
    // Initialize descriptor
    rx_desc_t *currDesc = &rxDescriptors[i];
    currDesc->address = rxBufferMemPhy + i * RX_BUFFER_SIZE;
    currDesc->status = 0;
}

// Pass receive descriptor buffer
i219_write(E1000_REG_RDBAH, rxDescriptorsPhy >> 32);
i219_write(E1000_REG_RDBAL, rxDescriptorsPhy & 0xFFFFFFFF);
i219_write(E1000_REG_RDLEN, RX_DESC_COUNT * sizeof(rx_desc_t));
i219_write(E1000_REG_RDH, 0);
i219_write(E1000_REG_RDT, RX_DESC_COUNT - 1);
rxTail = RX_DESC_COUNT - 1;

// Enable receiver
uint32_t rctl = i219_read(E1000_REG_RCTL);
rctl |= E1000_RCTL_EN; // EN (Receiver Enable)
rctl &= ~E1000_RCTL_SBP; // SBP (Store Pad Packets)
rctl |= E1000_RCTL_BAM; // BAM (Broadcast Accept Mode)
rctl &= ~E1000_RCTL_SZ_4096;
rctl |= E1000_RCTL_SZ_2048; // BSIZE = 2048 (Receive Buffer Size)
rctl &= ~E1000_RCTL_BSEX;
rctl |= E1000_RCTL_SECRC; // SECRC (Strip Ethernet CRC)
i219_write(E1000_REG_RCTL, rctl);
Did anyone encounter a similar issue or is experienced with Intel's way of building drivers? I appreciate any ideas and hints!
User avatar
bellezzasolo
Member
Member
Posts: 110
Joined: Sun Feb 20, 2011 2:01 pm

Re: Receiving packets on the i219-V

Post by bellezzasolo »

Janworks wrote:Hello,

I am currently working on a driver for the i219-V network card. While there unfortunately is little documentation on its software interface, I was able to figure out most of its functionality using old manuals and Intel's official e1000e driver; after understanding the relation between the PCH and PHY things are quite similar to older e1000 cards. At this point my driver is able to transmit packets on real hardware, as I successfully tested with a hand-crafted ARP packet and Wireshark.

Unfortunately, receiving does not work. I already tried debugging that problem by printing the configuration and status registers; but from my point of view, the respective flags seem to be correct. The various statistics registers did not change, even when I was sure that the card *must* have received a packet (e.g. when getting the ARP response). Manually examing the receive descriptor ring did not show anything, too. Right now it looks like the PHY never receives packets, either because there is some misconfiguration on a very low level or the packet filtering is not properly initialized.

I've already checked with the e1000e driver, but it implements very many features and thus makes it easy to miss something important. Intel's driver seems to be doing a full hardware reset on startup; but since transmitting works already, I hope to avoid this.

I put the working parts of my code into a Wiki article draft; I will be happy to turn it into a full Wiki article, since digging through the documentation took me a lot of time.

The receiving code looks like this:

Code: Select all

// Allocate receive data buffer
uint64_t rxBufferMemPhy;
rxBufferMem = heap_alloc_contiguous(RX_DESC_COUNT * RX_BUFFER_SIZE, VM_R | VM_W, &rxBufferMemPhy);
if(!rxBufferMem)
    panic("Could not allocate i219 receive data buffer.");

// Allocate and initialize receive descriptor buffer
uint64_t rxDescriptorsPhy;
rxDescriptors = heap_alloc_contiguous(RX_DESC_COUNT * sizeof(rx_desc_t), VM_R | VM_W, &rxDescriptorsPhy);
if(!rxDescriptors)
    panic("Could not allocate i219 receive descriptor buffer.");
for(int i = 0; i < RX_DESC_COUNT; ++i)
{
    // Initialize descriptor
    rx_desc_t *currDesc = &rxDescriptors[i];
    currDesc->address = rxBufferMemPhy + i * RX_BUFFER_SIZE;
    currDesc->status = 0;
}

// Pass receive descriptor buffer
i219_write(E1000_REG_RDBAH, rxDescriptorsPhy >> 32);
i219_write(E1000_REG_RDBAL, rxDescriptorsPhy & 0xFFFFFFFF);
i219_write(E1000_REG_RDLEN, RX_DESC_COUNT * sizeof(rx_desc_t));
i219_write(E1000_REG_RDH, 0);
i219_write(E1000_REG_RDT, RX_DESC_COUNT - 1);
rxTail = RX_DESC_COUNT - 1;

// Enable receiver
uint32_t rctl = i219_read(E1000_REG_RCTL);
rctl |= E1000_RCTL_EN; // EN (Receiver Enable)
rctl &= ~E1000_RCTL_SBP; // SBP (Store Pad Packets)
rctl |= E1000_RCTL_BAM; // BAM (Broadcast Accept Mode)
rctl &= ~E1000_RCTL_SZ_4096;
rctl |= E1000_RCTL_SZ_2048; // BSIZE = 2048 (Receive Buffer Size)
rctl &= ~E1000_RCTL_BSEX;
rctl |= E1000_RCTL_SECRC; // SECRC (Strip Ethernet CRC)
i219_write(E1000_REG_RCTL, rctl);
Did anyone encounter a similar issue or is experienced with Intel's way of building drivers? I appreciate any ideas and hints!
I'm up to this point with my i219[v] driver. I did get a report of a packet received, but you'd expect more than one, probably! It should be the reading the Interrupt Cause Register is enough, I think?
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS
Post Reply