Does the E1000 emulated by QEMU send an interrupt after every recieved packet?

103 Views Asked by At

I am doing the Network driver lab (part of mit's 6.1810)

When multiple packets are received (in case of multiple processes pinging at the same time) only 1 interrupt is issued by the E1000, (so when servicing the interrupt the code has to scan through all of the received packets), but the intel documentation (section 3.2.7.1.1) says (emphasis mine):

Setting the Packet Timer to 0b disables both the Packet Timer and the Absolute Timer (described below) and causes the Receive Timer Interrupt to be generated whenever a new packet has been stored in memory.

This is part of the code which initializes the device (with E1000_RDTR being the packet timer):

// ask e1000 for receive interrupts.
  regs[E1000_RDTR] = 0; // interrupt after every received packet (no timer)
  regs[E1000_RADV] = 0; // interrupt after every packet (no timer)

My understanding is that the code is exactly what the documentation describes for receiving interrupts after every packet, but that's not the case in practice.

My question is, why doesn't the E1000 emulated by qemu emit an interrupt after every received packet, or am I missing something?

If I try with more than 10 (between 11-15) simultaneous pings, sometimes the E1000 won't deliver all of the received packets (that is, when it issues an interrupt I can find at most 10 packets, and no more interrupts will be raised).

Here is my code for receiving packets when the e1000 raises an interrupt:

e1000_recv(void)
{
  int index = 0, i = 0;
  struct mbuf *m[RX_RING_SIZE];

  acquire(&e1000_lock);

  for (i = (regs[E1000_RDT]+1) % RX_RING_SIZE; rx_ring[i].status & E1000_RXD_STAT_DD; i++) {
    rx_mbufs[i]->len = rx_ring[i].length;
    rx_mbufs[i]->head = (char*)rx_ring[i].addr;

    m[index] = rx_mbufs[i];

    rx_mbufs[i] = mbufalloc(0);
    rx_ring[i].addr = (uint64) rx_mbufs[i]->head;
    rx_ring[i].status = 0;
    index++;
  }

  regs[E1000_RDT] = i-1;

  release(&e1000_lock);

  for (int i = 0; i < index; i++)
    net_rx(m[i]);
}
1

There are 1 best solutions below

0
On

I was recently doing this experiment with xv6 and ran into the same problem. After the same initialisation process. I set the variable to detect the number of interrupts in e1000_intr. Found that the number of interrupts does not equal to 10 after 10 processes call the ping function.

I thought that the interrupts may be lost due to acquire masking interrupts, but found that PLIC will put the interrupt pending, so I think that this behaviour should be e1000 Therefore I think this behaviour should be the default behaviour of e1000, the description in the manual is not consistent. I am also looking forward to a more reasonable answer from a more professional person.