iPXE
Defines | Functions | Variables
ns8390.c File Reference
#include "etherboot.h"
#include "nic.h"
#include "ns8390.h"
#include <ipxe/ethernet.h>
#include <ipxe/pci.h>

Go to the source code of this file.

Defines

#define INCLUDE_NS8390   1
#define eth_probe   nepci_probe
#define ASIC_PIO   NE_DATA

Functions

 FILE_LICENCE (BSD2)
static void eth_pio_read (unsigned int src, unsigned char *dst, unsigned int cnt)
static void eth_pio_write (const unsigned char *src, unsigned int dst, unsigned int cnt)
static void enable_multicast (unsigned short eth_nic_base)
static void ns8390_reset (struct nic *nic)
static int ns8390_poll (struct nic *nic, int retrieve)
static void eth_rx_overrun (struct nic *nic)
static void ns8390_transmit (struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
static void ns8390_disable (struct nic *nic)
static void ns8390_irq (struct nic *nic __unused, irq_action_t action __unused)
static int eth_probe (struct nic *nic, struct pci_device *pci)
 PCI_DRIVER (nepci_driver, nepci_nics, PCI_NO_CLASS)
 DRIVER ("NE2000/PCI", nic_driver, pci_driver, nepci_driver, nepci_probe, ns8390_disable)

Variables

static unsigned char eth_vendor
static unsigned char eth_flags
static unsigned short eth_nic_base
static unsigned short eth_asic_base
static unsigned char eth_memsize
static unsigned char eth_rx_start
static unsigned char eth_tx_start
static Address eth_bmem
static Address eth_rmem
static unsigned char eth_drain_receiver
static struct nic_operations ns8390_operations
static struct pci_device_id nepci_nics []

Define Documentation

#define INCLUDE_NS8390   1

Definition at line 38 of file ns8390.c.

#define eth_probe   nepci_probe

Definition at line 113 of file ns8390.c.

#define ASIC_PIO   NE_DATA

Definition at line 123 of file ns8390.c.

Referenced by eth_pio_read(), and eth_pio_write().


Function Documentation

FILE_LICENCE ( BSD2  )
static void eth_pio_read ( unsigned int  src,
unsigned char *  dst,
unsigned int  cnt 
) [static]
static void eth_pio_write ( const unsigned char *  src,
unsigned int  dst,
unsigned int  cnt 
) [static]

Definition at line 178 of file ns8390.c.

References _3COM_CR, _3COM_CR_DDIR, _3COM_CR_START, _3COM_DALSB, _3COM_DAMSB, _3COM_STREG, _3COM_STREG_DPRDY, ASIC_PIO, COMPEX_RL2000_TRIES, D8390_COMMAND_RD1, D8390_COMMAND_RD2, D8390_COMMAND_STA, D8390_ISR_RDC, D8390_P0_COMMAND, D8390_P0_ISR, D8390_P0_RBCR0, D8390_P0_RBCR1, D8390_P0_RSAR0, D8390_P0_RSAR1, eth_asic_base, eth_flags, eth_nic_base, FLAG_16BIT, inb(), outb(), outw(), printf(), and WD_GP2.

Referenced by eth_probe(), and ns8390_transmit().

{
#ifdef  COMPEX_RL2000_FIX
        unsigned int x;
#endif  /* COMPEX_RL2000_FIX */
#ifdef  INCLUDE_WD
        outb(dst & 0xff, eth_asic_base + WD_GP2);
        outb(dst >> 8, eth_asic_base + WD_GP2);
#else
        outb(D8390_COMMAND_RD2 |
                D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
        outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
        outb(cnt, eth_nic_base + D8390_P0_RBCR0);
        outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
        outb(dst, eth_nic_base + D8390_P0_RSAR0);
        outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
        outb(D8390_COMMAND_RD1 |
                D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);

#ifdef  INCLUDE_3C503
        outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
        outb(dst >> 8, eth_asic_base + _3COM_DAMSB);

        outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
#endif
#endif

        if (eth_flags & FLAG_16BIT)
                cnt = (cnt + 1) >> 1;

        while(cnt--)
        {
#ifdef  INCLUDE_3C503
                while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
                        ;
#endif

                if (eth_flags & FLAG_16BIT) {
                        outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
                        src += 2;
                }
                else
                        outb(*(src++), eth_asic_base + ASIC_PIO);
        }

#ifdef  INCLUDE_3C503
        outb(t503_output, eth_asic_base + _3COM_CR);
#else
#ifdef  COMPEX_RL2000_FIX
        for (x = 0;
                x < COMPEX_RL2000_TRIES &&
                (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
                != D8390_ISR_RDC;
                ++x);
        if (x >= COMPEX_RL2000_TRIES)
                printf("Warning: Compex RL2000 aborted wait!\n");
#endif  /* COMPEX_RL2000_FIX */
#ifndef INCLUDE_WD
        while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
                != D8390_ISR_RDC);
#endif
#endif
}
static void enable_multicast ( unsigned short  eth_nic_base) [static]

Definition at line 252 of file ns8390.c.

References D8390_COMMAND_PS0, D8390_COMMAND_PS1, D8390_COMMAND_RD2, D8390_P0_COMMAND, D8390_P0_RCR, inb(), memset(), outb(), and printf().

Referenced by ns8390_reset().

{
        unsigned char mcfilter[8];
        int i;
        memset(mcfilter, 0xFF, 8);
        outb(4, eth_nic_base+D8390_P0_RCR);     
        outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
        for(i=0;i<8;i++)
        {
                outb(mcfilter[i], eth_nic_base + 8 + i);
                if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
                        printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
        }
        outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
        outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
}
static void ns8390_reset ( struct nic nic) [static]

Definition at line 272 of file ns8390.c.

References _3COM_CR, _3COM_CR_XSEL, D8390_COMMAND_PS0, D8390_COMMAND_PS1, D8390_COMMAND_RD2, D8390_COMMAND_STA, D8390_COMMAND_STP, D8390_P0_BOUND, D8390_P0_COMMAND, D8390_P0_DCR, D8390_P0_IMR, D8390_P0_ISR, D8390_P0_PSTART, D8390_P0_PSTOP, D8390_P0_RBCR0, D8390_P0_RBCR1, D8390_P0_RCR, D8390_P0_TCR, D8390_P0_TPSR, D8390_P1_CURR, D8390_P1_MAR0, D8390_P1_PAR0, enable_multicast(), ETH_ALEN, eth_asic_base, eth_drain_receiver, eth_flags, eth_memsize, eth_nic_base, eth_rx_start, eth_tx_start, FLAG_16BIT, FLAG_790, and outb().

Referenced by eth_probe(), and ns8390_disable().

{
        int i;

        eth_drain_receiver = 0;
#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_790)
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
        else
#endif
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
                        D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
        if (eth_flags & FLAG_16BIT)
                outb(0x49, eth_nic_base+D8390_P0_DCR);
        else
                outb(0x48, eth_nic_base+D8390_P0_DCR);
        outb(0, eth_nic_base+D8390_P0_RBCR0);
        outb(0, eth_nic_base+D8390_P0_RBCR1);
        outb(0x20, eth_nic_base+D8390_P0_RCR);  /* monitor mode */
        outb(2, eth_nic_base+D8390_P0_TCR);
        outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
        outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_790) {
#ifdef  WD_790_PIO
                outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
                outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
#else
                outb(0, eth_nic_base + 0x09);
#endif
        }
#endif
        outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
        outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
        outb(0xFF, eth_nic_base+D8390_P0_ISR);
        outb(0, eth_nic_base+D8390_P0_IMR);
#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_790)
                outb(D8390_COMMAND_PS1 |
                        D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
        else
#endif
                outb(D8390_COMMAND_PS1 |
                        D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
        for (i=0; i<ETH_ALEN; i++)
                outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
        for (i=0; i<ETH_ALEN; i++)
                outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
        outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_790)
                outb(D8390_COMMAND_PS0 |
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
        else
#endif
                outb(D8390_COMMAND_PS0 |
                        D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
        outb(0xFF, eth_nic_base+D8390_P0_ISR);
        outb(0, eth_nic_base+D8390_P0_TCR);     /* transmitter on */
        outb(4, eth_nic_base+D8390_P0_RCR);     /* allow rx broadcast frames */

        enable_multicast(eth_nic_base);

#ifdef  INCLUDE_3C503
        /*
         * No way to tell whether or not we're supposed to use
         * the 3Com's transceiver unless the user tells us.
         * 'flags' should have some compile time default value
         * which can be changed from the command menu.
         */
        t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
        outb(t503_output, eth_asic_base + _3COM_CR);
#endif
}
static int ns8390_poll ( struct nic nic,
int  retrieve 
) [static]

Definition at line 502 of file ns8390.c.

References bus_to_virt(), D8390_COMMAND_PS0, D8390_COMMAND_PS1, D8390_ISR_OVW, D8390_P0_BOUND, D8390_P0_COMMAND, D8390_P0_ISR, D8390_P0_RSR, D8390_P1_CURR, D8390_RSTAT_PRX, eth_asic_base, eth_drain_receiver, eth_flags, ETH_FRAME_LEN, eth_memsize, eth_nic_base, eth_pio_read(), eth_rmem, eth_rx_overrun(), eth_rx_start, ETH_ZLEN, FLAG_16BIT, FLAG_790, FLAG_PIO, inb(), len, memcpy(), next, outb(), printf(), ret, WD_LAAR, WD_LAAR_M16EN, WD_MSR, and WD_MSR_MENB.

Referenced by eth_rx_overrun().

{
        int ret = 0;
        unsigned char rstat, curr, next;
        unsigned short len, frag;
        unsigned short pktoff;
        unsigned char *p;
        struct ringbuffer pkthdr;

#ifndef INCLUDE_3C503
        /* avoid infinite recursion: see eth_rx_overrun() */
        if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
                eth_rx_overrun(nic);
                return(0);
        }
#endif  /* INCLUDE_3C503 */
        rstat = inb(eth_nic_base+D8390_P0_RSR);
        if (!(rstat & D8390_RSTAT_PRX)) return(0);
        next = inb(eth_nic_base+D8390_P0_BOUND)+1;
        if (next >= eth_memsize) next = eth_rx_start;
        outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
        curr = inb(eth_nic_base+D8390_P1_CURR);
        outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
        if (curr >= eth_memsize) curr=eth_rx_start;
        if (curr == next) return(0);

        if ( ! retrieve ) return 1;

#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_16BIT) {
                outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
                inb(0x84);
        }
#ifndef WD_790_PIO
        if (eth_flags & FLAG_790) {
                outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
                inb(0x84);
        }
#endif
        inb(0x84);
#endif
        pktoff = next << 8;
        if (eth_flags & FLAG_PIO)
                eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
        else
                memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
        pktoff += sizeof(pkthdr);
        /* incoming length includes FCS so must sub 4 */
        len = pkthdr.len - 4;
        if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
                || len > ETH_FRAME_LEN) {
                printf("Bogus packet, ignoring\n");
                return (0);
        }
        else {
                p = nic->packet;
                nic->packetlen = len;           /* available to caller */
                frag = (eth_memsize << 8) - pktoff;
                if (len > frag) {               /* We have a wrap-around */
                        /* read first part */
                        if (eth_flags & FLAG_PIO)
                                eth_pio_read(pktoff, p, frag);
                        else
                                memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
                        pktoff = eth_rx_start << 8;
                        p += frag;
                        len -= frag;
                }
                /* read second part */
                if (eth_flags & FLAG_PIO)
                        eth_pio_read(pktoff, p, len);
                else
                        memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
                ret = 1;
        }
#ifdef  INCLUDE_WD
#ifndef WD_790_PIO
        if (eth_flags & FLAG_790) {
                outb(0, eth_asic_base + WD_MSR);
                inb(0x84);
        }
#endif
        if (eth_flags & FLAG_16BIT) {
                outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
                inb(0x84);
        }
        inb(0x84);
#endif
        next = pkthdr.next;             /* frame number of next packet */
        if (next == eth_rx_start)
                next = eth_memsize;
        outb(next-1, eth_nic_base+D8390_P0_BOUND);
        return(ret);
}
static void eth_rx_overrun ( struct nic nic) [static]

Definition at line 353 of file ns8390.c.

References currticks(), D8390_COMMAND_PS0, D8390_COMMAND_RD2, D8390_COMMAND_STA, D8390_COMMAND_STP, D8390_ISR_OVW, D8390_P0_COMMAND, D8390_P0_ISR, D8390_P0_RBCR0, D8390_P0_RBCR1, D8390_P0_TCR, eth_drain_receiver, eth_flags, eth_nic_base, FLAG_790, ns8390_poll(), and outb().

Referenced by ns8390_poll().

{
        int start_time;

#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_790)
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
        else
#endif
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
                        D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);

        /* wait for at least 1.6ms - we wait one timer tick */
        start_time = currticks();
        while (currticks() - start_time <= 1)
                /* Nothing */;

        outb(0, eth_nic_base+D8390_P0_RBCR0);   /* reset byte counter */
        outb(0, eth_nic_base+D8390_P0_RBCR1);

        /*
         * Linux driver checks for interrupted TX here. This is not necessary,
         * because the transmit routine waits until the frame is sent.
         */

        /* enter loopback mode and restart NIC */
        outb(2, eth_nic_base+D8390_P0_TCR);
#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_790)
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
        else
#endif
                outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);

        /* clear the RX ring, acknowledge overrun interrupt */
        eth_drain_receiver = 1;
        while (ns8390_poll(nic, 1))
                /* Nothing */;
        eth_drain_receiver = 0;
        outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);

        /* leave loopback mode - no packets to be resent (see Linux driver) */
        outb(0, eth_nic_base+D8390_P0_TCR);
}
static void ns8390_transmit ( struct nic nic,
const char *  d,
unsigned int  t,
unsigned int  s,
const char *  p 
) [static]

