!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/net/   drwxr-xr-x
Free 318.34 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     ioc3-eth.c (44.93 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card.
 *
 * Copyright (C) 1999, 2000, 2001 Ralf Baechle
 * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
 *
 * References:
 *  o IOC3 ASIC specification 4.51, 1996-04-18
 *  o IEEE 802.3 specification, 2000 edition
 *  o DP38840A Specification, National Semiconductor, March 1997
 *
 * To do:
 *
 *  o Handle allocation failures in ioc3_alloc_skb() more gracefully.
 *  o Handle allocation failures in ioc3_init_rings().
 *  o Use prefetching for large packets.  What is a good lower limit for
 *    prefetching?
 *  o We're probably allocating a bit too much memory.
 *  o Use hardware checksums.
 *  o Convert to using a IOC3 meta driver.
 *  o Which PHYs might possibly be attached to the IOC3 in real live,
 *    which workarounds are required for them?  Do we ever have Lucent's?
 *  o For the 2.5 branch kill the mii-tool ioctls.
 */
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>

#ifdef CONFIG_SERIAL
#include <linux/serial.h>
#include <asm/serial.h>
#define IOC3_BAUD (22000000 / (3*16))
#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
#endif

#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/dp83840.h>

#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/sn/types.h>
#include <asm/sn/sn0/addrs.h>
#include <asm/sn/sn0/hubni.h>
#include <asm/sn/sn0/hubio.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/ioc3.h>
#include <asm/sn/sn0/ip27.h>
#include <asm/pci/bridge.h>

/*
 * 64 RX buffers.  This is tunable in the range of 16 <= x < 512.  The
 * value must be a power of two.
 */
#define RX_BUFFS 64

/* Timer state engine. */
enum ioc3_timer_state {
    arbwait  = 0,    /* Waiting for auto negotiation to complete.          */
    lupwait  = 1,    /* Auto-neg complete, awaiting link-up status.        */
    ltrywait = 2,    /* Forcing try of all modes, from fastest to slowest. */
    asleep   = 3,    /* Time inactive.                                     */
};

/* Private per NIC data of the driver.  */
struct ioc3_private {
    struct ioc3 *regs;
    int phy;
    unsigned long *rxr;        /* pointer to receiver ring */
    struct ioc3_etxd *txr;
    struct sk_buff *rx_skbs[512];
    struct sk_buff *tx_skbs[128];
    struct net_device_stats stats;
    int rx_ci;            /* RX consumer index */
    int rx_pi;            /* RX producer index */
    int tx_ci;            /* TX consumer index */
    int tx_pi;            /* TX producer index */
    int txqlen;
    u32 emcr, ehar_h, ehar_l;
    spinlock_t ioc3_lock;
    struct net_device *dev;

    /* Members used by autonegotiation  */
    struct timer_list ioc3_timer;
    enum ioc3_timer_state timer_state; /* State of auto-neg timer.       */
    unsigned int timer_ticks;    /* Number of clicks at each state  */
    unsigned short sw_bmcr;        /* sw copy of MII config register  */
    unsigned short sw_bmsr;        /* sw copy of MII status register  */
    unsigned short sw_physid1;    /* sw copy of PHYSID1           */
    unsigned short sw_physid2;    /* sw copy of PHYSID2           */
    unsigned short sw_advertise;    /* sw copy of ADVERTISE           */
    unsigned short sw_lpa;        /* sw copy of LPA           */
    unsigned short sw_csconfig;    /* sw copy of CSCONFIG           */
};

static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void ioc3_set_multicast_list(struct net_device *dev);
static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void ioc3_timeout(struct net_device *dev);
static inline unsigned int ioc3_hash(const unsigned char *addr);
static inline void ioc3_stop(struct ioc3_private *ip);
static void ioc3_init(struct ioc3_private *ip);

static const char ioc3_str[] = "IOC3 Ethernet";

/* We use this to acquire receive skb's that we can DMA directly into. */
#define ALIGNED_RX_SKB_ADDR(addr) \
    ((((unsigned long)(addr) + (128 - 1)) & ~(128 - 1)) - (unsigned long)(addr))

#define ioc3_alloc_skb(__length, __gfp_flags) \
({    struct sk_buff *__skb; \
    __skb = alloc_skb((__length) + 128, (__gfp_flags)); \
    if (__skb) { \
        int __offset = ALIGNED_RX_SKB_ADDR(__skb->data); \
        if(__offset) \
            skb_reserve(__skb, __offset); \
    } \
    __skb; \
})

/* BEWARE: The IOC3 documentation documents the size of rx buffers as
   1644 while it's actually 1664.  This one was nasty to track down ...  */
#define RX_OFFSET        10
#define RX_BUF_ALLOC_SIZE    (1664 + RX_OFFSET + 128)

/* DMA barrier to separate cached and uncached accesses.  */
#define BARRIER()                            \
    __asm__("sync" ::: "memory")


#define IOC3_SIZE 0x100000

#define ioc3_r(reg)                            \
({                                    \
    u32 __res;                            \
    __res = ioc3->reg;                        \
    __res;                                \
})

#define ioc3_w(reg,val)                            \
do {                                    \
    (ioc3->reg = (val));                        \
} while(0)

static inline u32
mcr_pack(u32 pulse, u32 sample)
{
    return (pulse << 10) | (sample << 2);
}

static int
nic_wait(struct ioc3 *ioc3)
{
    u32 mcr;

        do {
                mcr = ioc3_r(mcr);
        } while (!(mcr & 2));

        return mcr & 1;
}

static int
nic_reset(struct ioc3 *ioc3)
{
        int presence;

    ioc3_w(mcr, mcr_pack(500, 65));
    presence = nic_wait(ioc3);

    ioc3_w(mcr, mcr_pack(0, 500));
    nic_wait(ioc3);

        return presence;
}

static inline int
nic_read_bit(struct ioc3 *ioc3)
{
    int result;

    ioc3_w(mcr, mcr_pack(6, 13));
    result = nic_wait(ioc3);
    ioc3_w(mcr, mcr_pack(0, 100));
    nic_wait(ioc3);

    return result;
}

static inline void
nic_write_bit(struct ioc3 *ioc3, int bit)
{
    if (bit)
        ioc3_w(mcr, mcr_pack(6, 110));
    else
        ioc3_w(mcr, mcr_pack(80, 30));

    nic_wait(ioc3);
}

/*
 * Read a byte from an iButton device
 */
static u32
nic_read_byte(struct ioc3 *ioc3)
{
    u32 result = 0;
    int i;

    for (i = 0; i < 8; i++)
        result = (result >> 1) | (nic_read_bit(ioc3) << 7);

    return result;
}

/*
 * Write a byte to an iButton device
 */
static void
nic_write_byte(struct ioc3 *ioc3, int byte)
{
    int i, bit;

    for (i = 8; i; i--) {
        bit = byte & 1;
        byte >>= 1;

        nic_write_bit(ioc3, bit);
    }
}

static u64
nic_find(struct ioc3 *ioc3, int *last)
{
    int a, b, index, disc;
    u64 address = 0;

    nic_reset(ioc3);
    /* Search ROM.  */
    nic_write_byte(ioc3, 0xf0);

    /* Algorithm from ``Book of iButton Standards''.  */
    for (index = 0, disc = 0; index < 64; index++) {
        a = nic_read_bit(ioc3);
        b = nic_read_bit(ioc3);

        if (a && b) {
            printk("NIC search failed (not fatal).\n");
            *last = 0;
            return 0;
        }

        if (!a && !b) {
            if (index == *last) {
                address |= 1UL << index;
            } else if (index > *last) {
                address &= ~(1UL << index);
                disc = index;
            } else if ((address & (1UL << index)) == 0)
                disc = index;
            nic_write_bit(ioc3, address & (1UL << index));
            continue;
        } else {
            if (a)
                address |= 1UL << index;
            else
                address &= ~(1UL << index);
            nic_write_bit(ioc3, a);
            continue;
        }
    }

    *last = disc;

    return address;
}

static int nic_init(struct ioc3 *ioc3)
{
    const char *type;
    u8 crc;
    u8 serial[6];
    int save = 0, i;

    type = "unknown";

    while (1) {
        u64 reg;
        reg = nic_find(ioc3, &save);

        switch (reg & 0xff) {
        case 0x91:
            type = "DS1981U";
            break;
        default:
            if (save == 0) {
                /* Let the caller try again.  */
                return -1;
            }
            continue;
        }

        nic_reset(ioc3);

        /* Match ROM.  */
        nic_write_byte(ioc3, 0x55);
        for (i = 0; i < 8; i++)
            nic_write_byte(ioc3, (reg >> (i << 3)) & 0xff);

        reg >>= 8; /* Shift out type.  */
        for (i = 0; i < 6; i++) {
            serial[i] = reg & 0xff;
            reg >>= 8;
        }
        crc = reg & 0xff;
        break;
    }

    printk("Found %s NIC", type);
    if (type != "unknown") {
        printk (" registration number %02x:%02x:%02x:%02x:%02x:%02x,"
            " CRC %02x", serial[0], serial[1], serial[2],
            serial[3], serial[4], serial[5], crc);
    }
    printk(".\n");

    return 0;
}

/*
 * Read the NIC (Number-In-a-Can) device.
 */
static void ioc3_get_eaddr(struct ioc3_private *ip)
{
    struct ioc3 *ioc3 = ip->regs;
    u8 nic[14];
    int i;
    int tries = 2; /* There may be some problem with the battery?  */

    ioc3_w(gpcr_s, (1 << 21));

    while (tries--) {
        if (!nic_init(ioc3))
            break;
        udelay(500);
    }

    if (tries < 0) {
        printk("Failed to read MAC address\n");
        return;
    }

    /* Read Memory.  */
    nic_write_byte(ioc3, 0xf0);
    nic_write_byte(ioc3, 0x00);
    nic_write_byte(ioc3, 0x00);

    for (i = 13; i >= 0; i--)
        nic[i] = nic_read_byte(ioc3);

    printk("Ethernet address is ");
    for (i = 2; i < 8; i++) {
        ip->dev->dev_addr[i - 2] = nic[i];
        printk("%02x", nic[i]);
        if (i < 7)
            printk(":");
    }
    printk(".\n");
}

/*
 * Caller must hold the ioc3_lock ever for MII readers.  This is also
 * used to protect the transmitter side but it's low contention.
 */
static u16 mii_read(struct ioc3_private *ip, int reg)
{
    struct ioc3 *ioc3 = ip->regs;
    int phy = ip->phy;

    while (ioc3->micr & MICR_BUSY);
    ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG;
    while (ioc3->micr & MICR_BUSY);

    return ioc3->midr_r & MIDR_DATA_MASK;
}

static void mii_write(struct ioc3_private *ip, int reg, u16 data)
{
    struct ioc3 *ioc3 = ip->regs;
    int phy = ip->phy;

    while (ioc3->micr & MICR_BUSY);
    ioc3->midr_w = data;
    ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg;
    while (ioc3->micr & MICR_BUSY);
}

static int ioc3_mii_init(struct ioc3_private *ip);

static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
{
    struct ioc3_private *ip = dev->priv;
    struct ioc3 *ioc3 = ip->regs;

    ip->stats.collisions += (ioc3->etcdc & ETCDC_COLLCNT_MASK);
    return &ip->stats;
}

static inline void
ioc3_rx(struct ioc3_private *ip)
{
    struct sk_buff *skb, *new_skb;
    struct ioc3 *ioc3 = ip->regs;
    int rx_entry, n_entry, len;
    struct ioc3_erxbuf *rxb;
    unsigned long *rxr;
    u32 w0, err;

    rxr = (unsigned long *) ip->rxr;        /* Ring base */
    rx_entry = ip->rx_ci;                /* RX consume index */
    n_entry = ip->rx_pi;

    skb = ip->rx_skbs[rx_entry];
    rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
    w0 = rxb->w0;

    while (w0 & ERXBUF_V) {
        err = rxb->err;                /* It's valid ...  */
        if (err & ERXBUF_GOODPKT) {
            len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
            skb_trim(skb, len);
            skb->protocol = eth_type_trans(skb, ip->dev);

            new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
            if (!new_skb) {
                /* Ouch, drop packet and just recycle packet
                   to keep the ring filled.  */
                ip->stats.rx_dropped++;
                new_skb = skb;
                goto next;
            }
            netif_rx(skb);

            ip->rx_skbs[rx_entry] = NULL;    /* Poison  */

            new_skb->dev = ip->dev;

            /* Because we reserve afterwards. */
            skb_put(new_skb, (1664 + RX_OFFSET));
            rxb = (struct ioc3_erxbuf *) new_skb->data;
            skb_reserve(new_skb, RX_OFFSET);

            ip->dev->last_rx = jiffies;
            ip->stats.rx_packets++;        /* Statistics */
            ip->stats.rx_bytes += len;
        } else {
             /* The frame is invalid and the skb never
                           reached the network layer so we can just
                           recycle it.  */
             new_skb = skb;
             ip->stats.rx_errors++;
        }
        if (err & ERXBUF_CRCERR)    /* Statistics */
            ip->stats.rx_crc_errors++;
        if (err & ERXBUF_FRAMERR)
            ip->stats.rx_frame_errors++;
next:
        ip->rx_skbs[n_entry] = new_skb;
        rxr[n_entry] = (0xa5UL << 56) |
                        ((unsigned long) rxb & TO_PHYS_MASK);
        rxb->w0 = 0;                /* Clear valid flag */
        n_entry = (n_entry + 1) & 511;        /* Update erpir */

        /* Now go on to the next ring entry.  */
        rx_entry = (rx_entry + 1) & 511;
        skb = ip->rx_skbs[rx_entry];
        rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
        w0 = rxb->w0;
    }
    ioc3->erpir = (n_entry << 3) | ERPIR_ARM;
    ip->rx_pi = n_entry;
    ip->rx_ci = rx_entry;
}

static inline void
ioc3_tx(struct ioc3_private *ip)
{
    unsigned long packets, bytes;
    struct ioc3 *ioc3 = ip->regs;
    int tx_entry, o_entry;
    struct sk_buff *skb;
    u32 etcir;

    spin_lock(&ip->ioc3_lock);
    etcir = ioc3->etcir;

    tx_entry = (etcir >> 7) & 127;
    o_entry = ip->tx_ci;
    packets = 0;
    bytes = 0;

    while (o_entry != tx_entry) {
        packets++;
        skb = ip->tx_skbs[o_entry];
        bytes += skb->len;
        dev_kfree_skb_irq(skb);
        ip->tx_skbs[o_entry] = NULL;

        o_entry = (o_entry + 1) & 127;        /* Next */

        etcir = ioc3->etcir;            /* More pkts sent?  */
        tx_entry = (etcir >> 7) & 127;
    }

    ip->stats.tx_packets += packets;
    ip->stats.tx_bytes += bytes;
    ip->txqlen -= packets;

    if (ip->txqlen < 128)
        netif_wake_queue(ip->dev);

    ip->tx_ci = o_entry;
    spin_unlock(&ip->ioc3_lock);
}

/*
 * Deal with fatal IOC3 errors.  This condition might be caused by a hard or
 * software problems, so we should try to recover
 * more gracefully if this ever happens.  In theory we might be flooded
 * with such error interrupts if something really goes wrong, so we might
 * also consider to take the interface down.
 */
static void
ioc3_error(struct ioc3_private *ip, u32 eisr)
{
    struct net_device *dev = ip->dev;
    unsigned char *iface = dev->name;

    if (eisr & EISR_RXOFLO)
        printk(KERN_ERR "%s: RX overflow.\n", iface);
    if (eisr & EISR_RXBUFOFLO)
        printk(KERN_ERR "%s: RX buffer overflow.\n", iface);
    if (eisr & EISR_RXMEMERR)
        printk(KERN_ERR "%s: RX PCI error.\n", iface);
    if (eisr & EISR_RXPARERR)
        printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface);
    if (eisr & EISR_TXBUFUFLO)
        printk(KERN_ERR "%s: TX buffer underflow.\n", iface);
    if (eisr & EISR_TXMEMERR)
        printk(KERN_ERR "%s: TX PCI error.\n", iface);

    ioc3_stop(ip);
    ioc3_init(ip);
    ioc3_mii_init(ip);

    dev->trans_start = jiffies;
    netif_wake_queue(dev);
}

