diff options
-rw-r--r-- | c/src/lib/libbsp/i386/pc386/ne2000/ne2000.c | 548 |
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; } + |