mirror of
https://github.com/Stichting-MINIX-Research-Foundation/u-boot.git
synced 2025-09-09 20:18:54 -04:00
DM9000: Make driver work properly for DM9000A
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 <linux@bohmer.net> Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
This commit is contained in:
parent
fbcb7ece0e
commit
850ba7555d
@ -40,6 +40,10 @@ v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>:
|
|||||||
Sascha Hauer <saschahauer@web.de>
|
Sascha Hauer <saschahauer@web.de>
|
||||||
|
|
||||||
06/03/2008 Remy Bohmer <linux@bohmer.net>
|
06/03/2008 Remy Bohmer <linux@bohmer.net>
|
||||||
|
- 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.
|
- Added autodetect of databus width.
|
||||||
- Made debug code compile again.
|
- Made debug code compile again.
|
||||||
- Adapt eth_send such that it matches the DM9000*
|
- Adapt eth_send such that it matches the DM9000*
|
||||||
@ -598,53 +602,64 @@ eth_rx(void)
|
|||||||
u16 RxStatus, RxLen = 0;
|
u16 RxStatus, RxLen = 0;
|
||||||
struct board_info *db = &dm9000_info;
|
struct board_info *db = &dm9000_info;
|
||||||
|
|
||||||
/* Check packet ready or not */
|
/* Check packet ready or not, we must check
|
||||||
DM9000_ior(DM9000_MRCMDX); /* Dummy read */
|
the ISR status first for DM9000A */
|
||||||
rxbyte = DM9000_inb(DM9000_DATA); /* Got most updated data */
|
if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
|
||||||
if (rxbyte == 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Status check: this byte must be 0 or 1 */
|
DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
|
||||||
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");
|
|
||||||
|
|
||||||
/* A packet ready now & Get status/length */
|
/* There is _at least_ 1 package in the fifo, read them all */
|
||||||
DM9000_outb(DM9000_MRCMD, DM9000_IO);
|
for (;;) {
|
||||||
|
DM9000_ior(DM9000_MRCMDX); /* Dummy read */
|
||||||
|
|
||||||
(db->rx_status)(&RxStatus, &RxLen);
|
/* Get most updated data */
|
||||||
|
rxbyte = DM9000_inb(DM9000_DATA);
|
||||||
|
|
||||||
DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
|
/* Status check: this byte must be 0 or 1 */
|
||||||
|
if (rxbyte > DM9000_PKT_RDY) {
|
||||||
/* Move data from DM9000 */
|
DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
|
||||||
/* Read received packet from RX SRAM */
|
DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
|
||||||
(db->inblk)(rdptr, RxLen);
|
printf("DM9000 error: status check fail: 0x%x\n",
|
||||||
|
rxbyte);
|
||||||
if ((RxStatus & 0xbf00) || (RxLen < 0x40)
|
return 0;
|
||||||
|| (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);
|
|
||||||
|
|
||||||
/* Pass to upper layer */
|
if (rxbyte != DM9000_PKT_RDY)
|
||||||
DM9000_DBG("passing packet to upper layer\n");
|
return 0; /* No packet received, ignore */
|
||||||
NetReceive(NetRxPackets[0], RxLen);
|
|
||||||
return RxLen;
|
DM9000_DBG("receiving packet\n");
|
||||||
|
|
||||||
|
/* A packet ready now & Get status/length */
|
||||||
|
(db->rx_status)(&RxStatus, &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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user