/* The interrupt handler does all of the Rx thread work and cleans up
   after the Tx thread.  */
static void ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs)
{
    struct net_device *dev = (struct net_device *)_dev;
    struct ioc3_private *ip = dev->priv;
    struct ioc3 *ioc3 = ip->regs;
    const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
                        EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
                        EISR_TXEXPLICIT | EISR_TXMEMERR;
    u32 eisr;

    eisr = ioc3->eisr & enabled;

    while (eisr) {
        ioc3->eisr = eisr;
        ioc3->eisr;                /* Flush */

        if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR |
                    EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR))
            ioc3_error(ip, eisr);
        if (eisr & EISR_RXTIMERINT)
            ioc3_rx(ip);
        if (eisr & EISR_TXEXPLICIT)
            ioc3_tx(ip);

        eisr = ioc3->eisr & enabled;
    }
}

/*
 * Auto negotiation.  The scheme is very simple.  We have a timer routine that
 * keeps watching the auto negotiation process as it progresses.  The DP83840
 * is first told to start doing it's thing, we set up the time and place the
 * timer state machine in it's initial state.
 *
 * Here the timer peeks at the DP83840 status registers at each click to see
 * if the auto negotiation has completed, we assume here that the DP83840 PHY
 * will time out at some point and just tell us what (didn't) happen.  For
 * complete coverage we only allow so many of the ticks at this level to run,
 * when this has expired we print a warning message and try another strategy.
 * This "other" strategy is to force the interface into various speed/duplex
 * configurations and we stop when we see a link-up condition before the
 * maximum number of "peek" ticks have occurred.
 *
 * Once a valid link status has been detected we configure the IOC3 to speak
 * the most efficient protocol we could get a clean link for.  The priority
 * for link configurations, highest first is:
 *
 *     100 Base-T Full Duplex
 *     100 Base-T Half Duplex
 *     10 Base-T Full Duplex
 *     10 Base-T Half Duplex
 *
 * We start a new timer now, after a successful auto negotiation status has
 * been detected.  This timer just waits for the link-up bit to get set in
 * the BMCR of the DP83840.  When this occurs we print a kernel log message
 * describing the link type in use and the fact that it is up.
 *
 * If a fatal error of some sort is signalled and detected in the interrupt
 * service routine, and the chip is reset, or the link is ifconfig'd down
 * and then back up, this entire process repeats itself all over again.
 */
