summaryrefslogtreecommitdiffstats
path: root/bsps/arm/gumstix/net/rtl8019.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/gumstix/net/rtl8019.c')
-rw-r--r--bsps/arm/gumstix/net/rtl8019.c1197
1 files changed, 0 insertions, 1197 deletions
diff --git a/bsps/arm/gumstix/net/rtl8019.c b/bsps/arm/gumstix/net/rtl8019.c
deleted file mode 100644
index 00fd2fdf09..0000000000
--- a/bsps/arm/gumstix/net/rtl8019.c
+++ /dev/null
@@ -1,1197 +0,0 @@
-/*
- *By Yang Xi <hiyangxi@gmail.com>.
- *RTL8019 ethernet driver for Gumstix on SKYEYE simulator
- *Based on NE2000 driver for pc386 bsp
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- */
-
-#include <machine/rtems-bsd-kernel-space.h>
-
-#include <bsp.h>
-#include <bsp/irq.h>
-#include "wd80x3.h"
-
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <rtems/bspIo.h>
-#include <rtems/error.h>
-#include <rtems/rtems_bsdnet.h>
-
-#include <sys/param.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/sockio.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-
-/* Define this to force byte-wide data transfers with the NIC. This
- is needed for boards like the TS-1325 386EX PC, which support only
- an 8-bit PC/104 bus. Undefine this on a normal PC.*/
-
-#define NE2000_BYTE_TRANSFERS
-
-/* 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. */
-
-#if (MCLBYTES < 1520)
-# error "Driver must have MCLBYTES >= 1520"
-#endif
-
-/* The 8390 macro definitions in wd80x3.h expect RO to be defined. */
-#define RO 0
-
-/* Minimum size of Ethernet packet. */
-#define ET_MINLEN 60
-
-/* The number of NE2000 devices supported by this driver. */
-
-#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
- network task synchronization. */
-#define INTERRUPT_EVENT RTEMS_EVENT_1
-
-/* RTEMS event number used to start the transmit daemon. This must
- not be the same as INTERRUPT_EVENT. */
-#define START_TRANSMIT_EVENT RTEMS_EVENT_2
-
-/* Interrupts we want to handle from the device. */
-
-#define NE_INTERRUPTS \
- (MSK_PRX | MSK_PTX | MSK_RXE | MSK_TXE | MSK_OVW | MSK_CNT)
-
-/* The size of a page in device memory. */
-
-#define NE_PAGE_SIZE (256)
-
-/* The first page address in device memory. */
-
-#define NE_START_PAGE (0x40)
-
-/* The last page address, plus 1. */
-
-#define NE_STOP_PAGE (0x80)
-
-/* The number of pages used for a single transmit buffer. This is
- 1536 bytes, enough for a full size packet. */
-
-#define NE_TX_PAGES (6)
-
-/* The number of transmit buffers. We use two, so we can load one
- packet while the other is being sent. */
-
-#define NE_TX_BUFS (2)
-
-/* We use the first pages in memory as transmit buffers, and the
- remaining ones as receive buffers. */
-
-#define NE_FIRST_TX_PAGE (NE_START_PAGE)
-
-#define NE_FIRST_RX_PAGE (NE_FIRST_TX_PAGE + NE_TX_PAGES * NE_TX_BUFS)
-
-/* Data we store for each NE2000 device. */
-
-struct ne_softc {
- /* The bsdnet information structure. */
- struct arpcom arpcom;
-
- /* The interrupt request number. */
- unsigned int irno;
- /* The base IO port number. */
- unsigned int port;
-
- /* Whether we accept broadcasts. */
- int accept_broadcasts;
-
- /* The thread ID of the transmit task. */
- rtems_id tx_daemon_tid;
- /* The thread ID of the receive task. */
- rtems_id rx_daemon_tid;
-
- /* Whether we use byte-transfers with the device. */
- bool byte_transfers;
-
- /* The number of memory buffers which the transmit daemon has loaded
- with data to be sent, but which have not yet been completely
- sent. */
- int inuse;
- /* The index of the next available transmit memory buffer. */
- int nextavail;
- /* The index of the next transmit buffer to send. */
- int nextsend;
- /* Nonzero if the device is currently transmitting a packet. */
- int transmitting;
- /* The length of the data stored in each transmit buffer. */
- int sendlen[NE_TX_BUFS];
-
- /* Set if we have a packet overrun while receiving. */
- int overrun;
- /* Set if we should resend after an overrun. */
- int resend;
-
- /* Statistics. */
- struct {
- /* Number of packets received. */
- unsigned long rx_packets;
- /* Number of packets sent. */
- unsigned long tx_packets;
- /* Number of interrupts. */
- unsigned long interrupts;
- /* Number of receive acknowledgements. */
- unsigned long rx_acks;
- /* Number of transmit acknowledgements. */
- unsigned long tx_acks;
- /* Number of packet overruns. */
- unsigned long overruns;
- /* Number of frame errors. */
- unsigned long rx_frame_errors;
- /* Number of CRC errors. */
- unsigned long rx_crc_errors;
- /* Number of missed packets. */
- unsigned long rx_missed_errors;
- } stats;
-};
-
-/* The list of NE2000 devices on this system. */
-
-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 (struct ne_softc *sc);
-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
-
-/* Read data from an NE2000 device. Read LEN bytes at ADDR, storing
- them into P. */
-
-static void
-ne_read_data (struct ne_softc *sc, int addr, int len, unsigned char *p)
-{
- unsigned int port = sc->port;
- unsigned int dport = port + DATAPORT;
- outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STA);
- outport_byte (port + RBCR0, len);
- outport_byte (port + RBCR1, len >> 8);
- outport_byte (port + RSAR0, addr);
- outport_byte (port + RSAR1, addr >> 8);
- outport_byte (port + CMDR, MSK_PG0 | MSK_RRE | MSK_STA);
-
- if (sc->byte_transfers)
- {
- unsigned char d;
- while (len > 0)
- {
- inport_byte(dport, d);
- *p++ = d;
- len--;
- }
- }
- else /* word transfers */
- {
- 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);
-}
-
-/* Handle the current NE2000 status. This is called when the device
- signals an interrupt. It is also called at other times while
- NE2000 interrupts have been disabled. */
-
-static void
-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;
-
- /* It seems that we need to use a loop here, because if the NE2000
- signals an interrupt because packet transmission is complete, and
- then receives a packet while interrupts are disabled, it seems to
- sometimes fail to signal the interrupt for the received packet
- when interrupts are reenabled. (Based on the behaviour of the
- Realtek 8019AS chip). */
-
- /* int count = 0; */
- while (1)
- {
- inport_byte (port + ISR, status);
-#ifdef DEBUG_NE2000
- printk ("NE2000 status 0x%x\n", status);
-#endif
- if (status == 0)
- break;
-
- /* ack */
- outport_byte (port + ISR, status);
-
- /* Check for incoming packet overwrite. */
- if (status & MSK_OVW)
- {
- ifp->if_timer = 0;
-#ifdef DEBUG_NE
- printk("^\n");
-#endif
- ++sc->stats.overruns;
- 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)
- {
- ifp->if_timer = 0;
- ++sc->stats.tx_acks;
- --sc->inuse;
- sc->transmitting = 0;
- if (sc->inuse > 0 || (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) != 0)
- rtems_bsdnet_event_send (sc->tx_daemon_tid, START_TRANSMIT_EVENT);
- }
-
- /* Check for received packet. */
- if ((status & (MSK_PRX | MSK_RXE)) != 0)
- {
- ++sc->stats.rx_acks;
- rtems_bsdnet_event_send (sc->rx_daemon_tid, INTERRUPT_EVENT);
- }
-
- /* Check for counter change. */
- 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;
- }
-
- break;
- }
-
- outport_byte (port + CMDR, MSK_PG0 | MSK_STA | MSK_RD2);
-
-}
-
-/* Handle an NE2000 interrupt. */
-
-static void
-ne_interrupt_handler (void *arg)
-{
- struct ne_softc *sc = arg;
-
- if (sc == NULL)
- return;
-
- ++sc->stats.interrupts;
-
-#ifdef DEBUG_NE
- printk("!");
-#endif
- ne_check_status(sc, 1);
-}
-
-/* Turn NE2000 interrupts on. */
-
-static void
-ne_interrupt_on (struct ne_softc *sc)
-{
-#ifdef DEBUG_NE
- printk ("ne_interrupt_on()\n");
-#endif
- if (sc != NULL)
- outport_byte (sc->port + IMR, NE_INTERRUPTS);
-}
-
-/* Initialize the NE2000 hardware. */
-
-static void
-ne_init_hardware (struct ne_softc *sc)
-{
- unsigned int port = sc->port;
- int i;
-
-#ifdef DEBUG_NE2000
- 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);
-
- /* 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);
- /* 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);
-
- /* 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 Boundary */
- outport_byte (port + PSTOP, NE_STOP_PAGE);
- outport_byte (port + BNRY, NE_STOP_PAGE - 1);
-
- /* 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);
-
- /* Set the Ethernet hardware address. */
- for (i = 0; i < ETHER_ADDR_LEN; ++i)
- outport_byte (port + PAR + i, sc->arpcom.ac_enaddr[i]);
-
- /* 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);
-
- /* Set page 0 registers */
- outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);
-
- /* accept broadcast */
- outport_byte (port + RCR, (sc->accept_broadcasts ? MSK_AB : 0));
-
- /* Start interface */
- outport_byte (port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STA);
-
- /* Take interface out of loopback */
- outport_byte (port + TCR, 0);
-}
-
-/* Set up interrupts.
-*/
-static void
-ne_init_irq_handler(struct ne_softc *sc)
-{
- rtems_status_code status = RTEMS_SUCCESSFUL;
-
-#ifdef DEBUG_NE
- printk("ne_init_irq_handler(%d)\n", sc->irno);
-#endif
-
- status = rtems_interrupt_handler_install(
- sc->irno,
- "RTL8019",
- RTEMS_INTERRUPT_UNIQUE,
- ne_interrupt_handler,
- sc
- );
- assert(status == RTEMS_SUCCESSFUL);
- ne_interrupt_on(sc);
-}
-
-/* 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;
-
- 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);
-
- /* Don't let the device interrupt us now. */
- outport_byte (port + IMR, 0);
-
- while (1)
- {
- unsigned char startpage, currpage;
- unsigned short len;
- unsigned char next, cnt1, cnt2;
- struct mbuf *m = NULL;
- 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);
-
- outport_byte (port + CMDR, MSK_PG1 | MSK_RD2);
- inport_byte (port + CURR, currpage);
- outport_byte (port + CMDR, MSK_PG0 | MSK_RD2);
-
- ++startpage;
- if (startpage >= NE_STOP_PAGE)
- startpage = NE_FIRST_RX_PAGE;
-
- if (startpage == currpage)
- break;
-
-#ifdef DEBUG_NE2000
- printk ("ne_rx_daemon: start page %x; current page %x\n",
- startpage, currpage);
-#endif
-
- reset = 0;
-
- /* 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)\n", 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;
- }
- 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
-
- /* reset interface */
- if (reset)
- {
- printk("Reset in RX\n");
- ne_reset(sc);
- goto Next;
- }
-
- /* The first four bytes of the length are the buffer header
- * Just decrease them by 2 since in ARM, we have to make sure
- * 4bytes memory access align on 4bytes
- */
- len -= 2;
- startaddr += 2;
-
- MGETHDR (m, M_WAIT, MT_DATA);
- MCLGET (m, M_WAIT);
-
- if (m == NULL)
- panic ("ne_rx_daemon");
-
- m->m_pkthdr.rcvif = ifp;
- m->m_nextpkt = 0;
-
- p = mtod (m, unsigned char *);
- m->m_len = m->m_pkthdr.len = len - (sizeof(struct ether_header) + 2);
-
- 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 (len > 0)
- ne_read_data (sc, startaddr, len, p);
-
- m->m_data +=2;
- eh = mtod(m, struct ether_header *);
- m->m_data += sizeof (struct ether_header);
-
-#ifdef DEBUG_NE
- /*printk("[r%d]", hdr.count - sizeof(hdr));*/
- printk("<\n");
-#endif
- ether_input (ifp, eh, m);
- ++sc->stats.rx_packets;
- outport_byte (port + BNRY, next - 1);
- }
-
- if (sc->overrun) {
- 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);
- sc->resend = 0;
- sc->overrun = 0;
- }
-
- Next:
- /* Reenable device interrupts. */
- outport_byte (port + IMR, NE_INTERRUPTS);
- }
-}
-
-/* Load an NE2000 packet onto the device. */
-
-static void
-ne_loadpacket (struct ne_softc *sc, struct mbuf *m)
-{
- unsigned int port = sc->port;
- unsigned int dport = port + DATAPORT;
- struct mbuf *mhold = m;
- int leftover;
- unsigned char leftover_data;
- int timeout;
- int send_cnt = 0;
-
-#ifdef DEBUG_NE2000
- printk ("Uploading NE2000 packet\n");
-#endif
-
- /* Reset remote DMA complete flag. */
- outport_byte (port + ISR, MSK_RDC);
-
- /* Write out the count. */
- outport_byte (port + RBCR0, m->m_pkthdr.len);
- outport_byte (port + RBCR1, m->m_pkthdr.len >> 8);
-
- sc->sendlen[sc->nextavail] = m->m_pkthdr.len;
-
- /* 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));
-
- /* Set up the write. */
- outport_byte (port + CMDR, MSK_PG0 | MSK_RWR | MSK_STA);
-
- /* Transfer the mbuf chain to device memory. NE2000 devices require
- that the data be transferred as words, so we need to handle odd
- length mbufs. Never occurs if we force byte transfers. */
-
- leftover = 0;
- leftover_data = '\0';
-
- for (; m != NULL; m = m->m_next) {
- int len;
- unsigned char *data;
-
- len = m->m_len;
- if (len == 0)
- continue;
-
- data = mtod (m, unsigned char *);
-
- if (leftover) {
- unsigned char next;
-
- /* Data left over from previous mbuf in chain. */
- 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
- there are no leftovers. */
-
- if (sc->byte_transfers)
- while (len > 0) {
- outport_byte (dport, *data++);
- len--;
- }
- else
- while (len > 1) {
- outport_word (dport, data[0] | (data[1] << 8));
- data += 2;
- len -= 2;
- send_cnt += 2;
- }
-
- if (len > 0)
- {
- 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
- limiting counter so that we don't wait too long. */
- for (timeout = 0; timeout < 1000; ++timeout)
- {
- unsigned char status;
-
- inport_byte (port + ISR, status);
-
-#ifdef DEBUG_NE2000
- if ((status &~ MSK_RDC) != 0)
- 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;
- }
- }
-
- if (timeout >= 1000)
- printk ("Timed out waiting for acknowledgement of uploaded NE2000 packet\n");
-
- ++sc->nextavail;
- if (sc->nextavail == NE_TX_BUFS)
- sc->nextavail = 0;
-}
-
-/* Tell the NE2000 to transmit a buffer whose contents we have already
- loaded onto the device. */
-
-static void
-ne_transmit (struct ne_softc *sc)
-{
- struct ifnet *ifp = &sc->arpcom.ac_if;
- unsigned int port = sc->port;
- int len;
-
-#ifdef DEBUG_NE2000
- printk ("Transmitting NE2000 packet\n");
-#endif
-
- len = sc->sendlen[sc->nextsend];
- if (len < ET_MINLEN)
- len = ET_MINLEN;
- outport_byte (port + TBCR0, len);
- outport_byte (port + TBCR1, len >> 8);
-
- outport_byte (port + TPSR, NE_FIRST_TX_PAGE + (sc->nextsend * NE_TX_PAGES));
-
- 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
- NE2000 driver is initialized. */
-
-static void
-ne_tx_daemon (void *arg)
-{
- struct ne_softc *sc = (struct ne_softc *) arg;
- unsigned int port = sc->port;
- struct ifnet *ifp = &sc->arpcom.ac_if;
-
- while (1) {
- rtems_event_set events;
-
- /* 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);
-
-#ifdef DEBUG_NE2000
- printk ("ne_tx_daemon\n");
-#endif
-
- /* This daemon handles both uploading data onto the device and
- telling the device to transmit data which has been uploaded.
- These are separate tasks, because while the device is
- transmitting one buffer we will upload another. */
-
- /* Don't let the device interrupt us now. */
- outport_byte (port + IMR, 0);
-
- while (1) {
- struct mbuf *m;
-
- /* 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);
- }
-
- /* 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;
- }
-
- /* 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;
-
- ++sc->inuse;
-
- IF_DEQUEUE (&ifp->if_snd, m);
- if (m == NULL)
- panic ("ne_tx_daemon");
-
- ne_loadpacket (sc, m);
-
- /* Check the device status. It may have finished transmitting
- the last packet. */
- ne_check_status(sc, 0);
- }
-
- /* Reenable device interrupts. */
- outport_byte (port + IMR, NE_INTERRUPTS);
- }
-}
-
-/* Start sending an NE2000 packet. */
-
-static void
-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_bsdnet_event_send (sc->tx_daemon_tid, START_TRANSMIT_EVENT);
- ifp->if_flags |= IFF_OACTIVE;
-}
-
-/* Initialize and start and NE2000. */
-
-static void
-ne_init (void *arg)
-{
- struct ne_softc *sc = (struct ne_softc *) arg;
- struct ifnet *ifp = &sc->arpcom.ac_if;
-
-#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;
- sc->transmitting = 0;
-
- ne_init_hardware (sc);
-
- 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);
- }
-
- ifp->if_flags |= IFF_RUNNING;
-}
-
-/* Stop an NE2000. */
-
-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;
-
- /* Stop everything. */
- outport_byte (port + CMDR, MSK_STP | MSK_RD2);
-
- /* Wait for the interface to stop, using I as a time limit. */
- for (i = 0; i < 5000; ++i)
- {
- unsigned char status;
-
- inport_byte (port + ISR, status);
- if ((status & MSK_RST) != 0)
- break;
- }
-}
-
-/* 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
-ne_stats (struct ne_softc *sc)
-{
- printf (" Received packets: %-8lu", sc->stats.rx_packets);
- printf (" Transmitted packets: %-8lu\n", sc->stats.tx_packets);
- printf (" Receive acks: %-8lu", sc->stats.rx_acks);
- printf (" Transmit acks: %-8lu\n", sc->stats.tx_acks);
- printf (" Packet overruns: %-8lu", sc->stats.overruns);
- printf (" Frame errors: %-8lu\n", sc->stats.rx_frame_errors);
- printf (" CRC errors: %-8lu", sc->stats.rx_crc_errors);
- printf (" Missed packets: %-8lu\n", sc->stats.rx_missed_errors);
- printf (" Interrupts: %-8lu\n", sc->stats.interrupts);
-}
-
-/* NE2000 driver ioctl handler. */
-
-static int
-ne_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
-{
- struct ne_softc *sc = ifp->if_softc;
- int error = 0;
-
- switch (command) {
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- error = ether_ioctl (ifp, command, data);
- break;
-
- case SIOCSIFFLAGS:
- switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
- case IFF_RUNNING:
- ne_stop (sc);
- break;
-
- case IFF_UP:
- printk("IFF_UP\n");
- ne_init (sc);
- break;
-
- case IFF_UP | IFF_RUNNING:
- ne_stop (sc);
- ne_init (sc);
- break;
-
- default:
- break;
- }
- break;
-
- case SIO_RTEMS_SHOW_STATS:
- ne_stats (sc);
- break;
-
- /* FIXME: Multicast commands must be added here. */
-
- default:
- error = EINVAL;
- break;
- }
-
- 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, 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) {
- sc = &ne_softc[i];
- ifp = &sc->arpcom.ac_if;
- if (ifp->if_softc == NULL)
- break;
- }
-
- if (sc == NULL) {
- printf ("Too many NE2000 drivers.\n");
- return 0;
- }
-
- memset (sc, 0, sizeof *sc);
-
- /* Check whether we do byte-wide or word-wide transfers. */
-
-#ifdef NE2000_BYTE_TRANSFERS
- sc->byte_transfers = true;
-#else
- sc->byte_transfers = false;
-#endif
-
- /* Handle the options passed in by the caller. */
-
- if (config->mtu != 0)
- mtu = config->mtu;
- else
- mtu = ETHERMTU;
-
- /* We use 16 as the default IRQ. */
- sc->irno = XSCALE_IRQ_NETWORK;
-
-
-
- /*IO prts are mapped to 0X40000600 */
- sc->port = 0x40000600;
-
- sc->accept_broadcasts = ! config->ignore_broadcast;
-
- if (config->hardware_address != NULL)
- memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
- ETHER_ADDR_LEN);
- else
- {
- unsigned char prom[16];
- int ia;
-
- /* Read the PROM to get the Ethernet hardware address. */
-
- outport_byte (sc->port + CMDR, MSK_PG0 | MSK_RD2 | MSK_STP);
-
- if (sc->byte_transfers) {
- 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 + RBCR0, 0);
- outport_byte (sc->port + RBCR1, 0);
- outport_byte (sc->port + RCR, MSK_MON);
- outport_byte (sc->port + TCR, MSK_LOOP);
- outport_byte (sc->port + IMR, 0);
- outport_byte (sc->port + ISR, 0xff);
-
- ne_read_data (sc, 0, sizeof prom, prom);
-
- 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];
- }
-
- /* Set up the network interface. */
-
- ifp->if_softc = sc;
- ifp->if_unit = i + 1;
- ifp->if_name = "ne";
- 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;
- if (ifp->if_snd.ifq_maxlen == 0)
- ifp->if_snd.ifq_maxlen = ifqmaxlen;
-
- /* Attach the interface. */
-
- 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;
-}