diff options
Diffstat (limited to 'c')
-rw-r--r-- | c/src/ChangeLog | 12 | ||||
-rw-r--r-- | c/src/libchip/network/smc91111.c | 127 | ||||
-rw-r--r-- | c/src/libchip/network/smc91111.h | 15 |
3 files changed, 115 insertions, 39 deletions
diff --git a/c/src/ChangeLog b/c/src/ChangeLog index e43d2eace7..0ba92e85db 100644 --- a/c/src/ChangeLog +++ b/c/src/ChangeLog @@ -1,3 +1,15 @@ +2007-09-12 Daniel Hellstrom <daniel@gaisler.com> + + * libchip/network/smc91111.c, libchip/network/smc91111.h: Multiple fixes. + - Odd bit bug in some chips taken care of. + - Buggy ASSERT removed, it seem to be inserted to detect if MBUF data + alignment but failing to do so must have made the driver writer to make + some incorrect assumptions about MBUFs. + - Fixed MBUF handling to handle mbuf chains better. The Data length of + MBUFs in middle of the mbuf chain are now checked for odd number of bytes. + - Made while loop responsible for copying data to fifo port copy 16 shorts + per loop instead of 1 short, increasing the copying process. + 2007-09-07 Daniel Hellstrom <daniel@gaisler.com> * libchip/network/greth.c, libchip/network/greth.h: GRETH_GBIT support diff --git a/c/src/libchip/network/smc91111.c b/c/src/libchip/network/smc91111.c index 767ca3fc93..e6ac775c9a 100644 --- a/c/src/libchip/network/smc91111.c +++ b/c/src/libchip/network/smc91111.c @@ -181,7 +181,7 @@ static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m) plen = CYG_LE16_TO_CPU(plen) - 6; #endif - if (LAN91CXX_RX_STATUS_IS_ODD(cpd, val)) + if ( cpd->c111_reva || LAN91CXX_RX_STATUS_IS_ODD(cpd, val) ) /* RevA Odd-bit BUG */ plen++; for (n = m; n; n = n->m_next) { @@ -257,13 +257,14 @@ static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m) val = get_data(cpd); /* Read control word (and potential data) unconditionally */ #ifdef LAN91CXX_32BIT_RX if (plen & 2) { - if (data) { + if (data && (mlen>1) ) { *(unsigned short *)data = (val >> 16) & 0xffff; - data = (rxd_t *)((unsigned short *)data + 1); + data = (rxd_t *)((unsigned short *)data + 1); val <<= 16; + mlen-=2; } } - if (plen & 1) + if ( (plen & 1) && data && (mlen>0) ) *(unsigned char *)data = val >> 24; #else val = CYG_LE16_TO_CPU(val); @@ -421,7 +422,7 @@ static int readpacket(struct lan91cxx_priv_data *cpd) INCR_STAT(cpd, rx_good); /* Then it's OK */ - if (LAN91CXX_RX_STATUS_IS_ODD(cpd, stat)) + if (cpd->c111_reva || LAN91CXX_RX_STATUS_IS_ODD(cpd, stat)) /* RevA Odd-bit BUG */ complen++; #if DEBUG & 1 @@ -491,7 +492,7 @@ static void smc91111_rxDaemon(void *arg) static void sendpacket(struct ifnet *ifp, struct mbuf *m) { struct lan91cxx_priv_data *cpd = ifp->if_softc; - int i, len, plen, tcr; + int i, len, plen, tcr, odd; struct mbuf *n = m; unsigned short *sdata = NULL; unsigned short ints, control; @@ -562,58 +563,89 @@ static void sendpacket(struct ifnet *ifp, struct mbuf *m) put_data(cpd, CYG_CPU_TO_LE16(0x7FE & (plen + 6))); /* Always even, always < 15xx(dec) */ /* Put data into buffer */ + odd = 0; n = m; while (n) { sdata = (unsigned short *)n->m_data; len = n->m_len; - CYG_ASSERT((0 == (len & 1) - || !(n->m_next)), "!odd length"); CYG_ASSERT(sdata, "!No sg data pointer here"); - while (len >= sizeof(*sdata)) { + /* start on an odd offset? + * If last byte also (1byte mbuf with different pointer should not occur) + * let following code handle it + */ + if ( ((unsigned int)sdata & 1) && (len>1) ){ + put_data8(cpd,*(unsigned char *)sdata); + sdata = (unsigned short *)((unsigned int)sdata + 1); + odd = ~odd; + len--; + } + + /* speed up copying a bit, never copy last word */ + while(len >= 17){ + put_data(cpd, *(sdata)); + put_data(cpd, *(sdata+1)); + put_data(cpd, *(sdata+2)); + put_data(cpd, *(sdata+3)); + put_data(cpd, *(sdata+4)); + put_data(cpd, *(sdata+5)); + put_data(cpd, *(sdata+6)); + put_data(cpd, *(sdata+7)); + sdata += 8; + len -= 16; + } + + /* copy word wise, skip last word */ + while (len >= 3) { put_data(cpd, *sdata++); len -= sizeof(*sdata); } - n = n->m_next; - } -#if DEBUG & 64 - n = m; - while (n) { - int lp = 0; - unsigned char *start = (unsigned char *)n->m_data; - len = n->m_len; - while (len > 0) { - unsigned char a = *(start++); - unsigned char b = *(start++); - db64_printf("%02x %02x ", a, b); - lp += 2; - if (lp >= 16) { - db64_printf("\n"); - lp = 0; + + /* one or two bytes left to put into fifo */ + if ( len > 1 ){ + /* the last 2bytes */ + if ( !odd || n->m_next ){ + put_data(cpd, *sdata++); + len -= sizeof(*sdata); + }else{ + /* write next byte, mark that we are not at an odd offset any more, + * remaining byte will be written outside while together with control byte. + */ + put_data8(cpd,*(unsigned char *)sdata); + sdata = (unsigned short *)((unsigned int)sdata + 1); + odd = 0; + len--; + /*break;*/ } - len -= 2; + }else if ( (len>0) && (n->m_next) ){ + /* one byte left to write, and more bytes is comming in next mbuf */ + put_data8(cpd,*(unsigned char *)sdata); + odd = ~odd; } + n = n->m_next; } - db64_printf(" \n"); -#endif - - m_freem(m); - CYG_ASSERT(sdata, "!No sg data pointer outside"); /* Lay down the control short unconditionally at the end. */ /* (or it might use random memory contents) */ control = 0; - if (1 & plen) { - /* Need to set ODD flag and insert the data */ - unsigned char onebyte = *(unsigned char *)sdata; - control = onebyte; - control |= LAN91CXX_CONTROLBYTE_ODD; + if ( len > 0 ){ + if ( !odd ) { + /* Need to set ODD flag and insert the data */ + unsigned char onebyte = *(unsigned char *)sdata; + control = onebyte; + control |= LAN91CXX_CONTROLBYTE_ODD; + }else{ + put_data8(cpd,*(unsigned char *)sdata); + } } control |= LAN91CXX_CONTROLBYTE_CRC; /* Just in case... */ put_data(cpd, CYG_CPU_TO_LE16(control)); + m_freem(m); + CYG_ASSERT(sdata, "!No sg data pointer outside"); + /* ############ start transmit ############ */ /* Ack TX empty int and unmask it. */ @@ -1057,7 +1089,7 @@ int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd) (val >> 4) & 0xf, val & 0xf); /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */ - cpd->c111_reva = (val == 0x3390); + cpd->c111_reva = (val == 0x3390); /* 90=A, 91=B, 92=C */ /* The controller may provide a function used to set up the ESA */ if (cpd->config_enaddr) @@ -1595,3 +1627,24 @@ lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr, } #endif + +#if 0 +void lan91cxx_print_bank(int bank){ + struct lan91cxx_priv_data *cpd = &smc91111; + int regno; + unsigned short regval[8]; + int i; + + if ( bank >= 4 ) + return; + for(i=0; i<8; i++){ + regno=i+bank<<3; + regval[i] = get_reg(cpd, regno); + } + printk("---- BANK %d ----\n\r",bank); + for(i=0; i<8; i++){ + printk("0x%x: 0x%x\n\r",i,regval[i]); + } + +} +#endif diff --git a/c/src/libchip/network/smc91111.h b/c/src/libchip/network/smc91111.h index 7cf047e42c..c3a6f32e10 100644 --- a/c/src/libchip/network/smc91111.h +++ b/c/src/libchip/network/smc91111.h @@ -460,7 +460,7 @@ get_reg(struct lan91cxx_priv_data *cpd, int regno) } dbg++; } -#else +#else db2_printf("%sread reg %d:%x -> 0x%04x\n", dbg_prefix, regno>>3,(regno&0x7)*2, val); #endif @@ -483,7 +483,7 @@ put_reg(struct lan91cxx_priv_data *cpd, int regno, unsigned short val) } dbg++; } -#else +#else db2_printf("%swrite reg %d:%x <- 0x%04x\n", dbg_prefix, regno>>3,(regno&0x7)*2, val); #endif @@ -508,6 +508,17 @@ put_data(struct lan91cxx_priv_data *cpd, unsigned short val) HAL_WRITE_UINT16(cpd->base+((LAN91CXX_DATA & 0x7)), val); } + +/* Assumes bank2 has been selected*/ +static __inline__ void +put_data8(struct lan91cxx_priv_data *cpd, unsigned char val) +{ + db2_printf("%s[bdata] <- 0x%02x\n", dbg_prefix, val); + + HAL_WRITE_UINT8(((unsigned char *)(cpd->base+((LAN91CXX_DATA & 0x7))))+1, val); + +} + #endif /* SMSC_PLATFORM_DEFINED_PUT_DATA*/ #ifndef SMSC_PLATFORM_DEFINED_GET_DATA |