The DM9000A network controller does not work with the U-boot DM9000x driver. Analysis showed that many incoming packets are lost. The DM9000A Application Notes V1.20 (section 5.6.1) recommend that the poll to check for a valid rx packet be done on the interrupt status register, not directly by performing the dummy read and the rx status check as is currently the case in the u-boot driver. When the recommended poll is done as suggested the driver starts working correctly on 10Mbit/HD, but on 100MBit/FD packets come in faster so that there can be more than 1 package in the fifo at the same time. The driver must perform the rx-status check in a loop and read and handle all packages until there is no more left _after_ the interrupt RX flag is set. This change has been tested with DM9000A, DM9000E, DM9000EP. Signed-off-by: Remy Bohmer --- drivers/net/dm9000x.c | 95 ++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 40 deletions(-) Index: u-boot-git-03062008/drivers/net/dm9000x.c =================================================================== --- u-boot-git-03062008.orig/drivers/net/dm9000x.c 2008-06-03 15:19:13.000000000 +0200 +++ u-boot-git-03062008/drivers/net/dm9000x.c 2008-06-03 15:19:17.000000000 +0200 @@ -40,6 +40,10 @@ v1.2 03/18/2003 Weilun Huang 06/03/2008 Remy Bohmer + - Fixed the driver to work with DM9000A. + (check on ISR receive status bit before reading the + FIFO as described in DM9000 programming guide and + application notes) - Added autodetect of databus width. - Made debug code compile again. - Adapt eth_send such that it matches the DM9000* @@ -598,53 +602,64 @@ eth_rx(void) u16 RxStatus, RxLen = 0; struct board_info *db = &dm9000_info; - /* Check packet ready or not */ - DM9000_ior(DM9000_MRCMDX); /* Dummy read */ - rxbyte = DM9000_inb(DM9000_DATA); /* Got most updated data */ - if (rxbyte == 0) + /* Check packet ready or not, we must check + the ISR status first for DM9000A */ + if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */ return 0; - /* Status check: this byte must be 0 or 1 */ - if (rxbyte > 1) { - DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */ - DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */ - DM9000_DBG("rx status check: %d\n", rxbyte); - } - DM9000_DBG("receiving packet\n"); + DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */ - /* A packet ready now & Get status/length */ - DM9000_outb(DM9000_MRCMD, DM9000_IO); + /* There is _at least_ 1 package in the fifo, read them all */ + for (;;) { + DM9000_ior(DM9000_MRCMDX); /* Dummy read */ + + /* Get most updated data */ + rxbyte = DM9000_inb(DM9000_DATA); + + /* Status check: this byte must be 0 or 1 */ + if (rxbyte > DM9000_PKT_RDY) { + DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */ + DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */ + printf("DM9000 error: status check fail: 0x%x\n", + rxbyte); + return 0; + } - (db->rx_status)(&RxStatus, &RxLen); + if (rxbyte != DM9000_PKT_RDY) + return 0; /* No packet received, ignore */ - DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen); + DM9000_DBG("receiving packet\n"); - /* Move data from DM9000 */ - /* Read received packet from RX SRAM */ - (db->inblk)(rdptr, RxLen); - - if ((RxStatus & 0xbf00) || (RxLen < 0x40) - || (RxLen > DM9000_PKT_MAX)) { - if (RxStatus & 0x100) { - printf("rx fifo error\n"); - } - if (RxStatus & 0x200) { - printf("rx crc error\n"); - } - if (RxStatus & 0x8000) { - printf("rx length error\n"); - } - if (RxLen > DM9000_PKT_MAX) { - printf("rx length too big\n"); - dm9000_reset(); - } - } else { - DM9000_DMP_PACKET("eth_rx", rdptr, RxLen); + /* A packet ready now & Get status/length */ + (db->rx_status)(&RxStatus, &RxLen); - /* Pass to upper layer */ - DM9000_DBG("passing packet to upper layer\n"); - NetReceive(NetRxPackets[0], RxLen); - return RxLen; + DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen); + + /* Move data from DM9000 */ + /* Read received packet from RX SRAM */ + (db->inblk)(rdptr, RxLen); + + if ((RxStatus & 0xbf00) || (RxLen < 0x40) + || (RxLen > DM9000_PKT_MAX)) { + if (RxStatus & 0x100) { + printf("rx fifo error\n"); + } + if (RxStatus & 0x200) { + printf("rx crc error\n"); + } + if (RxStatus & 0x8000) { + printf("rx length error\n"); + } + if (RxLen > DM9000_PKT_MAX) { + printf("rx length too big\n"); + dm9000_reset(); + } + } else { + DM9000_DMP_PACKET("eth_rx", rdptr, RxLen); + + DM9000_DBG("passing packet to upper layer\n"); + NetReceive(NetRxPackets[0], RxLen); + } } return 0; } --