summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
Diffstat (limited to 'c')
-rw-r--r--c/src/ChangeLog12
-rw-r--r--c/src/libchip/network/smc91111.c127
-rw-r--r--c/src/libchip/network/smc91111.h15
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