static int ioc3_try_next_permutation(struct ioc3_private *ip)
{
    ip->sw_bmcr = mii_read(ip, MII_BMCR);

    /* Downgrade from full to half duplex.  Only possible via ethtool.  */
    if (ip->sw_bmcr & BMCR_FULLDPLX) {
        ip->sw_bmcr &= ~BMCR_FULLDPLX;
        mii_write(ip, MII_BMCR, ip->sw_bmcr);

        return 0;
    }

    /* Downgrade from 100 to 10. */
    if (ip->sw_bmcr & BMCR_SPEED100) {
        ip->sw_bmcr &= ~BMCR_SPEED100;
        mii_write(ip, MII_BMCR, ip->sw_bmcr);

        return 0;
    }

    /* We've tried everything. */
    return -1;
}

static void
ioc3_display_link_mode(struct ioc3_private *ip)
{
    char *tmode = "";

    ip->sw_lpa = mii_read(ip, MII_LPA);

    if (ip->sw_lpa & (LPA_100HALF | LPA_100FULL)) {
        if (ip->sw_lpa & LPA_100FULL)
            tmode = "100Mb/s, Full Duplex";
        else
            tmode = "100Mb/s, Half Duplex";
    } else {
        if (ip->sw_lpa & LPA_10FULL)
            tmode = "10Mb/s, Full Duplex";
        else
            tmode = "10Mb/s, Half Duplex";
    }

    printk(KERN_INFO "%s: Link is up at %s.\n", ip->dev->name, tmode);
}

static void
ioc3_display_forced_link_mode(struct ioc3_private *ip)
{
    char *speed = "", *duplex = "";

    ip->sw_bmcr = mii_read(ip, MII_BMCR);
    if (ip->sw_bmcr & BMCR_SPEED100)
        speed = "100Mb/s, ";
    else
        speed = "10Mb/s, ";
    if (ip->sw_bmcr & BMCR_FULLDPLX)
        duplex = "Full Duplex.\n";
    else
        duplex = "Half Duplex.\n";

    printk(KERN_INFO "%s: Link has been forced up at %s%s", ip->dev->name,
           speed, duplex);
}

