/*
* RTEMS driver for TULIP based Ethernet Controller
*
* $Header$
*/
/* make sure we can identify the platform (is __i386 valid?) */
#if !defined(__PPC) && !defined(__i386)
# error "unknown platform: should be __i386 or __PPC"
#endif
#include <bsp.h>
#if defined(i386)
#include <pcibios.h>
#endif
/* #include <stdlib.h> */
#include <stdio.h>
#include <stdarg.h>
#include <rtems/error.h>
#include <rtems/rtems_bsdnet.h>
#include <rtems/score/cpu.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#if defined(i386)
#include <irq.h>
#endif
#ifdef malloc
#undef malloc
#endif
#ifdef free
#undef free
#endif
#define PCI_VENDOR_ID_DEC 0x1011
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
#define IO_MASK 0x3
#define MEM_MASK 0xF
/* command and status registers, 32-bit access, only if MEMORY-ACCESS */
#define CSR0 0x00 /* bus mode register */
#define CSR1 0x02 /* transmit poll demand */
#define CSR2 0x04 /* receive poll demand */
#define CSR3 0x06 /* receive list base address */
#define CSR4 0x08 /* transmit list base address */
#define CSR5 0x0A /* status register */
#define CSR6 0x0C /* operation mode register */
#define CSR7 0x0E /* interrupt mask register */
#define CSR8 0x10 /* missed frame counter */
#define CSR9 0x12 /* Ethernet ROM register */
#define CSR10 0x14 /* reserved */
#define CSR11 0x16 /* full-duplex register */
#define CSR12 0x18 /* SIA status register */
#define CSR13 0x1A
#define CSR14 0x1C
#define CSR15 0x1E /* SIA general register */
#define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */
#define RESET_CHIP 0x00000001
#if defined(__PPC)
#define CSR0_MODE 0x0020E002
#define CSR6_INIT 0x0224c000
#else
#define CSR0_MODE 0x01a08000
#define CSR6_INIT 0x020c0000
#endif
#define ROM_ADDRESS 0x00004800
#define CSR6_TX 0x00002000
#define CSR6_TXRX 0x00002002
#define IT_SETUP 0x0001a3ef
#define CLEAR_IT 0xFFFFFFFF
#define NO_IT 0x00000000
#define SETUP_PACKET 0x08000000
#define END_OF_RING 0x02000000
#define CHAINED_ADDRESS 0x01000000
#define OWNED_BY_DEC21140 0x80000000
#define OWNED_BY_HOST 0x00000000
#define LAST_SEGMENT 0x40000000
#define FIRST_SEGMENT 0x20000000
#define NRXBUFS 8 /* number of receive buffers */
#define NTXBUFS 32 /* number of transmit buffers */
/* message descriptor entry */
struct MD {
/* used by hardware */
volatile unsigned32 status;
volatile unsigned32 counts;
unsigned32 buf1, buf2;
/* used by software */
struct mbuf *m;
struct MD *next;
};
static inline void write_descr_status(volatile struct MD *m, unsigned32 status) {
st_le32(&(m->status), status);
}
static inline unsigned32 read_descr_status(volatile struct MD *m) {
return ld_le32(&(m->status));
}
static inline void write_descr_counts(volatile struct MD *m, unsigned32 counts) {
st_le32(&(m->counts), counts);
}
static inline unsigned32 read_descr_counts(volatile struct MD *m) {
return ld_le32(&(m->counts));
}
static inline void set_chain_address(volatile struct MD *m, void *addr) {
st_le32(&(m->buf2), LOCAL_TO_PCI(addr));
}
static inline void set_buffer_address(volatile struct MD *m, void *addr) {
st_le32(&(m->buf1), LOCAL_TO_PCI(addr));
}
static inline void *get_buffer_address(volatile struct MD *m) {
return (void *)INVERSE_LOCAL_TO_PCI(ld_le32(&(m->buf1)));
}
/*
* Number of WDs supported by this driver
*/
#define NDECDRIVER 1
/*
* Receive buffer size -- Allow for a full ethernet packet including CRC
*/
#define RBUF_SIZE 1520
#define ET_MINLEN 60 /* minimum message length */
/*
* RTEMS event used by interrupt handler to signal driver tasks.
* This must not be any of the events used by the network task synchronization.
*/
#define INTERRUPT_EVENT RTEMS_EVENT_1
/*
* RTEMS event used to start transmit daemon.
* This must not be the same as INTERRUPT_EVENT.
*/
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
#if (MCLBYTES < RBUF_SIZE)
# error "Driver must have MCLBYTES > RBUF_SIZE"
#endif
/*
* Per-device data
*/
struct dec21140_softc {
struct arpcom arpcom;
#if defined(__PPC)
int irqInfo;
#else
rtems_irq_connect_data irqInfo;
#endif
struct MD *MDbase;
char *bufferBase;
int acceptBroadcast;
rtems_id rxDaemonTid;
rtems_id txDaemonTid;
struct MD *TxMD;
struct MD *SentTxMD;
int PendingTxCount;
int TxSuspended;
unsigned32 port;
unsigned32 *base;
/*
* Statistics
*/
unsigned32 rxInterrupts;
unsigned32 rxNotFirst;
unsigned32 rxNotLast;
unsigned32 rxGiant;
unsigned32 rxNonOctet;
unsigned32 rxRunt;
unsigned32 rxBadCRC;
unsigned32 rxOverrun;
unsigned32 rxCollision;
unsigned32 txInterrupts;
unsigned32 txDeferred;
unsigned32 txHeartbeat;
unsigned32 txLateCollision;
unsigned32 txRetryLimit;
unsigned32 txUnderrun;
unsigned32 txLostCarrier;
unsigned32 txRawWait;
};
static struct dec21140_softc dec21140_softc[NDECDRIVER];
static rtems_interval ticks_per_second;
/* ================================================================ */
static inline void write_csr(unsigned32 *base, int csr, unsigned32 value) {
synchronize_io();
st_le32(base + csr, value);
}
static inline unsigned32 read_csr(unsigned32 *base, int csr) {
synchronize_io();
return ld_le32(base + csr);
}
/* ================================================================ */
/*
* DEC21140 interrupt handler
*/
static rtems_isr dec21140Enet_interrupt_handler (rtems_vector_number v) {
unsigned32 *tbase;
unsigned32 status;
struct dec21140_softc *sc;
#if NDECDRIVER == 1
sc = &dec21140_softc[0];
#else
# error "need to find dec21140_softc[i] based on vector number"
#endif
tbase = sc->base ;
/*
* Read status
*/
status = read_csr(tbase, CSR5);
write_csr(tbase, CSR5, status); /* clear the bits we've read */
/*
* severe error?
*/
if (status & 0x0000230a){
printk("FATAL ERROR in network driver: CSR5=0x%08x\n", status);
}
/*
* Frame received?
*/
if (status & 0x000000c0){
sc->rxInterrupts++;
rtems_event_send (sc->rxDaemonTid, INTERRUPT_EVENT);
}
/*
* Frame transmitted or transmit error?
*/
if (status & 0x00000025) {
if (status & 0x00000004) {
sc->TxSuspended = 1;
}
sc->txInterrupts++;
rtems_event_send (sc->txDaemonTid, INTERRUPT_EVENT);
}
}
#if defined(__i386)
static void nopOn(const rtems_irq_connect_data* notUsed) {
/*
* code should be moved from dec21140Enet_initialize_hardware
* to this location
*/
}
static int dec21140IsOn(const rtems_irq_connect_data* irq) {
return BSP_irq_enabled_at_i8259s (irq->name);
}
#endif
/*
* Initialize the ethernet hardware
*/
#define PPCBUG_HW_ADDR_STORAGE 0x1f2c
static void dec21140Enet_initialize_hardware (struct dec21140_softc *sc) {
rtems_status_code st;
unsigned32 *tbase;
int i;
char *cp, *setup_frm, *eaddrs;
unsigned char *buffer;
struct MD *rmd;
tbase = sc->base;
/*
* WARNING : First write in CSR6
* Then Reset the chip ( 1 in CSR0)
*/
write_csr(tbase, CSR6, CSR6_INIT);
write_csr(tbase, CSR0, RESET_CHIP);
delay_in_bus_cycles(200);
/*
* Init CSR0
*/
write_csr(tbase, CSR0, CSR0_MODE);
read_nvram(sc->arpcom.ac_enaddr, PPCBUG_HW_ADDR_STORAGE, 6);
#ifdef DEC_DEBUG
printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n",
sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1],
sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3],
sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5],
sc->irqInfo, sc->port, sc->base);
#endif
/*
* Init RX ring
*/
#if defined(__i386)
cp = (char *)malloc((NRXBUFS + NTXBUFS) * (sizeof(struct MD) + RBUF_SIZE) +
PG_SIZE);
sc->bufferBase = cp;
cp += (PG_SIZE - (int)cp) & MASK_OFFSET ;
if (_CPU_is_paging_enabled()) {
_CPU_change_memory_mapping_attribute
(NULL, cp,
(NRXBUFS + NTXBUFS) * (sizeof(struct MD) + RBUF_SIZE),
PTE_CACHE_DISABLE | PTE_WRITABLE);
}
#endif
#if defined(__PPC)
cp = (char *)malloc((NRXBUFS + NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE) +
4096);
#endif
rmd = (struct MD *)cp;
sc->MDbase = rmd;
buffer = cp + ((NRXBUFS + NTXBUFS)*sizeof(struct MD));
write_csr(tbase, CSR3, LOCAL_TO_PCI(sc->MDbase));
for (i = 0 ; i < NRXBUFS; i++){
struct mbuf *m;
/* allocate an mbuf for each receive descriptor */
MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT);
m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
rmd->m = m;
set_buffer_address(rmd, mtod(m, void *));
if (i == NRXBUFS - 1) {
write_descr_counts(rmd, END_OF_RING | RBUF_SIZE);
rmd->next = sc->MDbase;
} else {
write_descr_counts(rmd, CHAINED_ADDRESS | RBUF_SIZE);
set_chain_address(rmd, rmd + 1);
rmd->next = rmd + 1;
}
write_descr_status(rmd, OWNED_BY_DEC21140);
rmd++;
}
/*
* Init TX ring
*/
write_csr(tbase, CSR4, LOCAL_TO_PCI(rmd));
for (i = 0 ; i < NTXBUFS; i++){
set_buffer_address(rmd + i, buffer + NRXBUFS * RBUF_SIZE + i * RBUF_SIZE);
write_descr_counts(rmd + i, FIRST_SEGMENT | LAST_SEGMENT | CHAINED_ADDRESS);
if (i == NTXBUFS - 1) {
set_chain_address(rmd + i, rmd);
(rmd + i)->next = rmd;
} else {
set_chain_address(rmd + i, rmd + i + 1);
(rmd + i)->next = rmd + i + 1;
}
write_descr_status(rmd + i, OWNED_BY_HOST);
}
#if defined(__i386)
sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler;
sc->irqInfo.on = nopOn;
sc->irqInfo.off = nopOn;
sc->irqInfo.isOn = dec21140IsOn;
st = BSP_install_rtems_irq_handler (&sc->irqInfo);
if (!st) {
rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n",
sc->irqInfo.name);
}
#endif
#if defined(__PPC)
{
rtems_isr_entry old_handler;
st = bsp_interrupt_catch(dec21140Enet_interrupt_handler,
IRQ_ETHERNET, &old_handler);
if (st != RTEMS_SUCCESSFUL) {
rtems_panic("Can't attach DEC21140 interrupt handler\n");
}
bsp_interrupt_enable(IRQ_ETHERNET, PRIORITY_ISA_INT);
}
#endif
/* no interrupts for now */
write_csr(tbase, CSR7, NO_IT);
/*
* Build setup frame
*/
setup_frm = get_buffer_address(rmd);
eaddrs = (char *)(sc->arpcom.ac_enaddr);
/* Fill the buffer with our physical address. */
for (i = 1; i < 16; i++) {
*setup_frm++ = eaddrs[0];
*setup_frm++ = eaddrs[1];
setup_frm += 2;
*setup_frm++ = eaddrs[2];
*setup_frm++ = eaddrs[3];
setup_frm += 2;
*setup_frm++ = eaddrs[4];
*setup_frm++ = eaddrs[5];
setup_frm += 2;
}
/* Add the broadcast address when doing perfect filtering */
memset((char*)setup_frm, 0xff, 12);
write_descr_counts(rmd, SETUP_PACKET | CHAINED_ADDRESS | 192);
write_descr_status(rmd, OWNED_BY_DEC21140);
/*
* Start TX for setup frame
*/
write_csr(tbase, CSR6, CSR6_INIT | CSR6_TX);
write_csr(tbase, CSR1, 1);
while (read_descr_status(rmd) & OWNED_BY_DEC21140);
sc->SentTxMD = sc->TxMD = rmd + 1;
sc->PendingTxCount = 0;
sc->TxSuspended = 1;
/*
* Set up interrupts
*/
write_csr(tbase, CSR5, IT_SETUP);
write_csr(tbase, CSR7, IT_SETUP);
/*
* Enable RX and TX
*/
write_csr(tbase, CSR6, CSR6_INIT | CSR6_TXRX);
}
static void dec21140_rxDaemon (void *arg) {
unsigned32 *tbase;
struct dec21140_softc *sc = arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
struct MD *rmd;
unsigned32 len;
unsigned32 rx_status;
rtems_event_set events;
tbase = sc->base;
rmd = sc->MDbase;
for (;;){
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
RTEMS_WAIT | RTEMS_EVENT_ANY,
RTEMS_NO_TIMEOUT,
&events);
while (((rx_status = read_descr_status(rmd)) & OWNED_BY_DEC21140) == 0) {
struct ether_header *eh;
struct mbuf *m = rmd->m;
/*
* packet is good if Error Summary = 0 and First Descriptor = 1
* and Last Descriptor = 1
*/
if ((rx_status & 0x00008300) == 0x00000300) {
/* pass on the packet in the mbuf */
len = (rx_status >> 16) & 0x7ff;
m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
eh = mtod (m, struct ether_header *);
m->m_data += sizeof(struct ether_header);
ether_input (ifp, eh, m);
/* get a new mbuf for the 21140 */
MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT);
m->m_pkthdr.rcvif = ifp;
rmd->m = m;
set_buffer_address(rmd, mtod(m, void *));
} else {
if ((rx_status & (1 << 9)) == 0) {
sc->rxNotFirst++;
}
if ((rx_status & (1 << 8)) == 0) {
sc->rxNotLast++;
}
if (rx_status & (1 << 7)) {
sc->rxGiant++;
}
if (rx_status & (1 << 2)) {
sc->rxNonOctet++;
}
if (rx_status & (1 << 11)) {
sc->rxRunt++;
}
if (rx_status & (1 << 1)) {
sc->rxBadCRC++;
}
if (rx_status & (1 << 14)) {
sc->rxOverrun++;
}
if (rx_status & (1 << 6)) {
sc->rxCollision++;
}
}
/* give the descriptor back to the 21140 */
write_descr_status(rmd, OWNED_BY_DEC21140);
/* check for more ready descriptors */
rmd = rmd->next;
}
}
}
static void reap_sent_descriptors(struct dec21140_softc *sc) {
struct MD *descr = sc->SentTxMD;
unsigned32 *tbase = sc->base;
unsigned32 tx_status = 0;
struct mbuf *m, *n;
while (sc->PendingTxCount > 0 &&
((tx_status = read_descr_status(descr)) & OWNED_BY_DEC21140) == 0 ) {
for (m = descr->m; m; m = n) {
MFREE(m, n);
}
if (read_descr_counts(descr) & LAST_SEGMENT) {
if (tx_status & (1 << 0)) {
sc->txDeferred++;
}
if (tx_status & (1 << 7)) {
sc->txHeartbeat++;
}
if (tx_status & (1 << 9)) {
sc->txLateCollision++;
}
if (tx_status & (1 << 8)) {
sc->txRetryLimit++;
}
if (tx_status & (1 << 1)) {
sc->txUnderrun++;
write_csr(tbase, CSR1, 0x1); /* restart transmitter */
/* this shouldn't happen - descriptor should still be
owned by 21140 */
printk("ethernet chip underrun error\n");
}
if (tx_status & (1 << 10)) {
sc->txLostCarrier++;
}
}
descr = descr->next;
sc->PendingTxCount--;
}
sc->SentTxMD = descr;
/* check for Underflow and restart transmission */
if ((tx_status & 0x80000002) == 0x80000002) {
sc->txUnderrun++;
write_csr(tbase, CSR1, 0x1); /* restart transmitter */
printk("ethernet chip underrun error\n");
}
}
static void sendpacket (volatile struct ifnet *ifp, struct mbuf *m) {
struct mbuf *mbuf = m;
struct dec21140_softc *sc = ifp->if_softc;
struct MD *descr, *first, *last;
unsigned32 *tbase = sc->base;
int count = 0;
first = last = descr = sc->TxMD;
reap_sent_descriptors(sc);
while (mbuf) {
if (mbuf->m_len) {
/* if no descriptor is available, wait for interrupt */
while ((sc->PendingTxCount + count) == NTXBUFS) {
rtems_event_set events;
rtems_status_code result;
if (sc->PendingTxCount == 0) {
printk("ERROR: too many segments to transmit in mbuf\n");
}
result = rtems_bsdnet_event_receive(INTERRUPT_EVENT,
RTEMS_WAIT | RTEMS_EVENT_ANY,
20 * ticks_per_second,
&events);
if (result == RTEMS_TIMEOUT) {
printk("still waiting for tx descriptor in sendpacket\n");
}
reap_sent_descriptors(sc);
if (sc->TxSuspended) {
sc->TxSuspended = 0;
write_csr(tbase, CSR1, 0x1);
}
}
set_buffer_address(descr, mtod (mbuf, void *));
write_descr_counts(descr, CHAINED_ADDRESS | mbuf->m_len);
last = descr;
if (descr != first) {
write_descr_status(descr, OWNED_BY_DEC21140);
}
descr->m = 0;
count++;
descr = descr->next;
}
mbuf = mbuf->m_next;
}
write_descr_counts(first, read_descr_counts(first) | FIRST_SEGMENT);
write_descr_counts(last, read_descr_counts(last) | LAST_SEGMENT);
last->m = m;
sc->TxMD = descr;
synchronize_io();
write_descr_status(first, OWNED_BY_DEC21140);
sc->PendingTxCount += count;
if (sc->TxSuspended) {
sc->TxSuspended = 0;
synchronize_io();
write_csr(tbase, CSR1, 0x1);
}
}
/*
* Driver transmit daemon
*/
static void dec21140_txDaemon (void *arg) {
struct dec21140_softc *sc = (struct dec21140_softc *)arg;
volatile struct ifnet *ifp = &sc->arpcom.ac_if;
unsigned32 *tbase = sc->base;
struct mbuf *m;
rtems_event_set events;
for (;;) {
/*
* Wait for packet
*/
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
RTEMS_EVENT_ANY | RTEMS_WAIT,
RTEMS_NO_TIMEOUT, &events);
/*
* Send packets till queue is empty
*/
for (;;) {
/*
* Get the next mbuf chain to transmit.
*/
IF_DEQUEUE(&ifp->if_snd, m);
if (!m) {
break;
}
sendpacket (ifp, m);
}
ifp->if_flags &= ~IFF_OACTIVE;
}
}
static void dec21140_start (struct ifnet *ifp) {
struct dec21140_softc *sc = ifp->if_softc;
ifp->if_flags |= IFF_OACTIVE;
rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
}
/*
* Initialize and start the device
*/
static void dec21140_init (void *arg) {
struct dec21140_softc *sc = arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
if (sc->txDaemonTid == 0) {
/*
* Set up DEC21140 hardware
*/
dec21140Enet_initialize_hardware (sc);
/*
* Start driver tasks
*/
#if NDECDRIVER == 1
sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
dec21140_rxDaemon, sc);
sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
dec21140_txDaemon, sc);
#else
# error "need to fix task IDs"
#endif
}
/*
* Tell the world that we're running.
*/
ifp->if_flags |= IFF_RUNNING;
}
/*
* Stop the device
*/
static void dec21140_stop (struct dec21140_softc *sc) {
unsigned32 *tbase;
struct ifnet *ifp = &sc->arpcom.ac_if;
ifp->if_flags &= ~IFF_RUNNING;
/*
* Stop the transmitter
*/
tbase = sc->base;
write_csr(tbase, CSR7, NO_IT);
write_csr(tbase, CSR6, CSR6_INIT);
free(sc->bufferBase);
}
/*
* Show interface statistics
*/
static void dec21140_stats (struct dec21140_softc *sc) {
printf (" Rx Interrupts:%-8u", sc->rxInterrupts);
printf (" Not First:%-8u", sc->rxNotFirst);
printf (" Not Last:%-8u\n", sc->rxNotLast);
printf (" Giant:%-8u", sc->rxGiant);
printf (" Runt:%-8u", sc->rxRunt);
printf (" Non-octet:%-8u\n", sc->rxNonOctet);
printf (" Bad CRC:%-8u", sc->rxBadCRC);
printf (" Overrun:%-8u", sc->rxOverrun);
printf (" Collision:%-8u\n", sc->rxCollision);
printf (" Tx Interrupts:%-8u", sc->txInterrupts);
printf (" Deferred:%-8u", sc->txDeferred);
printf (" Missed Hearbeat:%-8u\n", sc->txHeartbeat);
printf (" No Carrier:%-8u", sc->txLostCarrier);
printf ("Retransmit Limit:%-8u", sc->txRetryLimit);
printf (" Late Collision:%-8u\n", sc->txLateCollision);
printf (" Underrun:%-8u", sc->txUnderrun);
printf (" Raw output wait:%-8u\n", sc->txRawWait);
}
/*
* Driver ioctl handler
*/
static int dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data) {
struct dec21140_softc *sc = ifp->if_softc;
int error = 0;
switch (command) {
case SIOCGIFADDR:
case SIOCSIFADDR:
ether_ioctl (ifp, command, data);
break;
case SIOCSIFFLAGS:
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
case IFF_RUNNING:
dec21140_stop (sc);
break;
case IFF_UP:
dec21140_init (sc);
break;
case IFF_UP | IFF_RUNNING:
dec21140_stop (sc);
dec21140_init (sc);
break;
default:
break;
}
break;
case SIO_RTEMS_SHOW_STATS:
dec21140_stats (sc);
break;
/*
* FIXME: All sorts of multicast commands need to be added here!
*/
default:
error = EINVAL;
break;
}
return error;
}
/*
* Attach an DEC21140 driver to the system
*/
int rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config) {
struct dec21140_softc *sc;
struct ifnet *ifp;
int mtu;
int i;
#if defined(__i386)
int signature;
int value;
char interrupt;
int diag;
/*
* Initialise PCI module
*/
if (pcib_init() == PCIB_ERR_NOTPRESENT) {
rtems_panic("PCI BIOS not found !!");
}
/*
* First, find a DEC board
*/
if ((diag = pcib_find_by_devid(PCI_VENDOR_ID_DEC,
PCI_DEVICE_ID_DEC_TULIP_FAST,
0,
&signature)) != PCIB_ERR_SUCCESS) {
rtems_panic("DEC PCI board not found !! (%d)\n", diag);
} else {
printk("DEC PCI Device found\n");
}
#endif
#if defined(__PPC)
int sig;
/* search PCI bus for Tulip chip */
sig = pci_find_by_devid(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, 0);
if (sig == PCI_NOT_FOUND) {
printk("PCI scan failed: DEC 21140 not found\n");
return 0;
}
#endif
/*
* Find a free driver
*/
for (i = 0 ; i < NDECDRIVER ; i++) {
sc = &dec21140_softc[i];
ifp = &sc->arpcom.ac_if;
if (ifp->if_softc == NULL) {
break;
}
}
if (i >= NDECDRIVER) {
printk ("Too many DEC drivers.\n");
return 0;
}
/*
* Process options
*/
sc->port = pci_conf_read32(sig, PCI_BASE_ADDRESS_0) & ~IO_MASK;
sc->base = (void *)
PCI_TO_LOCAL(pci_conf_read32(sig, PCI_BASE_ADDRESS_1) & ~MEM_MASK);
sc->irqInfo = pci_conf_read8(sig, 60);
#if defined(__i386)
pcib_conf_read32(signature, 16, &value);
sc->port = value & ~IO_MASK;
pcib_conf_read32(signature, 20, &value);
if (_CPU_is_paging_enabled()) {
_CPU_map_phys_address(&(sc->base),
(void *)(value & ~MEM_MASK),
DEC_REGISTER_SIZE ,
PTE_CACHE_DISABLE | PTE_WRITABLE);
} else {
sc->base = (unsigned32 *)(value & ~MEM_MASK);
}
pcib_conf_read8(signature, 60, &interrupt);
sc->irqInfo.name = (rtems_irq_symbolic_name)interrupt;
#endif
if (config->hardware_address) {
memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
} else {
memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
}
if (config->mtu) {
mtu = config->mtu;
} else {
mtu = ETHERMTU;
}
sc->acceptBroadcast = !config->ignore_broadcast;
/*
* Set up network interface values
*/
ifp->if_softc = sc;
ifp->if_unit = i + 1;
ifp->if_name = "dc";
ifp->if_mtu = mtu;
ifp->if_init = dec21140_init;
ifp->if_ioctl = dec21140_ioctl;
ifp->if_start = dec21140_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);
/*
* Determine clock rate for timeout calculation
*/
rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
return 1;
};