Definition at line 403 of file ns8390.c.

References bus_to_virt(), D8390_COMMAND_PS0, D8390_COMMAND_RD2, D8390_COMMAND_STA, D8390_COMMAND_TXP, D8390_P0_COMMAND, D8390_P0_TBCR0, D8390_P0_TBCR1, D8390_P0_TPSR, ETH_ALEN, eth_asic_base, eth_bmem, eth_flags, ETH_HLEN, eth_nic_base, eth_pio_write(), eth_tx_start, ETH_ZLEN, FLAG_16BIT, FLAG_790, FLAG_PIO, inb(), memcpy(), outb(), type, WD_LAAR, WD_LAAR_M16EN, WD_MSR, and WD_MSR_MENB.

{
#if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
        Address         eth_vmem = bus_to_virt(eth_bmem);
#endif
#ifdef  INCLUDE_3C503
        if (!(eth_flags & FLAG_PIO)) {
                memcpy((char *)eth_vmem, d, ETH_ALEN);  /* dst */
                memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
                *((char *)eth_vmem+12) = t>>8;          /* type */
                *((char *)eth_vmem+13) = t;
                memcpy((char *)eth_vmem+ETH_HLEN, p, s);
                s += ETH_HLEN;
                while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
        }
#endif

#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_16BIT) {
                outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
                inb(0x84);
        }