static int ioc3_set_link_modes(struct ioc3_private *ip)
{
    struct ioc3 *ioc3 = ip->regs;
    int full;

    /*
     * All we care about is making sure the bigmac tx_cfg has a
     * proper duplex setting.
     */
    if (ip->timer_state == arbwait) {
        ip->sw_lpa = mii_read(ip, MII_LPA);
        if (!(ip->sw_lpa & (LPA_10HALF | LPA_10FULL |
                            LPA_100HALF | LPA_100FULL)))
            goto no_response;
        if (ip->sw_lpa & LPA_100FULL)
            full = 1;
        else if (ip->sw_lpa & LPA_100HALF)
            full = 0;
        else if (ip->sw_lpa & LPA_10FULL)
            full = 1;
        else
            full = 0;
    } else {
        /* Forcing a link mode. */
        ip->sw_bmcr = mii_read(ip, MII_BMCR);
        if (ip->sw_bmcr & BMCR_FULLDPLX)
            full = 1;
        else
            full = 0;
    }

    if (full)
        ip->emcr |= EMCR_DUPLEX;
    else
        ip->emcr &= ~EMCR_DUPLEX;

    ioc3->emcr = ip->emcr;
    ioc3->emcr;

    return 0;

no_response:

    return 1;
}

static int is_lucent_phy(struct ioc3_private *ip)
{
    unsigned short mr2, mr3;
    int ret = 0;

    mr2 = mii_read(ip, MII_PHYSID1);
    mr3 = mii_read(ip, MII_PHYSID2);
    if ((mr2 & 0xffff) == 0x0180 && ((mr3 & 0xffff) >> 10) == 0x1d) {
        ret = 1;
    }

    return ret;
}

static void ioc3_timer(unsigned long data)
{
    struct ioc3_private *ip = (struct ioc3_private *) data;
    int restart_timer = 0;

    ip->timer_ticks++;
    switch (ip->timer_state) {
    case arbwait:
        /*
         * Only allow for 5 ticks, thats 10 seconds and much too
         * long to wait for arbitration to complete.
         */
        if (ip->timer_ticks >= 10) {
            /* Enter force mode. */
    do_force_mode:
            ip->sw_bmcr = mii_read(ip, MII_BMCR);
            printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
                   " trying force link mode\n", ip->dev->name);
            ip->sw_bmcr = BMCR_SPEED100;
            mii_write(ip, MII_BMCR, ip->sw_bmcr);

            if (!is_lucent_phy(ip)) {
                /*
                 * OK, seems we need do disable the transceiver
                 * for the first tick to make sure we get an
                 * accurate link state at the second tick.
                 */
                ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);
                ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
                mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
            }
            ip->timer_state = ltrywait;
            ip->timer_ticks = 0;
            restart_timer = 1;
        } else {
            /* Anything interesting happen? */
            ip->sw_bmsr = mii_read(ip, MII_BMSR);
            if (ip->sw_bmsr & BMSR_ANEGCOMPLETE) {
                int ret;

                /* Just what we've been waiting for... */
                ret = ioc3_set_link_modes(ip);
                if (ret) {
                    /* Ooops, something bad happened, go to
                     * force mode.
                     *
                     * XXX Broken hubs which don't support
                     * XXX 802.3u auto-negotiation make this
                     * XXX happen as well.
                     */
                    goto do_force_mode;
                }

                /*
                 * Success, at least so far, advance our state
                 * engine.
                 */
                ip->timer_state = lupwait;
                restart_timer = 1;
            } else {
                restart_timer = 1;
            }
        }
        break;

    case lupwait:
        /*
         * Auto negotiation was successful and we are awaiting a
         * link up status.  I have decided to let this timer run
         * forever until some sort of error is signalled, reporting
         * a message to the user at 10 second intervals.
         */
        ip->sw_bmsr = mii_read(ip, MII_BMSR);
        if (ip->sw_bmsr & BMSR_LSTATUS) {
            /*
             * Wheee, it's up, display the link mode in use and put
             * the timer to sleep.
             */
            ioc3_display_link_mode(ip);
            ip->timer_state = asleep;
            restart_timer = 0;
        } else {
            if (ip->timer_ticks >= 10) {
                printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
                       "not completely up.\n", ip->dev->name);
                ip->timer_ticks = 0;
                restart_timer = 1;
            } else {
                restart_timer = 1;
            }
        }
        break;

    case ltrywait:
        /*
         * Making the timeout here too long can make it take
         * annoyingly long to attempt all of the link mode
         * permutations, but then again this is essentially
         * error recovery code for the most part.
         */
        ip->sw_bmsr = mii_read(ip, MII_BMSR);
        ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);
        if (ip->timer_ticks == 1) {
            if (!is_lucent_phy(ip)) {
                /*
                 * Re-enable transceiver, we'll re-enable the
                 * transceiver next tick, then check link state
                 * on the following tick.
                 */
                ip->sw_csconfig |= CSCONFIG_TCVDISAB;
                mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
            }
            restart_timer = 1;
            break;
        }
        if (ip->timer_ticks == 2) {
            if (!is_lucent_phy(ip)) {
                ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
                mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
            }
            restart_timer = 1;
            break;
        }
        if (ip->sw_bmsr & BMSR_LSTATUS) {
            /* Force mode selection success. */
            ioc3_display_forced_link_mode(ip);
            ioc3_set_link_modes(ip);  /* XXX error? then what? */
            ip->timer_state = asleep;
            restart_timer = 0;
        } else {
            if (ip->timer_ticks >= 4) { /* 6 seconds or so... */
                int ret;

                ret = ioc3_try_next_permutation(ip);
                if (ret == -1) {
                    /*
                     * Aieee, tried them all, reset the
                     * chip and try all over again.
                     */
                    printk(KERN_NOTICE "%s: Link down, "
                           "cable problem?\n",
                           ip->dev->name);

                    ioc3_init(ip);
                    return;
                }
                if (!is_lucent_phy(ip)) {
                    ip->sw_csconfig = mii_read(ip,
                                        MII_CSCONFIG);
                    ip->sw_csconfig |= CSCONFIG_TCVDISAB;
                    mii_write(ip, MII_CSCONFIG,
                              ip->sw_csconfig);
                }
                ip->timer_ticks = 0;
                restart_timer = 1;
            } else {
                restart_timer = 1;
            }
        }
        break;

    case asleep:
    default:
        /* Can't happens.... */
        printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
               "one anyways!\n", ip->dev->name);
        restart_timer = 0;
        ip->timer_ticks = 0;
        ip->timer_state = asleep; /* foo on you */
        break;
    };

    if (restart_timer) {
        ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */
        add_timer(&ip->ioc3_timer);
    }
}

