This is the mail archive of the
ecos-patches@sourceware.org
mailing list for the eCos project.
SMSC LAN91CXX patch
- From: Jonathan Larmour <jifl at eCosCentric dot com>
- To: eCos Patches List <ecos-patches at ecos dot sourceware dot org>
- Date: Thu, 20 Jul 2006 17:41:08 +0100
- Subject: SMSC LAN91CXX patch
Another patch flushed from eCosCentric. This includes a different
implementation allowing 32-bit RX access. IMO this version is more elegant
and clear than what was previously in anoncvs, and thus replaces it. It
also removes the need for the CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT,
which I could not find used anywhere in anoncvs anyway.
I forgot to say in my previous message that I cannot guarantee all the
patches are error free due to the merge process (although they should be).
I do not have the ability or time to test with the variety of hardware
required, although the original changes in our tree were extensively tested
by eCosCentric of course.
Jifl
--
eCosCentric http://www.eCosCentric.com/ The eCos and RedBoot experts
------["The best things in life aren't things."]------ Opinions==mine
Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/smsc/lan91cxx/current/ChangeLog,v
retrieving revision 1.21
diff -u -5 -p -r1.21 ChangeLog
--- ChangeLog 29 Jun 2005 20:06:04 -0000 1.21
+++ ChangeLog 20 Jul 2006 16:37:23 -0000
@@ -10,10 +10,31 @@
2005-06-12 Yoshinori Sato <ysato@users.sourceforge.jp>
* src/if_lan91cxx.c: Reset the physical layer before configuring
it, otherwise it might not work.
+2005-01-24 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/if_lan91cxx.c (lan91cxx_send): Rewrote parts of transmit
+ machinery to deal with odd sized message buffers. The TCP/IP stack
+ generates these in rare circumstances.
+
+2005-01-21 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/smsc_lan91cxx.h:
+ * src/if_lan91cxx.c:
+ Rewrote parts of receive machinery to properly deal with 32 bit
+ wide access to the device. The original code didn't quite work.
+ Switched all calls the HAL_DELAY_US() to CYGACC_CALL_IF_DELAY_US().
+ Various small changes to debugging code.
+
+2004-12-01 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/if_lan91cxx.c (lan91cxx_start): Added option to force speed
+ negotiation to 10MHz. Some embedded boards cannot handle 100MHz.
+ Generally added some small improvements to debugging messages.
+
2004-05-22 Andrew Dyer <adyer@righthandtech.com>
* src/if_lan91cxx.c: Fail initialization if no device found.
2004-01-07 Uwe Kindler <ukindler@htwm.de>
@@ -183,10 +204,11 @@
//===========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2005 eCosCentric Ltd.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
Index: cdl/smsc_lan91cxx_eth_drivers.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/smsc/lan91cxx/current/cdl/smsc_lan91cxx_eth_drivers.cdl,v
retrieving revision 1.7
diff -u -5 -p -r1.7 smsc_lan91cxx_eth_drivers.cdl
--- cdl/smsc_lan91cxx_eth_drivers.cdl 29 Jun 2005 20:06:05 -0000 1.7
+++ cdl/smsc_lan91cxx_eth_drivers.cdl 20 Jul 2006 16:37:23 -0000
@@ -107,19 +107,10 @@ cdl_package CYGPKG_DEVS_ETH_SMSC_LAN91CX
description "
If this is nonzero, then the chip is assumed to be hardware
configured in PCMCIA mode."
}
- cdl_option CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT {
- display "use 32 bit data access"
- default_value 0
- description "
- The device driver uses 32 bit data access if
- this option is enabled, otherwise 16 bit data access is
- used."
- }
-
cdl_component CYGPKG_DEVS_ETH_SMSC_LAN91CXX_OPTIONS {
display "LAN91CXX ethernet driver build options"
flavor none
no_define
Index: src/if_lan91cxx.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/smsc/lan91cxx/current/src/if_lan91cxx.c,v
retrieving revision 1.19
diff -u -5 -p -r1.19 if_lan91cxx.c
--- src/if_lan91cxx.c 29 Jun 2005 20:06:05 -0000 1.19
+++ src/if_lan91cxx.c 20 Jul 2006 16:37:25 -0000
@@ -9,10 +9,11 @@
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Nick Garnett
// Copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2004 eCosCentric Ltd.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
@@ -33,12 +34,10 @@
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
-// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
-// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
@@ -125,15 +124,41 @@ static void db_printf( char *fmt, ... )
diag_vprintf( fmt, a );
end_console(old_console);
va_end( a );
}
#else
+#if 0
+static void db_printf( char *fmt, ... )
+{
+ va_list a;
+ int old_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ va_start( a, fmt );
+ CYGACC_CALL_IF_SET_CONSOLE_COMM( 0 );
+ diag_vprintf( fmt, a );
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(old_console);
+ va_end( a );
+}
+#else
#define db_printf diag_printf
#endif
+#endif
+#else
+#if 0
+static void db_printf( char *fmt, ... )
+{
+ va_list a;
+ int old_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ va_start( a, fmt );
+ CYGACC_CALL_IF_SET_CONSOLE_COMM( 0 );
+ diag_vprintf( fmt, a );
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(old_console);
+ va_end( a );
+}
#else
#define db_printf( fmt, ... )
#endif
+#endif
#if DEBUG & 1
#define DEBUG_FUNCTION() do { db_printf("%s\n", __FUNCTION__); } while (0)
#else
@@ -190,11 +215,11 @@ static int lan91cxx_isr(cyg_vector_t vec
{
struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
- DEBUG_FUNCTION();
+// DEBUG_FUNCTION();
INCR_STAT( interrupts );
cyg_drv_interrupt_mask(cpd->interrupt);
cyg_drv_interrupt_acknowledge(cpd->interrupt);
@@ -208,11 +233,11 @@ static void
lan91cxx_deliver(struct eth_drv_sc *sc)
{
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
- DEBUG_FUNCTION();
+// DEBUG_FUNCTION();
// Service the interrupt:
lan91cxx_poll(sc);
// Allow interrupts to happen again
cyg_drv_interrupt_unmask(cpd->interrupt);
@@ -260,11 +285,11 @@ smsc_lan91cxx_init(struct cyg_netdevtab_
// pulse SRESET on ECOR
ecor |= LAN91CXX_ECOR_RESET;
put_att(sc, LAN91CXX_ECOR, ecor);
- HAL_DELAY_US(1);
+ CYGACC_CALL_IF_DELAY_US(1);
ecor &= ~LAN91CXX_ECOR_RESET;
put_att(sc, LAN91CXX_ECOR, ecor);
// then, enable I/O map
@@ -296,13 +321,11 @@ smsc_lan91cxx_init(struct cyg_netdevtab_
&lan91cxx_interrupt_handle,
&lan91cxx_interrupt);
cyg_drv_interrupt_attach(lan91cxx_interrupt_handle);
#endif // !CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
cyg_drv_interrupt_acknowledge(cpd->interrupt);
-#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
cyg_drv_interrupt_unmask(cpd->interrupt);
-#endif // !CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
// probe chip by reading the signature in BS register
val = get_banksel(sc);
#if DEBUG & 9
db_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
@@ -338,11 +361,11 @@ smsc_lan91cxx_init(struct cyg_netdevtab_
val = get_reg(sc, LAN91CXX_EPH_STATUS);
#ifndef LAN91CXX_IS_LAN91C111
// LINK_OK on 91C111 is just a general purpose input and may not
// have anything to do with the link.
if (!(val & LAN91CXX_STATUS_LINK_OK)) {
- db_printf("no link\n");
+ db_printf("no link\n");
return false; // Link not connected
}
#endif
@@ -462,25 +485,29 @@ lan91cxx_start(struct eth_drv_sc *sc, un
DEBUG_FUNCTION();
#ifdef LAN91CXX_IS_LAN91C111
// 91C111 Errata. Internal PHY comes up disabled. Must enable here.
lan91cxx_write_phy(sc, 0, LAN91CXX_PHY_CTRL, LAN91CXX_PHY_CTRL_RST);
- HAL_DELAY_US(500000);
+ CYGACC_CALL_IF_DELAY_US(500000);
lan91cxx_write_phy(sc, 0, LAN91CXX_PHY_CTRL, LAN91CXX_PHY_CTRL_ANEG_EN |
LAN91CXX_PHY_CTRL_SPEED);
+#ifdef LAN91CXX_FORCE_10MHZ
+ lan91cxx_write_phy( sc, 0, LAN91CXX_PHY_AUTO_AD, 0x0061);
+#endif
+
// Start auto-negotiation
put_reg(sc, LAN91CXX_RPCR,
LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK | LAN91CXX_RPCR_ANEG);
// wait for auto-negotiation to finish.
// give it ~5 seconds before giving up (no cable?)
delay = 50;
while (!(lan91cxx_read_phy(sc, 0, LAN91CXX_PHY_STAT) & 0x20)) {
if (--delay <= 0)
break;
- HAL_DELAY_US(100000);
+ CYGACC_CALL_IF_DELAY_US(100000);
}
#if DEBUG & 1
if (delay <= 0)
diag_printf("auto-negotiation failed.\n");
#endif
@@ -730,11 +757,11 @@ lan91cxx_can_send(struct eth_drv_sc *sc)
{
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
int tcr;
- DEBUG_FUNCTION();
+// DEBUG_FUNCTION();
#ifndef LAN91CXX_IS_LAN91C111
// LINK_OK on 91C111 is just a general purpose input and may not
// have anything to do with the link.
if ((get_reg(sc, LAN91CXX_EPH_STATUS) & LAN91CXX_STATUS_LINK_OK) == 0) {
@@ -778,18 +805,25 @@ lan91cxx_send(struct eth_drv_sc *sc, str
{
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
int i, len, plen, tcr;
- unsigned short *sdata = NULL;
+ cyg_uint8 *sdata;
+ cyg_uint16 data = 0;
+ int dpos = 0;
unsigned short ints, control;
cyg_uint16 packet, status;
DEBUG_FUNCTION();
INCR_STAT( tx_count );
+#if DEBUG & 1
+ ints = get_reg(sc, LAN91CXX_INTERRUPT);
+ db_printf("%s:START: ints: %04x\n", __FUNCTION__, ints);
+#endif
+
// Worry about the TX engine stopping.
tcr = get_reg(sc, LAN91CXX_TCR);
if ( 0 == (LAN91CXX_TCR_TXENA & tcr) ) {
#if DEBUG & 1
db_printf("%s: ENGINE RESTART: tcr 0x%04x\n", __FUNCTION__, tcr );
@@ -860,36 +894,36 @@ lan91cxx_send(struct eth_drv_sc *sc, str
// Prepare header:
put_data(sc, CYG_CPU_TO_LE16(0)); // reserve space for status word
// packet length (includes status, byte-count and control shorts)
put_data(sc, CYG_CPU_TO_LE16(0x7FE & (plen + 6)) ); // Always even, always < 15xx(dec)
- // Put data into buffer
for (i = 0; i < sg_len; i++) {
- sdata = (unsigned short *)sg_list[i].buf;
+ sdata = (cyg_uint8 *)sg_list[i].buf;
len = sg_list[i].len;
-
- CYG_ASSERT(0 == (len & 1) || (i == (sg_len-1)), "odd length");
- CYG_ASSERT( sdata, "No sg data pointer here" );
- while(len >= sizeof(*sdata)) {
- put_data(sc, *sdata++);
- len -= sizeof(*sdata);
+ while( len > 0 )
+ {
+ data |= *sdata<<((dpos&1)*8);
+ dpos++, len--, sdata++;
+ if( (dpos & 1) == 0 )
+ {
+ put_data(sc, CYG_CPU_TO_LE16(data));
+ data = 0;
+ }
}
}
- 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 ) {
+ if( 1 & plen ) {
// Need to set ODD flag and insert the data
- unsigned char onebyte = *(unsigned char*)sdata;
- control = onebyte;
+ control = data;
control |= LAN91CXX_CONTROLBYTE_ODD;
}
control |= LAN91CXX_CONTROLBYTE_CRC; // Just in case...
put_data(sc, CYG_CPU_TO_LE16(control));
-
+
// Enqueue the packet
put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);
// Ack TX empty int and unmask it.
ints = get_reg(sc, LAN91CXX_INTERRUPT) & 0xff00;
@@ -962,11 +996,11 @@ lan91cxx_TxEvent(struct eth_drv_sc *sc,
// We do not really care about Tx failure. Ethernet is not a reliable
// medium. But we do care about the TX engine stopping.
tcr = get_reg(sc, LAN91CXX_TCR);
if ( 0 == (LAN91CXX_TCR_TXENA & tcr) ) {
#if DEBUG & 1
- db_printf("%s: ENGINE RESTART: tcr 0x%04x ints %04x\n", __FUNCTION__, tcr, ints);
+ db_printf("%s: ENGINE RESTART: tcr 0x%04x eph 0x%04x ints 0x%04x\n", __FUNCTION__, tcr, get_reg(sc, LAN91CXX_EPH_STATUS), ints);
#endif
tcr |= LAN91CXX_TCR_TXENA;
put_reg(sc, LAN91CXX_TCR, tcr);
success = 0; // And treat this as an error...
}
@@ -1008,10 +1042,47 @@ lan91cxx_TxEvent(struct eth_drv_sc *sc,
cpd->txbusy = 0;
(sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);
}
}
+void get_data_init(struct eth_drv_sc *sc)
+{
+ struct lan91cxx_priv_data *cpd =
+ (struct lan91cxx_priv_data *)sc->driver_private;
+
+ cpd->data_buf = 0xa5a5a5a5;
+ cpd->data_pos = sizeof(rxd_t);
+}
+
+cyg_uint8 get_data_byte(struct eth_drv_sc *sc)
+{
+ cyg_uint8 c;
+ struct lan91cxx_priv_data *cpd =
+ (struct lan91cxx_priv_data *)sc->driver_private;
+
+ if( cpd->data_pos == sizeof(rxd_t) )
+ {
+ cpd->data_buf = get_data(sc);
+ cpd->data_pos = 0;
+ }
+
+ c = (cpd->data_buf>>(cpd->data_pos*8))&0xFF;
+ cpd->data_pos++;
+
+ return c;
+
+}
+
+cyg_uint16 get_data_short(struct eth_drv_sc *sc)
+{
+ cyg_uint16 val;
+
+ val = get_data_byte(sc);
+ val |= get_data_byte(sc)<<8;
+
+ return CYG_LE16_TO_CPU(val);
+}
//
// This function is called when a packet has been received. Its job is
// to prepare to unload the packet from the hardware. Once the length of
// the packet is known, the upper layer of the driver can be told. When
@@ -1022,13 +1093,10 @@ static void
lan91cxx_RxEvent(struct eth_drv_sc *sc)
{
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
unsigned short stat, len;
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- cyg_uint32 val;
-#endif
DEBUG_FUNCTION();
stat = get_reg(sc, LAN91CXX_FIFO_PORTS);
#if DEBUG & 1
@@ -1052,21 +1120,15 @@ lan91cxx_RxEvent(struct eth_drv_sc *sc)
cpd->rxpacket = 0xff & (stat >> 8);
// Read status and (word) length
put_reg(sc, LAN91CXX_POINTER, (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
LAN91CXX_POINTER_AUTO_INCR | 0x0000));
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- val = get_data(sc);
- val = CYG_LE32_TO_CPU(val);
- stat = val & 0xffff;
- len = ((val >> 16) & 0xffff) - 6; // minus header/footer words
-#else
- stat = get_data(sc);
- stat = CYG_LE16_TO_CPU(stat);
- len = get_data(sc);
- len = CYG_LE16_TO_CPU(len) - 6; // minus header/footer words
-#endif
+ get_data_init(sc);
+
+ stat = get_data_short(sc);
+ len = get_data_short(sc);
+ len = len - 6; // minus header/footer words
#ifdef KEEP_STATISTICS
if ( stat & LAN91CXX_RX_STATUS_ALIGNERR ) INCR_STAT( rx_align_errors );
//if ( stat & LAN91CXX_RX_STATUS_BCAST ) INCR_STAT( );
if ( stat & LAN91CXX_RX_STATUS_BADCRC ) INCR_STAT( rx_crc_errors );
@@ -1097,16 +1159,28 @@ lan91cxx_RxEvent(struct eth_drv_sc *sc)
}
// Not OK for one reason or another...
#if DEBUG & 1
db_printf("RxEvent - bad rx: stat: 0x%04x, len: 0x%04x\n", stat, len);
+ db_printf("PHY %2d: %04x\n",0,lan91cxx_read_phy( sc, 0, 0));
+ db_printf("PHY %2d: %04x\n",1,lan91cxx_read_phy( sc, 0, 1));
+ db_printf("PHY %2d: %04x\n",2,lan91cxx_read_phy( sc, 0, 2));
+ db_printf("PHY %2d: %04x\n",3,lan91cxx_read_phy( sc, 0, 3));
+ db_printf("PHY %2d: %04x\n",4,lan91cxx_read_phy( sc, 0, 4));
+ db_printf("PHY %2d: %04x\n",5,lan91cxx_read_phy( sc, 0, 5));
+ db_printf("PHY %2d: %04x\n",16,lan91cxx_read_phy( sc, 0, 16));
+ db_printf("PHY %2d: %04x\n",17,lan91cxx_read_phy( sc, 0, 17));
+ db_printf("PHY %2d: %04x\n",18,lan91cxx_read_phy( sc, 0, 18));
+ db_printf("PHY %2d: %04x\n",19,lan91cxx_read_phy( sc, 0, 19));
+ db_printf("PHY %2d: %04x\n",20,lan91cxx_read_phy( sc, 0, 20));
#endif
// Free packet
put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
}
+
//
// This function is called as a result of the "eth_drv_recv()" call above.
// Its job is to actually fetch data for a packet from the hardware once
// memory buffers have been allocated for the packet. Note that the buffers
// may come in pieces, using a scatter-gather list. This allows for more
@@ -1120,102 +1194,63 @@ lan91cxx_recv(struct eth_drv_sc *sc, str
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
#endif
int i;
short mlen=0, plen;
- cyg_uint16 *data=NULL;
- unsigned char *cp, cval, odd_even = 0;
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- cyg_uint32 val;
-#else
- cyg_uint16 val;
-#endif
+ cyg_uint8 *data=NULL;
+ short val;
+ unsigned char *cp, cval;
DEBUG_FUNCTION();
INCR_STAT( rx_deliver );
put_reg(sc, LAN91CXX_POINTER, (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
LAN91CXX_POINTER_AUTO_INCR));
- val = get_data(sc);
-
- // packet length (minus header/footer)
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- val = CYG_LE32_TO_CPU(val);
- plen = (val >> 16) - 6;
-#else
- val = CYG_LE16_TO_CPU(val);
- plen = get_data(sc);
- plen = CYG_LE16_TO_CPU(plen) - 6;
-#endif
-
- if( LAN91CXX_RX_STATUS_IS_ODD(cpd,val) )
- plen++;
+ get_data_init(sc);
+
+ val = get_data_short(sc);
+ plen = get_data_short(sc);
+ plen = plen - 6;
for (i = 0; i < sg_len; i++) {
- data = (cyg_uint16 *)sg_list[i].buf;
+ int clen;
+ data = (cyg_uint8 *)sg_list[i].buf;
mlen = sg_list[i].len;
- CYG_ASSERT(0 == (mlen & (sizeof(*data) - 1)) || (i == (sg_len-1)), "odd length");
+ clen = mlen;
+ if( clen > plen )
+ clen = plen;
#if DEBUG & 1
- db_printf("%s : mlen 0x%04x, plen 0x%04x\n", __FUNCTION__, mlen, plen);
+ db_printf("%s : mlen 0x%04x plen 0x%04x clen 0x%04x\n", __FUNCTION__, mlen, plen, clen);
#endif
+ mlen -= clen;
+ plen -= clen;
+
if (data) {
- while (mlen >= sizeof(*data)) {
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- if (!(odd_even)) { // because of the 32bit to 16bit conversion, read only every 2nd word
-#endif
- val = get_data(sc);
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- odd_even = 1;
- }
- else {
- val >>= 16;
- odd_even = 0;
- }
-#endif
- *data++ = val;
- mlen -= sizeof(*data);
- plen -= sizeof(*data);
+ while( clen > 0 ) {
+ *data++ = get_data_byte(sc);
+ clen--;
}
}
else { // must actively discard ie. read it from the chip anyway.
- while (mlen >= sizeof(*data)) {
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- if (!(odd_even)) {
-#endif
- val = get_data(sc);
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- odd_even = 1;
- }
- else {
- val >>= 16;
- odd_even = 0;
- }
+#if DEBUG & 1
+ db_printf("lan91cxx_recv: No data!!!!!\n");
#endif
- mlen -= sizeof(*data);
- plen -= sizeof(*data);
+ while( clen > 0 ) {
+ (void)get_data_byte(sc);
+ clen--;
}
}
- }
- if (!(odd_even)) { // read the control word only if we not already have it because of a 32bit access
- val = get_data(sc); // Read control word (and potential data) unconditionally
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
- val = CYG_LE32_TO_CPU(val);
- if (plen & 2) {
- if (data)
- *(cyg_uint16 *)data = val & 0xffff;
- cp = (unsigned char *)data + 2;
- val >>= 16;
- mlen -= 2;
- }
-#else
- val = CYG_LE16_TO_CPU(val);
+#if DEBUG & 1
+ diag_dump_buf( sg_list[i].buf, sg_list[i].len > 64 ? 64 : sg_list[i].len );
#endif
}
- cp = (unsigned char *)data;
+ val = get_data_short(sc); // Read control word (and potential data) unconditionally
+
+ cp = (unsigned char *)data;
CYG_ASSERT(val & LAN91CXX_CONTROLBYTE_RX,
"Controlbyte is not for Rx");
CYG_ASSERT( (1 == mlen) == (0 != LAN91CXX_CONTROLBYTE_IS_ODD(cpd,val)),
"Controlbyte does not match");
@@ -1237,10 +1272,11 @@ lan91cxx_recv(struct eth_drv_sc *sc, str
// Free packet
put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
}
+
static void
lan91cxx_poll(struct eth_drv_sc *sc)
{
unsigned short event;
struct lan91cxx_priv_data *cpd =
@@ -1250,24 +1286,29 @@ lan91cxx_poll(struct eth_drv_sc *sc)
while (1) {
cyg_drv_interrupt_acknowledge(cpd->interrupt);
// Get the (unmasked) requests
event = get_reg(sc, LAN91CXX_INTERRUPT);
event = event & (event >> 8) & 0xff;
+
if (0 == event)
break;
#if 0
if (event & LAN91CXX_INTERRUPT_ERCV_INT) {
// Early receive interrupt
+ db_printf("Early receive interrupt\n");
}
else if (event & LAN91CXX_INTERRUPT_EPH_INT) {
// ethernet protocol handler failures
+ db_printf("Ethernet protocol handler failures\n");
}
else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) {
// receive overrun
+ db_printf("Receive overrun\n");
}
else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) {
// allocation interrupt
+ db_printf("Allocation interrupt\n");
}
else
#endif
if (event & LAN91CXX_INTERRUPT_TX_SET) {
lan91cxx_TxEvent(sc, event);
@@ -1340,22 +1381,22 @@ lan91cxx_read_phy(struct eth_drv_sc *sc,
// Clock all 64 cycles
for (i = 0; i < sizeof(bits); ++i) {
// Clock Low - output data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i]);
- HAL_DELAY_US(50);
+ CYGACC_CALL_IF_DELAY_US(50);
// Clock Hi - input data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
- HAL_DELAY_US(50);
+ CYGACC_CALL_IF_DELAY_US(50);
bits[i] |= get_reg(sc, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
}
// Return to idle state
put_reg(sc, LAN91CXX_MGMT, mii_reg);
- HAL_DELAY_US(50);
+ CYGACC_CALL_IF_DELAY_US(50);
// Recover input data
for (value = 0, i = 0; i < 16; ++i) {
value <<= 1;
if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
@@ -1424,21 +1465,21 @@ lan91cxx_write_phy(struct eth_drv_sc *sc
// Clock all cycles
for (i = 0; i < sizeof(bits); ++i) {
// Clock Low - output data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i]);
- HAL_DELAY_US(50);
+ CYGACC_CALL_IF_DELAY_US(50);
// Clock Hi - input data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
- HAL_DELAY_US(50);
+ CYGACC_CALL_IF_DELAY_US(50);
// bits[i] |= get_reg(sc, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
}
// Return to idle state
put_reg(sc, LAN91CXX_MGMT, mii_reg);
- HAL_DELAY_US(50);
+ CYGACC_CALL_IF_DELAY_US(50);
}
#endif // LAN91CXX_IS_LAN91C111
// EOF if_lan91cxx.c
Index: src/smsc_lan91cxx.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/smsc/lan91cxx/current/src/smsc_lan91cxx.h,v
retrieving revision 1.12
diff -u -5 -p -r1.12 smsc_lan91cxx.h
--- src/smsc_lan91cxx.h 29 Jun 2005 20:06:05 -0000 1.12
+++ src/smsc_lan91cxx.h 20 Jul 2006 16:37:26 -0000
@@ -328,20 +328,22 @@ typedef struct lan91cxx_priv_data {
int txpacket;
int rxpacket;
int within_send;
int addrsh; // Address bits to shift
int c111_reva; // true if this is a revA LAN91C111
+ cyg_uint32 data_buf;
+ int data_pos;
#ifdef KEEP_STATISTICS
struct smsc_lan91cxx_stats stats;
#endif
} lan91cxx_priv_data;
// ------------------------------------------------------------------------
#include CYGDAT_DEVS_ETH_SMSC_LAN91CXX_INL
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
+#ifdef LAN91CXX_32BIT_RX
typedef cyg_uint32 rxd_t;
#else
typedef cyg_uint16 rxd_t;
#endif
@@ -404,11 +406,11 @@ get_data(struct eth_drv_sc *sc)
{
rxd_t val;
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
-#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_USE_32BIT
+#ifdef LAN91CXX_32BIT_RX
HAL_READ_UINT32(cpd->base+((LAN91CXX_DATA_HIGH & 0x7) << cpd->addrsh), val);
#else
HAL_READ_UINT16(cpd->base+((LAN91CXX_DATA & 0x7) << cpd->addrsh), val);
#endif