#ifndef WD_790_PIO
        /* Memory interface */
        if (eth_flags & FLAG_790) {
                outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
                inb(0x84);
        }
        inb(0x84);
        memcpy((char *)eth_vmem, d, ETH_ALEN);  /* dst */
        memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
        *((char *)eth_vmem+12) = t>>8;          /* type */
        *((char *)eth_vmem+13) = t;
        memcpy((char *)eth_vmem+ETH_HLEN, p, s);
        s += ETH_HLEN;
        while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
        if (eth_flags & FLAG_790) {
                outb(0, eth_asic_base + WD_MSR);
                inb(0x84);
        }
#else
        inb(0x84);
#endif
#endif

#if     defined(INCLUDE_3C503)
        if (eth_flags & FLAG_PIO)
#endif
#if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
        {
                /* Programmed I/O */
                unsigned short type;
                type = (t >> 8) | (t << 8);
                eth_pio_write( (unsigned char *) d, eth_tx_start<<8, ETH_ALEN);
                eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
                /* bcc generates worse code without (const+const) below */
                eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
                eth_pio_write( (unsigned char *) p, (eth_tx_start<<8)+ETH_HLEN, s);
                s += ETH_HLEN;
                if (s < ETH_ZLEN) s = ETH_ZLEN;
        }