static void
ioc3_start_auto_negotiation(struct ioc3_private *ip, struct ethtool_cmd *ep)
{
    int timeout;

    /* Read all of the registers we are interested in now. */
    ip->sw_bmsr      = mii_read(ip, MII_BMSR);
    ip->sw_bmcr      = mii_read(ip, MII_BMCR);
    ip->sw_physid1   = mii_read(ip, MII_PHYSID1);
    ip->sw_physid2   = mii_read(ip, MII_PHYSID2);

    /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */

    ip->sw_advertise = mii_read(ip, MII_ADVERTISE);
    if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
        /* Advertise everything we can support. */
        if (ip->sw_bmsr & BMSR_10HALF)
            ip->sw_advertise |= ADVERTISE_10HALF;
        else
            ip->sw_advertise &= ~ADVERTISE_10HALF;

        if (ip->sw_bmsr & BMSR_10FULL)
            ip->sw_advertise |= ADVERTISE_10FULL;
        else
            ip->sw_advertise &= ~ADVERTISE_10FULL;
        if (ip->sw_bmsr & BMSR_100HALF)
            ip->sw_advertise |= ADVERTISE_100HALF;
        else
            ip->sw_advertise &= ~ADVERTISE_100HALF;
        if (ip->sw_bmsr & BMSR_100FULL)
            ip->sw_advertise |= ADVERTISE_100FULL;
        else
            ip->sw_advertise &= ~ADVERTISE_100FULL;
        mii_write(ip, MII_ADVERTISE, ip->sw_advertise);

        /*
         * XXX Currently no IOC3 card I know off supports 100BaseT4,
         * XXX and this is because the DP83840 does not support it,
         * XXX changes XXX would need to be made to the tx/rx logic in
         * XXX the driver as well so I completely skip checking for it
         * XXX in the BMSR for now.
         */

#ifdef AUTO_SWITCH_DEBUG
        ASD(("%s: Advertising [ ", ip->dev->name));
        if (ip->sw_advertise & ADVERTISE_10HALF)
            ASD(("10H "));
        if (ip->sw_advertise & ADVERTISE_10FULL)
            ASD(("10F "));
        if (ip->sw_advertise & ADVERTISE_100HALF)
            ASD(("100H "));
        if (ip->sw_advertise & ADVERTISE_100FULL)
            ASD(("100F "));
#endif

        /* Enable Auto-Negotiation, this is usually on already... */
        ip->sw_bmcr |= BMCR_ANENABLE;
        mii_write(ip, MII_BMCR, ip->sw_bmcr);

        /* Restart it to make sure it is going. */
        ip->sw_bmcr |= BMCR_ANRESTART;
        mii_write(ip, MII_BMCR, ip->sw_bmcr);

        /* BMCR_ANRESTART self clears when the process has begun. */

        timeout = 64;  /* More than enough. */
        while (--timeout) {
            ip->sw_bmcr = mii_read(ip, MII_BMCR);
            if (!(ip->sw_bmcr & BMCR_ANRESTART))
                break; /* got it. */
            udelay(10);
        }
        if (!timeout) {
            printk(KERN_ERR "%s: IOC3 would not start auto "
                   "negotiation BMCR=0x%04x\n",
                   ip->dev->name, ip->sw_bmcr);
            printk(KERN_NOTICE "%s: Performing force link "
                   "detection.\n", ip->dev->name);
            goto force_link;
        } else {
            ip->timer_state = arbwait;
        }
    } else {
force_link:
        /*
         * Force the link up, trying first a particular mode.  Either
         * we are here at the request of ethtool or because the IOC3
         * would not start to autoneg.
         */

        /*
         * Disable auto-negotiation in BMCR, enable the duplex and
         * speed setting, init the timer state machine, and fire it off.
         */
        if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
            ip->sw_bmcr = BMCR_SPEED100;
        } else {
            if (ep->speed == SPEED_100)
                ip->sw_bmcr = BMCR_SPEED100;
            else
                ip->sw_bmcr = 0;
            if (ep->duplex == DUPLEX_FULL)
                ip->sw_bmcr |= BMCR_FULLDPLX;
        }
        mii_write(ip, MII_BMCR, ip->sw_bmcr);

        if (!is_lucent_phy(ip)) {
            /*
             * OK, seems we need do disable the transceiver for the
             * first tick to make sure we get an accurate link
             * state at the second tick.
             */
            ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);
            ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
            mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);
        }
        ip->timer_state = ltrywait;
    }

    del_timer(&ip->ioc3_timer);
    ip->timer_ticks = 0;
    ip->ioc3_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
    ip->ioc3_timer.data = (unsigned long) ip;
    ip->ioc3_timer.function = &ioc3_timer;
    add_timer(&ip->ioc3_timer);
}

static int ioc3_mii_init(struct ioc3_private *ip)
{
    int i, found;
    u16 word;

    found = 0;
    spin_lock_irq(&ip->ioc3_lock);
    for (i = 0; i < 32; i++) {
        ip->phy = i;
        word = mii_read(ip, 2);
        if ((word != 0xffff) && (word != 0x0000)) {
            found = 1;
            break;            /* Found a PHY        */
        }
    }
    if (!found) {
        spin_unlock_irq(&ip->ioc3_lock);
        return -ENODEV;
    }

    ioc3_start_auto_negotiation(ip, NULL);        // XXX ethtool

    spin_unlock_irq(&ip->ioc3_lock);

    return 0;
}

static inline void
ioc3_clean_rx_ring(struct ioc3_private *ip)
{
    struct sk_buff *skb;
    int i;

    for (i = ip->rx_ci; i & 15; i++) {
        ip->rx_skbs[ip->rx_pi] = ip->rx_skbs[ip->rx_ci];
        ip->rxr[ip->rx_pi++] = ip->rxr[ip->rx_ci++];
    }
    ip->rx_pi &= 511;
    ip->rx_ci &= 511;

    for (i = ip->rx_ci; i != ip->rx_pi; i = (i+1) & 511) {
        struct ioc3_erxbuf *rxb;
        skb = ip->rx_skbs[i];
        rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
        rxb->w0 = 0;
    }
}

static inline void
ioc3_clean_tx_ring(struct ioc3_private *ip)
{
    struct sk_buff *skb;
    int i;

    for (i=0; i < 128; i++) {
        skb = ip->tx_skbs[i];
        if (skb) {
            ip->tx_skbs[i] = NULL;
            dev_kfree_skb_any(skb);
        }
        ip->txr[i].cmd = 0;
    }
    ip->tx_pi = 0;
    ip->tx_ci = 0;
}

static void
ioc3_free_rings(struct ioc3_private *ip)
{
    struct sk_buff *skb;
    int rx_entry, n_entry;

    if (ip->txr) {
        ioc3_clean_tx_ring(ip);
        free_pages((unsigned long)ip->txr, 2);
        ip->txr = NULL;
    }

    if (ip->rxr) {
        n_entry = ip->rx_ci;
        rx_entry = ip->rx_pi;

        while (n_entry != rx_entry) {
            skb = ip->rx_skbs[n_entry];
            if (skb)
                dev_kfree_skb_any(skb);

            n_entry = (n_entry + 1) & 511;
        }
        free_page((unsigned long)ip->rxr);
        ip->rxr = NULL;
    }
}

static void
ioc3_alloc_rings(struct net_device *dev, struct ioc3_private *ip,
         struct ioc3 *ioc3)
{
    struct ioc3_erxbuf *rxb;
    unsigned long *rxr;
    int i;

    if (ip->rxr == NULL) {
        /* Allocate and initialize rx ring.  4kb = 512 entries  */
        ip->rxr = (unsigned long *) get_free_page(GFP_ATOMIC);
        rxr = (unsigned long *) ip->rxr;
        if (!rxr)
            printk("ioc3_alloc_rings(): get_free_page() failed!\n");

        /* Now the rx buffers.  The RX ring may be larger but
           we only allocate 16 buffers for now.  Need to tune
           this for performance and memory later.  */
        for (i = 0; i < RX_BUFFS; i++) {
            struct sk_buff *skb;

            skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
            if (!skb) {
                show_free_areas();
                continue;
            }

            ip->rx_skbs[i] = skb;
            skb->dev = dev;

            /* Because we reserve afterwards. */
            skb_put(skb, (1664 + RX_OFFSET));
            rxb = (struct ioc3_erxbuf *) skb->data;
            rxr[i] = (0xa5UL << 56)
                | ((unsigned long) rxb & TO_PHYS_MASK);
            skb_reserve(skb, RX_OFFSET);
        }
        ip->rx_ci = 0;
        ip->rx_pi = RX_BUFFS;
    }

