summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/lib/libbsp/i386/pc386/ne2000/ne2000.c548
1 files changed, 385 insertions, 163 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/ne2000/ne2000.c b/c/src/lib/libbsp/i386/pc386/ne2000/ne2000.c
index a65897763a..8e28bad5f3 100644
--- a/c/src/lib/libbsp/i386/pc386/ne2000/ne2000.c
+++ b/c/src/lib/libbsp/i386/pc386/ne2000/ne2000.c
@@ -23,12 +23,14 @@
* is any point to having more than two transmit buffers. However, the
* code does make it possible, by changing NE_TX_BUFS, although that
* would of course reduce the number of receive buffers.
- *
+ *
* I suspect that the wd80x3 driver would benefit slightly from copying
* the multiple transmit buffer code. However, I have no way to test
* that.
*/
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
#include <bsp.h>
#include <wd80x3.h>
@@ -59,6 +61,7 @@
/* Define this to print debugging messages with printk. */
/* #define DEBUG_NE2000 */
+/* #define DEBUG_NE */
/* We expect to be able to read a complete packet into an mbuf. */
@@ -70,11 +73,11 @@
#define RO 0
/* Minimum size of Ethernet packet. */
-#define ET_MINLEN 60
+#define ET_MINLEN 60
/* The number of NE2000 devices supported by this driver. */
-#define NNEDRIVER 1
+#define NNEDRIVER 1
/* RTEMS event number used by the interrupt handler to signal the
driver task. This must not be any of the events used by the
@@ -186,10 +189,37 @@ struct ne_softc {
static struct ne_softc ne_softc[NNEDRIVER];
+/*
+ * receive ring descriptor
+ *
+ * The National Semiconductor DS8390 Network interface controller uses
+ * the following receive ring headers. The way this works is that the
+ * memory on the interface card is chopped up into 256 bytes blocks.
+ * A contiguous portion of those blocks are marked for receive packets
+ * by setting start and end block #'s in the NIC. For each packet that
+ * is put into the receive ring, one of these headers (4 bytes each) is
+ * tacked onto the front. The first byte is a copy of the receiver status
+ * register at the time the packet was received.
+ */
+struct ne_ring
+{
+ unsigned char rsr; /* receiver status */
+ unsigned char next; /* pointer to next packet */
+ unsigned short count; /* bytes in packet (length + 4) */
+};
+
/* Forward declarations to avoid warnings */
+static void ne_init_irq_handler (int irno);
static void ne_stop (struct ne_softc *sc);
+static void ne_stop_hardware (struct ne_softc *sc);
static void ne_init (void *arg);
+static void ne_init_hardware (struct ne_softc *sc);
+
+static void ne_reset(struct ne_softc *sc);
+#ifdef DEBUG_NE
+static void ne_dump(struct ne_softc *sc);
+#endif
/* Find the NE2000 device which is attached at a particular interrupt
vector. */
@@ -202,8 +232,8 @@ ne_device_for_irno (int irno)
for (i = 0; i < NNEDRIVER; ++i)
{
if (ne_softc[i].irno == irno
- && ne_softc[i].arpcom.ac_if.if_softc != NULL)
- return &ne_softc[i];
+ && ne_softc[i].arpcom.ac_if.if_softc != NULL)
+ return &ne_softc[i];
}
return NULL;
@@ -226,22 +256,31 @@ ne_read_data (struct ne_softc *sc, int addr, int len, unsigned char *p)
outport_byte (port + CMDR, MSK_PG0 | MSK_RRE | MSK_STA);
if (sc->byte_transfers)
- while (len > 0) {
- unsigned char d;
-
- inport_byte (dport, d);
+ {
+ unsigned char d;
+ while (len > 0)
+ {
+ inport_byte(dport, d);
*p++ = d;
len--;
}
+ }
else /* word transfers */
- while (len > 0) {
- unsigned short d;
-
- inport_word (dport, d);
+ {
+ unsigned short d;
+ while (len > 1)
+ {
+ inport_word(dport, d);
*p++ = d;
*p++ = d >> 8;
len -= 2;
}
+ if (len)
+ {
+ inport_word(dport, d);
+ *p++ = d;
+ }
+ }
outport_byte (port + ISR, MSK_RDC);
}
@@ -251,8 +290,9 @@ ne_read_data (struct ne_softc *sc, int addr, int len, unsigned char *p)
NE2000 interrupts have been disabled. */
static void
-ne_check_status (struct ne_softc *sc)
+ne_check_status (struct ne_softc *sc, int from_irq_handler)
{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
unsigned int port = sc->port;
unsigned char status;
@@ -263,66 +303,77 @@ ne_check_status (struct ne_softc *sc)
when interrupts are reenabled. (Based on the behaviour of the
Realtek 8019AS chip). */
- while (1) {
+ /* int count = 0; */
+ while (1)
+ {
inport_byte (port + ISR, status);
if (status == 0)
break;
+ /* ack */
+ outport_byte (port + ISR, status);
+
#ifdef DEBUG_NE2000
printk ("NE2000 status 0x%x (8259 enabled: %s; mask: %x)\n", status,
- i8259s_cache & (1 << sc->irno) ? "no" : "yes",
- i8259s_cache);
+ i8259s_cache & (1 << sc->irno) ? "no" : "yes",
+ i8259s_cache);
#endif
/* Check for incoming packet overwrite. */
- if (status & MSK_OVW) {
- unsigned char status2;
-
+ if (status & MSK_OVW)
+ {
+ ifp->if_timer = 0;
+#ifdef DEBUG_NE
+ printk("^");
+#endif
++sc->stats.overruns;
- outport_byte (port + CMDR, MSK_PG0 | MSK_STP | MSK_RD2);
- Wait_X_ms (2);
- outport_byte (port + RBCR0, 0);
- outport_byte (port + RBCR1, 0);
- inport_byte (port + ISR, status2);
- status |= status2 & (MSK_PTX | MSK_TXE);
- outport_byte (port + TCR, MSK_LOOP);
- outport_byte (port + CMDR, MSK_PG0 | MSK_STA | MSK_RD2);
- sc->overrun = 1;
- if ((status & (MSK_PTX | MSK_TXE)) == 0)
- sc->resend = 1;
- rtems_event_send (sc->rx_daemon_tid, INTERRUPT_EVENT);
+ ne_reset(sc);
+ /* Reenable device interrupts. */
+ if (from_irq_handler)
+ outport_byte(port + IMR, NE_INTERRUPTS);
+ return;
}
/* Check for transmitted packet. The transmit daemon may now be
able to send another packet to the device. */
- if ((status & (MSK_PTX | MSK_TXE)) != 0) {
+ if ((status & (MSK_PTX | MSK_TXE)) != 0)
+ {
+ ifp->if_timer = 0;
++sc->stats.tx_acks;
- outport_byte (port + ISR, status & (MSK_PTX | MSK_TXE));
--sc->inuse;
sc->transmitting = 0;
if (sc->inuse > 0 || (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) != 0)
- rtems_event_send (sc->tx_daemon_tid, START_TRANSMIT_EVENT);
+ rtems_event_send (sc->tx_daemon_tid, START_TRANSMIT_EVENT);
}
/* Check for received packet. */
- if ((status & (MSK_PRX | MSK_RXE)) != 0) {
+ if ((status & (MSK_PRX | MSK_RXE)) != 0)
+ {
++sc->stats.rx_acks;
- outport_byte (port + ISR, status & (MSK_PRX | MSK_RXE));
rtems_event_send (sc->rx_daemon_tid, INTERRUPT_EVENT);
}
/* Check for counter change. */
- if ((status & MSK_CNT) != 0) {
+ if ((status & MSK_CNT) != 0)
+ {
unsigned char add;
-
inport_byte (port + CNTR0, add);
sc->stats.rx_frame_errors += add;
inport_byte (port + CNTR1, add);
sc->stats.rx_crc_errors += add;
inport_byte (port + CNTR2, add);
sc->stats.rx_missed_errors += add;
- outport_byte (port + ISR, MSK_CNT);
}
+
+ break;
+ /* if (++count >= 1000)
+ {
+ printk("status: %x\n", status);
+ ne_reset(sc);
+ if (from_irq_handler)
+ outport_byte(port + IMR, NE_INTERRUPTS);
+ return;
+ } */
}
outport_byte (port + CMDR, MSK_PG0 | MSK_STA | MSK_RD2);
@@ -341,7 +392,10 @@ ne_interrupt_handler (rtems_vector_number v)
++sc->stats.interrupts;
- ne_check_status (sc);
+#ifdef DEBUG_NE
+ printk("!");
+#endif
+ ne_check_status(sc, 1);
}
/* Turn NE2000 interrupts on. */
@@ -351,8 +405,8 @@ ne_interrupt_on (const rtems_irq_connect_data *irq)
{
struct ne_softc *sc;
-#ifdef DEBUG_NE2000
- printk ("ne_interrupt_on\n");
+#ifdef DEBUG_NE
+ printk ("ne_interrupt_on()\n");
#endif
sc = ne_device_for_irno (irq->name);
if (sc != NULL)
@@ -366,8 +420,8 @@ ne_interrupt_off (const rtems_irq_connect_data *irq)
{
struct ne_softc *sc;
-#ifdef DEBUG_NE2000
- printk ("ne_interrupt_off\n");
+#ifdef DEBUG_NE
+ printk ("ne_interrupt_off()\n");
#endif
sc = ne_device_for_irno (irq->name);
if (sc != NULL)
@@ -389,108 +443,134 @@ ne_init_hardware (struct ne_softc *sc)
{
unsigned int port = sc->port;
int i;
- rtems_irq_connect_data irq;
#ifdef DEBUG_NE2000
- printk ("ne_init_hardware\n");
+ printk ("ne_init_hardware()\n");
#endif
/* Initialize registers. */
+ /* Set interface for page 0, Remote DMA complete, Stopped */
outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);
- if (sc->byte_transfers) {
+ /* Set FIFO threshold to 8, No auto-init Remote DMA, byte order=80x86 */
+ /* byte-wide DMA xfers */
+ if (sc->byte_transfers)
outport_byte (port + DCR, MSK_FT10 | MSK_BMS);
- }
- else {
+ /* word-wide DMA xfers */
+ else
outport_byte (port + DCR, MSK_FT10 | MSK_BMS | MSK_WTS);
- }
+ /* Clear Remote Byte Count Registers */
outport_byte (port + RBCR0, 0);
outport_byte (port + RBCR1, 0);
+
+ /* For the moment, don't store incoming packets in memory. */
outport_byte (port + RCR, MSK_MON);
+
+ /* Place NIC in internal loopback mode */
outport_byte (port + TCR, MSK_LOOP);
- outport_byte (port + IMR, 0);
- outport_byte (port + ISR, 0xff);
- outport_byte (port + PSTOP, NE_STOP_PAGE);
+
+ /* Initialize transmit/receive (ring-buffer) Page Start */
+ outport_byte (port + TPSR, NE_FIRST_TX_PAGE);
outport_byte (port + PSTART, NE_FIRST_RX_PAGE);
+
+ /* Initialize Receiver (ring-buffer) Page Stop and Boundry */
+ outport_byte (port + PSTOP, NE_STOP_PAGE);
outport_byte (port + BNRY, NE_STOP_PAGE - 1);
- /* Set the Ethernet hardware address. */
+ /* Clear all interrupts */
+ outport_byte (port + ISR, 0xff);
+ /* Disable all interrupts */
+ outport_byte (port + IMR, 0);
+
+ /* Program Command Register for page 1 */
+ outport_byte (port + CMDR, MSK_PG1 | MSK_RD2 | MSK_STP);
- outport_byte (port + CMDR, MSK_PG1 | MSK_RD2);
+ /* Set the Ethernet hardware address. */
for (i = 0; i < ETHER_ADDR_LEN; ++i)
outport_byte (port + PAR + i, sc->arpcom.ac_enaddr[i]);
-#ifdef DEBUG_NE2000
- printk ("Using ethernet address: ");
- for (i = 0; i < ETHER_ADDR_LEN; ++i)
- printk("%x ",sc->arpcom.ac_enaddr[i]);
- printk ("\n");
-#endif
+ /* Set Current Page pointer to next_packet */
+ outport_byte (port + CURR, NE_FIRST_RX_PAGE);
/* Clear the multicast address. */
for (i = 0; i < MARsize; ++i)
outport_byte (port + MAR + i, 0);
- outport_byte (port + CURR, NE_FIRST_RX_PAGE);
+ /* Set page 0 registers */
+ outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);
- outport_byte (port + CMDR, MSK_PG0 | MSK_RD2);
+ /* accept broadcast */
+ outport_byte (port + RCR, (sc->accept_broadcasts ? MSK_AB : 0));
- /* Put the device on line. */
- outport_byte (port + CMDR, MSK_PG0 | MSK_STA | MSK_RD2);
+ /* Start interface */
+ outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STA);
- /* Set up interrupts. */
+ /* Take interface out of loopback */
+ outport_byte (port + TCR, 0);
+}
+
+/* Set up interrupts.
+*/
+static void
+ne_init_irq_handler(int irno)
+{
+ rtems_irq_connect_data irq;
- irq.name = sc->irno;
- irq.hdl = ne_interrupt_handler;
+#ifdef DEBUG_NE
+ printk("ne_init_irq_handler(%d)\n", irno);
+#endif
+ irq.name = irno;
+ irq.hdl = (rtems_irq_hdl)ne_interrupt_handler;
irq.on = ne_interrupt_on;
irq.off = ne_interrupt_off;
irq.isOn = ne_interrupt_is_on;
- if (! BSP_install_rtems_irq_handler (&irq))
- rtems_panic ("Can't attach NE interrupt handler for irq %d.\n",
- sc->irno);
-
- /* Prepare to receive packets. */
-
- outport_byte (port + TCR, 0);
- outport_byte (port + RCR, (sc->accept_broadcasts ? MSK_AB : 0));
+ if (!BSP_install_rtems_irq_handler (&irq))
+ rtems_panic ("Can't attach NE interrupt handler for irq %d\n", irno);
}
/* The NE2000 packet receive daemon. This task is started when the
NE2000 driver is initialized. */
+#ifdef DEBUG_NE
+static int ccc = 0; /* experinent! */
+#endif
+
static void
ne_rx_daemon (void *arg)
{
struct ne_softc *sc = (struct ne_softc *) arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
unsigned int port = sc->port;
- unsigned int dport = port + DATAPORT;
- while (1) {
+ while (1)
+ {
rtems_event_set events;
/* Wait for the interrupt handler to tell us that there is a
packet ready to receive. */
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- RTEMS_NO_TIMEOUT,
- &events);
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
/* Don't let the device interrupt us now. */
outport_byte (port + IMR, 0);
- while (1) {
+ while (1)
+ {
unsigned char startpage, currpage;
- unsigned short statnext, len;
- int next;
+ unsigned short len;
+ unsigned char next, stat, cnt1, cnt2;
struct mbuf *m;
unsigned char *p;
int startaddr;
int toend;
struct ether_header *eh;
+ struct ne_ring hdr; /* ring buffer header */
+ int reset;
inport_byte (port + BNRY, startpage);
@@ -500,75 +580,109 @@ ne_rx_daemon (void *arg)
++startpage;
if (startpage >= NE_STOP_PAGE)
- startpage = NE_FIRST_RX_PAGE;
+ startpage = NE_FIRST_RX_PAGE;
if (startpage == currpage)
- break;
+ break;
#ifdef DEBUG_NE2000
printk ("ne_rx_daemon: start page %x; current page %x\n",
- startpage, currpage);
+ startpage, currpage);
#endif
- /* Read the buffer header. This is 1 byte receive status, 1
- byte page of next buffer, 2 bytes length. */
- outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STA);
- outport_byte (port + RBCR0, 4);
- outport_byte (port + RBCR1, 0);
- outport_byte (port + RSAR0, 0);
- outport_byte (port + RSAR1, startpage);
- outport_byte (port + CMDR, MSK_PG0 | MSK_RRE | MSK_STA);
-
- if (sc->byte_transfers) {
- unsigned char data;
-
- inport_byte (dport, data); /* Throw away status */
- inport_byte (dport, data);
- next = data;
+ reset = 0;
- inport_byte (dport, data);
- len = data;
- inport_byte (dport, data);
- len |= data << 8;
+ /* Read the buffer header */
+ startaddr = startpage * NE_PAGE_SIZE;
+ ne_read_data(sc, startaddr, sizeof(hdr), (unsigned char *)&hdr);
+ next = hdr.next;
+ if (next >= NE_STOP_PAGE)
+ next = NE_FIRST_RX_PAGE;
+
+ /* check packet length */
+ len = hdr.count;
+ if (currpage < startpage)
+ cnt1 = currpage + (NE_STOP_PAGE - NE_FIRST_RX_PAGE) - startpage;
+ else
+ cnt1 = currpage - startpage;
+ cnt2 = len / NE_PAGE_SIZE;
+ if (len % NE_PAGE_SIZE)
+ cnt2++;
+ if (cnt1 < cnt2)
+ {
+#ifdef DEBUG_NE
+ printk("(%x<%x:%x)", cnt1, cnt2, len);
+/*
+ printk("start page 0x%x; current page 0x%x\n",
+ startpage, currpage);
+ printk("cnt1 < cnt2 (0x%x, 0x%x); len 0x%x\n",
+ cnt1, cnt2, len);
+*/
+#endif
+ reset = 1;
}
- else { /* Word transfers */
- inport_word (dport, statnext);
- inport_word (dport, len);
-
- next = statnext >> 8;
+ if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN + sizeof(struct ne_ring)) ||
+ len < (ETHER_MIN_LEN - ETHER_CRC_LEN + sizeof(struct ne_ring)) ||
+ len > MCLBYTES)
+ {
+#ifdef DEBUG_NE
+ printk("(%x)", len);
+/*
+ printk("start page 0x%x; current page 0x%x\n",
+ startpage, currpage);
+ printk("len out of range: 0x%x\n", len);
+ printk("stat: 0x%x, next: 0x%x\n", hdr.rsr, hdr.next);
+*/
+#endif
+ reset = 1;
+ }
+#ifdef DEBUG_NE
+ if (++ccc == 100)
+ { ccc = 0; reset = 1;
+ printk("T");
}
+#endif
- outport_byte (port + ISR, MSK_RDC);
+ /* reset interface */
+ if (reset)
+ {
+ ne_reset(sc);
+ goto Next;
+ }
- if (next >= NE_STOP_PAGE)
- next = NE_FIRST_RX_PAGE;
+ stat = hdr.rsr;
/* The first four bytes of the length are the buffer header. */
- len -= 4;
- startaddr = startpage * NE_PAGE_SIZE + 4;
+ len -= sizeof(struct ne_ring);
+ startaddr += sizeof(struct ne_ring);
MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT);
m->m_pkthdr.rcvif = ifp;
p = mtod (m, unsigned char *);
- m->m_len = m->m_pkthdr.len = len - sizeof (struct ether_header);
+ m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
toend = NE_STOP_PAGE * NE_PAGE_SIZE - startaddr;
- if (toend < len) {
- ne_read_data (sc, startaddr, toend, p);
- p += toend;
- len -= toend;
- startaddr = NE_FIRST_RX_PAGE * NE_PAGE_SIZE;
+ if (toend < len)
+ {
+ ne_read_data (sc, startaddr, toend, p);
+ p += toend;
+ len -= toend;
+ startaddr = NE_FIRST_RX_PAGE * NE_PAGE_SIZE;
}
if (len > 0)
- ne_read_data (sc, startaddr, len, p);
+ ne_read_data (sc, startaddr, len, p);
eh = mtod (m, struct ether_header *);
m->m_data += sizeof (struct ether_header);
- ether_input (ifp, eh, m);
+#ifdef DEBUG_NE
+ /* printk("[r%d]", hdr.count - sizeof(hdr)); */
+ printk("<");
+#endif
+ ether_input (ifp, eh, m);
++sc->stats.rx_packets;
outport_byte (port + BNRY, next - 1);
@@ -578,11 +692,12 @@ ne_rx_daemon (void *arg)
outport_byte (port + ISR, MSK_OVW);
outport_byte (port + TCR, 0);
if (sc->resend)
- outport_byte (port + CMDR, MSK_PG0 | MSK_TXP | MSK_RD2 | MSK_STA);
+ outport_byte (port + CMDR, MSK_PG0 | MSK_TXP | MSK_RD2 | MSK_STA);
sc->resend = 0;
sc->overrun = 0;
}
+ Next:
/* Reenable device interrupts. */
outport_byte (port + IMR, NE_INTERRUPTS);
}
@@ -599,6 +714,7 @@ ne_loadpacket (struct ne_softc *sc, struct mbuf *m)
int leftover;
unsigned char leftover_data;
int timeout;
+ int send_cnt = 0;
#ifdef DEBUG_NE2000
printk ("Uploading NE2000 packet\n");
@@ -616,7 +732,7 @@ ne_loadpacket (struct ne_softc *sc, struct mbuf *m)
/* Tell the device which address we want to write to. */
outport_byte (port + RSAR0, 0);
outport_byte (port + RSAR1,
- NE_FIRST_TX_PAGE + (sc->nextavail * NE_TX_PAGES));
+ NE_FIRST_TX_PAGE + (sc->nextavail * NE_TX_PAGES));
/* Set up the write. */
outport_byte (port + CMDR, MSK_PG0 | MSK_RWR | MSK_STA);
@@ -645,34 +761,43 @@ ne_loadpacket (struct ne_softc *sc, struct mbuf *m)
next = *data++;
--len;
outport_word (dport, leftover_data | (next << 8));
+ send_cnt += 2;
leftover = 0;
}
- /* If using byte transfers, len always ends up as zero so
+ /* If using byte transfers, len always ends up as zero so
there are no leftovers. */
if (sc->byte_transfers)
while (len > 0) {
- outport_byte (dport, *data++);
- len--;
+ outport_byte (dport, *data++);
+ len--;
}
else
while (len > 1) {
- outport_word (dport, data[0] | (data[1] << 8));
- data += 2;
- len -= 2;
+ outport_word (dport, data[0] | (data[1] << 8));
+ data += 2;
+ len -= 2;
+ send_cnt += 2;
}
if (len > 0)
{
- leftover = 1;
- leftover_data = *data++;
+ leftover = 1;
+ leftover_data = *data++;
}
}
if (leftover)
+ {
outport_word (dport, leftover_data);
+ send_cnt += 2;
+ }
+#ifdef DEBUG_NE
+ /* printk("{l%d|%d}", send_cnt, sc->nextavail); */
+ printk("v");
+#endif
m_freem (mhold);
/* Wait for the device to complete accepting the data, with a
@@ -685,13 +810,13 @@ ne_loadpacket (struct ne_softc *sc, struct mbuf *m)
#ifdef DEBUG_NE2000
if ((status &~ MSK_RDC) != 0)
- printk ("Status 0x%x while waiting for acknowledgement of uploaded packet\n",
- status);
+ printk ("Status 0x%x while waiting for acknowledgement of uploaded packet\n",
+ status);
#endif
if ((status & MSK_RDC) != 0) {
- outport_byte (port + ISR, MSK_RDC);
- break;
+ outport_byte (port + ISR, MSK_RDC);
+ break;
}
}
@@ -709,6 +834,7 @@ ne_loadpacket (struct ne_softc *sc, struct mbuf *m)
static void
ne_transmit (struct ne_softc *sc)
{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
unsigned int port = sc->port;
int len;
@@ -726,11 +852,18 @@ ne_transmit (struct ne_softc *sc)
outport_byte (port + CMDR, MSK_PG0 | MSK_TXP | MSK_RD2 | MSK_STA);
+#ifdef DEBUG_NE
+ /* printk("{s%d|%d}", len, sc->nextsend); */
+ printk(">");
+#endif
++sc->nextsend;
if (sc->nextsend == NE_TX_BUFS)
sc->nextsend = 0;
++sc->stats.tx_packets;
+
+ /* set watchdog timer */
+ ifp->if_timer = 2;
}
/* The NE2000 packet transmit daemon. This task is started when the
@@ -749,9 +882,9 @@ ne_tx_daemon (void *arg)
/* Wait for a packet to be ready for sending, or for there to be
room for another packet in the device memory. */
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
- RTEMS_EVENT_ANY | RTEMS_WAIT,
- RTEMS_NO_TIMEOUT,
- &events);
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &events);
#ifdef DEBUG_NE2000
printk ("ne_tx_daemon\n");
@@ -771,32 +904,32 @@ ne_tx_daemon (void *arg)
/* If the device is not transmitting a packet, and we have
uploaded a packet, tell the device to transmit it. */
if (! sc->transmitting && sc->inuse > 0) {
- sc->transmitting = 1;
- ne_transmit (sc);
+ sc->transmitting = 1;
+ ne_transmit (sc);
}
/* If we don't have any more buffers to send, quit now. */
if (ifp->if_snd.ifq_head == NULL) {
- ifp->if_flags &= ~IFF_OACTIVE;
- break;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ break;
}
/* Allocate a buffer to load data into. If there are none
available, quit until a buffer has been transmitted. */
if (sc->inuse >= NE_TX_BUFS)
- break;
+ break;
++sc->inuse;
IF_DEQUEUE (&ifp->if_snd, m);
if (m == NULL)
- panic ("ne_tx_daemon");
+ panic ("ne_tx_daemon");
ne_loadpacket (sc, m);
/* Check the device status. It may have finished transmitting
the last packet. */
- ne_check_status (sc);
+ ne_check_status(sc, 0);
}
/* Reenable device interrupts. */
@@ -811,6 +944,9 @@ ne_start (struct ifnet *ifp)
{
struct ne_softc *sc = ifp->if_softc;
+#ifdef DEBUG_NE
+ printk("S");
+#endif
/* Tell the transmit daemon to wake up and send a packet. */
rtems_event_send (sc->tx_daemon_tid, START_TRANSMIT_EVENT);
ifp->if_flags |= IFF_OACTIVE;
@@ -824,7 +960,14 @@ ne_init (void *arg)
struct ne_softc *sc = (struct ne_softc *) arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
- if (sc->tx_daemon_tid == 0) {
+#ifdef DEBUG_NE
+ printk("ne_init()\n");
+ ne_dump(sc);
+#endif
+
+ /* only once... */
+ if (sc->tx_daemon_tid == 0)
+ {
sc->inuse = 0;
sc->nextavail = 0;
sc->nextsend = 0;
@@ -834,6 +977,9 @@ ne_init (void *arg)
sc->tx_daemon_tid = rtems_bsdnet_newproc ("SCtx", 4096, ne_tx_daemon, sc);
sc->rx_daemon_tid = rtems_bsdnet_newproc ("SCrx", 4096, ne_rx_daemon, sc);
+
+ /* install rtems irq handler */
+ ne_init_irq_handler(sc->irno);
}
ifp->if_flags |= IFF_RUNNING;
@@ -844,11 +990,24 @@ ne_init (void *arg)
static void
ne_stop (struct ne_softc *sc)
{
+ sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING;
+
+ ne_stop_hardware(sc);
+
+ sc->inuse = 0;
+ sc->nextavail = 0;
+ sc->nextsend = 0;
+ sc->transmitting = 0;
+ sc->overrun = 0;
+ sc->resend = 0;
+}
+
+static void
+ne_stop_hardware (struct ne_softc *sc)
+{
unsigned int port = sc->port;
int i;
- sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING;
-
/* Stop everything. */
outport_byte (port + CMDR, MSK_STP | MSK_RD2);
@@ -859,15 +1018,43 @@ ne_stop (struct ne_softc *sc)
inport_byte (port + ISR, status);
if ((status & MSK_RST) != 0)
- break;
+ break;
}
+}
- sc->inuse = 0;
- sc->nextavail = 0;
- sc->nextsend = 0;
- sc->transmitting = 0;
+/* reinitializing interface
+*/
+static void
+ne_reset(struct ne_softc *sc)
+{
+ ne_stop(sc);
+ ne_init_hardware(sc);
+ sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+#ifdef DEBUG_NE
+ printk("*");
+#endif
}
+#ifdef DEBUG_NE
+/* show anything about ne
+*/
+static void
+ne_dump(struct ne_softc *sc)
+{
+ int i;
+ printk("\nne configuration:\n");
+ printk("ethernet addr:");
+ for (i=0; i<ETHER_ADDR_LEN; i++)
+ printk(" %x", sc->arpcom.ac_enaddr[i]);
+ printk("\n");
+ printk("irq = %d\n", sc->irno);
+ printk("port = 0x%x\n", sc->port);
+ printk("accept_broadcasts = %d\n", sc->accept_broadcasts);
+ printk("byte_transfers = %d\n", sc->byte_transfers);
+}
+#endif
+
/* Show NE2000 interface statistics. */
static void
@@ -932,16 +1119,41 @@ ne_ioctl (struct ifnet *ifp, int command, caddr_t data)
return error;
}
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to
+ * generate an interrupt after a transmit has been started on it.
+ */
+static void
+ne_watchdog(struct ifnet *ifp)
+{
+ struct ne_softc *sc = ifp->if_softc;
+
+ printk("ne2000: device timeout\n");
+ ifp->if_oerrors++;
+
+ ne_reset(sc);
+}
+
+static void
+print_byte(unsigned char b)
+{
+ printk("%x%x", b >> 4, b & 0x0f);
+}
+
/* Attach an NE2000 driver to the system. */
int
-rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config)
+rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach)
{
int i;
struct ne_softc *sc;
struct ifnet *ifp;
int mtu;
+ /* dettach ... */
+ if (!attach)
+ return 0;
+
/* Find a free driver. */
sc = NULL;
for (i = 0; i < NNEDRIVER; ++i) {
@@ -959,7 +1171,7 @@ rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config)
memset (sc, 0, sizeof *sc);
/* Check whether we do byte-wide or word-wide transfers. */
-
+
#ifdef NE2000_BYTE_TRANSFERS
sc->byte_transfers = TRUE;
#else
@@ -991,7 +1203,7 @@ rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config)
if (config->hardware_address != NULL)
memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
- ETHER_ADDR_LEN);
+ ETHER_ADDR_LEN);
else
{
unsigned char prom[16];
@@ -1002,10 +1214,10 @@ rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config)
outport_byte (sc->port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);
if (sc->byte_transfers) {
- outport_byte (sc->port + DCR, MSK_FT10 | MSK_BMS);
+ outport_byte (sc->port + DCR, MSK_FT10 | MSK_BMS);
}
else {
- outport_byte (sc->port + DCR, MSK_FT10 | MSK_BMS | MSK_WTS);
+ outport_byte (sc->port + DCR, MSK_FT10 | MSK_BMS | MSK_WTS);
}
outport_byte (sc->port + RBCR0, 0);
@@ -1020,7 +1232,7 @@ rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config)
outport_byte (sc->port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);
for (ia = 0; ia < ETHER_ADDR_LEN; ++ia)
- sc->arpcom.ac_enaddr[ia] = prom[ia * 2];
+ sc->arpcom.ac_enaddr[ia] = prom[ia * 2];
}
/* Set up the network interface. */
@@ -1031,6 +1243,7 @@ rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config)
ifp->if_mtu = mtu;
ifp->if_init = ne_init;
ifp->if_ioctl = ne_ioctl;
+ ifp->if_watchdog = ne_watchdog;
ifp->if_start = ne_start;
ifp->if_output = ether_output;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
@@ -1042,5 +1255,14 @@ rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config)
if_attach (ifp);
ether_ifattach (ifp);
+ printk("network device '%s' <", config->name);
+ print_byte(sc->arpcom.ac_enaddr[0]);
+ for (i=1; i<ETHER_ADDR_LEN; i++)
+ { printk(":");
+ print_byte(sc->arpcom.ac_enaddr[i]);
+ }
+ printk("> initialized on port 0x%x, irq %d\n", sc->port, sc->irno);
+
return 1;
}
+