[eepro100] About eepro "out of resources" bug

Joe Kulig joek@websprocket.com
Tue, 25 Sep 2001 17:04:57 -0400


Let me share my observations on the "out of resources" bug. I too have
come across this and this what I have seen:

The Receive Frame Area (RFA) looks like this:

RFD 0
+0         0xc0000001
+12        0xSSSS0000

RFD 1
+0        0x1
+12        0xSSSSc040

RFD 2
+0        0xa020
+12        0xSSSSc040

...

RFD N
+0        0xa020
+12        0xSSSSc040

SSSS = data buffer size

I have concluded (from dumping received packets in memory and a snooping
the tcp line) that the eepro100 did not update the first field in RFD 1
when it received the packet.  The EOF, F, and ACTUAL COUNT fields are
updated in the fourth field. I have verified that the data has been
received correctly. What happens is the rx processing for the eepro100
is looking for an rxComplete (bit 15, 0x8000) to be set. This has not
happened, but the EOF, F, and ACTUAL COUNT fields in fourth RFD field
have been updated. The interrupt does occur but RFD 1 is not processed.
So the eepro keeps dumping packets into the remain RFD's until the RFD
is reached and then it reports that it is out resources.

I don't know why this condition happens but I suspect it is a
hardware/pci problem. I do not know if Intel is aware of this condition.

I do have a fix for this. Instead of looking for rxComplete in the first
RFD field, I look for EOF and F in the fourth field. This seems to work.
At least I have no seen this type of "out resources error" condition
occur.

The code for the relevant fix is below and is written Java. This is
because my driver is written for an object oriented OS that is written
in Java. One should see how the fix could be applied to the eepro100.c
linux version.


with best regards,

Joe Kulig      phone: 216-357-2580
joek@websprocket.com   fax: 216-357-2584
2253 Professor Street   Cleveland, OH 44113


 final static int PacketReceived = 0xc000;

 final int rx() {
  int entry = cur_rx & RX_RING_SIZE-1;
  int status;
  int rx_work_limit = dirty_rx + RX_RING_SIZE - cur_rx;
  RxFD rxf;

  if (debug > 4)
   System.out.println(" In rx().");
  rxRing[entry].flushHeader();
  int count;
  while (rxRing[entry] != null &&
      ((count = rxRing[entry].count()) & PacketReceived) ==
PacketReceived) {
   int pkt_len = count & 0x07ff;

   if (--rx_work_limit < 0)
    break;
   status = rxRing[entry].status();
   if (debug > 4)
    System.out.println(" rx() status " + Integer.toHexString(status) +
           " len " + pkt_len);
   if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) {
    if ((status & RxErrTooBig)!=0)
     System.out.println(name +": Ethernet frame overran the Rx buffer,
status " + Integer.toHexString(status));
    else if ( ! ((status & RxOK)!=0)) {
     /* There was a fatal error.  This *should* be impossible. */
     rx_errors++;
     sb.append(name).append(": Anomalous event in rx(), status ");
     sb.append(Integer.toHexString(status));
     System.out.println(sb.toString());
     sb.setLength(0);
    }
   } else {
    if ((drv_flags & HasChksum)!=0)
     pkt_len -= 2;

    /* Check if the packet is long enough to just accept without
       copying to a properly sized skbuff. */
    //    if (pkt_len < rx_copybreak) {
    //     /* Packet is in one chunk -- we can copy + cksum. */
    //     // eth_copy_and_sum(skb, rx_skbuff[entry]->tail, pkt_len, 0);

    //    } else {
    /* Pass up the already-filled skbuff. */
    addPacket(rxRing[entry]);
    rxRing[entry].size(pkt_len);
    rxRing[entry].flush();
    rxRing[entry] = null;
    if ((drv_flags & HasChksum)!=0) {
     //     u16 csum = get_unaligned((u16*)(skb->head + pkt_len))
     //     if (desc_count & 0x8000)
     //      skb->ip_summed = CHECKSUM_UNNECESSARY;
    }
    rx_packets++;
   }
   entry = (++cur_rx) & RX_RING_SIZE-1;
   rxRing[entry].flushHeader();
  }

  for(; cur_rx-dirty_rx>0; dirty_rx++){
   entry = dirty_rx & RX_RING_SIZE-1;

   rxRing[entry] = rxPackets[rxPacketIndex];
   rxf = rxRing[entry];
   rxPacketIndex++;
   rxPacketIndex &= (rxPackets.length-1);

   rxf.status(0xc0000001);
   rxf.count(PKT_BUF_SZ<<16);
   rxf.link(0);

   last_rxf.link(rxf.bufferAddress);
   last_rxf.status(last_rxf.status() & ~0xc0000000);
   last_rxf.cleanHeader();
   last_rxf = rxf;
   rxf.cleanHeader();
  }

  last_rx_time = jiffies;
  return 0;
 }