    if (ip->txr == NULL) {
        /* Allocate and initialize tx rings.  16kb = 128 bufs.  */
        ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2);
        if (!ip->txr)
            printk("ioc3_alloc_rings(): get_free_page() failed!\n");
        ip->tx_pi = 0;
        ip->tx_ci = 0;
    }
}

static void
ioc3_init_rings(struct net_device *dev, struct ioc3_private *ip,
            struct ioc3 *ioc3)
{
    unsigned long ring;

    ioc3_free_rings(ip);
    ioc3_alloc_rings(dev, ip, ioc3);

    ioc3_clean_rx_ring(ip);
    ioc3_clean_tx_ring(ip);

    /* Now the rx ring base, consume & produce registers.  */
    ring = (0xa5UL << 56) | ((unsigned long)ip->rxr & TO_PHYS_MASK);
    ioc3->erbr_h = ring >> 32;
    ioc3->erbr_l = ring & 0xffffffff;
    ioc3->ercir  = (ip->rx_ci << 3);
    ioc3->erpir  = (ip->rx_pi << 3) | ERPIR_ARM;

    ring = (0xa5UL << 56) | ((unsigned long)ip->txr & TO_PHYS_MASK);

    ip->txqlen = 0;                    /* nothing queued  */

    /* Now the tx ring base, consume & produce registers.  */
    ioc3->etbr_h = ring >> 32;
    ioc3->etbr_l = ring & 0xffffffff;
    ioc3->etpir  = (ip->tx_pi << 7);
    ioc3->etcir  = (ip->tx_ci << 7);
    ioc3->etcir;                    /* Flush */
}

static inline void
ioc3_ssram_disc(struct ioc3_private *ip)
{
    struct ioc3 *ioc3 = ip->regs;
    volatile u32 *ssram0 = &ioc3->ssram[0x0000];
    volatile u32 *ssram1 = &ioc3->ssram[0x4000];
    unsigned int pattern = 0x5555;

    /* Assume the larger size SSRAM and enable parity checking */
    ioc3->emcr |= (EMCR_BUFSIZ | EMCR_RAMPAR);

    *ssram0 = pattern;
    *ssram1 = ~pattern & IOC3_SSRAM_DM;

    if ((*ssram0 & IOC3_SSRAM_DM) != pattern ||
        (*ssram1 & IOC3_SSRAM_DM) != (~pattern & IOC3_SSRAM_DM)) {
        /* set ssram size to 64 KB */
        ip->emcr = EMCR_RAMPAR;
        ioc3->emcr &= ~EMCR_BUFSIZ;
    } else {
        ip->emcr = EMCR_BUFSIZ | EMCR_RAMPAR;
    }
}

static void ioc3_init(struct ioc3_private *ip)
{
    struct net_device *dev = ip->dev;
    struct ioc3 *ioc3 = ip->regs;

    del_timer(&ip->ioc3_timer);        /* Kill if running    */

    ioc3->emcr = EMCR_RST;            /* Reset        */
    ioc3->emcr;                /* Flush WB        */
    udelay(4);                /* Give it time ...    */
    ioc3->emcr = 0;
    ioc3->emcr;

    /* Misc registers  */
    ioc3->erbar = 0;
    ioc3->etcsr = (17<<ETCSR_IPGR2_SHIFT) | (11<<ETCSR_IPGR1_SHIFT) | 21;
    ioc3->etcdc;                /* Clear on read */
    ioc3->ercsr = 15;            /* RX low watermark  */
    ioc3->ertr = 0;                /* Interrupt immediately */
    ioc3->emar_h = (dev->dev_addr[5] << 8) | dev->dev_addr[4];
    ioc3->emar_l = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) |
                   (dev->dev_addr[1] <<  8) | dev->dev_addr[0];
    ioc3->ehar_h = ip->ehar_h;
    ioc3->ehar_l = ip->ehar_l;
    ioc3->ersr = 42;            /* XXX should be random */

    ioc3_init_rings(ip->dev, ip, ioc3);

    ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN |
                 EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN;
    ioc3->emcr = ip->emcr;
    ioc3->eier = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
                 EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
                 EISR_TXEXPLICIT | EISR_TXMEMERR;
    ioc3->eier;
}

static inline void ioc3_stop(struct ioc3_private *ip)
{
    struct ioc3 *ioc3 = ip->regs;

    ioc3->emcr = 0;                /* Shutup */
    ioc3->eier = 0;                /* Disable interrupts */
    ioc3->eier;                /* Flush */
}

static int
ioc3_open(struct net_device *dev)
{
    struct ioc3_private *ip = dev->priv;

    if (request_irq(dev->irq, ioc3_interrupt, SA_SHIRQ, ioc3_str, dev)) {
        printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);

        return -EAGAIN;
    }

    ip->ehar_h = 0;
    ip->ehar_l = 0;
    ioc3_init(ip);

    netif_start_queue(dev);
    return 0;
}

static int
ioc3_close(struct net_device *dev)
{
    struct ioc3_private *ip = dev->priv;

    del_timer(&ip->ioc3_timer);

    netif_stop_queue(dev);

    ioc3_stop(ip);
    free_irq(dev->irq, dev);

    ioc3_free_rings(ip);
    return 0;
}

/*
 * MENET cards have four IOC3 chips, which are attached to two sets of
 * PCI slot resources each: the primary connections are on slots
 * 0..3 and the secondaries are on 4..7
 *
 * All four ethernets are brought out to connectors; six serial ports
 * (a pair from each of the first three IOC3s) are brought out to
 * MiniDINs; all other subdevices are left swinging in the wind, leave
 * them disabled.
 */
static inline int ioc3_is_menet(struct pci_dev *pdev)
{
    struct pci_dev *dev;

    return pdev->bus->parent == NULL
           && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(0, 0)))
           && dev->vendor == PCI_VENDOR_ID_SGI
           && dev->device == PCI_DEVICE_ID_SGI_IOC3
           && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(1, 0)))
           && dev->vendor == PCI_VENDOR_ID_SGI
           && dev->device == PCI_DEVICE_ID_SGI_IOC3
           && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(2, 0)))
           && dev->vendor == PCI_VENDOR_ID_SGI
           && dev->device == PCI_DEVICE_ID_SGI_IOC3;
}

static void inline ioc3_serial_probe(struct pci_dev *pdev,
                struct ioc3 *ioc3)
{
    struct serial_struct req;

    /*
     * We need to recognice and treat the fourth MENET serial as it
     * does not have an SuperIO chip attached to it, therefore attempting
     * to access it will result in bus errors.  We call something an
     * MENET if PCI slot 0, 1, 2 and 3 of a master PCI bus all have an IOC3
     * in it.  This is paranoid but we want to avoid blowing up on a
     * showhorn PCI box that happens to have 4 IOC3 cards in it so it's
     * not paranoid enough ...
     */
    if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
        return;