#endif
#if     defined(INCLUDE_3C503)
#endif

#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_16BIT) {
                outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
                inb(0x84);
        }
        if (eth_flags & FLAG_790)
                outb(D8390_COMMAND_PS0 |
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
        else
#endif
                outb(D8390_COMMAND_PS0 |
                        D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
        outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
        outb(s, eth_nic_base+D8390_P0_TBCR0);
        outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
#ifdef  INCLUDE_WD
        if (eth_flags & FLAG_790)
                outb(D8390_COMMAND_PS0 |
                        D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
        else
#endif
                outb(D8390_COMMAND_PS0 |
                        D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
                        D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
}
static void ns8390_disable ( struct nic nic) [static]

Definition at line 600 of file ns8390.c.

References ns8390_reset().

static void ns8390_irq ( struct nic *nic  __unused,
irq_action_t action  __unused 
) [static]

Definition at line 607 of file ns8390.c.

{
  switch ( action ) {
  case DISABLE :
    break;
  case ENABLE :
    break;
  case FORCE :
    break;
  }
}
static int eth_probe ( struct nic nic,
struct pci_device pci 
) [static]

Definition at line 631 of file ns8390.c.

References _3COM_ASIC_OFFSET, _3COM_BCFR, _3COM_CR, _3COM_CR_EALO, _3COM_CR_RST, _3COM_CR_XSEL, _3COM_GACFR, _3COM_GACFR_MBS0, _3COM_GACFR_NIM, _3COM_GACFR_RSEL, _3COM_GACFR_TCM, _3COM_PCFR, _3COM_PCFR_C8000, _3COM_PCFR_CC000, _3COM_PCFR_D8000, _3COM_PCFR_DC000, _3COM_PCFR_PIO, _3COM_PSPR, _3COM_PSTR, _3COM_VPTR0, _3COM_VPTR1, _3COM_VPTR2, addr, base, bus_to_virt(), D8390_COMMAND_RD2, D8390_COMMAND_STP, D8390_DCR_FT1, D8390_DCR_LS, D8390_DCR_WTS, D8390_P0_COMMAND, D8390_P0_DCR, D8390_P0_PSTART, D8390_P0_PSTOP, D8390_P0_RCR, D8390_RCR_MON, D8390_TXBUF_SIZE, DBG, ETH_ALEN, eth_asic_base, eth_bmem, eth_drain_receiver, eth_flags, eth_memsize, eth_nic_base, eth_ntoa(), eth_pio_read(), eth_pio_write(), eth_rmem, eth_rx_start, eth_tx_start, eth_vendor, FLAG_16BIT, FLAG_790, FLAG_PIO, GENERIC_ISAPNP_VENDOR, htons, inb(), pci_device::ioaddr, ISA_MAX_ADDR, MEM_16384, MEM_32768, MEM_8192, memcmp(), memset(), NE_ASIC_OFFSET, NE_RESET, ns8390_operations, ns8390_reset(), NULL, outb(), printf(), test, TYPE_SMC8216C, TYPE_SMC8216T, TYPE_WD8013EP, VENDOR_3COM, VENDOR_NONE, VENDOR_NOVELL, VENDOR_WD, WD_BID, WD_HIGH_BASE, WD_ICR, WD_ICR_16BIT, WD_LAAR, WD_LAAR_L16EN, WD_LAAR_M16EN, WD_LAR, WD_LOW_BASE, WD_MSR, WD_MSR_MENB, WD_NIC_ADDR, and WD_SOFTCONFIG.

{
        int i;
#ifdef INCLUDE_NS8390
        unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
        unsigned short *probe_addrs = pci_probe_addrs;
#endif
        eth_vendor = VENDOR_NONE;
        eth_drain_receiver = 0;

        nic->irqno  = 0;

#ifdef  INCLUDE_WD
{
        /******************************************************************
        Search for WD/SMC cards
        ******************************************************************/
        struct wd_board *brd;
        unsigned short chksum;
        unsigned char c;
        for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
                eth_asic_base += 0x20) {
                chksum = 0;
                for (i=8; i<16; i++)
                        chksum += inb(eth_asic_base+i);
                /* Extra checks to avoid soundcard */
                if ((chksum & 0xFF) == 0xFF &&
                        inb(eth_asic_base+8) != 0xFF &&
                        inb(eth_asic_base+9) != 0xFF)
                        break;
        }
        if (eth_asic_base > WD_HIGH_BASE)
                return (0);
        /* We've found a board */
        eth_vendor = VENDOR_WD;
        eth_nic_base = eth_asic_base + WD_NIC_ADDR;

        nic->ioaddr = eth_nic_base;

        c = inb(eth_asic_base+WD_BID);  /* Get board id */
        for (brd = wd_boards; brd->name; brd++)
                if (brd->id == c) break;
        if (!brd->name) {
                printf("Unknown WD/SMC NIC type %hhX\n", c);
                return (0);     /* Unknown type */
        }
        eth_flags = brd->flags;
        eth_memsize = brd->memsize;
        eth_tx_start = 0;
        eth_rx_start = D8390_TXBUF_SIZE;
        if ((c == TYPE_WD8013EP) &&
                (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
                        eth_flags = FLAG_16BIT;
                        eth_memsize = MEM_16384;
        }
        if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
                eth_bmem = (0x80000 |
                 ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
        } else
                eth_bmem = WD_DEFAULT_MEM;
        if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
                /* from Linux driver, 8416BT detects as 8216 sometimes */
                unsigned int addr = inb(eth_asic_base + 0xb);
                if (((addr >> 4) & 3) == 0) {
                        brd += 2;
                        eth_memsize = brd->memsize;
                }
        }
        outb(0x80, eth_asic_base + WD_MSR);     /* Reset */
        for (i=0; i<ETH_ALEN; i++) {
                nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
        }
        DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
        if (eth_flags & FLAG_790) {
#ifdef  WD_790_PIO
                DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
                eth_bmem = 0;
                eth_flags |= FLAG_PIO;          /* force PIO mode */
                outb(0, eth_asic_base+WD_MSR);
#else
                DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );

                outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
                outb((inb(eth_asic_base+0x04) |
                        0x80), eth_asic_base+0x04);
                outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
                        ((unsigned)(eth_bmem >> 11) & 0x40) |
                        (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
                outb((inb(eth_asic_base+0x04) &
                        ~0x80), eth_asic_base+0x04);
#endif
        } else {

                DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );

                outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
        }
        if (eth_flags & FLAG_16BIT) {
                if (eth_flags & FLAG_790) {
                        eth_laar = inb(eth_asic_base + WD_LAAR);
                        outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
                } else {
                        outb((eth_laar =
                                WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
/*
        The previous line used to be
                                WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
        jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
        it work for WD8013s.  This seems to work for my 8013 boards. I
        don't know what is really happening.  I wish I had data sheets
        or more time to decode the Linux driver. - Ken
*/
                }
                inb(0x84);
        }
}
#endif
#ifdef  INCLUDE_3C503
#ifdef  T503_AUI
        nic->flags = 1;         /* aui */
#else
        nic->flags = 0;         /* no aui */
#endif
        /******************************************************************
        Search for 3Com 3c503 if no WD/SMC cards
        ******************************************************************/
        if (eth_vendor == VENDOR_NONE) {
                int     idx;
                int     iobase_reg, membase_reg;
                static unsigned short   base[] = {
                        0x300, 0x310, 0x330, 0x350,
                        0x250, 0x280, 0x2A0, 0x2E0, 0 };

                /* Loop through possible addresses checking each one */

                for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {

                        eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
/*
 * Note that we use the same settings for both 8 and 16 bit cards:
 * both have an 8K bank of memory at page 1 while only the 16 bit
 * cards have a bank at page 0.
 */
                        eth_memsize = MEM_16384;
                        eth_tx_start = 32;
                        eth_rx_start = 32 + D8390_TXBUF_SIZE;

                /* Check our base address. iobase and membase should */
                /* both have a maximum of 1 bit set or be 0. */

                        iobase_reg = inb(eth_asic_base + _3COM_BCFR);
                        membase_reg = inb(eth_asic_base + _3COM_PCFR);

                        if ((iobase_reg & (iobase_reg - 1)) ||
                                (membase_reg & (membase_reg - 1)))
                                continue;               /* nope */

                /* Now get the shared memory address */

                        eth_flags = 0;

                        switch (membase_reg) {
                                case _3COM_PCFR_DC000:
                                        eth_bmem = 0xdc000;
                                        break;
                                case _3COM_PCFR_D8000:
                                        eth_bmem = 0xd8000;
                                        break;
                                case _3COM_PCFR_CC000:
                                        eth_bmem = 0xcc000;
                                        break;
                                case _3COM_PCFR_C8000:
                                        eth_bmem = 0xc8000;
                                        break;
                                case _3COM_PCFR_PIO:
                                        eth_flags |= FLAG_PIO;
                                        eth_bmem = 0;
                                        break;
                                default:
                                        continue;       /* nope */
                                }
                        break;
                }

                if (base[idx] == 0)             /* not found */
                        return (0);
#ifndef T503_SHMEM
                eth_flags |= FLAG_PIO;          /* force PIO mode */
                eth_bmem = 0;
#endif
                eth_vendor = VENDOR_3COM;


        /* Need this to make ns8390_poll() happy. */

                eth_rmem = eth_bmem - 0x2000;

        /* Reset NIC and ASIC */

                outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
                outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );

        /* Get our ethernet address */

                outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
                nic->ioaddr = eth_nic_base;
                DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
                if (eth_flags & FLAG_PIO)
                        DBG ( "PIO mode" );
                else
                        DBG ( "memory %4.4x", eth_bmem );
                for (i=0; i<ETH_ALEN; i++) {
                        nic->node_addr[i] = inb(eth_nic_base+i);
                }
                DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
                      eth_ntoa ( nic->node_addr ) );

                outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
        /*
         * Initialize GA configuration register. Set bank and enable shared
         * mem. We always use bank 1. Disable interrupts.
         */
                outb(_3COM_GACFR_RSEL |
                        _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);

                outb(0xff, eth_asic_base + _3COM_VPTR2);
                outb(0xff, eth_asic_base + _3COM_VPTR1);
                outb(0x00, eth_asic_base + _3COM_VPTR0);
        /*
         * Clear memory and verify that it worked (we use only 8K)
         */

                if (!(eth_flags & FLAG_PIO)) {
                        memset(bus_to_virt(eth_bmem), 0, 0x2000);
                        for(i = 0; i < 0x2000; ++i)
                                if (*((char *)(bus_to_virt(eth_bmem+i)))) {
                                        printf ("Failed to clear 3c503 shared mem.\n");
                                        return (0);
                                }
                }
        /*
         * Initialize GA page/start/stop registers.
         */
                outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
                outb(eth_memsize, eth_asic_base + _3COM_PSPR);
        }
#endif
#if     defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
{
        /******************************************************************
        Search for NE1000/2000 if no WD/SMC or 3com cards
        ******************************************************************/
        unsigned char c;
        if (eth_vendor == VENDOR_NONE) {
                unsigned char romdata[16];
                unsigned char testbuf[32];
                int idx;
                static unsigned char test[] = "NE*000 memory";
                static unsigned short base[] = {
#ifdef  NE_SCAN
                        NE_SCAN,
#endif
                        0 };
                /* if no addresses supplied, fall back on defaults */
                if (probe_addrs == NULL || probe_addrs[0] == 0)
                        probe_addrs = base;
                eth_bmem = 0;           /* No shared memory */
                for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
                        eth_flags = FLAG_PIO;
                        eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
                        eth_memsize = MEM_16384;
                        eth_tx_start = 32;
                        eth_rx_start = 32 + D8390_TXBUF_SIZE;
                        c = inb(eth_asic_base + NE_RESET);
                        outb(c, eth_asic_base + NE_RESET);
                        (void) inb(0x84);
                        outb(D8390_COMMAND_STP |
                                D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
                        outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
                        outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
                        outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
                        outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
#ifdef  NS8390_FORCE_16BIT
                        eth_flags |= FLAG_16BIT;        /* force 16-bit mode */
#endif

                        eth_pio_write( (unsigned char *) test, 8192, sizeof(test));
                        eth_pio_read(8192, testbuf, sizeof(test));
                        if (!memcmp(test, testbuf, sizeof(test)))
                                break;
                        eth_flags |= FLAG_16BIT;
                        eth_memsize = MEM_32768;
                        eth_tx_start = 64;
                        eth_rx_start = 64 + D8390_TXBUF_SIZE;
                        outb(D8390_DCR_WTS |
                                D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
                        outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
                        outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
                        eth_pio_write( (unsigned char *) test, 16384, sizeof(test));
                        eth_pio_read(16384, testbuf, sizeof(test));
                        if (!memcmp(testbuf, test, sizeof(test)))
                                break;
                }
                if (eth_nic_base == 0)
                        return (0);
                if (eth_nic_base > ISA_MAX_ADDR)        /* PCI probably */
                        eth_flags |= FLAG_16BIT;
                eth_vendor = VENDOR_NOVELL;
                eth_pio_read(0, romdata, sizeof(romdata));
                for (i=0; i<ETH_ALEN; i++) {
                        nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
                }
                nic->ioaddr = eth_nic_base;
                DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
                      (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
                      eth_ntoa ( nic->node_addr ) );
        }
}
#endif
        if (eth_vendor == VENDOR_NONE)
                return(0);
        if (eth_vendor != VENDOR_3COM)
                eth_rmem = eth_bmem;
        ns8390_reset(nic);
        nic->nic_op     = &ns8390_operations;

        /* Based on PnP ISA map */
#ifdef  INCLUDE_WD
        dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
        dev->devid.device_id = htons(0x812a);
#endif
#ifdef  INCLUDE_3C503
        dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
        dev->devid.device_id = htons(0x80f3);
#endif
#ifdef  INCLUDE_NE
        dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
        dev->devid.device_id = htons(0x80d6);
#endif
        return 1;
}
PCI_DRIVER ( nepci_driver  ,
nepci_nics  ,
PCI_NO_CLASS   
)
DRIVER ( "NE2000/PCI"  ,
nic_driver  ,
pci_driver  ,
nepci_driver  ,
nepci_probe  ,
ns8390_disable   
)

Variable Documentation

unsigned char eth_vendor [static]

Definition at line 51 of file ns8390.c.

Referenced by eth_probe().

unsigned char eth_flags [static]
unsigned short eth_nic_base [static]
unsigned short eth_asic_base [static]
unsigned char eth_memsize [static]

Definition at line 56 of file ns8390.c.

Referenced by eth_probe(), ns8390_poll(), and ns8390_reset().

unsigned char eth_rx_start [static]

Definition at line 56 of file ns8390.c.

Referenced by eth_probe(), ns8390_poll(), and ns8390_reset().

unsigned char eth_tx_start [static]

Definition at line 56 of file ns8390.c.

Referenced by eth_probe(), ns8390_reset(), and ns8390_transmit().

Address eth_bmem [static]

Definition at line 57 of file ns8390.c.

Referenced by eth_probe(), and ns8390_transmit().

Address eth_rmem [static]

Definition at line 57 of file ns8390.c.

Referenced by eth_probe(), and ns8390_poll().

unsigned char eth_drain_receiver [static]

Definition at line 58 of file ns8390.c.

Referenced by eth_probe(), eth_rx_overrun(), ns8390_poll(), and ns8390_reset().

static struct nic_operations ns8390_operations [static]
Initial value:
 {
        .connect        = dummy_connect,
        .poll           = ns8390_poll,
        .transmit       = ns8390_transmit,
        .irq            = ns8390_irq,
}

Definition at line 619 of file ns8390.c.

Referenced by eth_probe().

struct pci_device_id nepci_nics[] [static]
Initial value:
 {

PCI_ROM(0x10ec, 0x8029, "rtl8029",      "Realtek 8029", 0),
PCI_ROM(0x1186, 0x0300, "dlink-528",    "D-Link DE-528", 0),
PCI_ROM(0x1050, 0x0940, "winbond940",   "Winbond NE2000-PCI", 0),               
PCI_ROM(0x1050, 0x5a5a, "winbond940f",  "Winbond W89c940F", 0),         
PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0),
PCI_ROM(0x8e2e, 0x3000, "ktiet32p2",    "KTI ET32P2", 0),
PCI_ROM(0x4a14, 0x5000, "nv5000sc",     "NetVin NV5000SC", 0),
PCI_ROM(0x12c3, 0x0058, "holtek80232",  "Holtek HT80232", 0),
PCI_ROM(0x12c3, 0x5598, "holtek80229",  "Holtek HT80229", 0),
PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0),
PCI_ROM(0x1106, 0x0926, "via86c926",    "Via 86c926", 0),
}

Definition at line 1007 of file ns8390.c.