    /* Register to interrupt zero because we share the interrupt with
       the serial driver which we don't properly support yet.  */
    memset(&req, 0, sizeof(req));
    req.irq             = 0;
    req.flags           = IOC3_COM_FLAGS;
    req.io_type         = SERIAL_IO_MEM;
    req.iomem_reg_shift = 0;
    req.baud_base       = IOC3_BAUD;

    req.iomem_base      = (unsigned char *) &ioc3->sregs.uarta;
    register_serial(&req);

    req.iomem_base      = (unsigned char *) &ioc3->sregs.uartb;
    register_serial(&req);
}

static int __devinit ioc3_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
{
    struct net_device *dev = NULL;
    struct ioc3_private *ip;
    struct ioc3 *ioc3;
    unsigned long ioc3_base, ioc3_size;
    u32 vendor, model, rev;
    int err;

    dev = alloc_etherdev(sizeof(struct ioc3_private));
    if (!dev)
        return -ENOMEM;

    err = pci_request_regions(pdev, "ioc3");
    if (err)
        goto out_free;

    SET_MODULE_OWNER(dev);
    ip = dev->priv;
    ip->dev = dev;

    dev->irq = pdev->irq;

    ioc3_base = pci_resource_start(pdev, 0);
    ioc3_size = pci_resource_len(pdev, 0);
    ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size);
    if (!ioc3) {
        printk(KERN_CRIT "ioc3eth(%s): ioremap failed, goodbye.\n",
               pdev->slot_name);
        err = -ENOMEM;
        goto out_res;
    }
    ip->regs = ioc3;

#ifdef CONFIG_SERIAL
    ioc3_serial_probe(pdev, ioc3);
#endif

    spin_lock_init(&ip->ioc3_lock);

    ioc3_stop(ip);
    ioc3_init(ip);

    init_timer(&ip->ioc3_timer);
    ioc3_mii_init(ip);

    if (ip->phy == -1) {
        printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n",
               pdev->slot_name);
        err = -ENODEV;
        goto out_stop;
    }

    ioc3_ssram_disc(ip);
    ioc3_get_eaddr(ip);

    /* The IOC3-specific entries in the device structure. */
    dev->open        = ioc3_open;
    dev->hard_start_xmit    = ioc3_start_xmit;
    dev->tx_timeout        = ioc3_timeout;
    dev->watchdog_timeo    = 5 * HZ;
    dev->stop        = ioc3_close;
    dev->get_stats        = ioc3_get_stats;
    dev->do_ioctl        = ioc3_ioctl;
    dev->set_multicast_list    = ioc3_set_multicast_list;

    err = register_netdev(dev);
    if (err)
        goto out_stop;

    vendor = (ip->sw_physid1 << 12) | (ip->sw_physid2 >> 4);
    model  = (ip->sw_physid2 >> 4) & 0x3f;
    rev    = ip->sw_physid2 & 0xf;
    printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, "
           "rev %d.\n", dev->name, ip->phy, vendor, model, rev);
    printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name,
           ip->emcr & EMCR_BUFSIZ ? 128 : 64);

    return 0;

out_stop:
    ioc3_stop(ip);
    free_irq(dev->irq, dev);
    ioc3_free_rings(ip);
out_res:
    pci_release_regions(pdev);
out_free:
    kfree(dev);
    return err;
}

static void __devexit ioc3_remove_one (struct pci_dev *pdev)
{
    struct net_device *dev = pci_get_drvdata(pdev);
    struct ioc3_private *ip = dev->priv;
    struct ioc3 *ioc3 = ip->regs;

    iounmap(ioc3);
    pci_release_regions(pdev);
    kfree(dev);
}

static struct pci_device_id ioc3_pci_tbl[] __devinitdata = {
    { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
    { 0 }
};
MODULE_DEVICE_TABLE(pci, ioc3_pci_tbl);

static struct pci_driver ioc3_driver = {
    name:        "ioc3-eth",
    id_table:    ioc3_pci_tbl,
    probe:        ioc3_probe,
    remove:        __devexit_p(ioc3_remove_one),
};

static int __init ioc3_init_module(void)
{
    return pci_module_init(&ioc3_driver);
}

static void __exit ioc3_cleanup_module(void)
{
    pci_unregister_driver(&ioc3_driver);
}

static int
ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    unsigned long data;
    struct ioc3_private *ip = dev->priv;
    struct ioc3 *ioc3 = ip->regs;
    unsigned int len;
    struct ioc3_etxd *desc;
    int produce;

    spin_lock_irq(&ip->ioc3_lock);

    data = (unsigned long) skb->data;
    len = skb->len;

    produce = ip->tx_pi;
    desc = &ip->txr[produce];

    if (len <= 104) {
        /* Short packet, let's copy it directly into the ring.  */
        memcpy(desc->data, skb->data, skb->len);
        if (len < ETH_ZLEN) {
            /* Very short packet, pad with zeros at the end. */
            memset(desc->data + len, 0, ETH_ZLEN - len);
            len = ETH_ZLEN;
        }
        desc->cmd    = len | ETXD_INTWHENDONE | ETXD_D0V;
        desc->bufcnt = len;
    } else if ((data ^ (data + len)) & 0x4000) {
        unsigned long b2, s1, s2;

        b2 = (data | 0x3fffUL) + 1UL;
        s1 = b2 - data;
        s2 = data + len - b2;

        desc->cmd    = len | ETXD_INTWHENDONE | ETXD_B1V | ETXD_B2V;
        desc->bufcnt = (s1 << ETXD_B1CNT_SHIFT) |
                       (s2 << ETXD_B2CNT_SHIFT);
        desc->p1     = (0xa5UL << 56) | (data & TO_PHYS_MASK);
        desc->p2     = (0xa5UL << 56) | (data & TO_PHYS_MASK);
    } else {
        /* Normal sized packet that doesn't cross a page boundary. */
        desc->cmd    = len | ETXD_INTWHENDONE | ETXD_B1V;
        desc->bufcnt = len << ETXD_B1CNT_SHIFT;
        desc->p1     = (0xa5UL << 56) | (data & TO_PHYS_MASK);
    }

    BARRIER();

    dev->trans_start = jiffies;
    ip->tx_skbs[produce] = skb;            /* Remember skb */
    produce = (produce + 1) & 127;
    ip->tx_pi = produce;
    ioc3->etpir = produce << 7;            /* Fire ... */

    ip->txqlen++;

    if (ip->txqlen > 127)
        netif_stop_queue(dev);

    spin_unlock_irq(&ip->ioc3_lock);

    return 0;
}

static void ioc3_timeout(struct net_device *dev)
{
    struct ioc3_private *ip = dev->priv;

    printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);

    ioc3_stop(ip);
    ioc3_init(ip);
    ioc3_mii_init(ip);

    dev->trans_start = jiffies;
    netif_wake_queue(dev);
}

/*
 * Given a multicast ethernet address, this routine calculates the
 * address's bit index in the logical address filter mask
 */
#define CRC_MASK        0xedb88320

static inline unsigned int
ioc3_hash(const unsigned char *addr)
{
    unsigned int temp = 0;
    unsigned char byte;
    unsigned int crc;
    int bits, len;

    len = ETH_ALEN;
    for (crc = ~0; --len >= 0; addr++) {
        byte = *addr;
        for (bits = 8; --bits >= 0; ) {
            if ((byte ^ crc) & 1)
                crc = (crc >> 1) ^ CRC_MASK;
            else
                crc >>= 1;
            byte >>= 1;
        }
    }

    crc &= 0x3f;    /* bit reverse lowest 6 bits for hash index */
    for (bits = 6; --bits >= 0; ) {
        temp <<= 1;
        temp |= (crc & 0x1);
        crc >>= 1;
    }

    return temp;
}


/* We provide both the mii-tools and the ethtool ioctls.  */
static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
    struct ioc3_private *ip = dev->priv;
    struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data;
    u16 *data = (u16 *)&rq->ifr_data;
    struct ioc3 *ioc3 = ip->regs;
    struct ethtool_cmd ecmd;

    switch (cmd) {
    case SIOCGMIIPHY:    /* Get the address of the PHY in use.  */
        if (ip->phy == -1)
            return -ENODEV;
        data[0] = ip->phy;
        return 0;

    case SIOCGMIIREG: {    /* Read a PHY register.  */
        unsigned int phy = data[0];
        unsigned int reg = data[1];

        if (phy > 0x1f || reg > 0x1f)
            return -EINVAL;

        spin_lock_irq(&ip->ioc3_lock);
        while (ioc3->micr & MICR_BUSY);
        ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG;
        while (ioc3->micr & MICR_BUSY);
        data[3] = (ioc3->midr_r & MIDR_DATA_MASK);
        spin_unlock_irq(&ip->ioc3_lock);

        return 0;

    case SIOCSMIIREG:    /* Write a PHY register.  */
        phy = data[0];
        reg = data[1];

        if (!capable(CAP_NET_ADMIN))
            return -EPERM;

        if (phy > 0x1f || reg > 0x1f)
            return -EINVAL;

        spin_lock_irq(&ip->ioc3_lock);
        while (ioc3->micr & MICR_BUSY);
        ioc3->midr_w = data[2];
        ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg;
        while (ioc3->micr & MICR_BUSY);
        spin_unlock_irq(&ip->ioc3_lock);

        return 0;
        }
    case SIOCETHTOOL:
        if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
            return -EFAULT;

        if (ecmd.cmd == ETHTOOL_GSET) {
            ecmd.supported =
                (SUPPORTED_10baseT_Half |
                 SUPPORTED_10baseT_Full |
                 SUPPORTED_100baseT_Half |
                 SUPPORTED_100baseT_Full | SUPPORTED_Autoneg |
                 SUPPORTED_TP | SUPPORTED_MII);

            ecmd.port = PORT_TP;
            ecmd.transceiver = XCVR_INTERNAL;
            ecmd.phy_address = ip->phy;

            /* Record PHY settings. */
            spin_lock_irq(&ip->ioc3_lock);
            ip->sw_bmcr = mii_read(ip, MII_BMCR);
            ip->sw_lpa = mii_read(ip, MII_LPA);
            spin_unlock_irq(&ip->ioc3_lock);
            if (ip->sw_bmcr & BMCR_ANENABLE) {
                ecmd.autoneg = AUTONEG_ENABLE;
                ecmd.speed = (ip->sw_lpa &
                         (LPA_100HALF | LPA_100FULL)) ?
                         SPEED_100 : SPEED_10;
            if (ecmd.speed == SPEED_100)
                ecmd.duplex = (ip->sw_lpa & (LPA_100FULL)) ?
                              DUPLEX_FULL : DUPLEX_HALF;
            else
                ecmd.duplex = (ip->sw_lpa & (LPA_10FULL)) ?
                              DUPLEX_FULL : DUPLEX_HALF;
            } else {
                ecmd.autoneg = AUTONEG_DISABLE;
                ecmd.speed = (ip->sw_bmcr & BMCR_SPEED100) ?
                             SPEED_100 : SPEED_10;
                ecmd.duplex = (ip->sw_bmcr & BMCR_FULLDPLX) ?
                              DUPLEX_FULL : DUPLEX_HALF;
            }
            if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
                return -EFAULT;
            return 0;
        } else if (ecmd.cmd == ETHTOOL_SSET) {
            if (!capable(CAP_NET_ADMIN))
                return -EPERM;

            /* Verify the settings we care about. */
            if (ecmd.autoneg != AUTONEG_ENABLE &&
                ecmd.autoneg != AUTONEG_DISABLE)
                return -EINVAL;

            if (ecmd.autoneg == AUTONEG_DISABLE &&
                ((ecmd.speed != SPEED_100 &&
                  ecmd.speed != SPEED_10) ||
                 (ecmd.duplex != DUPLEX_HALF &&
                  ecmd.duplex != DUPLEX_FULL)))
                return -EINVAL;

            /* Ok, do it to it. */
            del_timer(&ip->ioc3_timer);
            spin_lock_irq(&ip->ioc3_lock);
            ioc3_start_auto_negotiation(ip, &ecmd);
            spin_unlock_irq(&ip->ioc3_lock);

            return 0;
        } else
        default:
            return -EOPNOTSUPP;
    }

    return -EOPNOTSUPP;
}

static void ioc3_set_multicast_list(struct net_device *dev)
{
    struct dev_mc_list *dmi = dev->mc_list;
    struct ioc3_private *ip = dev->priv;
    struct ioc3 *ioc3 = ip->regs;
    u64 ehar = 0;
    int i;

    netif_stop_queue(dev);                /* Lock out others. */

    if (dev->flags & IFF_PROMISC) {            /* Set promiscuous.  */
        /* Unconditionally log net taps.  */
        printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
        ip->emcr |= EMCR_PROMISC;
        ioc3->emcr = ip->emcr;
        ioc3->emcr;
    } else {
        ip->emcr &= ~EMCR_PROMISC;
        ioc3->emcr = ip->emcr;            /* Clear promiscuous. */
        ioc3->emcr;

        if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
            /* Too many for hashing to make sense or we want all
               multicast packets anyway,  so skip computing all the
               hashes and just accept all packets.  */
            ip->ehar_h = 0xffffffff;
            ip->ehar_l = 0xffffffff;
        } else {
            for (i = 0; i < dev->mc_count; i++) {
                char *addr = dmi->dmi_addr;
                dmi = dmi->next;

                if (!(*addr & 1))
                    continue;

                ehar |= (1UL << ioc3_hash(addr));
            }
            ip->ehar_h = ehar >> 32;
            ip->ehar_l = ehar & 0xffffffff;
        }
        ioc3->ehar_h = ip->ehar_h;
        ioc3->ehar_l = ip->ehar_l;
    }

    netif_wake_queue(dev);            /* Let us get going again. */
}

MODULE_AUTHOR("Ralf Baechle <ralf@oss.sgi.com>");
MODULE_DESCRIPTION("SGI IOC3 Ethernet driver");
MODULE_LICENSE("GPL");

module_init(ioc3_init_module);
module_exit(ioc3_cleanup_module);

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0072 ]--