summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/net/ethernet/3com
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/net/ethernet/3com')
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.c896
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.h91
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/3c509.c1594
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/3c515.c1582
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/3c574_cs.c1180
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/3c589_cs.c943
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/3c59x.c3329
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/Kconfig122
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/Makefile11
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.c2558
-rw-r--r--ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.h624
11 files changed, 0 insertions, 12930 deletions
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.c b/ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.c
deleted file mode 100644
index bf73e1a0..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/* 3c501.c: A 3Com 3c501 Ethernet driver for Linux. */
-/*
- Written 1992,1993,1994 Donald Becker
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
-
- This is a device driver for the 3Com Etherlink 3c501.
- Do not purchase this card, even as a joke. It's performance is horrible,
- and it breaks in many ways.
-
- The original author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- Fixed (again!) the missing interrupt locking on TX/RX shifting.
- Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Removed calls to init_etherdev since they are no longer needed, and
- cleaned up modularization just a bit. The driver still allows only
- the default address for cards when loaded as a module, but that's
- really less braindead than anyone using a 3c501 board. :)
- 19950208 (invid@msen.com)
-
- Added traps for interrupts hitting the window as we clear and TX load
- the board. Now getting 150K/second FTP with a 3c501 card. Still playing
- with a TX-TX optimisation to see if we can touch 180-200K/second as seems
- theoretically maximum.
- 19950402 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Cleaned up for 2.3.x because we broke SMP now.
- 20000208 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Check up pass for 2.5. Nothing significant changed
- 20021009 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Fixed zero fill corner case
- 20030104 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-
- For the avoidance of doubt the "preferred form" of this code is one which
- is in an open non patent encumbered format. Where cryptographic key signing
- forms part of the process of creating an executable the information
- including keys needed to generate an equivalently functional executable
- are deemed to be part of the source code.
-
-*/
-
-
-/**
- * DOC: 3c501 Card Notes
- *
- * Some notes on this thing if you have to hack it. [Alan]
- *
- * Some documentation is available from 3Com. Due to the boards age
- * standard responses when you ask for this will range from 'be serious'
- * to 'give it to a museum'. The documentation is incomplete and mostly
- * of historical interest anyway.
- *
- * The basic system is a single buffer which can be used to receive or
- * transmit a packet. A third command mode exists when you are setting
- * things up.
- *
- * If it's transmitting it's not receiving and vice versa. In fact the
- * time to get the board back into useful state after an operation is
- * quite large.
- *
- * The driver works by keeping the board in receive mode waiting for a
- * packet to arrive. When one arrives it is copied out of the buffer
- * and delivered to the kernel. The card is reloaded and off we go.
- *
- * When transmitting lp->txing is set and the card is reset (from
- * receive mode) [possibly losing a packet just received] to command
- * mode. A packet is loaded and transmit mode triggered. The interrupt
- * handler runs different code for transmit interrupts and can handle
- * returning to receive mode or retransmissions (yes you have to help
- * out with those too).
- *
- * DOC: Problems
- *
- * There are a wide variety of undocumented error returns from the card
- * and you basically have to kick the board and pray if they turn up. Most
- * only occur under extreme load or if you do something the board doesn't
- * like (eg touching a register at the wrong time).
- *
- * The driver is less efficient than it could be. It switches through
- * receive mode even if more transmits are queued. If this worries you buy
- * a real Ethernet card.
- *
- * The combination of slow receive restart and no real multicast
- * filter makes the board unusable with a kernel compiled for IP
- * multicasting in a real multicast environment. That's down to the board,
- * but even with no multicast programs running a multicast IP kernel is
- * in group 224.0.0.1 and you will therefore be listening to all multicasts.
- * One nv conference running over that Ethernet and you can give up.
- *
- */
-
-#define DRV_NAME "3c501"
-#define DRV_VERSION "2002/10/09"
-
-
-static const char version[] =
- DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n";
-
-/*
- * Braindamage remaining:
- * The 3c501 board.
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c501.h"
-
-/*
- * The boilerplate probe code.
- */
-
-static int io = 0x280;
-static int irq = 5;
-static int mem_start;
-
-/**
- * el1_probe: - probe for a 3c501
- * @dev: The device structure passed in to probe.
- *
- * This can be called from two places. The network layer will probe using
- * a device structure passed in with the probe information completed. For a
- * modular driver we use #init_module to fill in our own structure and probe
- * for it.
- *
- * Returns 0 on success. ENXIO if asked not to probe and ENODEV if asked to
- * probe and failing to find anything.
- */
-
-struct net_device * __init el1_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- static const unsigned ports[] = { 0x280, 0x300, 0};
- const unsigned *port;
- int err = 0;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- mem_start = dev->mem_start & 7;
- }
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = el1_probe1(dev, io);
- } else if (io != 0) {
- err = -ENXIO; /* Don't probe at all. */
- } else {
- for (port = ports; *port && el1_probe1(dev, *port); port++)
- ;
- if (!*port)
- err = -ENODEV;
- }
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- release_region(dev->base_addr, EL1_IO_EXTENT);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops el_netdev_ops = {
- .ndo_open = el_open,
- .ndo_stop = el1_close,
- .ndo_start_xmit = el_start_xmit,
- .ndo_tx_timeout = el_timeout,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/**
- * el1_probe1:
- * @dev: The device structure to use
- * @ioaddr: An I/O address to probe at.
- *
- * The actual probe. This is iterated over by #el1_probe in order to
- * check all the applicable device locations.
- *
- * Returns 0 for a success, in which case the device is activated,
- * EAGAIN if the IRQ is in use by another driver, and ENODEV if the
- * board cannot be found.
- */
-
-static int __init el1_probe1(struct net_device *dev, int ioaddr)
-{
- struct net_local *lp;
- const char *mname; /* Vendor name */
- unsigned char station_addr[6];
- int autoirq = 0;
- int i;
-
- /*
- * Reserve I/O resource for exclusive use by this driver
- */
-
- if (!request_region(ioaddr, EL1_IO_EXTENT, DRV_NAME))
- return -ENODEV;
-
- /*
- * Read the station address PROM data from the special port.
- */
-
- for (i = 0; i < 6; i++) {
- outw(i, ioaddr + EL1_DATAPTR);
- station_addr[i] = inb(ioaddr + EL1_SAPROM);
- }
- /*
- * Check the first three octets of the S.A. for 3Com's prefix, or
- * for the Sager NP943 prefix.
- */
-
- if (station_addr[0] == 0x02 && station_addr[1] == 0x60 &&
- station_addr[2] == 0x8c)
- mname = "3c501";
- else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 &&
- station_addr[2] == 0xC8)
- mname = "NP943";
- else {
- release_region(ioaddr, EL1_IO_EXTENT);
- return -ENODEV;
- }
-
- /*
- * We auto-IRQ by shutting off the interrupt line and letting it
- * float high.
- */
-
- dev->irq = irq;
-
- if (dev->irq < 2) {
- unsigned long irq_mask;
-
- irq_mask = probe_irq_on();
- inb(RX_STATUS); /* Clear pending interrupts. */
- inb(TX_STATUS);
- outb(AX_LOOP + 1, AX_CMD);
-
- outb(0x00, AX_CMD);
-
- mdelay(20);
- autoirq = probe_irq_off(irq_mask);
-
- if (autoirq == 0) {
- pr_warning("%s probe at %#x failed to detect IRQ line.\n",
- mname, ioaddr);
- release_region(ioaddr, EL1_IO_EXTENT);
- return -EAGAIN;
- }
- }
-
- outb(AX_RESET+AX_LOOP, AX_CMD); /* Loopback mode. */
- dev->base_addr = ioaddr;
- memcpy(dev->dev_addr, station_addr, ETH_ALEN);
-
- if (mem_start & 0xf)
- el_debug = mem_start & 0x7;
- if (autoirq)
- dev->irq = autoirq;
-
- pr_info("%s: %s EtherLink at %#lx, using %sIRQ %d.\n",
- dev->name, mname, dev->base_addr,
- autoirq ? "auto":"assigned ", dev->irq);
-
-#ifdef CONFIG_IP_MULTICAST
- pr_warning("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n");
-#endif
-
- if (el_debug)
- pr_debug("%s", version);
-
- lp = netdev_priv(dev);
- memset(lp, 0, sizeof(struct net_local));
- spin_lock_init(&lp->lock);
-
- /*
- * The EL1-specific entries in the device structure.
- */
-
- dev->netdev_ops = &el_netdev_ops;
- dev->watchdog_timeo = HZ;
- dev->ethtool_ops = &netdev_ethtool_ops;
- return 0;
-}
-
-/**
- * el1_open:
- * @dev: device that is being opened
- *
- * When an ifconfig is issued which changes the device flags to include
- * IFF_UP this function is called. It is only called when the change
- * occurs, not when the interface remains up. #el1_close will be called
- * when it goes down.
- *
- * Returns 0 for a successful open, or -EAGAIN if someone has run off
- * with our interrupt line.
- */
-
-static int el_open(struct net_device *dev)
-{
- int retval;
- int ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
-
- if (el_debug > 2)
- pr_debug("%s: Doing el_open()...\n", dev->name);
-
- retval = request_irq(dev->irq, el_interrupt, 0, dev->name, dev);
- if (retval)
- return retval;
-
- spin_lock_irqsave(&lp->lock, flags);
- el_reset(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
-
- lp->txing = 0; /* Board in RX mode */
- outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
- netif_start_queue(dev);
- return 0;
-}
-
-/**
- * el_timeout:
- * @dev: The 3c501 card that has timed out
- *
- * Attempt to restart the board. This is basically a mixture of extreme
- * violence and prayer
- *
- */
-
-static void el_timeout(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- if (el_debug)
- pr_debug("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
- dev->name, inb(TX_STATUS),
- inb(AX_STATUS), inb(RX_STATUS));
- dev->stats.tx_errors++;
- outb(TX_NORM, TX_CMD);
- outb(RX_NORM, RX_CMD);
- outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */
- outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
- lp->txing = 0; /* Ripped back in to RX */
- netif_wake_queue(dev);
-}
-
-
-/**
- * el_start_xmit:
- * @skb: The packet that is queued to be sent
- * @dev: The 3c501 card we want to throw it down
- *
- * Attempt to send a packet to a 3c501 card. There are some interesting
- * catches here because the 3c501 is an extremely old and therefore
- * stupid piece of technology.
- *
- * If we are handling an interrupt on the other CPU we cannot load a packet
- * as we may still be attempting to retrieve the last RX packet buffer.
- *
- * When a transmit times out we dump the card into control mode and just
- * start again. It happens enough that it isn't worth logging.
- *
- * We avoid holding the spin locks when doing the packet load to the board.
- * The device is very slow, and its DMA mode is even slower. If we held the
- * lock while loading 1500 bytes onto the controller we would drop a lot of
- * serial port characters. This requires we do extra locking, but we have
- * no real choice.
- */
-
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
-
- /*
- * Avoid incoming interrupts between us flipping txing and flipping
- * mode as the driver assumes txing is a faithful indicator of card
- * state
- */
-
- spin_lock_irqsave(&lp->lock, flags);
-
- /*
- * Avoid timer-based retransmission conflicts.
- */
-
- netif_stop_queue(dev);
-
- do {
- int len = skb->len;
- int pad = 0;
- int gp_start;
- unsigned char *buf = skb->data;
-
- if (len < ETH_ZLEN)
- pad = ETH_ZLEN - len;
-
- gp_start = 0x800 - (len + pad);
-
- lp->tx_pkt_start = gp_start;
- lp->collisions = 0;
-
- dev->stats.tx_bytes += skb->len;
-
- /*
- * Command mode with status cleared should [in theory]
- * mean no more interrupts can be pending on the card.
- */
-
- outb_p(AX_SYS, AX_CMD);
- inb_p(RX_STATUS);
- inb_p(TX_STATUS);
-
- lp->loading = 1;
- lp->txing = 1;
-
- /*
- * Turn interrupts back on while we spend a pleasant
- * afternoon loading bytes into the board
- */
-
- spin_unlock_irqrestore(&lp->lock, flags);
-
- /* Set rx packet area to 0. */
- outw(0x00, RX_BUF_CLR);
- /* aim - packet will be loaded into buffer start */
- outw(gp_start, GP_LOW);
- /* load buffer (usual thing each byte increments the pointer) */
- outsb(DATAPORT, buf, len);
- if (pad) {
- while (pad--) /* Zero fill buffer tail */
- outb(0, DATAPORT);
- }
- /* the board reuses the same register */
- outw(gp_start, GP_LOW);
-
- if (lp->loading != 2) {
- /* fire ... Trigger xmit. */
- outb(AX_XMIT, AX_CMD);
- lp->loading = 0;
- if (el_debug > 2)
- pr_debug(" queued xmit.\n");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- /* A receive upset our load, despite our best efforts */
- if (el_debug > 2)
- pr_debug("%s: burped during tx load.\n", dev->name);
- spin_lock_irqsave(&lp->lock, flags);
- } while (1);
-}
-
-/**
- * el_interrupt:
- * @irq: Interrupt number
- * @dev_id: The 3c501 that burped
- *
- * Handle the ether interface interrupts. The 3c501 needs a lot more
- * hand holding than most cards. In particular we get a transmit interrupt
- * with a collision error because the board firmware isn't capable of rewinding
- * its own transmit buffer pointers. It can however count to 16 for us.
- *
- * On the receive side the card is also very dumb. It has no buffering to
- * speak of. We simply pull the packet out of its PIO buffer (which is slow)
- * and queue it for the kernel. Then we reset the card for the next packet.
- *
- * We sometimes get surprise interrupts late both because the SMP IRQ delivery
- * is message passing and because the card sometimes seems to deliver late. I
- * think if it is part way through a receive and the mode is changed it carries
- * on receiving and sends us an interrupt. We have to band aid all these cases
- * to get a sensible 150kBytes/second performance. Even then you want a small
- * TCP window.
- */
-
-static irqreturn_t el_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct net_local *lp;
- int ioaddr;
- int axsr; /* Aux. status reg. */
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
-
- spin_lock(&lp->lock);
-
- /*
- * What happened ?
- */
-
- axsr = inb(AX_STATUS);
-
- /*
- * Log it
- */
-
- if (el_debug > 3)
- pr_debug("%s: el_interrupt() aux=%#02x\n", dev->name, axsr);
-
- if (lp->loading == 1 && !lp->txing)
- pr_warning("%s: Inconsistent state loading while not in tx\n",
- dev->name);
-
- if (lp->txing) {
- /*
- * Board in transmit mode. May be loading. If we are
- * loading we shouldn't have got this.
- */
- int txsr = inb(TX_STATUS);
-
- if (lp->loading == 1) {
- if (el_debug > 2)
- pr_debug("%s: Interrupt while loading [txsr=%02x gp=%04x rp=%04x]\n",
- dev->name, txsr, inw(GP_LOW), inw(RX_LOW));
-
- /* Force a reload */
- lp->loading = 2;
- spin_unlock(&lp->lock);
- goto out;
- }
- if (el_debug > 6)
- pr_debug("%s: txsr=%02x gp=%04x rp=%04x\n", dev->name,
- txsr, inw(GP_LOW), inw(RX_LOW));
-
- if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
- /*
- * FIXME: is there a logic to whether to keep
- * on trying or reset immediately ?
- */
- if (el_debug > 1)
- pr_debug("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n",
- dev->name, txsr, axsr,
- inw(ioaddr + EL1_DATAPTR),
- inw(ioaddr + EL1_RXPTR));
- lp->txing = 0;
- netif_wake_queue(dev);
- } else if (txsr & TX_16COLLISIONS) {
- /*
- * Timed out
- */
- if (el_debug)
- pr_debug("%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name);
- outb(AX_SYS, AX_CMD);
- lp->txing = 0;
- dev->stats.tx_aborted_errors++;
- netif_wake_queue(dev);
- } else if (txsr & TX_COLLISION) {
- /*
- * Retrigger xmit.
- */
-
- if (el_debug > 6)
- pr_debug("%s: retransmitting after a collision.\n", dev->name);
- /*
- * Poor little chip can't reset its own start
- * pointer
- */
-
- outb(AX_SYS, AX_CMD);
- outw(lp->tx_pkt_start, GP_LOW);
- outb(AX_XMIT, AX_CMD);
- dev->stats.collisions++;
- spin_unlock(&lp->lock);
- goto out;
- } else {
- /*
- * It worked.. we will now fall through and receive
- */
- dev->stats.tx_packets++;
- if (el_debug > 6)
- pr_debug("%s: Tx succeeded %s\n", dev->name,
- (txsr & TX_RDY) ? "." : "but tx is busy!");
- /*
- * This is safe the interrupt is atomic WRT itself.
- */
- lp->txing = 0;
- /* In case more to transmit */
- netif_wake_queue(dev);
- }
- } else {
- /*
- * In receive mode.
- */
-
- int rxsr = inb(RX_STATUS);
- if (el_debug > 5)
- pr_debug("%s: rxsr=%02x txsr=%02x rp=%04x\n",
- dev->name, rxsr, inb(TX_STATUS), inw(RX_LOW));
- /*
- * Just reading rx_status fixes most errors.
- */
- if (rxsr & RX_MISSED)
- dev->stats.rx_missed_errors++;
- else if (rxsr & RX_RUNT) {
- /* Handled to avoid board lock-up. */
- dev->stats.rx_length_errors++;
- if (el_debug > 5)
- pr_debug("%s: runt.\n", dev->name);
- } else if (rxsr & RX_GOOD) {
- /*
- * Receive worked.
- */
- el_receive(dev);
- } else {
- /*
- * Nothing? Something is broken!
- */
- if (el_debug > 2)
- pr_debug("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
- dev->name, rxsr);
- el_reset(dev);
- }
- }
-
- /*
- * Move into receive mode
- */
-
- outb(AX_RX, AX_CMD);
- outw(0x00, RX_BUF_CLR);
- inb(RX_STATUS); /* Be certain that interrupts are cleared. */
- inb(TX_STATUS);
- spin_unlock(&lp->lock);
-out:
- return IRQ_HANDLED;
-}
-
-
-/**
- * el_receive:
- * @dev: Device to pull the packets from
- *
- * We have a good packet. Well, not really "good", just mostly not broken.
- * We must check everything to see if it is good. In particular we occasionally
- * get wild packet sizes from the card. If the packet seems sane we PIO it
- * off the card and queue it for the protocol layers.
- */
-
-static void el_receive(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- int pkt_len;
- struct sk_buff *skb;
-
- pkt_len = inw(RX_LOW);
-
- if (el_debug > 4)
- pr_debug(" el_receive %d.\n", pkt_len);
-
- if (pkt_len < 60 || pkt_len > 1536) {
- if (el_debug)
- pr_debug("%s: bogus packet, length=%d\n",
- dev->name, pkt_len);
- dev->stats.rx_over_errors++;
- return;
- }
-
- /*
- * Command mode so we can empty the buffer
- */
-
- outb(AX_SYS, AX_CMD);
- skb = netdev_alloc_skb(dev, pkt_len + 2);
-
- /*
- * Start of frame
- */
-
- outw(0x00, GP_LOW);
- if (skb == NULL) {
- pr_info("%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- return;
- } else {
- skb_reserve(skb, 2); /* Force 16 byte alignment */
- /*
- * The read increments through the bytes. The interrupt
- * handler will fix the pointer when it returns to
- * receive mode.
- */
- insb(DATAPORT, skb_put(skb, pkt_len), pkt_len);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
-}
-
-/**
- * el_reset: Reset a 3c501 card
- * @dev: The 3c501 card about to get zapped
- *
- * Even resetting a 3c501 isn't simple. When you activate reset it loses all
- * its configuration. You must hold the lock when doing this. The function
- * cannot take the lock itself as it is callable from the irq handler.
- */
-
-static void el_reset(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- if (el_debug > 2)
- pr_info("3c501 reset...\n");
- outb(AX_RESET, AX_CMD); /* Reset the chip */
- /* Aux control, irq and loopback enabled */
- outb(AX_LOOP, AX_CMD);
- {
- int i;
- for (i = 0; i < 6; i++) /* Set the station address. */
- outb(dev->dev_addr[i], ioaddr + i);
- }
-
- outw(0, RX_BUF_CLR); /* Set rx packet area to 0. */
- outb(TX_NORM, TX_CMD); /* tx irq on done, collision */
- outb(RX_NORM, RX_CMD); /* Set Rx commands. */
- inb(RX_STATUS); /* Clear status. */
- inb(TX_STATUS);
- lp->txing = 0;
-}
-
-/**
- * el1_close:
- * @dev: 3c501 card to shut down
- *
- * Close a 3c501 card. The IFF_UP flag has been cleared by the user via
- * the SIOCSIFFLAGS ioctl. We stop any further transmissions being queued,
- * and then disable the interrupts. Finally we reset the chip. The effects
- * of the rest will be cleaned up by #el1_open. Always returns 0 indicating
- * a success.
- */
-
-static int el1_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (el_debug > 2)
- pr_info("%s: Shutting down Ethernet card at %#x.\n",
- dev->name, ioaddr);
-
- netif_stop_queue(dev);
-
- /*
- * Free and disable the IRQ.
- */
-
- free_irq(dev->irq, dev);
- outb(AX_RESET, AX_CMD); /* Reset the chip */
-
- return 0;
-}
-
-/**
- * set_multicast_list:
- * @dev: The device to adjust
- *
- * Set or clear the multicast filter for this adaptor to use the best-effort
- * filtering supported. The 3c501 supports only three modes of filtering.
- * It always receives broadcasts and packets for itself. You can choose to
- * optionally receive all packets, or all multicast packets on top of this.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (dev->flags & IFF_PROMISC) {
- outb(RX_PROM, RX_CMD);
- inb(RX_STATUS);
- } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
- /* Multicast or all multicast is the same */
- outb(RX_MULT, RX_CMD);
- inb(RX_STATUS); /* Clear status. */
- } else {
- outb(RX_NORM, RX_CMD);
- inb(RX_STATUS);
- }
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-
-static struct net_device *dev_3c501;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink I/O base address");
-MODULE_PARM_DESC(irq, "EtherLink IRQ number");
-
-/**
- * init_module:
- *
- * When the driver is loaded as a module this function is called. We fake up
- * a device structure with the base I/O and interrupt set as if it were being
- * called from Space.c. This minimises the extra code that would otherwise
- * be required.
- *
- * Returns 0 for success or -EIO if a card is not found. Returning an error
- * here also causes the module to be unloaded
- */
-
-int __init init_module(void)
-{
- dev_3c501 = el1_probe(-1);
- if (IS_ERR(dev_3c501))
- return PTR_ERR(dev_3c501);
- return 0;
-}
-
-/**
- * cleanup_module:
- *
- * The module is being unloaded. We unhook our network device from the system
- * and then free up the resources we took when the card was found.
- */
-
-void __exit cleanup_module(void)
-{
- struct net_device *dev = dev_3c501;
- unregister_netdev(dev);
- release_region(dev->base_addr, EL1_IO_EXTENT);
- free_netdev(dev);
-}
-
-#endif /* MODULE */
-
-MODULE_AUTHOR("Donald Becker, Alan Cox");
-MODULE_DESCRIPTION("Support for the ancient 3Com 3c501 ethernet card");
-MODULE_LICENSE("GPL");
-
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.h b/ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.h
deleted file mode 100644
index 183fd55f..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c501.h
+++ /dev/null
@@ -1,91 +0,0 @@
-
-/*
- * Index to functions.
- */
-
-static int el1_probe1(struct net_device *dev, int ioaddr);
-static int el_open(struct net_device *dev);
-static void el_timeout(struct net_device *dev);
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el_interrupt(int irq, void *dev_id);
-static void el_receive(struct net_device *dev);
-static void el_reset(struct net_device *dev);
-static int el1_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-#define EL1_IO_EXTENT 16
-
-#ifndef EL_DEBUG
-#define EL_DEBUG 0 /* use 0 for production, 1 for devel., >2 for debug */
-#endif /* Anything above 5 is wordy death! */
-#define debug el_debug
-static int el_debug = EL_DEBUG;
-
-/*
- * Board-specific info in netdev_priv(dev).
- */
-
-struct net_local
-{
- int tx_pkt_start; /* The length of the current Tx packet. */
- int collisions; /* Tx collisions this packet */
- int loading; /* Spot buffer load collisions */
- int txing; /* True if card is in TX mode */
- spinlock_t lock; /* Serializing lock */
-};
-
-
-#define RX_STATUS (ioaddr + 0x06)
-#define RX_CMD RX_STATUS
-#define TX_STATUS (ioaddr + 0x07)
-#define TX_CMD TX_STATUS
-#define GP_LOW (ioaddr + 0x08)
-#define GP_HIGH (ioaddr + 0x09)
-#define RX_BUF_CLR (ioaddr + 0x0A)
-#define RX_LOW (ioaddr + 0x0A)
-#define RX_HIGH (ioaddr + 0x0B)
-#define SAPROM (ioaddr + 0x0C)
-#define AX_STATUS (ioaddr + 0x0E)
-#define AX_CMD AX_STATUS
-#define DATAPORT (ioaddr + 0x0F)
-#define TX_RDY 0x08 /* In TX_STATUS */
-
-#define EL1_DATAPTR 0x08
-#define EL1_RXPTR 0x0A
-#define EL1_SAPROM 0x0C
-#define EL1_DATAPORT 0x0f
-
-/*
- * Writes to the ax command register.
- */
-
-#define AX_OFF 0x00 /* Irq off, buffer access on */
-#define AX_SYS 0x40 /* Load the buffer */
-#define AX_XMIT 0x44 /* Transmit a packet */
-#define AX_RX 0x48 /* Receive a packet */
-#define AX_LOOP 0x0C /* Loopback mode */
-#define AX_RESET 0x80
-
-/*
- * Normal receive mode written to RX_STATUS. We must intr on short packets
- * to avoid bogus rx lockups.
- */
-
-#define RX_NORM 0xA8 /* 0x68 == all addrs, 0xA8 only to me. */
-#define RX_PROM 0x68 /* Senior Prom, uhmm promiscuous mode. */
-#define RX_MULT 0xE8 /* Accept multicast packets. */
-#define TX_NORM 0x0A /* Interrupt on everything that might hang the chip */
-
-/*
- * TX_STATUS register.
- */
-
-#define TX_COLLISION 0x02
-#define TX_16COLLISIONS 0x04
-#define TX_READY 0x08
-
-#define RX_RUNT 0x08
-#define RX_MISSED 0x01 /* Missed a packet due to 3c501 braindamage. */
-#define RX_GOOD 0x30 /* Good packet 0x20, or simple overflow 0x10. */
-
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c509.c b/ANDROID_3.4.5/drivers/net/ethernet/3com/3c509.c
deleted file mode 100644
index 41719da2..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c509.c
+++ /dev/null
@@ -1,1594 +0,0 @@
-/* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */
-/*
- Written 1993-2000 by Donald Becker.
-
- Copyright 1994-2000 by Donald Becker.
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
-
- This driver is for the 3Com EtherLinkIII series.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- Known limitations:
- Because of the way 3c509 ISA detection works it's difficult to predict
- a priori which of several ISA-mode cards will be detected first.
-
- This driver does not use predictive interrupt mode, resulting in higher
- packet latency but lower overhead. If interrupts are disabled for an
- unusually long time it could also result in missed packets, but in
- practice this rarely happens.
-
-
- FIXES:
- Alan Cox: Removed the 'Unexpected interrupt' bug.
- Michael Meskes: Upgraded to Donald Becker's version 1.07.
- Alan Cox: Increased the eeprom delay. Regardless of
- what the docs say some people definitely
- get problems with lower (but in card spec)
- delays
- v1.10 4/21/97 Fixed module code so that multiple cards may be detected,
- other cleanups. -djb
- Andrea Arcangeli: Upgraded to Donald Becker's version 1.12.
- Rick Payne: Fixed SMP race condition
- v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb
- v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb
- v1.15 1/31/98 Faster recovery for Tx errors. -djb
- v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb
- v1.18 12Mar2001 Andrew Morton
- - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz)
- - Reviewed against 1.18 from scyld.com
- v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com>
- - ethtool support
- v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com>
- - Power Management support
- v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
- - Full duplex support
- v1.19 16Oct2002 Zwane Mwaikambo <zwane@linuxpower.ca>
- - Additional ethtool features
- v1.19a 28Oct2002 Davud Ruggiero <jdr@farfalle.com>
- - Increase *read_eeprom udelay to workaround oops with 2 cards.
- v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org>
- - Introduce driver model for EISA cards.
- v1.20 04Feb2008 Ondrej Zary <linux@rainbow-software.org>
- - convert to isa_driver and pnp_driver and some cleanups
-*/
-
-#define DRV_NAME "3c509"
-#define DRV_VERSION "1.20"
-#define DRV_RELDATE "04Feb2008"
-
-/* A few values that may be tweaked. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (400*HZ/1000)
-
-#include <linux/module.h>
-#include <linux/mca.h>
-#include <linux/isa.h>
-#include <linux/pnp.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/pm.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h> /* for udelay() */
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/device.h>
-#include <linux/eisa.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-static char version[] __devinitdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
-
-#ifdef EL3_DEBUG
-static int el3_debug = EL3_DEBUG;
-#else
-static int el3_debug = 2;
-#endif
-
-/* Used to do a global count of all the cards in the system. Must be
- * a global variable so that the mca/eisa probe routines can increment
- * it */
-static int el3_cards = 0;
-#define EL3_MAX_CARDS 8
-
-/* To minimize the size of the driver source I only define operating
- constants if they are used several times. You'll need the manual
- anyway if you want to understand driver details. */
-/* Offsets from base I/O address. */
-#define EL3_DATA 0x00
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-#define EEPROM_READ 0x80
-
-#define EL3_IO_EXTENT 16
-
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-
-
-/* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable. */
-enum c509cmd {
- TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
- RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
- TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
- FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
- SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
- SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
- StatsDisable = 22<<11, StopCoax = 23<<11, PowerUp = 27<<11,
- PowerDown = 28<<11, PowerAuto = 29<<11};
-
-enum c509status {
- IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
- TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
- IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000, };
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
- RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
-
-/* Register window 1 offsets, the window used in normal operation. */
-#define TX_FIFO 0x00
-#define RX_FIFO 0x00
-#define RX_STATUS 0x08
-#define TX_STATUS 0x0B
-#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */
-
-#define WN0_CONF_CTRL 0x04 /* Window 0: Configuration control register */
-#define WN0_ADDR_CONF 0x06 /* Window 0: Address configuration register */
-#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */
-#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
-#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
-#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */
-#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */
-
-/*
- * Must be a power of two (we use a binary and in the
- * circular queue)
- */
-#define SKB_QUEUE_SIZE 64
-
-enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA };
-
-struct el3_private {
- spinlock_t lock;
- /* skb send-queue */
- int head, size;
- struct sk_buff *queue[SKB_QUEUE_SIZE];
- enum el3_cardtype type;
-};
-static int id_port;
-static int current_tag;
-static struct net_device *el3_devs[EL3_MAX_CARDS];
-
-/* Parameters that may be passed into the module. */
-static int debug = -1;
-static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 10;
-#ifdef CONFIG_PNP
-static int nopnp;
-#endif
-
-static int __devinit el3_common_init(struct net_device *dev);
-static void el3_common_remove(struct net_device *dev);
-static ushort id_read_eeprom(int index);
-static ushort read_eeprom(int ioaddr, int index);
-static int el3_open(struct net_device *dev);
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id);
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *el3_get_stats(struct net_device *dev);
-static int el3_rx(struct net_device *dev);
-static int el3_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void el3_tx_timeout (struct net_device *dev);
-static void el3_down(struct net_device *dev);
-static void el3_up(struct net_device *dev);
-static const struct ethtool_ops ethtool_ops;
-#ifdef CONFIG_PM
-static int el3_suspend(struct device *, pm_message_t);
-static int el3_resume(struct device *);
-#else
-#define el3_suspend NULL
-#define el3_resume NULL
-#endif
-
-
-/* generic device remove for all device types */
-static int el3_device_remove (struct device *device);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void el3_poll_controller(struct net_device *dev);
-#endif
-
-/* Return 0 on success, 1 on error, 2 when found already detected PnP card */
-static int el3_isa_id_sequence(__be16 *phys_addr)
-{
- short lrs_state = 0xff;
- int i;
-
- /* ISA boards are detected by sending the ID sequence to the
- ID_PORT. We find cards past the first by setting the 'current_tag'
- on cards as they are found. Cards with their tag set will not
- respond to subsequent ID sequences. */
-
- outb(0x00, id_port);
- outb(0x00, id_port);
- for (i = 0; i < 255; i++) {
- outb(lrs_state, id_port);
- lrs_state <<= 1;
- lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
- }
- /* For the first probe, clear all board's tag registers. */
- if (current_tag == 0)
- outb(0xd0, id_port);
- else /* Otherwise kill off already-found boards. */
- outb(0xd8, id_port);
- if (id_read_eeprom(7) != 0x6d50)
- return 1;
- /* Read in EEPROM data, which does contention-select.
- Only the lowest address board will stay "on-line".
- 3Com got the byte order backwards. */
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(id_read_eeprom(i));
-#ifdef CONFIG_PNP
- if (!nopnp) {
- /* The ISA PnP 3c509 cards respond to the ID sequence too.
- This check is needed in order not to register them twice. */
- for (i = 0; i < el3_cards; i++) {
- struct el3_private *lp = netdev_priv(el3_devs[i]);
- if (lp->type == EL3_PNP &&
- !memcmp(phys_addr, el3_devs[i]->dev_addr,
- ETH_ALEN)) {
- if (el3_debug > 3)
- pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
- phys_addr[0] & 0xff, phys_addr[0] >> 8,
- phys_addr[1] & 0xff, phys_addr[1] >> 8,
- phys_addr[2] & 0xff, phys_addr[2] >> 8);
- /* Set the adaptor tag so that the next card can be found. */
- outb(0xd0 + ++current_tag, id_port);
- return 2;
- }
- }
- }
-#endif /* CONFIG_PNP */
- return 0;
-
-}
-
-static void __devinit el3_dev_fill(struct net_device *dev, __be16 *phys_addr,
- int ioaddr, int irq, int if_port,
- enum el3_cardtype type)
-{
- struct el3_private *lp = netdev_priv(dev);
-
- memcpy(dev->dev_addr, phys_addr, ETH_ALEN);
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->if_port = if_port;
- lp->type = type;
-}
-
-static int __devinit el3_isa_match(struct device *pdev,
- unsigned int ndev)
-{
- struct net_device *dev;
- int ioaddr, isa_irq, if_port, err;
- unsigned int iobase;
- __be16 phys_addr[3];
-
- while ((err = el3_isa_id_sequence(phys_addr)) == 2)
- ; /* Skip to next card when PnP card found */
- if (err == 1)
- return 0;
-
- iobase = id_read_eeprom(8);
- if_port = iobase >> 14;
- ioaddr = 0x200 + ((iobase & 0x1f) << 4);
- if (irq[el3_cards] > 1 && irq[el3_cards] < 16)
- isa_irq = irq[el3_cards];
- else
- isa_irq = id_read_eeprom(9) >> 12;
-
- dev = alloc_etherdev(sizeof(struct el3_private));
- if (!dev)
- return -ENOMEM;
-
- netdev_boot_setup_check(dev);
-
- if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) {
- free_netdev(dev);
- return 0;
- }
-
- /* Set the adaptor tag so that the next card can be found. */
- outb(0xd0 + ++current_tag, id_port);
-
- /* Activate the adaptor at the EEPROM location. */
- outb((ioaddr >> 4) | 0xe0, id_port);
-
- EL3WINDOW(0);
- if (inw(ioaddr) != 0x6d50) {
- free_netdev(dev);
- return 0;
- }
-
- /* Free the interrupt so that some other card can use it. */
- outw(0x0f00, ioaddr + WN0_IRQ);
-
- el3_dev_fill(dev, phys_addr, ioaddr, isa_irq, if_port, EL3_ISA);
- dev_set_drvdata(pdev, dev);
- if (el3_common_init(dev)) {
- free_netdev(dev);
- return 0;
- }
-
- el3_devs[el3_cards++] = dev;
- return 1;
-}
-
-static int __devexit el3_isa_remove(struct device *pdev,
- unsigned int ndev)
-{
- el3_device_remove(pdev);
- dev_set_drvdata(pdev, NULL);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int el3_isa_suspend(struct device *dev, unsigned int n,
- pm_message_t state)
-{
- current_tag = 0;
- return el3_suspend(dev, state);
-}
-
-static int el3_isa_resume(struct device *dev, unsigned int n)
-{
- struct net_device *ndev = dev_get_drvdata(dev);
- int ioaddr = ndev->base_addr, err;
- __be16 phys_addr[3];
-
- while ((err = el3_isa_id_sequence(phys_addr)) == 2)
- ; /* Skip to next card when PnP card found */
- if (err == 1)
- return 0;
- /* Set the adaptor tag so that the next card can be found. */
- outb(0xd0 + ++current_tag, id_port);
- /* Enable the card */
- outb((ioaddr >> 4) | 0xe0, id_port);
- EL3WINDOW(0);
- if (inw(ioaddr) != 0x6d50)
- return 1;
- /* Free the interrupt so that some other card can use it. */
- outw(0x0f00, ioaddr + WN0_IRQ);
- return el3_resume(dev);
-}
-#endif
-
-static struct isa_driver el3_isa_driver = {
- .match = el3_isa_match,
- .remove = __devexit_p(el3_isa_remove),
-#ifdef CONFIG_PM
- .suspend = el3_isa_suspend,
- .resume = el3_isa_resume,
-#endif
- .driver = {
- .name = "3c509"
- },
-};
-static int isa_registered;
-
-#ifdef CONFIG_PNP
-static struct pnp_device_id el3_pnp_ids[] = {
- { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */
- { .id = "TCM5091" }, /* 3Com Etherlink III */
- { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */
- { .id = "TCM5095" }, /* 3Com Etherlink III (TPO) */
- { .id = "TCM5098" }, /* 3Com Etherlink III (TPC) */
- { .id = "PNP80f7" }, /* 3Com Etherlink III compatible */
- { .id = "PNP80f8" }, /* 3Com Etherlink III compatible */
- { .id = "" }
-};
-MODULE_DEVICE_TABLE(pnp, el3_pnp_ids);
-
-static int __devinit el3_pnp_probe(struct pnp_dev *pdev,
- const struct pnp_device_id *id)
-{
- short i;
- int ioaddr, irq, if_port;
- __be16 phys_addr[3];
- struct net_device *dev = NULL;
- int err;
-
- ioaddr = pnp_port_start(pdev, 0);
- if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-pnp"))
- return -EBUSY;
- irq = pnp_irq(pdev, 0);
- EL3WINDOW(0);
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(read_eeprom(ioaddr, i));
- if_port = read_eeprom(ioaddr, 8) >> 14;
- dev = alloc_etherdev(sizeof(struct el3_private));
- if (!dev) {
- release_region(ioaddr, EL3_IO_EXTENT);
- return -ENOMEM;
- }
- SET_NETDEV_DEV(dev, &pdev->dev);
- netdev_boot_setup_check(dev);
-
- el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_PNP);
- pnp_set_drvdata(pdev, dev);
- err = el3_common_init(dev);
-
- if (err) {
- pnp_set_drvdata(pdev, NULL);
- free_netdev(dev);
- return err;
- }
-
- el3_devs[el3_cards++] = dev;
- return 0;
-}
-
-static void __devexit el3_pnp_remove(struct pnp_dev *pdev)
-{
- el3_common_remove(pnp_get_drvdata(pdev));
- pnp_set_drvdata(pdev, NULL);
-}
-
-#ifdef CONFIG_PM
-static int el3_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
-{
- return el3_suspend(&pdev->dev, state);
-}
-
-static int el3_pnp_resume(struct pnp_dev *pdev)
-{
- return el3_resume(&pdev->dev);
-}
-#endif
-
-static struct pnp_driver el3_pnp_driver = {
- .name = "3c509",
- .id_table = el3_pnp_ids,
- .probe = el3_pnp_probe,
- .remove = __devexit_p(el3_pnp_remove),
-#ifdef CONFIG_PM
- .suspend = el3_pnp_suspend,
- .resume = el3_pnp_resume,
-#endif
-};
-static int pnp_registered;
-#endif /* CONFIG_PNP */
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id el3_eisa_ids[] = {
- { "TCM5090" },
- { "TCM5091" },
- { "TCM5092" },
- { "TCM5093" },
- { "TCM5094" },
- { "TCM5095" },
- { "TCM5098" },
- { "" }
-};
-MODULE_DEVICE_TABLE(eisa, el3_eisa_ids);
-
-static int el3_eisa_probe (struct device *device);
-
-static struct eisa_driver el3_eisa_driver = {
- .id_table = el3_eisa_ids,
- .driver = {
- .name = "3c579",
- .probe = el3_eisa_probe,
- .remove = __devexit_p (el3_device_remove),
- .suspend = el3_suspend,
- .resume = el3_resume,
- }
-};
-static int eisa_registered;
-#endif
-
-#ifdef CONFIG_MCA
-static int el3_mca_probe(struct device *dev);
-
-static short el3_mca_adapter_ids[] __initdata = {
- 0x627c,
- 0x627d,
- 0x62db,
- 0x62f6,
- 0x62f7,
- 0x0000
-};
-
-static char *el3_mca_adapter_names[] __initdata = {
- "3Com 3c529 EtherLink III (10base2)",
- "3Com 3c529 EtherLink III (10baseT)",
- "3Com 3c529 EtherLink III (test mode)",
- "3Com 3c529 EtherLink III (TP or coax)",
- "3Com 3c529 EtherLink III (TP)",
- NULL
-};
-
-static struct mca_driver el3_mca_driver = {
- .id_table = el3_mca_adapter_ids,
- .driver = {
- .name = "3c529",
- .bus = &mca_bus_type,
- .probe = el3_mca_probe,
- .remove = __devexit_p(el3_device_remove),
- .suspend = el3_suspend,
- .resume = el3_resume,
- },
-};
-static int mca_registered;
-#endif /* CONFIG_MCA */
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = el3_open,
- .ndo_stop = el3_close,
- .ndo_start_xmit = el3_start_xmit,
- .ndo_get_stats = el3_get_stats,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_tx_timeout = el3_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = el3_poll_controller,
-#endif
-};
-
-static int __devinit el3_common_init(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- int err;
- const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
-
- spin_lock_init(&lp->lock);
-
- if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */
- dev->if_port = (dev->mem_start & 0x0f);
- } else { /* xcvr codes 0/8 */
- /* use eeprom value, but save user's full-duplex selection */
- dev->if_port |= (dev->mem_start & 0x08);
- }
-
- /* The EL3-specific entries in the device structure. */
- dev->netdev_ops = &netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- SET_ETHTOOL_OPS(dev, &ethtool_ops);
-
- err = register_netdev(dev);
- if (err) {
- pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n",
- dev->base_addr, dev->irq);
- release_region(dev->base_addr, EL3_IO_EXTENT);
- return err;
- }
-
- pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n",
- dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
- dev->dev_addr, dev->irq);
-
- if (el3_debug > 0)
- pr_info("%s", version);
- return 0;
-
-}
-
-static void el3_common_remove (struct net_device *dev)
-{
- unregister_netdev (dev);
- release_region(dev->base_addr, EL3_IO_EXTENT);
- free_netdev (dev);
-}
-
-#ifdef CONFIG_MCA
-static int __init el3_mca_probe(struct device *device)
-{
- /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
- * heavily modified by Chris Beauregard
- * (cpbeaure@csclub.uwaterloo.ca) to support standard MCA
- * probing.
- *
- * redone for multi-card detection by ZP Gu (zpg@castle.net)
- * now works as a module */
-
- short i;
- int ioaddr, irq, if_port;
- __be16 phys_addr[3];
- struct net_device *dev = NULL;
- u_char pos4, pos5;
- struct mca_device *mdev = to_mca_device(device);
- int slot = mdev->slot;
- int err;
-
- pos4 = mca_device_read_stored_pos(mdev, 4);
- pos5 = mca_device_read_stored_pos(mdev, 5);
-
- ioaddr = ((short)((pos4&0xfc)|0x02)) << 8;
- irq = pos5 & 0x0f;
-
-
- pr_info("3c529: found %s at slot %d\n",
- el3_mca_adapter_names[mdev->index], slot + 1);
-
- /* claim the slot */
- strncpy(mdev->name, el3_mca_adapter_names[mdev->index],
- sizeof(mdev->name));
- mca_device_set_claim(mdev, 1);
-
- if_port = pos4 & 0x03;
-
- irq = mca_device_transform_irq(mdev, irq);
- ioaddr = mca_device_transform_ioport(mdev, ioaddr);
- if (el3_debug > 2) {
- pr_debug("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
- }
- EL3WINDOW(0);
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(read_eeprom(ioaddr, i));
-
- dev = alloc_etherdev(sizeof (struct el3_private));
- if (dev == NULL) {
- release_region(ioaddr, EL3_IO_EXTENT);
- return -ENOMEM;
- }
-
- netdev_boot_setup_check(dev);
-
- el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_MCA);
- dev_set_drvdata(device, dev);
- err = el3_common_init(dev);
-
- if (err) {
- dev_set_drvdata(device, NULL);
- free_netdev(dev);
- return -ENOMEM;
- }
-
- el3_devs[el3_cards++] = dev;
- return 0;
-}
-
-#endif /* CONFIG_MCA */
-
-#ifdef CONFIG_EISA
-static int __init el3_eisa_probe (struct device *device)
-{
- short i;
- int ioaddr, irq, if_port;
- __be16 phys_addr[3];
- struct net_device *dev = NULL;
- struct eisa_device *edev;
- int err;
-
- /* Yeepee, The driver framework is calling us ! */
- edev = to_eisa_device (device);
- ioaddr = edev->base_addr;
-
- if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa"))
- return -EBUSY;
-
- /* Change the register set to the configuration window 0. */
- outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD);
-
- irq = inw(ioaddr + WN0_IRQ) >> 12;
- if_port = inw(ioaddr + 6)>>14;
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(read_eeprom(ioaddr, i));
-
- /* Restore the "Product ID" to the EEPROM read register. */
- read_eeprom(ioaddr, 3);
-
- dev = alloc_etherdev(sizeof (struct el3_private));
- if (dev == NULL) {
- release_region(ioaddr, EL3_IO_EXTENT);
- return -ENOMEM;
- }
-
- netdev_boot_setup_check(dev);
-
- el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA);
- eisa_set_drvdata (edev, dev);
- err = el3_common_init(dev);
-
- if (err) {
- eisa_set_drvdata (edev, NULL);
- free_netdev(dev);
- return err;
- }
-
- el3_devs[el3_cards++] = dev;
- return 0;
-}
-#endif
-
-/* This remove works for all device types.
- *
- * The net dev must be stored in the driver data field */
-static int __devexit el3_device_remove (struct device *device)
-{
- struct net_device *dev;
-
- dev = dev_get_drvdata(device);
-
- el3_common_remove (dev);
- return 0;
-}
-
-/* Read a word from the EEPROM using the regular EEPROM access register.
- Assume that we are in register window zero.
- */
-static ushort read_eeprom(int ioaddr, int index)
-{
- outw(EEPROM_READ + index, ioaddr + 10);
- /* Pause for at least 162 us. for the read to take place.
- Some chips seem to require much longer */
- mdelay(2);
- return inw(ioaddr + 12);
-}
-
-/* Read a word from the EEPROM when in the ISA ID probe state. */
-static ushort id_read_eeprom(int index)
-{
- int bit, word = 0;
-
- /* Issue read command, and pause for at least 162 us. for it to complete.
- Assume extra-fast 16Mhz bus. */
- outb(EEPROM_READ + index, id_port);
-
- /* Pause for at least 162 us. for the read to take place. */
- /* Some chips seem to require much longer */
- mdelay(4);
-
- for (bit = 15; bit >= 0; bit--)
- word = (word << 1) + (inb(id_port) & 0x01);
-
- if (el3_debug > 3)
- pr_debug(" 3c509 EEPROM word %d %#4.4x.\n", index, word);
-
- return word;
-}
-
-
-static int
-el3_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- int i;
-
- outw(TxReset, ioaddr + EL3_CMD);
- outw(RxReset, ioaddr + EL3_CMD);
- outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
- i = request_irq(dev->irq, el3_interrupt, 0, dev->name, dev);
- if (i)
- return i;
-
- EL3WINDOW(0);
- if (el3_debug > 3)
- pr_debug("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name,
- dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
-
- el3_up(dev);
-
- if (el3_debug > 3)
- pr_debug("%s: Opened 3c509 IRQ %d status %4.4x.\n",
- dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
-
- return 0;
-}
-
-static void
-el3_tx_timeout (struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- /* Transmitter timeout, serious problems. */
- pr_warning("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d.\n",
- dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
- inw(ioaddr + TX_FREE));
- dev->stats.tx_errors++;
- dev->trans_start = jiffies; /* prevent tx timeout */
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- outw(TxEnable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
-}
-
-
-static netdev_tx_t
-el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
-
- netif_stop_queue (dev);
-
- dev->stats.tx_bytes += skb->len;
-
- if (el3_debug > 4) {
- pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
- dev->name, skb->len, inw(ioaddr + EL3_STATUS));
- }
-#if 0
-#ifndef final_version
- { /* Error-checking code, delete someday. */
- ushort status = inw(ioaddr + EL3_STATUS);
- if (status & 0x0001 && /* IRQ line active, missed one. */
- inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */
- pr_debug("%s: Missed interrupt, status then %04x now %04x"
- " Tx %2.2x Rx %4.4x.\n", dev->name, status,
- inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
- inw(ioaddr + RX_STATUS));
- /* Fake interrupt trigger by masking, acknowledge interrupts. */
- outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
- outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
- }
- }
-#endif
-#endif
- /*
- * We lock the driver against other processors. Note
- * we don't need to lock versus the IRQ as we suspended
- * that. This means that we lose the ability to take
- * an RX during a TX upload. That sucks a bit with SMP
- * on an original 3c509 (2K buffer)
- *
- * Using disable_irq stops us crapping on other
- * time sensitive devices.
- */
-
- spin_lock_irqsave(&lp->lock, flags);
-
- /* Put out the doubleword header... */
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0x00, ioaddr + TX_FIFO);
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-
- if (inw(ioaddr + TX_FREE) > 1536)
- netif_start_queue(dev);
- else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
-
- spin_unlock_irqrestore(&lp->lock, flags);
-
- dev_kfree_skb (skb);
-
- /* Clear the Tx status stack. */
- {
- short tx_status;
- int i = 4;
-
- while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
- if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
- if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
- outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
- }
- }
- return NETDEV_TX_OK;
-}
-
-/* The EL3 interrupt handler. */
-static irqreturn_t
-el3_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct el3_private *lp;
- int ioaddr, status;
- int i = max_interrupt_work;
-
- lp = netdev_priv(dev);
- spin_lock(&lp->lock);
-
- ioaddr = dev->base_addr;
-
- if (el3_debug > 4) {
- status = inw(ioaddr + EL3_STATUS);
- pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status);
- }
-
- while ((status = inw(ioaddr + EL3_STATUS)) &
- (IntLatch | RxComplete | StatsFull)) {
-
- if (status & RxComplete)
- el3_rx(dev);
-
- if (status & TxAvailable) {
- if (el3_debug > 5)
- pr_debug(" TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- netif_wake_queue (dev);
- }
- if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) {
- /* Handle all uncommon interrupts. */
- if (status & StatsFull) /* Empty statistics. */
- update_stats(dev);
- if (status & RxEarly) { /* Rx early is unused. */
- el3_rx(dev);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
- if (status & TxComplete) { /* Really Tx error. */
- short tx_status;
- int i = 4;
-
- while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
- if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
- if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
- outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
- }
- }
- if (status & AdapterFailure) {
- /* Adapter failure requires Rx reset and reinit. */
- outw(RxReset, ioaddr + EL3_CMD);
- /* Set the Rx filter to the current state. */
- outw(SetRxFilter | RxStation | RxBroadcast
- | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0)
- | (dev->flags & IFF_PROMISC ? RxProm : 0),
- ioaddr + EL3_CMD);
- outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
- }
- }
-
- if (--i < 0) {
- pr_err("%s: Infinite loop in interrupt, status %4.4x.\n",
- dev->name, status);
- /* Clear all interrupts. */
- outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
- break;
- }
- /* Acknowledge the IRQ. */
- outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */
- }
-
- if (el3_debug > 4) {
- pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name,
- inw(ioaddr + EL3_STATUS));
- }
- spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void el3_poll_controller(struct net_device *dev)
-{
- disable_irq(dev->irq);
- el3_interrupt(dev->irq, dev);
- enable_irq(dev->irq);
-}
-#endif
-
-static struct net_device_stats *
-el3_get_stats(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- unsigned long flags;
-
- /*
- * This is fast enough not to bother with disable IRQ
- * stuff.
- */
-
- spin_lock_irqsave(&lp->lock, flags);
- update_stats(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- return &dev->stats;
-}
-
-/* Update statistics. We change to register window 6, so this should be run
- single-threaded if the device is active. This is expected to be a rare
- operation, and it's simpler for the rest of the driver to assume that
- window 1 is always valid rather than use a special window-state variable.
- */
-static void update_stats(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (el3_debug > 5)
- pr_debug(" Updating the statistics.\n");
- /* Turn off statistics updates while reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- /* Switch to the stats window, and read everything. */
- EL3WINDOW(6);
- dev->stats.tx_carrier_errors += inb(ioaddr + 0);
- dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
- /* Multiple collisions. */ inb(ioaddr + 2);
- dev->stats.collisions += inb(ioaddr + 3);
- dev->stats.tx_window_errors += inb(ioaddr + 4);
- dev->stats.rx_fifo_errors += inb(ioaddr + 5);
- dev->stats.tx_packets += inb(ioaddr + 6);
- /* Rx packets */ inb(ioaddr + 7);
- /* Tx deferrals */ inb(ioaddr + 8);
- inw(ioaddr + 10); /* Total Rx and Tx octets. */
- inw(ioaddr + 12);
-
- /* Back to window 1, and turn statistics back on. */
- EL3WINDOW(1);
- outw(StatsEnable, ioaddr + EL3_CMD);
-}
-
-static int
-el3_rx(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- short rx_status;
-
- if (el3_debug > 5)
- pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
- while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {
- if (rx_status & 0x4000) { /* Error, update stats. */
- short error = rx_status & 0x3800;
-
- outw(RxDiscard, ioaddr + EL3_CMD);
- dev->stats.rx_errors++;
- switch (error) {
- case 0x0000: dev->stats.rx_over_errors++; break;
- case 0x0800: dev->stats.rx_length_errors++; break;
- case 0x1000: dev->stats.rx_frame_errors++; break;
- case 0x1800: dev->stats.rx_length_errors++; break;
- case 0x2000: dev->stats.rx_frame_errors++; break;
- case 0x2800: dev->stats.rx_crc_errors++; break;
- }
- } else {
- short pkt_len = rx_status & 0x7ff;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 5);
- if (el3_debug > 4)
- pr_debug("Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
- if (skb != NULL) {
- skb_reserve(skb, 2); /* Align IP on 16 byte */
-
- /* 'skb->data' points to the start of sk_buff data area. */
- insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),
- (pkt_len + 3) >> 2);
-
- outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_bytes += pkt_len;
- dev->stats.rx_packets++;
- continue;
- }
- outw(RxDiscard, ioaddr + EL3_CMD);
- dev->stats.rx_dropped++;
- if (el3_debug)
- pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, pkt_len);
- }
- inw(ioaddr + EL3_STATUS); /* Delay. */
- while (inw(ioaddr + EL3_STATUS) & 0x1000)
- pr_debug(" Waiting for 3c509 to discard packet, status %x.\n",
- inw(ioaddr + EL3_STATUS) );
- }
-
- return 0;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
- unsigned long flags;
- struct el3_private *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int mc_count = netdev_mc_count(dev);
-
- if (el3_debug > 1) {
- static int old;
- if (old != mc_count) {
- old = mc_count;
- pr_debug("%s: Setting Rx mode to %d addresses.\n",
- dev->name, mc_count);
- }
- }
- spin_lock_irqsave(&lp->lock, flags);
- if (dev->flags&IFF_PROMISC) {
- outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
- ioaddr + EL3_CMD);
- }
- else if (mc_count || (dev->flags&IFF_ALLMULTI)) {
- outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);
- }
- else
- outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
- spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-static int
-el3_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- struct el3_private *lp = netdev_priv(dev);
-
- if (el3_debug > 2)
- pr_debug("%s: Shutting down ethercard.\n", dev->name);
-
- el3_down(dev);
-
- free_irq(dev->irq, dev);
- /* Switching back to window 0 disables the IRQ. */
- EL3WINDOW(0);
- if (lp->type != EL3_EISA) {
- /* But we explicitly zero the IRQ line select anyway. Don't do
- * it on EISA cards, it prevents the module from getting an
- * IRQ after unload+reload... */
- outw(0x0f00, ioaddr + WN0_IRQ);
- }
-
- return 0;
-}
-
-static int
-el3_link_ok(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- u16 tmp;
-
- EL3WINDOW(4);
- tmp = inw(ioaddr + WN4_MEDIA);
- EL3WINDOW(1);
- return tmp & (1<<11);
-}
-
-static int
-el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- u16 tmp;
- int ioaddr = dev->base_addr;
-
- EL3WINDOW(0);
- /* obtain current transceiver via WN4_MEDIA? */
- tmp = inw(ioaddr + WN0_ADDR_CONF);
- ecmd->transceiver = XCVR_INTERNAL;
- switch (tmp >> 14) {
- case 0:
- ecmd->port = PORT_TP;
- break;
- case 1:
- ecmd->port = PORT_AUI;
- ecmd->transceiver = XCVR_EXTERNAL;
- break;
- case 3:
- ecmd->port = PORT_BNC;
- default:
- break;
- }
-
- ecmd->duplex = DUPLEX_HALF;
- ecmd->supported = 0;
- tmp = inw(ioaddr + WN0_CONF_CTRL);
- if (tmp & (1<<13))
- ecmd->supported |= SUPPORTED_AUI;
- if (tmp & (1<<12))
- ecmd->supported |= SUPPORTED_BNC;
- if (tmp & (1<<9)) {
- ecmd->supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full; /* hmm... */
- EL3WINDOW(4);
- tmp = inw(ioaddr + WN4_NETDIAG);
- if (tmp & FD_ENABLE)
- ecmd->duplex = DUPLEX_FULL;
- }
-
- ethtool_cmd_speed_set(ecmd, SPEED_10);
- EL3WINDOW(1);
- return 0;
-}
-
-static int
-el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- u16 tmp;
- int ioaddr = dev->base_addr;
-
- if (ecmd->speed != SPEED_10)
- return -EINVAL;
- if ((ecmd->duplex != DUPLEX_HALF) && (ecmd->duplex != DUPLEX_FULL))
- return -EINVAL;
- if ((ecmd->transceiver != XCVR_INTERNAL) && (ecmd->transceiver != XCVR_EXTERNAL))
- return -EINVAL;
-
- /* change XCVR type */
- EL3WINDOW(0);
- tmp = inw(ioaddr + WN0_ADDR_CONF);
- switch (ecmd->port) {
- case PORT_TP:
- tmp &= ~(3<<14);
- dev->if_port = 0;
- break;
- case PORT_AUI:
- tmp |= (1<<14);
- dev->if_port = 1;
- break;
- case PORT_BNC:
- tmp |= (3<<14);
- dev->if_port = 3;
- break;
- default:
- return -EINVAL;
- }
-
- outw(tmp, ioaddr + WN0_ADDR_CONF);
- if (dev->if_port == 3) {
- /* fire up the DC-DC convertor if BNC gets enabled */
- tmp = inw(ioaddr + WN0_ADDR_CONF);
- if (tmp & (3 << 14)) {
- outw(StartCoax, ioaddr + EL3_CMD);
- udelay(800);
- } else
- return -EIO;
- }
-
- EL3WINDOW(4);
- tmp = inw(ioaddr + WN4_NETDIAG);
- if (ecmd->duplex == DUPLEX_FULL)
- tmp |= FD_ENABLE;
- else
- tmp &= ~FD_ENABLE;
- outw(tmp, ioaddr + WN4_NETDIAG);
- EL3WINDOW(1);
-
- return 0;
-}
-
-static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
-}
-
-static int el3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- struct el3_private *lp = netdev_priv(dev);
- int ret;
-
- spin_lock_irq(&lp->lock);
- ret = el3_netdev_get_ecmd(dev, ecmd);
- spin_unlock_irq(&lp->lock);
- return ret;
-}
-
-static int el3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- struct el3_private *lp = netdev_priv(dev);
- int ret;
-
- spin_lock_irq(&lp->lock);
- ret = el3_netdev_set_ecmd(dev, ecmd);
- spin_unlock_irq(&lp->lock);
- return ret;
-}
-
-static u32 el3_get_link(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- u32 ret;
-
- spin_lock_irq(&lp->lock);
- ret = el3_link_ok(dev);
- spin_unlock_irq(&lp->lock);
- return ret;
-}
-
-static u32 el3_get_msglevel(struct net_device *dev)
-{
- return el3_debug;
-}
-
-static void el3_set_msglevel(struct net_device *dev, u32 v)
-{
- el3_debug = v;
-}
-
-static const struct ethtool_ops ethtool_ops = {
- .get_drvinfo = el3_get_drvinfo,
- .get_settings = el3_get_settings,
- .set_settings = el3_set_settings,
- .get_link = el3_get_link,
- .get_msglevel = el3_get_msglevel,
- .set_msglevel = el3_set_msglevel,
-};
-
-static void
-el3_down(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- netif_stop_queue(dev);
-
- /* Turn off statistics ASAP. We update lp->stats below. */
- outw(StatsDisable, ioaddr + EL3_CMD);
-
- /* Disable the receiver and transmitter. */
- outw(RxDisable, ioaddr + EL3_CMD);
- outw(TxDisable, ioaddr + EL3_CMD);
-
- if (dev->if_port == 3)
- /* Turn off thinnet power. Green! */
- outw(StopCoax, ioaddr + EL3_CMD);
- else if (dev->if_port == 0) {
- /* Disable link beat and jabber, if_port may change here next open(). */
- EL3WINDOW(4);
- outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
- }
-
- outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
- update_stats(dev);
-}
-
-static void
-el3_up(struct net_device *dev)
-{
- int i, sw_info, net_diag;
- int ioaddr = dev->base_addr;
-
- /* Activating the board required and does no harm otherwise */
- outw(0x0001, ioaddr + 4);
-
- /* Set the IRQ line. */
- outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
-
- /* Set the station address in window 2 each time opened. */
- EL3WINDOW(2);
-
- for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + i);
-
- if ((dev->if_port & 0x03) == 3) /* BNC interface */
- /* Start the thinnet transceiver. We should really wait 50ms...*/
- outw(StartCoax, ioaddr + EL3_CMD);
- else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */
- /* Combine secondary sw_info word (the adapter level) and primary
- sw_info word (duplex setting plus other useless bits) */
- EL3WINDOW(0);
- sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) |
- (read_eeprom(ioaddr, 0x0d) & 0xBff0);
-
- EL3WINDOW(4);
- net_diag = inw(ioaddr + WN4_NETDIAG);
- net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */
- pr_info("%s: ", dev->name);
- switch (dev->if_port & 0x0c) {
- case 12:
- /* force full-duplex mode if 3c5x9b */
- if (sw_info & 0x000f) {
- pr_cont("Forcing 3c5x9b full-duplex mode");
- break;
- }
- case 8:
- /* set full-duplex mode based on eeprom config setting */
- if ((sw_info & 0x000f) && (sw_info & 0x8000)) {
- pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)");
- break;
- }
- default:
- /* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */
- pr_cont("Setting 3c5x9/3c5x9B half-duplex mode");
- net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */
- }
-
- outw(net_diag, ioaddr + WN4_NETDIAG);
- pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info);
- if (el3_debug > 3)
- pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag);
- /* Enable link beat and jabber check. */
- outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);
- }
-
- /* Switch to the stats window, and clear all stats by reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
- for (i = 0; i < 9; i++)
- inb(ioaddr + i);
- inw(ioaddr + 10);
- inw(ioaddr + 12);
-
- /* Switch to register set 1 for normal use. */
- EL3WINDOW(1);
-
- /* Accept b-case and phys addr only. */
- outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
- outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
- outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
- /* Allow status bits to be seen. */
- outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
- /* Ack all pending events, and set active indicator mask. */
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
- outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,
- ioaddr + EL3_CMD);
-
- netif_start_queue(dev);
-}
-
-/* Power Management support functions */
-#ifdef CONFIG_PM
-
-static int
-el3_suspend(struct device *pdev, pm_message_t state)
-{
- unsigned long flags;
- struct net_device *dev;
- struct el3_private *lp;
- int ioaddr;
-
- dev = dev_get_drvdata(pdev);
- lp = netdev_priv(dev);
- ioaddr = dev->base_addr;
-
- spin_lock_irqsave(&lp->lock, flags);
-
- if (netif_running(dev))
- netif_device_detach(dev);
-
- el3_down(dev);
- outw(PowerDown, ioaddr + EL3_CMD);
-
- spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
-}
-
-static int
-el3_resume(struct device *pdev)
-{
- unsigned long flags;
- struct net_device *dev;
- struct el3_private *lp;
- int ioaddr;
-
- dev = dev_get_drvdata(pdev);
- lp = netdev_priv(dev);
- ioaddr = dev->base_addr;
-
- spin_lock_irqsave(&lp->lock, flags);
-
- outw(PowerUp, ioaddr + EL3_CMD);
- EL3WINDOW(0);
- el3_up(dev);
-
- if (netif_running(dev))
- netif_device_attach(dev);
-
- spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-module_param(debug,int, 0);
-module_param_array(irq, int, NULL, 0);
-module_param(max_interrupt_work, int, 0);
-MODULE_PARM_DESC(debug, "debug level (0-6)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-#ifdef CONFIG_PNP
-module_param(nopnp, int, 0);
-MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
-#endif /* CONFIG_PNP */
-MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ethernet driver");
-MODULE_LICENSE("GPL");
-
-static int __init el3_init_module(void)
-{
- int ret = 0;
-
- if (debug >= 0)
- el3_debug = debug;
-
-#ifdef CONFIG_PNP
- if (!nopnp) {
- ret = pnp_register_driver(&el3_pnp_driver);
- if (!ret)
- pnp_registered = 1;
- }
-#endif
- /* Select an open I/O location at 0x1*0 to do ISA contention select. */
- /* Start with 0x110 to avoid some sound cards.*/
- for (id_port = 0x110 ; id_port < 0x200; id_port += 0x10) {
- if (!request_region(id_port, 1, "3c509-control"))
- continue;
- outb(0x00, id_port);
- outb(0xff, id_port);
- if (inb(id_port) & 0x01)
- break;
- else
- release_region(id_port, 1);
- }
- if (id_port >= 0x200) {
- id_port = 0;
- pr_err("No I/O port available for 3c509 activation.\n");
- } else {
- ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS);
- if (!ret)
- isa_registered = 1;
- }
-#ifdef CONFIG_EISA
- ret = eisa_driver_register(&el3_eisa_driver);
- if (!ret)
- eisa_registered = 1;
-#endif
-#ifdef CONFIG_MCA
- ret = mca_register_driver(&el3_mca_driver);
- if (!ret)
- mca_registered = 1;
-#endif
-
-#ifdef CONFIG_PNP
- if (pnp_registered)
- ret = 0;
-#endif
- if (isa_registered)
- ret = 0;
-#ifdef CONFIG_EISA
- if (eisa_registered)
- ret = 0;
-#endif
-#ifdef CONFIG_MCA
- if (mca_registered)
- ret = 0;
-#endif
- return ret;
-}
-
-static void __exit el3_cleanup_module(void)
-{
-#ifdef CONFIG_PNP
- if (pnp_registered)
- pnp_unregister_driver(&el3_pnp_driver);
-#endif
- if (isa_registered)
- isa_unregister_driver(&el3_isa_driver);
- if (id_port)
- release_region(id_port, 1);
-#ifdef CONFIG_EISA
- if (eisa_registered)
- eisa_driver_unregister(&el3_eisa_driver);
-#endif
-#ifdef CONFIG_MCA
- if (mca_registered)
- mca_unregister_driver(&el3_mca_driver);
-#endif
-}
-
-module_init (el3_init_module);
-module_exit (el3_cleanup_module);
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c515.c b/ANDROID_3.4.5/drivers/net/ethernet/3com/3c515.c
deleted file mode 100644
index 59e1e001..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c515.c
+++ /dev/null
@@ -1,1582 +0,0 @@
-/*
- Written 1997-1998 by Donald Becker.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- This driver is for the 3Com ISA EtherLink XL "Corkscrew" 3c515 ethercard.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
-
- 2000/2/2- Added support for kernel-level ISAPnP
- by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo
- Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
-
- 2001/11/17 - Added ethtool support (jgarzik)
-
- 2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk)
-
-*/
-
-#define DRV_NAME "3c515"
-#define DRV_VERSION "0.99t-ac"
-#define DRV_RELDATE "28-Oct-2002"
-
-static char *version =
-DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " becker@scyld.com and others\n";
-
-#define CORKSCREW 1
-
-/* "Knobs" that adjust features and parameters. */
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- Setting to > 1512 effectively disables this feature. */
-static int rx_copybreak = 200;
-
-/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const int mtu = 1500;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Enable the automatic media selection code -- usually set. */
-#define AUTOMEDIA 1
-
-/* Allow the use of fragment bus master transfers instead of only
- programmed-I/O for Vortex cards. Full-bus-master transfers are always
- enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined,
- the feature may be turned on using 'options'. */
-#define VORTEX_BUS_MASTER
-
-/* A few values that may be tweaked. */
-/* Keep the ring sizes a power of two for efficiency. */
-#define TX_RING_SIZE 16
-#define RX_RING_SIZE 16
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
-
-#include <linux/module.h>
-#include <linux/isapnp.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define NEW_MULTICAST
-#include <linux/delay.h>
-
-#define MAX_UNITS 8
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-/* "Knobs" for adjusting internal parameters. */
-/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define DRIVER_DEBUG 1
-/* Some values here only for performance evaluation and path-coverage
- debugging. */
-static int rx_nocopy, rx_copy, queued_packet;
-
-/* Number of times to check to see if the Tx FIFO has space, used in some
- limited cases. */
-#define WAIT_TX_AVAIL 200
-
-/* Operational parameter that usually are not changed. */
-#define TX_TIMEOUT ((4*HZ)/10) /* Time in jiffies before concluding Tx hung */
-
-/* The size here is somewhat misleading: the Corkscrew also uses the ISA
- aliased registers at <base>+0x400.
- */
-#define CORKSCREW_TOTAL_SIZE 0x20
-
-#ifdef DRIVER_DEBUG
-static int corkscrew_debug = DRIVER_DEBUG;
-#else
-static int corkscrew_debug = 1;
-#endif
-
-#define CORKSCREW_ID 10
-
-/*
- Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the 3Com 3c515 ISA Fast EtherLink XL,
-3Com's ISA bus adapter for Fast Ethernet. Due to the unique I/O port layout,
-it's not practical to integrate this driver with the other EtherLink drivers.
-
-II. Board-specific settings
-
-The Corkscrew has an EEPROM for configuration, but no special settings are
-needed for Linux.
-
-III. Driver operation
-
-The 3c515 series use an interface that's very similar to the 3c900 "Boomerang"
-PCI cards, with the bus master interface extensively modified to work with
-the ISA bus.
-
-The card is capable of full-bus-master transfers with separate
-lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
-DEC Tulip and Intel Speedo3.
-
-This driver uses a "RX_COPYBREAK" scheme rather than a fixed intermediate
-receive buffer. This scheme allocates full-sized skbuffs as receive
-buffers. The value RX_COPYBREAK is used as the copying breakpoint: it is
-chosen to trade-off the memory wasted by passing the full-sized skbuff to
-the queue layer for all frames vs. the copying cost of copying a frame to a
-correctly-sized skbuff.
-
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control. One
-is the send-packet routine, which enforces single-threaded use by the netif
-layer. The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-IV. Notes
-
-Thanks to Terry Murphy of 3Com for providing documentation and a development
-board.
-
-The names "Vortex", "Boomerang" and "Corkscrew" are the internal 3Com
-project names. I use these names to eliminate confusion -- 3Com product
-numbers and names are very similar and often confused.
-
-The new chips support both ethernet (1.5K) and FDDI (4.5K) frame sizes!
-This driver only supports ethernet frames because of the recent MTU limit
-of 1.5K, but the changes to support 4.5K are minimal.
-*/
-
-/* Operational definitions.
- These are not used by other compilation units and thus are not
- exported in a ".h" file.
-
- First the windows. There are eight register windows, with the command
- and status registers available in each.
- */
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-/* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable.
- Note that 11 parameters bits was fine for ethernet, but the new chips
- can handle FDDI length frames (~4500 octets) and now parameters count
- 32-bit 'Dwords' rather than octets. */
-
-enum corkscrew_cmd {
- TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
- RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
- UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, DownStall = (6 << 11) + 2,
- DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
- TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
- AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
- SetRxFilter = 16 << 11, SetRxThreshold = 17 << 11,
- SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, StartDMAUp = 20 << 11,
- StartDMADown = (20 << 11) + 1, StatsEnable = 21 << 11,
- StatsDisable = 22 << 11, StopCoax = 23 << 11,
-};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
- RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
-};
-
-/* Bits in the general status register. */
-enum corkscrew_status {
- IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
- TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
- IntReq = 0x0040, StatsFull = 0x0080,
- DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10,
- DMAInProgress = 1 << 11, /* DMA controller is still busy. */
- CmdInProgress = 1 << 12, /* EL3_CMD is still busy. */
-};
-
-/* Register window 1 offsets, the window used in normal operation.
- On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */
-enum Window1 {
- TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
- RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B,
- TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
-};
-enum Window0 {
- Wn0IRQ = 0x08,
-#if defined(CORKSCREW)
- Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */
- Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */
-#else
- Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
- Wn0EepromData = 12, /* Window 0: EEPROM results register. */
-#endif
-};
-enum Win0_EEPROM_bits {
- EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
- EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
- EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
-};
-
-/* EEPROM locations. */
-enum eeprom_offset {
- PhysAddr01 = 0, PhysAddr23 = 1, PhysAddr45 = 2, ModelID = 3,
- EtherLink3ID = 7,
-};
-
-enum Window3 { /* Window 3: MAC/config bits. */
- Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
-};
-enum wn3_config {
- Ram_size = 7,
- Ram_width = 8,
- Ram_speed = 0x30,
- Rom_size = 0xc0,
- Ram_split_shift = 16,
- Ram_split = 3 << Ram_split_shift,
- Xcvr_shift = 20,
- Xcvr = 7 << Xcvr_shift,
- Autoselect = 0x1000000,
-};
-
-enum Window4 {
- Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */
-};
-enum Win4_Media_bits {
- Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
- Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
- Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
- Media_LnkBeat = 0x0800,
-};
-enum Window7 { /* Window 7: Bus Master control. */
- Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
-};
-
-/* Boomerang-style bus master control registers. Note ISA aliases! */
-enum MasterCtrl {
- PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen =
- 0x40c,
- TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418,
-};
-
-/* The Rx and Tx descriptor lists.
- Caution Alpha hackers: these types are 32 bits! Note also the 8 byte
- alignment contraint on tx_ring[] and rx_ring[]. */
-struct boom_rx_desc {
- u32 next;
- s32 status;
- u32 addr;
- s32 length;
-};
-
-/* Values for the Rx status entry. */
-enum rx_desc_status {
- RxDComplete = 0x00008000, RxDError = 0x4000,
- /* See boomerang_rx() for actual error bits */
-};
-
-struct boom_tx_desc {
- u32 next;
- s32 status;
- u32 addr;
- s32 length;
-};
-
-struct corkscrew_private {
- const char *product_name;
- struct list_head list;
- struct net_device *our_dev;
- /* The Rx and Tx rings are here to keep them quad-word-aligned. */
- struct boom_rx_desc rx_ring[RX_RING_SIZE];
- struct boom_tx_desc tx_ring[TX_RING_SIZE];
- /* The addresses of transmit- and receive-in-place skbuffs. */
- struct sk_buff *rx_skbuff[RX_RING_SIZE];
- struct sk_buff *tx_skbuff[TX_RING_SIZE];
- unsigned int cur_rx, cur_tx; /* The next free ring entry */
- unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
- struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
- struct timer_list timer; /* Media selection timer. */
- int capabilities ; /* Adapter capabilities word. */
- int options; /* User-settable misc. driver options. */
- int last_rx_packets; /* For media autoselection. */
- unsigned int available_media:8, /* From Wn3_Options */
- media_override:3, /* Passed-in media type. */
- default_media:3, /* Read from the EEPROM. */
- full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */
- full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */
- tx_full:1;
- spinlock_t lock;
- struct device *dev;
-};
-
-/* The action to take with a media selection timer tick.
- Note that we deviate from the 3Com order by checking 10base2 before AUI.
- */
-enum xcvr_types {
- XCVR_10baseT = 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
- XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8,
-};
-
-static struct media_table {
- char *name;
- unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
- mask:8, /* The transceiver-present bit in Wn3_Config. */
- next:8; /* The media type to try next. */
- short wait; /* Time before we check media status. */
-} media_tbl[] = {
- { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
- { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
- { "undefined", 0, 0x80, XCVR_10baseT, 10000},
- { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
- { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
- { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
- { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
- { "undefined", 0, 0x01, XCVR_10baseT, 10000},
- { "Default", 0, 0xFF, XCVR_10baseT, 10000},
-};
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id corkscrew_isapnp_adapters[] = {
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
- ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051),
- (long) "3Com Fast EtherLink ISA" },
- { } /* terminate list */
-};
-
-MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters);
-
-static int nopnp;
-#endif /* __ISAPNP__ */
-
-static struct net_device *corkscrew_scan(int unit);
-static int corkscrew_setup(struct net_device *dev, int ioaddr,
- struct pnp_dev *idev, int card_number);
-static int corkscrew_open(struct net_device *dev);
-static void corkscrew_timer(unsigned long arg);
-static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static int corkscrew_rx(struct net_device *dev);
-static void corkscrew_timeout(struct net_device *dev);
-static int boomerang_rx(struct net_device *dev);
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id);
-static int corkscrew_close(struct net_device *dev);
-static void update_stats(int addr, struct net_device *dev);
-static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-
-/*
- Unfortunately maximizing the shared code between the integrated and
- module version of the driver results in a complicated set of initialization
- procedures.
- init_module() -- modules / tc59x_init() -- built-in
- The wrappers for corkscrew_scan()
- corkscrew_scan() The common routine that scans for PCI and EISA cards
- corkscrew_found_device() Allocate a device structure when we find a card.
- Different versions exist for modules and built-in.
- corkscrew_probe1() Fill in the device structure -- this is separated
- so that the modules code can put it in dev->init.
-*/
-/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
-/* Note: this is the only limit on the number of cards supported!! */
-static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1, };
-
-#ifdef MODULE
-static int debug = -1;
-
-module_param(debug, int, 0);
-module_param_array(options, int, NULL, 0);
-module_param(rx_copybreak, int, 0);
-module_param(max_interrupt_work, int, 0);
-MODULE_PARM_DESC(debug, "3c515 debug level (0-6)");
-MODULE_PARM_DESC(options, "3c515: Bits 0-2: media type, bit 3: full duplex, bit 4: bus mastering");
-MODULE_PARM_DESC(rx_copybreak, "3c515 copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "3c515 maximum events handled per interrupt");
-
-/* A list of all installed Vortex devices, for removing the driver module. */
-/* we will need locking (and refcounting) if we ever use it for more */
-static LIST_HEAD(root_corkscrew_dev);
-
-int init_module(void)
-{
- int found = 0;
- if (debug >= 0)
- corkscrew_debug = debug;
- if (corkscrew_debug)
- pr_debug("%s", version);
- while (corkscrew_scan(-1))
- found++;
- return found ? 0 : -ENODEV;
-}
-
-#else
-struct net_device *tc515_probe(int unit)
-{
- struct net_device *dev = corkscrew_scan(unit);
- static int printed;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- if (corkscrew_debug > 0 && !printed) {
- printed = 1;
- pr_debug("%s", version);
- }
-
- return dev;
-}
-#endif /* not MODULE */
-
-static int check_device(unsigned ioaddr)
-{
- int timer;
-
- if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515"))
- return 0;
- /* Check the resource configuration for a matching ioaddr. */
- if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) {
- release_region(ioaddr, CORKSCREW_TOTAL_SIZE);
- return 0;
- }
- /* Verify by reading the device ID from the EEPROM. */
- outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd);
- /* Pause for at least 162 us. for the read to take place. */
- for (timer = 4; timer >= 0; timer--) {
- udelay(162);
- if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
- break;
- }
- if (inw(ioaddr + Wn0EepromData) != 0x6d50) {
- release_region(ioaddr, CORKSCREW_TOTAL_SIZE);
- return 0;
- }
- return 1;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- struct corkscrew_private *vp = netdev_priv(dev);
- list_del_init(&vp->list);
- if (dev->dma)
- free_dma(dev->dma);
- outw(TotalReset, dev->base_addr + EL3_CMD);
- release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE);
- if (vp->dev)
- pnp_device_detach(to_pnp_dev(vp->dev));
-}
-
-static struct net_device *corkscrew_scan(int unit)
-{
- struct net_device *dev;
- static int cards_found = 0;
- static int ioaddr;
- int err;
-#ifdef __ISAPNP__
- short i;
- static int pnp_cards;
-#endif
-
- dev = alloc_etherdev(sizeof(struct corkscrew_private));
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
-#ifdef __ISAPNP__
- if(nopnp == 1)
- goto no_pnp;
- for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
- struct pnp_dev *idev = NULL;
- int irq;
- while((idev = pnp_find_dev(NULL,
- corkscrew_isapnp_adapters[i].vendor,
- corkscrew_isapnp_adapters[i].function,
- idev))) {
-
- if (pnp_device_attach(idev) < 0)
- continue;
- if (pnp_activate_dev(idev) < 0) {
- pr_warning("pnp activate failed (out of resources?)\n");
- pnp_device_detach(idev);
- continue;
- }
- if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) {
- pnp_device_detach(idev);
- continue;
- }
- ioaddr = pnp_port_start(idev, 0);
- irq = pnp_irq(idev, 0);
- if (!check_device(ioaddr)) {
- pnp_device_detach(idev);
- continue;
- }
- if(corkscrew_debug)
- pr_debug("ISAPNP reports %s at i/o 0x%x, irq %d\n",
- (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq);
- pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
- inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
- /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
- SET_NETDEV_DEV(dev, &idev->dev);
- pnp_cards++;
- err = corkscrew_setup(dev, ioaddr, idev, cards_found++);
- if (!err)
- return dev;
- cleanup_card(dev);
- }
- }
-no_pnp:
-#endif /* __ISAPNP__ */
-
- /* Check all locations on the ISA bus -- evil! */
- for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
- if (!check_device(ioaddr))
- continue;
-
- pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
- inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
- err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
- if (!err)
- return dev;
- cleanup_card(dev);
- }
- free_netdev(dev);
- return NULL;
-}
-
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = corkscrew_open,
- .ndo_stop = corkscrew_close,
- .ndo_start_xmit = corkscrew_start_xmit,
- .ndo_tx_timeout = corkscrew_timeout,
- .ndo_get_stats = corkscrew_get_stats,
- .ndo_set_rx_mode = set_rx_mode,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-
-static int corkscrew_setup(struct net_device *dev, int ioaddr,
- struct pnp_dev *idev, int card_number)
-{
- struct corkscrew_private *vp = netdev_priv(dev);
- unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
- int i;
- int irq;
-
-#ifdef __ISAPNP__
- if (idev) {
- irq = pnp_irq(idev, 0);
- vp->dev = &idev->dev;
- } else {
- irq = inw(ioaddr + 0x2002) & 15;
- }
-#else
- irq = inw(ioaddr + 0x2002) & 15;
-#endif
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->dma = inw(ioaddr + 0x2000) & 7;
- vp->product_name = "3c515";
- vp->options = dev->mem_start;
- vp->our_dev = dev;
-
- if (!vp->options) {
- if (card_number >= MAX_UNITS)
- vp->options = -1;
- else
- vp->options = options[card_number];
- }
-
- if (vp->options >= 0) {
- vp->media_override = vp->options & 7;
- if (vp->media_override == 2)
- vp->media_override = 0;
- vp->full_duplex = (vp->options & 8) ? 1 : 0;
- vp->bus_master = (vp->options & 16) ? 1 : 0;
- } else {
- vp->media_override = 7;
- vp->full_duplex = 0;
- vp->bus_master = 0;
- }
-#ifdef MODULE
- list_add(&vp->list, &root_corkscrew_dev);
-#endif
-
- pr_info("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
-
- spin_lock_init(&vp->lock);
-
- /* Read the station address from the EEPROM. */
- EL3WINDOW(0);
- for (i = 0; i < 0x18; i++) {
- __be16 *phys_addr = (__be16 *) dev->dev_addr;
- int timer;
- outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
- /* Pause for at least 162 us. for the read to take place. */
- for (timer = 4; timer >= 0; timer--) {
- udelay(162);
- if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
- break;
- }
- eeprom[i] = inw(ioaddr + Wn0EepromData);
- checksum ^= eeprom[i];
- if (i < 3)
- phys_addr[i] = htons(eeprom[i]);
- }
- checksum = (checksum ^ (checksum >> 8)) & 0xff;
- if (checksum != 0x00)
- pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
- pr_cont(" %pM", dev->dev_addr);
- if (eeprom[16] == 0x11c7) { /* Corkscrew */
- if (request_dma(dev->dma, "3c515")) {
- pr_cont(", DMA %d allocation failed", dev->dma);
- dev->dma = 0;
- } else
- pr_cont(", DMA %d", dev->dma);
- }
- pr_cont(", IRQ %d\n", dev->irq);
- /* Tell them about an invalid IRQ. */
- if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15))
- pr_warning(" *** Warning: this IRQ is unlikely to work! ***\n");
-
- {
- static const char * const ram_split[] = {
- "5:3", "3:1", "1:1", "3:5"
- };
- __u32 config;
- EL3WINDOW(3);
- vp->available_media = inw(ioaddr + Wn3_Options);
- config = inl(ioaddr + Wn3_Config);
- if (corkscrew_debug > 1)
- pr_info(" Internal config register is %4.4x, transceivers %#x.\n",
- config, inw(ioaddr + Wn3_Options));
- pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
- 8 << config & Ram_size,
- config & Ram_width ? "word" : "byte",
- ram_split[(config & Ram_split) >> Ram_split_shift],
- config & Autoselect ? "autoselect/" : "",
- media_tbl[(config & Xcvr) >> Xcvr_shift].name);
- vp->default_media = (config & Xcvr) >> Xcvr_shift;
- vp->autoselect = config & Autoselect ? 1 : 0;
- dev->if_port = vp->default_media;
- }
- if (vp->media_override != 7) {
- pr_info(" Media override to transceiver type %d (%s).\n",
- vp->media_override,
- media_tbl[vp->media_override].name);
- dev->if_port = vp->media_override;
- }
-
- vp->capabilities = eeprom[16];
- vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0;
- /* Rx is broken at 10mbps, so we always disable it. */
- /* vp->full_bus_master_rx = 0; */
- vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
-
- /* The 3c51x-specific entries in the device structure. */
- dev->netdev_ops = &netdev_ops;
- dev->watchdog_timeo = (400 * HZ) / 1000;
- dev->ethtool_ops = &netdev_ethtool_ops;
-
- return register_netdev(dev);
-}
-
-
-static int corkscrew_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- struct corkscrew_private *vp = netdev_priv(dev);
- __u32 config;
- int i;
-
- /* Before initializing select the active media port. */
- EL3WINDOW(3);
- if (vp->full_duplex)
- outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
- config = inl(ioaddr + Wn3_Config);
-
- if (vp->media_override != 7) {
- if (corkscrew_debug > 1)
- pr_info("%s: Media override to transceiver %d (%s).\n",
- dev->name, vp->media_override,
- media_tbl[vp->media_override].name);
- dev->if_port = vp->media_override;
- } else if (vp->autoselect) {
- /* Find first available media type, starting with 100baseTx. */
- dev->if_port = 4;
- while (!(vp->available_media & media_tbl[dev->if_port].mask))
- dev->if_port = media_tbl[dev->if_port].next;
-
- if (corkscrew_debug > 1)
- pr_debug("%s: Initial media type %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- init_timer(&vp->timer);
- vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
- vp->timer.data = (unsigned long) dev;
- vp->timer.function = corkscrew_timer; /* timer handler */
- add_timer(&vp->timer);
- } else
- dev->if_port = vp->default_media;
-
- config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
- outl(config, ioaddr + Wn3_Config);
-
- if (corkscrew_debug > 1) {
- pr_debug("%s: corkscrew_open() InternalConfig %8.8x.\n",
- dev->name, config);
- }
-
- outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0; i--)
- if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
-
- outw(RxReset, ioaddr + EL3_CMD);
- /* Wait a few ticks for the RxReset command to complete. */
- for (i = 20; i >= 0; i--)
- if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
-
- outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
- /* Use the now-standard shared IRQ implementation. */
- if (vp->capabilities == 0x11c7) {
- /* Corkscrew: Cannot share ISA resources. */
- if (dev->irq == 0 ||
- dev->dma == 0 ||
- request_irq(dev->irq, corkscrew_interrupt, 0,
- vp->product_name, dev))
- return -EAGAIN;
- enable_dma(dev->dma);
- set_dma_mode(dev->dma, DMA_MODE_CASCADE);
- } else if (request_irq(dev->irq, corkscrew_interrupt, IRQF_SHARED,
- vp->product_name, dev)) {
- return -EAGAIN;
- }
-
- if (corkscrew_debug > 1) {
- EL3WINDOW(4);
- pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n",
- dev->name, dev->irq, inw(ioaddr + Wn4_Media));
- }
-
- /* Set the station address and mask in window 2 each time opened. */
- EL3WINDOW(2);
- for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + i);
- for (; i < 12; i += 2)
- outw(0, ioaddr + i);
-
- if (dev->if_port == 3)
- /* Start the thinnet transceiver. We should really wait 50ms... */
- outw(StartCoax, ioaddr + EL3_CMD);
- EL3WINDOW(4);
- outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) |
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
-
- /* Switch to the stats window, and clear all stats by reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
- for (i = 0; i < 10; i++)
- inb(ioaddr + i);
- inw(ioaddr + 10);
- inw(ioaddr + 12);
- /* New: On the Vortex we must also clear the BadSSD counter. */
- EL3WINDOW(4);
- inb(ioaddr + 12);
- /* ..and on the Boomerang we enable the extra statistics bits. */
- outw(0x0040, ioaddr + Wn4_NetDiag);
-
- /* Switch to register set 7 for normal use. */
- EL3WINDOW(7);
-
- if (vp->full_bus_master_rx) { /* Boomerang bus master. */
- vp->cur_rx = vp->dirty_rx = 0;
- if (corkscrew_debug > 2)
- pr_debug("%s: Filling in the Rx ring.\n", dev->name);
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb;
- if (i < (RX_RING_SIZE - 1))
- vp->rx_ring[i].next =
- isa_virt_to_bus(&vp->rx_ring[i + 1]);
- else
- vp->rx_ring[i].next = 0;
- vp->rx_ring[i].status = 0; /* Clear complete bit. */
- vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000;
- skb = netdev_alloc_skb(dev, PKT_BUF_SZ);
- vp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break; /* Bad news! */
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
- }
- if (i != 0)
- vp->rx_ring[i - 1].next =
- isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
- outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
- }
- if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
- vp->cur_tx = vp->dirty_tx = 0;
- outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold); /* Room for a packet. */
- /* Clear the Tx ring. */
- for (i = 0; i < TX_RING_SIZE; i++)
- vp->tx_skbuff[i] = NULL;
- outl(0, ioaddr + DownListPtr);
- }
- /* Set receiver mode: presumably accept b-case and phys addr only. */
- set_rx_mode(dev);
- outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
- netif_start_queue(dev);
-
- outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
- /* Allow status bits to be seen. */
- outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull |
- (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
- (vp->full_bus_master_rx ? UpComplete : RxComplete) |
- (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD);
- /* Ack all pending events, and set active indicator mask. */
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
- outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
- | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
- ioaddr + EL3_CMD);
-
- return 0;
-}
-
-static void corkscrew_timer(unsigned long data)
-{
-#ifdef AUTOMEDIA
- struct net_device *dev = (struct net_device *) data;
- struct corkscrew_private *vp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
- int ok = 0;
-
- if (corkscrew_debug > 1)
- pr_debug("%s: Media selection timer tick happened, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- spin_lock_irqsave(&vp->lock, flags);
-
- {
- int old_window = inw(ioaddr + EL3_CMD) >> 13;
- int media_status;
- EL3WINDOW(4);
- media_status = inw(ioaddr + Wn4_Media);
- switch (dev->if_port) {
- case 0:
- case 4:
- case 5: /* 10baseT, 100baseTX, 100baseFX */
- if (media_status & Media_LnkBeat) {
- ok = 1;
- if (corkscrew_debug > 1)
- pr_debug("%s: Media %s has link beat, %x.\n",
- dev->name,
- media_tbl[dev->if_port].name,
- media_status);
- } else if (corkscrew_debug > 1)
- pr_debug("%s: Media %s is has no link beat, %x.\n",
- dev->name,
- media_tbl[dev->if_port].name,
- media_status);
-
- break;
- default: /* Other media types handled by Tx timeouts. */
- if (corkscrew_debug > 1)
- pr_debug("%s: Media %s is has no indication, %x.\n",
- dev->name,
- media_tbl[dev->if_port].name,
- media_status);
- ok = 1;
- }
- if (!ok) {
- __u32 config;
-
- do {
- dev->if_port =
- media_tbl[dev->if_port].next;
- }
- while (!(vp->available_media & media_tbl[dev->if_port].mask));
-
- if (dev->if_port == 8) { /* Go back to default. */
- dev->if_port = vp->default_media;
- if (corkscrew_debug > 1)
- pr_debug("%s: Media selection failing, using default %s port.\n",
- dev->name,
- media_tbl[dev->if_port].name);
- } else {
- if (corkscrew_debug > 1)
- pr_debug("%s: Media selection failed, now trying %s port.\n",
- dev->name,
- media_tbl[dev->if_port].name);
- vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
- add_timer(&vp->timer);
- }
- outw((media_status & ~(Media_10TP | Media_SQE)) |
- media_tbl[dev->if_port].media_bits,
- ioaddr + Wn4_Media);
-
- EL3WINDOW(3);
- config = inl(ioaddr + Wn3_Config);
- config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
- outl(config, ioaddr + Wn3_Config);
-
- outw(dev->if_port == 3 ? StartCoax : StopCoax,
- ioaddr + EL3_CMD);
- }
- EL3WINDOW(old_window);
- }
-
- spin_unlock_irqrestore(&vp->lock, flags);
- if (corkscrew_debug > 1)
- pr_debug("%s: Media selection timer finished, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
-#endif /* AUTOMEDIA */
-}
-
-static void corkscrew_timeout(struct net_device *dev)
-{
- int i;
- struct corkscrew_private *vp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- pr_warning("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, inb(ioaddr + TxStatus),
- inw(ioaddr + EL3_STATUS));
- /* Slight code bloat to be user friendly. */
- if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
- pr_warning("%s: Transmitter encountered 16 collisions --"
- " network cable problem?\n", dev->name);
-#ifndef final_version
- pr_debug(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
- vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx,
- vp->cur_tx);
- pr_debug(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
- &vp->tx_ring[0]);
- for (i = 0; i < TX_RING_SIZE; i++) {
- pr_debug(" %d: %p length %8.8x status %8.8x\n", i,
- &vp->tx_ring[i],
- vp->tx_ring[i].length, vp->tx_ring[i].status);
- }
-#endif
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0; i--)
- if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies; /* prevent tx timeout */
- dev->stats.tx_errors++;
- dev->stats.tx_dropped++;
- netif_wake_queue(dev);
-}
-
-static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct corkscrew_private *vp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* Block a timer-based transmit from overlapping. */
-
- netif_stop_queue(dev);
-
- if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */
- /* Calculate the next Tx descriptor entry. */
- int entry = vp->cur_tx % TX_RING_SIZE;
- struct boom_tx_desc *prev_entry;
- unsigned long flags;
- int i;
-
- if (vp->tx_full) /* No room to transmit with */
- return NETDEV_TX_BUSY;
- if (vp->cur_tx != 0)
- prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE];
- else
- prev_entry = NULL;
- if (corkscrew_debug > 3)
- pr_debug("%s: Trying to send a packet, Tx index %d.\n",
- dev->name, vp->cur_tx);
- /* vp->tx_full = 1; */
- vp->tx_skbuff[entry] = skb;
- vp->tx_ring[entry].next = 0;
- vp->tx_ring[entry].addr = isa_virt_to_bus(skb->data);
- vp->tx_ring[entry].length = skb->len | 0x80000000;
- vp->tx_ring[entry].status = skb->len | 0x80000000;
-
- spin_lock_irqsave(&vp->lock, flags);
- outw(DownStall, ioaddr + EL3_CMD);
- /* Wait for the stall to complete. */
- for (i = 20; i >= 0; i--)
- if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
- break;
- if (prev_entry)
- prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]);
- if (inl(ioaddr + DownListPtr) == 0) {
- outl(isa_virt_to_bus(&vp->tx_ring[entry]),
- ioaddr + DownListPtr);
- queued_packet++;
- }
- outw(DownUnstall, ioaddr + EL3_CMD);
- spin_unlock_irqrestore(&vp->lock, flags);
-
- vp->cur_tx++;
- if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
- vp->tx_full = 1;
- else { /* Clear previous interrupt enable. */
- if (prev_entry)
- prev_entry->status &= ~0x80000000;
- netif_wake_queue(dev);
- }
- return NETDEV_TX_OK;
- }
- /* Put out the doubleword header... */
- outl(skb->len, ioaddr + TX_FIFO);
- dev->stats.tx_bytes += skb->len;
-#ifdef VORTEX_BUS_MASTER
- if (vp->bus_master) {
- /* Set the bus-master controller to transfer the packet. */
- outl((int) (skb->data), ioaddr + Wn7_MasterAddr);
- outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
- vp->tx_skb = skb;
- outw(StartDMADown, ioaddr + EL3_CMD);
- /* queue will be woken at the DMADone interrupt. */
- } else {
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb(skb);
- if (inw(ioaddr + TxFree) > 1536) {
- netif_wake_queue(dev);
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536 >> 2),
- ioaddr + EL3_CMD);
- }
-#else
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb(skb);
- if (inw(ioaddr + TxFree) > 1536) {
- netif_wake_queue(dev);
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD);
-#endif /* bus master */
-
-
- /* Clear the Tx status stack. */
- {
- short tx_status;
- int i = 4;
-
- while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
- if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
- if (corkscrew_debug > 2)
- pr_debug("%s: Tx error, status %2.2x.\n",
- dev->name, tx_status);
- if (tx_status & 0x04)
- dev->stats.tx_fifo_errors++;
- if (tx_status & 0x38)
- dev->stats.tx_aborted_errors++;
- if (tx_status & 0x30) {
- int j;
- outw(TxReset, ioaddr + EL3_CMD);
- for (j = 20; j >= 0; j--)
- if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- }
- outw(TxEnable, ioaddr + EL3_CMD);
- }
- outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
- }
- }
- return NETDEV_TX_OK;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
-{
- /* Use the now-standard shared IRQ implementation. */
- struct net_device *dev = dev_id;
- struct corkscrew_private *lp = netdev_priv(dev);
- int ioaddr, status;
- int latency;
- int i = max_interrupt_work;
-
- ioaddr = dev->base_addr;
- latency = inb(ioaddr + Timer);
-
- spin_lock(&lp->lock);
-
- status = inw(ioaddr + EL3_STATUS);
-
- if (corkscrew_debug > 4)
- pr_debug("%s: interrupt, status %4.4x, timer %d.\n",
- dev->name, status, latency);
- if ((status & 0xE000) != 0xE000) {
- static int donedidthis;
- /* Some interrupt controllers store a bogus interrupt from boot-time.
- Ignore a single early interrupt, but don't hang the machine for
- other interrupt problems. */
- if (donedidthis++ > 100) {
- pr_err("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
- dev->name, status, netif_running(dev));
- free_irq(dev->irq, dev);
- dev->irq = -1;
- }
- }
-
- do {
- if (corkscrew_debug > 5)
- pr_debug("%s: In interrupt loop, status %4.4x.\n",
- dev->name, status);
- if (status & RxComplete)
- corkscrew_rx(dev);
-
- if (status & TxAvailable) {
- if (corkscrew_debug > 5)
- pr_debug(" TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
- }
- if (status & DownComplete) {
- unsigned int dirty_tx = lp->dirty_tx;
-
- while (lp->cur_tx - dirty_tx > 0) {
- int entry = dirty_tx % TX_RING_SIZE;
- if (inl(ioaddr + DownListPtr) == isa_virt_to_bus(&lp->tx_ring[entry]))
- break; /* It still hasn't been processed. */
- if (lp->tx_skbuff[entry]) {
- dev_kfree_skb_irq(lp->tx_skbuff[entry]);
- lp->tx_skbuff[entry] = NULL;
- }
- dirty_tx++;
- }
- lp->dirty_tx = dirty_tx;
- outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
- if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
- lp->tx_full = 0;
- netif_wake_queue(dev);
- }
- }
-#ifdef VORTEX_BUS_MASTER
- if (status & DMADone) {
- outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- dev_kfree_skb_irq(lp->tx_skb); /* Release the transferred buffer */
- netif_wake_queue(dev);
- }
-#endif
- if (status & UpComplete) {
- boomerang_rx(dev);
- outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
- }
- if (status & (AdapterFailure | RxEarly | StatsFull)) {
- /* Handle all uncommon interrupts at once. */
- if (status & RxEarly) { /* Rx early is unused. */
- corkscrew_rx(dev);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
- if (status & StatsFull) { /* Empty statistics. */
- static int DoneDidThat;
- if (corkscrew_debug > 4)
- pr_debug("%s: Updating stats.\n", dev->name);
- update_stats(ioaddr, dev);
- /* DEBUG HACK: Disable statistics as an interrupt source. */
- /* This occurs when we have the wrong media type! */
- if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) {
- int win, reg;
- pr_notice("%s: Updating stats failed, disabling stats as an interrupt source.\n",
- dev->name);
- for (win = 0; win < 8; win++) {
- EL3WINDOW(win);
- pr_notice("Vortex window %d:", win);
- for (reg = 0; reg < 16; reg++)
- pr_cont(" %2.2x", inb(ioaddr + reg));
- pr_cont("\n");
- }
- EL3WINDOW(7);
- outw(SetIntrEnb | TxAvailable |
- RxComplete | AdapterFailure |
- UpComplete | DownComplete |
- TxComplete, ioaddr + EL3_CMD);
- DoneDidThat++;
- }
- }
- if (status & AdapterFailure) {
- /* Adapter failure requires Rx reset and reinit. */
- outw(RxReset, ioaddr + EL3_CMD);
- /* Set the Rx filter to the current state. */
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- outw(AckIntr | AdapterFailure,
- ioaddr + EL3_CMD);
- }
- }
-
- if (--i < 0) {
- pr_err("%s: Too much work in interrupt, status %4.4x. Disabling functions (%4.4x).\n",
- dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
- /* Disable all pending interrupts. */
- outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
- outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
- break;
- }
- /* Acknowledge the IRQ. */
- outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-
- } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-
- spin_unlock(&lp->lock);
-
- if (corkscrew_debug > 4)
- pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
- return IRQ_HANDLED;
-}
-
-static int corkscrew_rx(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- int i;
- short rx_status;
-
- if (corkscrew_debug > 5)
- pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
- inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
- while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
- if (rx_status & 0x4000) { /* Error, update stats. */
- unsigned char rx_error = inb(ioaddr + RxErrors);
- if (corkscrew_debug > 2)
- pr_debug(" Rx error: status %2.2x.\n",
- rx_error);
- dev->stats.rx_errors++;
- if (rx_error & 0x01)
- dev->stats.rx_over_errors++;
- if (rx_error & 0x02)
- dev->stats.rx_length_errors++;
- if (rx_error & 0x04)
- dev->stats.rx_frame_errors++;
- if (rx_error & 0x08)
- dev->stats.rx_crc_errors++;
- if (rx_error & 0x10)
- dev->stats.rx_length_errors++;
- } else {
- /* The packet length: up to 4.5K!. */
- short pkt_len = rx_status & 0x1fff;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 5 + 2);
- if (corkscrew_debug > 4)
- pr_debug("Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
- if (skb != NULL) {
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- /* 'skb_put()' points to the start of sk_buff data area. */
- insl(ioaddr + RX_FIFO,
- skb_put(skb, pkt_len),
- (pkt_len + 3) >> 2);
- outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- /* Wait a limited time to go to next packet. */
- for (i = 200; i >= 0; i--)
- if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- continue;
- } else if (corkscrew_debug)
- pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
- }
- outw(RxDiscard, ioaddr + EL3_CMD);
- dev->stats.rx_dropped++;
- /* Wait a limited time to skip this packet. */
- for (i = 200; i >= 0; i--)
- if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- }
- return 0;
-}
-
-static int boomerang_rx(struct net_device *dev)
-{
- struct corkscrew_private *vp = netdev_priv(dev);
- int entry = vp->cur_rx % RX_RING_SIZE;
- int ioaddr = dev->base_addr;
- int rx_status;
-
- if (corkscrew_debug > 5)
- pr_debug(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
- inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
- while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
- if (rx_status & RxDError) { /* Error, update stats. */
- unsigned char rx_error = rx_status >> 16;
- if (corkscrew_debug > 2)
- pr_debug(" Rx error: status %2.2x.\n",
- rx_error);
- dev->stats.rx_errors++;
- if (rx_error & 0x01)
- dev->stats.rx_over_errors++;
- if (rx_error & 0x02)
- dev->stats.rx_length_errors++;
- if (rx_error & 0x04)
- dev->stats.rx_frame_errors++;
- if (rx_error & 0x08)
- dev->stats.rx_crc_errors++;
- if (rx_error & 0x10)
- dev->stats.rx_length_errors++;
- } else {
- /* The packet length: up to 4.5K!. */
- short pkt_len = rx_status & 0x1fff;
- struct sk_buff *skb;
-
- dev->stats.rx_bytes += pkt_len;
- if (corkscrew_debug > 4)
- pr_debug("Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
-
- /* Check if the packet is long enough to just accept without
- copying to a properly sized skbuff. */
- if (pkt_len < rx_copybreak &&
- (skb = netdev_alloc_skb(dev, pkt_len + 4)) != NULL) {
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- /* 'skb_put()' points to the start of sk_buff data area. */
- memcpy(skb_put(skb, pkt_len),
- isa_bus_to_virt(vp->rx_ring[entry].
- addr), pkt_len);
- rx_copy++;
- } else {
- void *temp;
- /* Pass up the skbuff already on the Rx ring. */
- skb = vp->rx_skbuff[entry];
- vp->rx_skbuff[entry] = NULL;
- temp = skb_put(skb, pkt_len);
- /* Remove this checking code for final release. */
- if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp)
- pr_warning("%s: Warning -- the skbuff addresses do not match"
- " in boomerang_rx: %p vs. %p / %p.\n",
- dev->name,
- isa_bus_to_virt(vp->
- rx_ring[entry].
- addr), skb->head,
- temp);
- rx_nocopy++;
- }
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- }
- entry = (++vp->cur_rx) % RX_RING_SIZE;
- }
- /* Refill the Rx ring buffers. */
- for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {
- struct sk_buff *skb;
- entry = vp->dirty_rx % RX_RING_SIZE;
- if (vp->rx_skbuff[entry] == NULL) {
- skb = netdev_alloc_skb(dev, PKT_BUF_SZ);
- if (skb == NULL)
- break; /* Bad news! */
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data);
- vp->rx_skbuff[entry] = skb;
- }
- vp->rx_ring[entry].status = 0; /* Clear complete bit. */
- }
- return 0;
-}
-
-static int corkscrew_close(struct net_device *dev)
-{
- struct corkscrew_private *vp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int i;
-
- netif_stop_queue(dev);
-
- if (corkscrew_debug > 1) {
- pr_debug("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n",
- dev->name, inw(ioaddr + EL3_STATUS),
- inb(ioaddr + TxStatus));
- pr_debug("%s: corkscrew close stats: rx_nocopy %d rx_copy %d tx_queued %d.\n",
- dev->name, rx_nocopy, rx_copy, queued_packet);
- }
-
- del_timer(&vp->timer);
-
- /* Turn off statistics ASAP. We update lp->stats below. */
- outw(StatsDisable, ioaddr + EL3_CMD);
-
- /* Disable the receiver and transmitter. */
- outw(RxDisable, ioaddr + EL3_CMD);
- outw(TxDisable, ioaddr + EL3_CMD);
-
- if (dev->if_port == XCVR_10base2)
- /* Turn off thinnet power. Green! */
- outw(StopCoax, ioaddr + EL3_CMD);
-
- free_irq(dev->irq, dev);
-
- outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
- update_stats(ioaddr, dev);
- if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
- outl(0, ioaddr + UpListPtr);
- for (i = 0; i < RX_RING_SIZE; i++)
- if (vp->rx_skbuff[i]) {
- dev_kfree_skb(vp->rx_skbuff[i]);
- vp->rx_skbuff[i] = NULL;
- }
- }
- if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
- outl(0, ioaddr + DownListPtr);
- for (i = 0; i < TX_RING_SIZE; i++)
- if (vp->tx_skbuff[i]) {
- dev_kfree_skb(vp->tx_skbuff[i]);
- vp->tx_skbuff[i] = NULL;
- }
- }
-
- return 0;
-}
-
-static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
-{
- struct corkscrew_private *vp = netdev_priv(dev);
- unsigned long flags;
-
- if (netif_running(dev)) {
- spin_lock_irqsave(&vp->lock, flags);
- update_stats(dev->base_addr, dev);
- spin_unlock_irqrestore(&vp->lock, flags);
- }
- return &dev->stats;
-}
-
-/* Update statistics.
- Unlike with the EL3 we need not worry about interrupts changing
- the window setting from underneath us, but we must still guard
- against a race condition with a StatsUpdate interrupt updating the
- table. This is done by checking that the ASM (!) code generated uses
- atomic updates with '+='.
- */
-static void update_stats(int ioaddr, struct net_device *dev)
-{
- /* Unlike the 3c5x9 we need not turn off stats updates while reading. */
- /* Switch to the stats window, and read everything. */
- EL3WINDOW(6);
- dev->stats.tx_carrier_errors += inb(ioaddr + 0);
- dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
- /* Multiple collisions. */ inb(ioaddr + 2);
- dev->stats.collisions += inb(ioaddr + 3);
- dev->stats.tx_window_errors += inb(ioaddr + 4);
- dev->stats.rx_fifo_errors += inb(ioaddr + 5);
- dev->stats.tx_packets += inb(ioaddr + 6);
- dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
- /* Rx packets */ inb(ioaddr + 7);
- /* Must read to clear */
- /* Tx deferrals */ inb(ioaddr + 8);
- /* Don't bother with register 9, an extension of registers 6&7.
- If we do use the 6&7 values the atomic update assumption above
- is invalid. */
- inw(ioaddr + 10); /* Total Rx and Tx octets. */
- inw(ioaddr + 12);
- /* New: On the Vortex we must also clear the BadSSD counter. */
- EL3WINDOW(4);
- inb(ioaddr + 12);
-
- /* We change back to window 7 (not 1) with the Vortex. */
- EL3WINDOW(7);
-}
-
-/* This new version of set_rx_mode() supports v1.4 kernels.
- The Vortex chip has no documented multicast filter, so the only
- multicast setting is to receive all multicast frames. At least
- the chip has a very clean way to set the mode, unlike many others. */
-static void set_rx_mode(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- short new_mode;
-
- if (dev->flags & IFF_PROMISC) {
- if (corkscrew_debug > 3)
- pr_debug("%s: Setting promiscuous mode.\n",
- dev->name);
- new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm;
- } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
- new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast;
- } else
- new_mode = SetRxFilter | RxStation | RxBroadcast;
-
- outw(new_mode, ioaddr + EL3_CMD);
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return corkscrew_debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- corkscrew_debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- while (!list_empty(&root_corkscrew_dev)) {
- struct net_device *dev;
- struct corkscrew_private *vp;
-
- vp = list_entry(root_corkscrew_dev.next,
- struct corkscrew_private, list);
- dev = vp->our_dev;
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
-}
-#endif /* MODULE */
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c574_cs.c b/ANDROID_3.4.5/drivers/net/ethernet/3com/3c574_cs.c
deleted file mode 100644
index 66df9363..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c574_cs.c
+++ /dev/null
@@ -1,1180 +0,0 @@
-/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner".
-
- Written 1993-1998 by
- Donald Becker, becker@scyld.com, (driver core) and
- David Hinds, dahinds@users.sourceforge.net (from his PC card code).
- Locking fixes (C) Copyright 2003 Red Hat Inc
-
- This software may be used and distributed according to the terms of
- the GNU General Public License, incorporated herein by reference.
-
- This driver derives from Donald Becker's 3c509 core, which has the
- following copyright:
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency.
-
-
-*/
-
-/*
- Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the 3Com 3c574 PC card Fast Ethernet
-Adapter.
-
-II. Board-specific settings
-
-None -- PC cards are autoconfigured.
-
-III. Driver operation
-
-The 3c574 uses a Boomerang-style interface, without the bus-master capability.
-See the Boomerang driver and documentation for most details.
-
-IV. Notes and chip documentation.
-
-Two added registers are used to enhance PIO performance, RunnerRdCtrl and
-RunnerWrCtrl. These are 11 bit down-counters that are preloaded with the
-count of word (16 bits) reads or writes the driver is about to do to the Rx
-or Tx FIFO. The chip is then able to hide the internal-PCI-bus to PC-card
-translation latency by buffering the I/O operations with an 8 word FIFO.
-Note: No other chip accesses are permitted when this buffer is used.
-
-A second enhancement is that both attribute and common memory space
-0x0800-0x0fff can translated to the PIO FIFO. Thus memory operations (faster
-with *some* PCcard bridges) may be used instead of I/O operations.
-This is enabled by setting the 0x10 bit in the PCMCIA LAN COR.
-
-Some slow PC card bridges work better if they never see a WAIT signal.
-This is configured by setting the 0x20 bit in the PCMCIA LAN COR.
-Only do this after testing that it is reliable and improves performance.
-
-The upper five bits of RunnerRdCtrl are used to window into PCcard
-configuration space registers. Window 0 is the regular Boomerang/Odie
-register set, 1-5 are various PC card control registers, and 16-31 are
-the (reversed!) CIS table.
-
-A final note: writing the InternalConfig register in window 3 with an
-invalid ramWidth is Very Bad.
-
-V. References
-
-http://www.scyld.com/expert/NWay.html
-http://www.national.com/opf/DP/DP83840A.html
-
-Thanks to Terry Murphy of 3Com for providing development information for
-earlier 3Com products.
-
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/bitops.h>
-#include <linux/mii.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("3Com 3c574 series PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-INT_MODULE_PARM(max_interrupt_work, 32);
-
-/* Force full duplex modes? */
-INT_MODULE_PARM(full_duplex, 0);
-
-/* Autodetect link polarity reversal? */
-INT_MODULE_PARM(auto_polarity, 1);
-
-
-/*====================================================================*/
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT ((800*HZ)/1000)
-
-/* To minimize the size of the driver source and make the driver more
- readable not all constants are symbolically defined.
- You'll need the manual if you want to understand driver details anyway. */
-/* Offsets from base I/O address. */
-#define EL3_DATA 0x00
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-
-/* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable. */
-enum el3_cmds {
- TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
- RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
- TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
- FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
- SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
- SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
- StatsDisable = 22<<11, StopCoax = 23<<11,
-};
-
-enum elxl_status {
- IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
- TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
- IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 };
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
- RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
-};
-
-enum Window0 {
- Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */
- IntrStatus=0x0E, /* Valid in all windows. */
-};
-/* These assumes the larger EEPROM. */
-enum Win0_EEPROM_cmds {
- EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300,
- EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
- EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
-};
-
-/* Register window 1 offsets, the window used in normal operation.
- On the "Odie" this window is always mapped at offsets 0x10-0x1f.
- Except for TxFree, which is overlapped by RunnerWrCtrl. */
-enum Window1 {
- TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
- RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B,
- TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */
- RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c,
-};
-
-enum Window3 { /* Window 3: MAC/config bits. */
- Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
-};
-enum wn3_config {
- Ram_size = 7,
- Ram_width = 8,
- Ram_speed = 0x30,
- Rom_size = 0xc0,
- Ram_split_shift = 16,
- Ram_split = 3 << Ram_split_shift,
- Xcvr_shift = 20,
- Xcvr = 7 << Xcvr_shift,
- Autoselect = 0x1000000,
-};
-
-enum Window4 { /* Window 4: Xcvr/media bits. */
- Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
-};
-
-#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
-
-struct el3_private {
- struct pcmcia_device *p_dev;
- u16 advertising, partner; /* NWay media advertisement */
- unsigned char phys; /* MII device address */
- unsigned int autoselect:1, default_media:3; /* Read from the EEPROM/Wn3_Config. */
- /* for transceiver monitoring */
- struct timer_list media;
- unsigned short media_status;
- unsigned short fast_poll;
- unsigned long last_irq;
- spinlock_t window_lock; /* Guards the Window selection */
-};
-
-/* Set iff a MII transceiver on any interface requires mdio preamble.
- This only set with the original DP83840 on older 3c905 boards, so the extra
- code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required = 0;
-
-/* Index of functions. */
-
-static int tc574_config(struct pcmcia_device *link);
-static void tc574_release(struct pcmcia_device *link);
-
-static void mdio_sync(unsigned int ioaddr, int bits);
-static int mdio_read(unsigned int ioaddr, int phy_id, int location);
-static void mdio_write(unsigned int ioaddr, int phy_id, int location,
- int value);
-static unsigned short read_eeprom(unsigned int ioaddr, int index);
-static void tc574_wait_for_completion(struct net_device *dev, int cmd);
-
-static void tc574_reset(struct net_device *dev);
-static void media_check(unsigned long arg);
-static int el3_open(struct net_device *dev);
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id);
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *el3_get_stats(struct net_device *dev);
-static int el3_rx(struct net_device *dev, int worklimit);
-static int el3_close(struct net_device *dev);
-static void el3_tx_timeout(struct net_device *dev);
-static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void set_rx_mode(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-static void tc574_detach(struct pcmcia_device *p_dev);
-
-/*
- tc574_attach() creates an "instance" of the driver, allocating
- local data structures for one device. The device is registered
- with Card Services.
-*/
-static const struct net_device_ops el3_netdev_ops = {
- .ndo_open = el3_open,
- .ndo_stop = el3_close,
- .ndo_start_xmit = el3_start_xmit,
- .ndo_tx_timeout = el3_tx_timeout,
- .ndo_get_stats = el3_get_stats,
- .ndo_do_ioctl = el3_ioctl,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int tc574_probe(struct pcmcia_device *link)
-{
- struct el3_private *lp;
- struct net_device *dev;
-
- dev_dbg(&link->dev, "3c574_attach()\n");
-
- /* Create the PC card device object. */
- dev = alloc_etherdev(sizeof(struct el3_private));
- if (!dev)
- return -ENOMEM;
- lp = netdev_priv(dev);
- link->priv = dev;
- lp->p_dev = link;
-
- spin_lock_init(&lp->window_lock);
- link->resource[0]->end = 32;
- link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
- link->config_flags |= CONF_ENABLE_IRQ;
- link->config_index = 1;
-
- dev->netdev_ops = &el3_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- return tc574_config(link);
-}
-
-static void tc574_detach(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- dev_dbg(&link->dev, "3c574_detach()\n");
-
- unregister_netdev(dev);
-
- tc574_release(link);
-
- free_netdev(dev);
-} /* tc574_detach */
-
-static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-
-static int tc574_config(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
- struct el3_private *lp = netdev_priv(dev);
- int ret, i, j;
- unsigned int ioaddr;
- __be16 *phys_addr;
- char *cardname;
- __u32 config;
- u8 *buf;
- size_t len;
-
- phys_addr = (__be16 *)dev->dev_addr;
-
- dev_dbg(&link->dev, "3c574_config()\n");
-
- link->io_lines = 16;
-
- for (i = j = 0; j < 0x400; j += 0x20) {
- link->resource[0]->start = j ^ 0x300;
- i = pcmcia_request_io(link);
- if (i == 0)
- break;
- }
- if (i != 0)
- goto failed;
-
- ret = pcmcia_request_irq(link, el3_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
-
- ioaddr = dev->base_addr;
-
- /* The 3c574 normally uses an EEPROM for configuration info, including
- the hardware address. The future products may include a modem chip
- and put the address in the CIS. */
-
- len = pcmcia_get_tuple(link, 0x88, &buf);
- if (buf && len >= 6) {
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(le16_to_cpu(buf[i * 2]));
- kfree(buf);
- } else {
- kfree(buf); /* 0 < len < 6 */
- EL3WINDOW(0);
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
- if (phys_addr[0] == htons(0x6060)) {
- pr_notice("IO port conflict at 0x%03lx-0x%03lx\n",
- dev->base_addr, dev->base_addr+15);
- goto failed;
- }
- }
- if (link->prod_id[1])
- cardname = link->prod_id[1];
- else
- cardname = "3Com 3c574";
-
- {
- u_char mcr;
- outw(2<<11, ioaddr + RunnerRdCtrl);
- mcr = inb(ioaddr + 2);
- outw(0<<11, ioaddr + RunnerRdCtrl);
- pr_info(" ASIC rev %d,", mcr>>3);
- EL3WINDOW(3);
- config = inl(ioaddr + Wn3_Config);
- lp->default_media = (config & Xcvr) >> Xcvr_shift;
- lp->autoselect = config & Autoselect ? 1 : 0;
- }
-
- init_timer(&lp->media);
-
- {
- int phy;
-
- /* Roadrunner only: Turn on the MII transceiver */
- outw(0x8040, ioaddr + Wn3_Options);
- mdelay(1);
- outw(0xc040, ioaddr + Wn3_Options);
- tc574_wait_for_completion(dev, TxReset);
- tc574_wait_for_completion(dev, RxReset);
- mdelay(1);
- outw(0x8040, ioaddr + Wn3_Options);
-
- EL3WINDOW(4);
- for (phy = 1; phy <= 32; phy++) {
- int mii_status;
- mdio_sync(ioaddr, 32);
- mii_status = mdio_read(ioaddr, phy & 0x1f, 1);
- if (mii_status != 0xffff) {
- lp->phys = phy & 0x1f;
- dev_dbg(&link->dev, " MII transceiver at "
- "index %d, status %x.\n",
- phy, mii_status);
- if ((mii_status & 0x0040) == 0)
- mii_preamble_required = 1;
- break;
- }
- }
- if (phy > 32) {
- pr_notice(" No MII transceivers found!\n");
- goto failed;
- }
- i = mdio_read(ioaddr, lp->phys, 16) | 0x40;
- mdio_write(ioaddr, lp->phys, 16, i);
- lp->advertising = mdio_read(ioaddr, lp->phys, 4);
- if (full_duplex) {
- /* Only advertise the FD media types. */
- lp->advertising &= ~0x02a0;
- mdio_write(ioaddr, lp->phys, 4, lp->advertising);
- }
- }
-
- SET_NETDEV_DEV(dev, &link->dev);
-
- if (register_netdev(dev) != 0) {
- pr_notice("register_netdev() failed\n");
- goto failed;
- }
-
- netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n",
- cardname, dev->base_addr, dev->irq, dev->dev_addr);
- netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n",
- 8 << config & Ram_size,
- ram_split[(config & Ram_split) >> Ram_split_shift],
- config & Autoselect ? "autoselect " : "");
-
- return 0;
-
-failed:
- tc574_release(link);
- return -ENODEV;
-
-} /* tc574_config */
-
-static void tc574_release(struct pcmcia_device *link)
-{
- pcmcia_disable_device(link);
-}
-
-static int tc574_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open)
- netif_device_detach(dev);
-
- return 0;
-}
-
-static int tc574_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open) {
- tc574_reset(dev);
- netif_device_attach(dev);
- }
-
- return 0;
-}
-
-static void dump_status(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- EL3WINDOW(1);
- netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x, tx free %04x\n",
- inw(ioaddr+EL3_STATUS),
- inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
- inw(ioaddr+TxFree));
- EL3WINDOW(4);
- netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
- inw(ioaddr+0x04), inw(ioaddr+0x06),
- inw(ioaddr+0x08), inw(ioaddr+0x0a));
- EL3WINDOW(1);
-}
-
-/*
- Use this for commands that may take time to finish
-*/
-static void tc574_wait_for_completion(struct net_device *dev, int cmd)
-{
- int i = 1500;
- outw(cmd, dev->base_addr + EL3_CMD);
- while (--i > 0)
- if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
- if (i == 0)
- netdev_notice(dev, "command 0x%04x did not complete!\n", cmd);
-}
-
-/* Read a word from the EEPROM using the regular EEPROM access register.
- Assume that we are in register window zero.
- */
-static unsigned short read_eeprom(unsigned int ioaddr, int index)
-{
- int timer;
- outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
- /* Pause for at least 162 usec for the read to take place. */
- for (timer = 1620; timer >= 0; timer--) {
- if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
- break;
- }
- return inw(ioaddr + Wn0EepromData);
-}
-
-/* MII transceiver control section.
- Read and write the MII registers using software-generated serial
- MDIO protocol. See the MII specifications or DP83840A data sheet
- for details.
- The maxium data clock rate is 2.5 Mhz. The timing is easily met by the
- slow PC card interface. */
-
-#define MDIO_SHIFT_CLK 0x01
-#define MDIO_DIR_WRITE 0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ 0x02
-#define MDIO_ENB_IN 0x00
-
-/* Generate the preamble required for initial synchronization and
- a few older transceivers. */
-static void mdio_sync(unsigned int ioaddr, int bits)
-{
- unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
- /* Establish sync by sending at least 32 logic ones. */
- while (-- bits >= 0) {
- outw(MDIO_DATA_WRITE1, mdio_addr);
- outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
- }
-}
-
-static int mdio_read(unsigned int ioaddr, int phy_id, int location)
-{
- int i;
- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- unsigned int retval = 0;
- unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
- if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
-
- /* Shift the read command bits out. */
- for (i = 14; i >= 0; i--) {
- int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outw(dataval, mdio_addr);
- outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
- }
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- outw(MDIO_ENB_IN, mdio_addr);
- retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- }
- return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(unsigned int ioaddr, int phy_id, int location, int value)
-{
- int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
- int i;
-
- if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
-
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outw(dataval, mdio_addr);
- outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
- }
- /* Leave the interface idle. */
- for (i = 1; i >= 0; i--) {
- outw(MDIO_ENB_IN, mdio_addr);
- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- }
-}
-
-/* Reset and restore all of the 3c574 registers. */
-static void tc574_reset(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- int i;
- unsigned int ioaddr = dev->base_addr;
- unsigned long flags;
-
- tc574_wait_for_completion(dev, TotalReset|0x10);
-
- spin_lock_irqsave(&lp->window_lock, flags);
- /* Clear any transactions in progress. */
- outw(0, ioaddr + RunnerWrCtrl);
- outw(0, ioaddr + RunnerRdCtrl);
-
- /* Set the station address and mask. */
- EL3WINDOW(2);
- for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + i);
- for (; i < 12; i+=2)
- outw(0, ioaddr + i);
-
- /* Reset config options */
- EL3WINDOW(3);
- outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
- outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b,
- ioaddr + Wn3_Config);
- /* Roadrunner only: Turn on the MII transceiver. */
- outw(0x8040, ioaddr + Wn3_Options);
- mdelay(1);
- outw(0xc040, ioaddr + Wn3_Options);
- EL3WINDOW(1);
- spin_unlock_irqrestore(&lp->window_lock, flags);
-
- tc574_wait_for_completion(dev, TxReset);
- tc574_wait_for_completion(dev, RxReset);
- mdelay(1);
- spin_lock_irqsave(&lp->window_lock, flags);
- EL3WINDOW(3);
- outw(0x8040, ioaddr + Wn3_Options);
-
- /* Switch to the stats window, and clear all stats by reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
- for (i = 0; i < 10; i++)
- inb(ioaddr + i);
- inw(ioaddr + 10);
- inw(ioaddr + 12);
- EL3WINDOW(4);
- inb(ioaddr + 12);
- inb(ioaddr + 13);
-
- /* .. enable any extra statistics bits.. */
- outw(0x0040, ioaddr + Wn4_NetDiag);
-
- EL3WINDOW(1);
- spin_unlock_irqrestore(&lp->window_lock, flags);
-
- /* .. re-sync MII and re-fill what NWay is advertising. */
- mdio_sync(ioaddr, 32);
- mdio_write(ioaddr, lp->phys, 4, lp->advertising);
- if (!auto_polarity) {
- /* works for TDK 78Q2120 series MII's */
- i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
- mdio_write(ioaddr, lp->phys, 16, i);
- }
-
- spin_lock_irqsave(&lp->window_lock, flags);
- /* Switch to register set 1 for normal use, just for TxFree. */
- set_rx_mode(dev);
- spin_unlock_irqrestore(&lp->window_lock, flags);
- outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
- outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
- /* Allow status bits to be seen. */
- outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
- /* Ack all pending events, and set active indicator mask. */
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
- outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
- | AdapterFailure | RxEarly, ioaddr + EL3_CMD);
-}
-
-static int el3_open(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- struct pcmcia_device *link = lp->p_dev;
-
- if (!pcmcia_dev_present(link))
- return -ENODEV;
-
- link->open++;
- netif_start_queue(dev);
-
- tc574_reset(dev);
- lp->media.function = media_check;
- lp->media.data = (unsigned long) dev;
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
-
- dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
- dev->name, inw(dev->base_addr + EL3_STATUS));
-
- return 0;
-}
-
-static void el3_tx_timeout(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
-
- netdev_notice(dev, "Transmit timed out!\n");
- dump_status(dev);
- dev->stats.tx_errors++;
- dev->trans_start = jiffies; /* prevent tx timeout */
- /* Issue TX_RESET and TX_START commands. */
- tc574_wait_for_completion(dev, TxReset);
- outw(TxEnable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
-}
-
-static void pop_tx_status(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- int i;
-
- /* Clear the Tx status stack. */
- for (i = 32; i > 0; i--) {
- u_char tx_status = inb(ioaddr + TxStatus);
- if (!(tx_status & 0x84))
- break;
- /* reset transmitter on jabber error or underrun */
- if (tx_status & 0x30)
- tc574_wait_for_completion(dev, TxReset);
- if (tx_status & 0x38) {
- pr_debug("%s: transmit error: status 0x%02x\n",
- dev->name, tx_status);
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->stats.tx_aborted_errors++;
- }
- outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
- }
-}
-
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- struct el3_private *lp = netdev_priv(dev);
- unsigned long flags;
-
- pr_debug("%s: el3_start_xmit(length = %ld) called, "
- "status %4.4x.\n", dev->name, (long)skb->len,
- inw(ioaddr + EL3_STATUS));
-
- spin_lock_irqsave(&lp->window_lock, flags);
-
- dev->stats.tx_bytes += skb->len;
-
- /* Put out the doubleword header... */
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0, ioaddr + TX_FIFO);
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
-
- /* TxFree appears only in Window 1, not offset 0x1c. */
- if (inw(ioaddr + TxFree) <= 1536) {
- netif_stop_queue(dev);
- /* Interrupt us when the FIFO has room for max-sized packet.
- The threshold is in units of dwords. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
- }
-
- pop_tx_status(dev);
- spin_unlock_irqrestore(&lp->window_lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-/* The EL3 interrupt handler. */
-static irqreturn_t el3_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *) dev_id;
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr;
- unsigned status;
- int work_budget = max_interrupt_work;
- int handled = 0;
-
- if (!netif_device_present(dev))
- return IRQ_NONE;
- ioaddr = dev->base_addr;
-
- pr_debug("%s: interrupt, status %4.4x.\n",
- dev->name, inw(ioaddr + EL3_STATUS));
-
- spin_lock(&lp->window_lock);
-
- while ((status = inw(ioaddr + EL3_STATUS)) &
- (IntLatch | RxComplete | RxEarly | StatsFull)) {
- if (!netif_device_present(dev) ||
- ((status & 0xe000) != 0x2000)) {
- pr_debug("%s: Interrupt from dead card\n", dev->name);
- break;
- }
-
- handled = 1;
-
- if (status & RxComplete)
- work_budget = el3_rx(dev, work_budget);
-
- if (status & TxAvailable) {
- pr_debug(" TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
- }
-
- if (status & TxComplete)
- pop_tx_status(dev);
-
- if (status & (AdapterFailure | RxEarly | StatsFull)) {
- /* Handle all uncommon interrupts. */
- if (status & StatsFull)
- update_stats(dev);
- if (status & RxEarly) {
- work_budget = el3_rx(dev, work_budget);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
- if (status & AdapterFailure) {
- u16 fifo_diag;
- EL3WINDOW(4);
- fifo_diag = inw(ioaddr + Wn4_FIFODiag);
- EL3WINDOW(1);
- netdev_notice(dev, "adapter failure, FIFO diagnostic register %04x\n",
- fifo_diag);
- if (fifo_diag & 0x0400) {
- /* Tx overrun */
- tc574_wait_for_completion(dev, TxReset);
- outw(TxEnable, ioaddr + EL3_CMD);
- }
- if (fifo_diag & 0x2000) {
- /* Rx underrun */
- tc574_wait_for_completion(dev, RxReset);
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD);
- }
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
- }
- }
-
- if (--work_budget < 0) {
- pr_debug("%s: Too much work in interrupt, "
- "status %4.4x.\n", dev->name, status);
- /* Clear all interrupts */
- outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
- break;
- }
- /* Acknowledge the IRQ. */
- outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
- }
-
- pr_debug("%s: exiting interrupt, status %4.4x.\n",
- dev->name, inw(ioaddr + EL3_STATUS));
-
- spin_unlock(&lp->window_lock);
- return IRQ_RETVAL(handled);
-}
-
-/*
- This timer serves two purposes: to check for missed interrupts
- (and as a last resort, poll the NIC for events), and to monitor
- the MII, reporting changes in cable status.
-*/
-static void media_check(unsigned long arg)
-{
- struct net_device *dev = (struct net_device *) arg;
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr = dev->base_addr;
- unsigned long flags;
- unsigned short /* cable, */ media, partner;
-
- if (!netif_device_present(dev))
- goto reschedule;
-
- /* Check for pending interrupt with expired latency timer: with
- this, we can limp along even if the interrupt is blocked */
- if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
- if (!lp->fast_poll)
- netdev_info(dev, "interrupt(s) dropped!\n");
-
- local_irq_save(flags);
- el3_interrupt(dev->irq, dev);
- local_irq_restore(flags);
-
- lp->fast_poll = HZ;
- }
- if (lp->fast_poll) {
- lp->fast_poll--;
- lp->media.expires = jiffies + 2*HZ/100;
- add_timer(&lp->media);
- return;
- }
-
- spin_lock_irqsave(&lp->window_lock, flags);
- EL3WINDOW(4);
- media = mdio_read(ioaddr, lp->phys, 1);
- partner = mdio_read(ioaddr, lp->phys, 5);
- EL3WINDOW(1);
-
- if (media != lp->media_status) {
- if ((media ^ lp->media_status) & 0x0004)
- netdev_info(dev, "%s link beat\n",
- (lp->media_status & 0x0004) ? "lost" : "found");
- if ((media ^ lp->media_status) & 0x0020) {
- lp->partner = 0;
- if (lp->media_status & 0x0020) {
- netdev_info(dev, "autonegotiation restarted\n");
- } else if (partner) {
- partner &= lp->advertising;
- lp->partner = partner;
- netdev_info(dev, "autonegotiation complete: "
- "%dbaseT-%cD selected\n",
- (partner & 0x0180) ? 100 : 10,
- (partner & 0x0140) ? 'F' : 'H');
- } else {
- netdev_info(dev, "link partner did not autonegotiate\n");
- }
-
- EL3WINDOW(3);
- outb((partner & 0x0140 ? 0x20 : 0) |
- (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
- EL3WINDOW(1);
-
- }
- if (media & 0x0010)
- netdev_info(dev, "remote fault detected\n");
- if (media & 0x0002)
- netdev_info(dev, "jabber detected\n");
- lp->media_status = media;
- }
- spin_unlock_irqrestore(&lp->window_lock, flags);
-
-reschedule:
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
-}
-
-static struct net_device_stats *el3_get_stats(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
-
- if (netif_device_present(dev)) {
- unsigned long flags;
- spin_lock_irqsave(&lp->window_lock, flags);
- update_stats(dev);
- spin_unlock_irqrestore(&lp->window_lock, flags);
- }
- return &dev->stats;
-}
-
-/* Update statistics.
- Surprisingly this need not be run single-threaded, but it effectively is.
- The counters clear when read, so the adds must merely be atomic.
- */
-static void update_stats(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- u8 rx, tx, up;
-
- pr_debug("%s: updating the statistics.\n", dev->name);
-
- if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */
- return;
-
- /* Unlike the 3c509 we need not turn off stats updates while reading. */
- /* Switch to the stats window, and read everything. */
- EL3WINDOW(6);
- dev->stats.tx_carrier_errors += inb(ioaddr + 0);
- dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
- /* Multiple collisions. */ inb(ioaddr + 2);
- dev->stats.collisions += inb(ioaddr + 3);
- dev->stats.tx_window_errors += inb(ioaddr + 4);
- dev->stats.rx_fifo_errors += inb(ioaddr + 5);
- dev->stats.tx_packets += inb(ioaddr + 6);
- up = inb(ioaddr + 9);
- dev->stats.tx_packets += (up&0x30) << 4;
- /* Rx packets */ inb(ioaddr + 7);
- /* Tx deferrals */ inb(ioaddr + 8);
- rx = inw(ioaddr + 10);
- tx = inw(ioaddr + 12);
-
- EL3WINDOW(4);
- /* BadSSD */ inb(ioaddr + 12);
- up = inb(ioaddr + 13);
-
- EL3WINDOW(1);
-}
-
-static int el3_rx(struct net_device *dev, int worklimit)
-{
- unsigned int ioaddr = dev->base_addr;
- short rx_status;
-
- pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
- dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
- while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&
- worklimit > 0) {
- worklimit--;
- if (rx_status & 0x4000) { /* Error, update stats. */
- short error = rx_status & 0x3800;
- dev->stats.rx_errors++;
- switch (error) {
- case 0x0000: dev->stats.rx_over_errors++; break;
- case 0x0800: dev->stats.rx_length_errors++; break;
- case 0x1000: dev->stats.rx_frame_errors++; break;
- case 0x1800: dev->stats.rx_length_errors++; break;
- case 0x2000: dev->stats.rx_frame_errors++; break;
- case 0x2800: dev->stats.rx_crc_errors++; break;
- }
- } else {
- short pkt_len = rx_status & 0x7ff;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 5);
-
- pr_debug(" Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
- if (skb != NULL) {
- skb_reserve(skb, 2);
- insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
- ((pkt_len+3)>>2));
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- } else {
- pr_debug("%s: couldn't allocate a sk_buff of"
- " size %d.\n", dev->name, pkt_len);
- dev->stats.rx_dropped++;
- }
- }
- tc574_wait_for_completion(dev, RxDiscard);
- }
-
- return worklimit;
-}
-
-/* Provide ioctl() calls to examine the MII xcvr state. */
-static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr = dev->base_addr;
- struct mii_ioctl_data *data = if_mii(rq);
- int phy = lp->phys & 0x1f;
-
- pr_debug("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
- dev->name, rq->ifr_ifrn.ifrn_name, cmd,
- data->phy_id, data->reg_num, data->val_in, data->val_out);
-
- switch(cmd) {
- case SIOCGMIIPHY: /* Get the address of the PHY in use. */
- data->phy_id = phy;
- case SIOCGMIIREG: /* Read the specified MII register. */
- {
- int saved_window;
- unsigned long flags;
-
- spin_lock_irqsave(&lp->window_lock, flags);
- saved_window = inw(ioaddr + EL3_CMD) >> 13;
- EL3WINDOW(4);
- data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f,
- data->reg_num & 0x1f);
- EL3WINDOW(saved_window);
- spin_unlock_irqrestore(&lp->window_lock, flags);
- return 0;
- }
- case SIOCSMIIREG: /* Write the specified MII register */
- {
- int saved_window;
- unsigned long flags;
-
- spin_lock_irqsave(&lp->window_lock, flags);
- saved_window = inw(ioaddr + EL3_CMD) >> 13;
- EL3WINDOW(4);
- mdio_write(ioaddr, data->phy_id & 0x1f,
- data->reg_num & 0x1f, data->val_in);
- EL3WINDOW(saved_window);
- spin_unlock_irqrestore(&lp->window_lock, flags);
- return 0;
- }
- default:
- return -EOPNOTSUPP;
- }
-}
-
-/* The Odie chip has a 64 bin multicast filter, but the bit layout is not
- documented. Until it is we revert to receiving all multicast frames when
- any multicast reception is desired.
- Note: My other drivers emit a log message whenever promiscuous mode is
- entered to help detect password sniffers. This is less desirable on
- typical PC card machines, so we omit the message.
- */
-
-static void set_rx_mode(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
-
- if (dev->flags & IFF_PROMISC)
- outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
- ioaddr + EL3_CMD);
- else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
- outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
- else
- outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&lp->window_lock, flags);
- set_rx_mode(dev);
- spin_unlock_irqrestore(&lp->window_lock, flags);
-}
-
-static int el3_close(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- struct el3_private *lp = netdev_priv(dev);
- struct pcmcia_device *link = lp->p_dev;
-
- dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
-
- if (pcmcia_dev_present(link)) {
- unsigned long flags;
-
- /* Turn off statistics ASAP. We update lp->stats below. */
- outw(StatsDisable, ioaddr + EL3_CMD);
-
- /* Disable the receiver and transmitter. */
- outw(RxDisable, ioaddr + EL3_CMD);
- outw(TxDisable, ioaddr + EL3_CMD);
-
- /* Note: Switching to window 0 may disable the IRQ. */
- EL3WINDOW(0);
- spin_lock_irqsave(&lp->window_lock, flags);
- update_stats(dev);
- spin_unlock_irqrestore(&lp->window_lock, flags);
-
- /* force interrupts off */
- outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
- }
-
- link->open--;
- netif_stop_queue(dev);
- del_timer_sync(&lp->media);
-
- return 0;
-}
-
-static const struct pcmcia_device_id tc574_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
- PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
-
-static struct pcmcia_driver tc574_driver = {
- .owner = THIS_MODULE,
- .name = "3c574_cs",
- .probe = tc574_probe,
- .remove = tc574_detach,
- .id_table = tc574_ids,
- .suspend = tc574_suspend,
- .resume = tc574_resume,
-};
-
-static int __init init_tc574(void)
-{
- return pcmcia_register_driver(&tc574_driver);
-}
-
-static void __exit exit_tc574(void)
-{
- pcmcia_unregister_driver(&tc574_driver);
-}
-
-module_init(init_tc574);
-module_exit(exit_tc574);
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c589_cs.c b/ANDROID_3.4.5/drivers/net/ethernet/3com/3c589_cs.c
deleted file mode 100644
index a556c01e..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c589_cs.c
+++ /dev/null
@@ -1,943 +0,0 @@
-/*======================================================================
-
- A PCMCIA ethernet driver for the 3com 3c589 card.
-
- Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
-
- 3c589_cs.c 1.162 2001/10/13 00:08:50
-
- The network driver code is based on Donald Becker's 3c589 code:
-
- Written 1994 by Donald Becker.
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
- Donald Becker may be reached at becker@scyld.com
-
- Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define DRV_NAME "3c589_cs"
-#define DRV_VERSION "1.162-ac"
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/* To minimize the size of the driver source I only define operating
- constants if they are used several times. You'll need the manual
- if you want to understand driver details. */
-/* Offsets from base I/O address. */
-#define EL3_DATA 0x00
-#define EL3_TIMER 0x0a
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-#define EEPROM_READ 0x0080
-#define EEPROM_BUSY 0x8000
-
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-
-/* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable. */
-enum c509cmd {
- TotalReset = 0<<11,
- SelectWindow = 1<<11,
- StartCoax = 2<<11,
- RxDisable = 3<<11,
- RxEnable = 4<<11,
- RxReset = 5<<11,
- RxDiscard = 8<<11,
- TxEnable = 9<<11,
- TxDisable = 10<<11,
- TxReset = 11<<11,
- FakeIntr = 12<<11,
- AckIntr = 13<<11,
- SetIntrEnb = 14<<11,
- SetStatusEnb = 15<<11,
- SetRxFilter = 16<<11,
- SetRxThreshold = 17<<11,
- SetTxThreshold = 18<<11,
- SetTxStart = 19<<11,
- StatsEnable = 21<<11,
- StatsDisable = 22<<11,
- StopCoax = 23<<11
-};
-
-enum c509status {
- IntLatch = 0x0001,
- AdapterFailure = 0x0002,
- TxComplete = 0x0004,
- TxAvailable = 0x0008,
- RxComplete = 0x0010,
- RxEarly = 0x0020,
- IntReq = 0x0040,
- StatsFull = 0x0080,
- CmdBusy = 0x1000
-};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
- RxStation = 1,
- RxMulticast = 2,
- RxBroadcast = 4,
- RxProm = 8
-};
-
-/* Register window 1 offsets, the window used in normal operation. */
-#define TX_FIFO 0x00
-#define RX_FIFO 0x00
-#define RX_STATUS 0x08
-#define TX_STATUS 0x0B
-#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */
-
-#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */
-#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
-#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
-#define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */
-
-/* Time in jiffies before concluding Tx hung */
-#define TX_TIMEOUT ((400*HZ)/1000)
-
-struct el3_private {
- struct pcmcia_device *p_dev;
- /* For transceiver monitoring */
- struct timer_list media;
- u16 media_status;
- u16 fast_poll;
- unsigned long last_irq;
- spinlock_t lock;
-};
-
-static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/* Special hook for setting if_port when module is loaded */
-INT_MODULE_PARM(if_port, 0);
-
-
-/*====================================================================*/
-
-static int tc589_config(struct pcmcia_device *link);
-static void tc589_release(struct pcmcia_device *link);
-
-static u16 read_eeprom(unsigned int ioaddr, int index);
-static void tc589_reset(struct net_device *dev);
-static void media_check(unsigned long arg);
-static int el3_config(struct net_device *dev, struct ifmap *map);
-static int el3_open(struct net_device *dev);
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id);
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *el3_get_stats(struct net_device *dev);
-static int el3_rx(struct net_device *dev);
-static int el3_close(struct net_device *dev);
-static void el3_tx_timeout(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-static void tc589_detach(struct pcmcia_device *p_dev);
-
-static const struct net_device_ops el3_netdev_ops = {
- .ndo_open = el3_open,
- .ndo_stop = el3_close,
- .ndo_start_xmit = el3_start_xmit,
- .ndo_tx_timeout = el3_tx_timeout,
- .ndo_set_config = el3_config,
- .ndo_get_stats = el3_get_stats,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int tc589_probe(struct pcmcia_device *link)
-{
- struct el3_private *lp;
- struct net_device *dev;
-
- dev_dbg(&link->dev, "3c589_attach()\n");
-
- /* Create new ethernet device */
- dev = alloc_etherdev(sizeof(struct el3_private));
- if (!dev)
- return -ENOMEM;
- lp = netdev_priv(dev);
- link->priv = dev;
- lp->p_dev = link;
-
- spin_lock_init(&lp->lock);
- link->resource[0]->end = 16;
- link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-
- link->config_flags |= CONF_ENABLE_IRQ;
- link->config_index = 1;
-
- dev->netdev_ops = &el3_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-
- return tc589_config(link);
-}
-
-static void tc589_detach(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- dev_dbg(&link->dev, "3c589_detach\n");
-
- unregister_netdev(dev);
-
- tc589_release(link);
-
- free_netdev(dev);
-} /* tc589_detach */
-
-static int tc589_config(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
- __be16 *phys_addr;
- int ret, i, j, multi = 0, fifo;
- unsigned int ioaddr;
- static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
- u8 *buf;
- size_t len;
-
- dev_dbg(&link->dev, "3c589_config\n");
-
- phys_addr = (__be16 *)dev->dev_addr;
- /* Is this a 3c562? */
- if (link->manf_id != MANFID_3COM)
- dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
- multi = (link->card_id == PRODID_3COM_3C562);
-
- link->io_lines = 16;
-
- /* For the 3c562, the base address must be xx00-xx7f */
- for (i = j = 0; j < 0x400; j += 0x10) {
- if (multi && (j & 0x80)) continue;
- link->resource[0]->start = j ^ 0x300;
- i = pcmcia_request_io(link);
- if (i == 0)
- break;
- }
- if (i != 0)
- goto failed;
-
- ret = pcmcia_request_irq(link, el3_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
- ioaddr = dev->base_addr;
- EL3WINDOW(0);
-
- /* The 3c589 has an extra EEPROM for configuration info, including
- the hardware address. The 3c562 puts the address in the CIS. */
- len = pcmcia_get_tuple(link, 0x88, &buf);
- if (buf && len >= 6) {
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
- kfree(buf);
- } else {
- kfree(buf); /* 0 < len < 6 */
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(read_eeprom(ioaddr, i));
- if (phys_addr[0] == htons(0x6060)) {
- dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
- dev->base_addr, dev->base_addr+15);
- goto failed;
- }
- }
-
- /* The address and resource configuration register aren't loaded from
- the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
- outw(0x3f00, ioaddr + 8);
- fifo = inl(ioaddr);
-
- /* The if_port symbol can be set when the module is loaded */
- if ((if_port >= 0) && (if_port <= 3))
- dev->if_port = if_port;
- else
- dev_err(&link->dev, "invalid if_port requested\n");
-
- SET_NETDEV_DEV(dev, &link->dev);
-
- if (register_netdev(dev) != 0) {
- dev_err(&link->dev, "register_netdev() failed\n");
- goto failed;
- }
-
- netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
- (multi ? "562" : "589"), dev->base_addr, dev->irq,
- dev->dev_addr);
- netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n",
- (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
- if_names[dev->if_port]);
- return 0;
-
-failed:
- tc589_release(link);
- return -ENODEV;
-} /* tc589_config */
-
-static void tc589_release(struct pcmcia_device *link)
-{
- pcmcia_disable_device(link);
-}
-
-static int tc589_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open)
- netif_device_detach(dev);
-
- return 0;
-}
-
-static int tc589_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open) {
- tc589_reset(dev);
- netif_device_attach(dev);
- }
-
- return 0;
-}
-
-/*====================================================================*/
-
-/*
- Use this for commands that may take time to finish
-*/
-static void tc589_wait_for_completion(struct net_device *dev, int cmd)
-{
- int i = 100;
- outw(cmd, dev->base_addr + EL3_CMD);
- while (--i > 0)
- if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
- if (i == 0)
- netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
-}
-
-/*
- Read a word from the EEPROM using the regular EEPROM access register.
- Assume that we are in register window zero.
-*/
-static u16 read_eeprom(unsigned int ioaddr, int index)
-{
- int i;
- outw(EEPROM_READ + index, ioaddr + 10);
- /* Reading the eeprom takes 162 us */
- for (i = 1620; i >= 0; i--)
- if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
- break;
- return inw(ioaddr + 12);
-}
-
-/*
- Set transceiver type, perhaps to something other than what the user
- specified in dev->if_port.
-*/
-static void tc589_set_xcvr(struct net_device *dev, int if_port)
-{
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr = dev->base_addr;
-
- EL3WINDOW(0);
- switch (if_port) {
- case 0: case 1: outw(0, ioaddr + 6); break;
- case 2: outw(3<<14, ioaddr + 6); break;
- case 3: outw(1<<14, ioaddr + 6); break;
- }
- /* On PCMCIA, this just turns on the LED */
- outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
- /* 10baseT interface, enable link beat and jabber check. */
- EL3WINDOW(4);
- outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
- EL3WINDOW(1);
- if (if_port == 2)
- lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
- else
- lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
-}
-
-static void dump_status(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- EL3WINDOW(1);
- netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
- inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
- EL3WINDOW(4);
- netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
- inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
- inw(ioaddr+0x0a));
- EL3WINDOW(1);
-}
-
-/* Reset and restore all of the 3c589 registers. */
-static void tc589_reset(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- int i;
-
- EL3WINDOW(0);
- outw(0x0001, ioaddr + 4); /* Activate board. */
- outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */
-
- /* Set the station address in window 2. */
- EL3WINDOW(2);
- for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + i);
-
- tc589_set_xcvr(dev, dev->if_port);
-
- /* Switch to the stats window, and clear all stats by reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
- for (i = 0; i < 9; i++)
- inb(ioaddr+i);
- inw(ioaddr + 10);
- inw(ioaddr + 12);
-
- /* Switch to register set 1 for normal use. */
- EL3WINDOW(1);
-
- set_rx_mode(dev);
- outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
- outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
- /* Allow status bits to be seen. */
- outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
- /* Ack all pending events, and set active indicator mask. */
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
- outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
- | AdapterFailure, ioaddr + EL3_CMD);
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
- strlcpy(info->version, DRV_VERSION, sizeof(info->version));
- snprintf(info->bus_info, sizeof(info->bus_info),
- "PCMCIA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
-static int el3_config(struct net_device *dev, struct ifmap *map)
-{
- if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
- if (map->port <= 3) {
- dev->if_port = map->port;
- netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
- tc589_set_xcvr(dev, dev->if_port);
- } else
- return -EINVAL;
- }
- return 0;
-}
-
-static int el3_open(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- struct pcmcia_device *link = lp->p_dev;
-
- if (!pcmcia_dev_present(link))
- return -ENODEV;
-
- link->open++;
- netif_start_queue(dev);
-
- tc589_reset(dev);
- init_timer(&lp->media);
- lp->media.function = media_check;
- lp->media.data = (unsigned long) dev;
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
-
- dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
- dev->name, inw(dev->base_addr + EL3_STATUS));
-
- return 0;
-}
-
-static void el3_tx_timeout(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
-
- netdev_warn(dev, "Transmit timed out!\n");
- dump_status(dev);
- dev->stats.tx_errors++;
- dev->trans_start = jiffies; /* prevent tx timeout */
- /* Issue TX_RESET and TX_START commands. */
- tc589_wait_for_completion(dev, TxReset);
- outw(TxEnable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
-}
-
-static void pop_tx_status(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- int i;
-
- /* Clear the Tx status stack. */
- for (i = 32; i > 0; i--) {
- u_char tx_status = inb(ioaddr + TX_STATUS);
- if (!(tx_status & 0x84)) break;
- /* reset transmitter on jabber error or underrun */
- if (tx_status & 0x30)
- tc589_wait_for_completion(dev, TxReset);
- if (tx_status & 0x38) {
- netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->stats.tx_aborted_errors++;
- }
- outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
- }
-}
-
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- struct el3_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
- (long)skb->len, inw(ioaddr + EL3_STATUS));
-
- spin_lock_irqsave(&priv->lock, flags);
-
- dev->stats.tx_bytes += skb->len;
-
- /* Put out the doubleword header... */
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0x00, ioaddr + TX_FIFO);
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-
- if (inw(ioaddr + TX_FREE) <= 1536) {
- netif_stop_queue(dev);
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
- }
-
- pop_tx_status(dev);
- spin_unlock_irqrestore(&priv->lock, flags);
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-/* The EL3 interrupt handler. */
-static irqreturn_t el3_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *) dev_id;
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr;
- __u16 status;
- int i = 0, handled = 1;
-
- if (!netif_device_present(dev))
- return IRQ_NONE;
-
- ioaddr = dev->base_addr;
-
- netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
-
- spin_lock(&lp->lock);
- while ((status = inw(ioaddr + EL3_STATUS)) &
- (IntLatch | RxComplete | StatsFull)) {
- if ((status & 0xe000) != 0x2000) {
- netdev_dbg(dev, "interrupt from dead card\n");
- handled = 0;
- break;
- }
- if (status & RxComplete)
- el3_rx(dev);
- if (status & TxAvailable) {
- netdev_dbg(dev, " TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- netif_wake_queue(dev);
- }
- if (status & TxComplete)
- pop_tx_status(dev);
- if (status & (AdapterFailure | RxEarly | StatsFull)) {
- /* Handle all uncommon interrupts. */
- if (status & StatsFull) /* Empty statistics. */
- update_stats(dev);
- if (status & RxEarly) { /* Rx early is unused. */
- el3_rx(dev);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
- if (status & AdapterFailure) {
- u16 fifo_diag;
- EL3WINDOW(4);
- fifo_diag = inw(ioaddr + 4);
- EL3WINDOW(1);
- netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
- fifo_diag);
- if (fifo_diag & 0x0400) {
- /* Tx overrun */
- tc589_wait_for_completion(dev, TxReset);
- outw(TxEnable, ioaddr + EL3_CMD);
- }
- if (fifo_diag & 0x2000) {
- /* Rx underrun */
- tc589_wait_for_completion(dev, RxReset);
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD);
- }
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
- }
- }
- if (++i > 10) {
- netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
- status);
- /* Clear all interrupts */
- outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
- break;
- }
- /* Acknowledge the IRQ. */
- outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
- }
- lp->last_irq = jiffies;
- spin_unlock(&lp->lock);
- netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
- inw(ioaddr + EL3_STATUS));
- return IRQ_RETVAL(handled);
-}
-
-static void media_check(unsigned long arg)
-{
- struct net_device *dev = (struct net_device *)(arg);
- struct el3_private *lp = netdev_priv(dev);
- unsigned int ioaddr = dev->base_addr;
- u16 media, errs;
- unsigned long flags;
-
- if (!netif_device_present(dev)) goto reschedule;
-
- /* Check for pending interrupt with expired latency timer: with
- this, we can limp along even if the interrupt is blocked */
- if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
- (inb(ioaddr + EL3_TIMER) == 0xff)) {
- if (!lp->fast_poll)
- netdev_warn(dev, "interrupt(s) dropped!\n");
-
- local_irq_save(flags);
- el3_interrupt(dev->irq, dev);
- local_irq_restore(flags);
-
- lp->fast_poll = HZ;
- }
- if (lp->fast_poll) {
- lp->fast_poll--;
- lp->media.expires = jiffies + HZ/100;
- add_timer(&lp->media);
- return;
- }
-
- /* lp->lock guards the EL3 window. Window should always be 1 except
- when the lock is held */
- spin_lock_irqsave(&lp->lock, flags);
- EL3WINDOW(4);
- media = inw(ioaddr+WN4_MEDIA) & 0xc810;
-
- /* Ignore collisions unless we've had no irq's recently */
- if (time_before(jiffies, lp->last_irq + HZ)) {
- media &= ~0x0010;
- } else {
- /* Try harder to detect carrier errors */
- EL3WINDOW(6);
- outw(StatsDisable, ioaddr + EL3_CMD);
- errs = inb(ioaddr + 0);
- outw(StatsEnable, ioaddr + EL3_CMD);
- dev->stats.tx_carrier_errors += errs;
- if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
- }
-
- if (media != lp->media_status) {
- if ((media & lp->media_status & 0x8000) &&
- ((lp->media_status ^ media) & 0x0800))
- netdev_info(dev, "%s link beat\n",
- (lp->media_status & 0x0800 ? "lost" : "found"));
- else if ((media & lp->media_status & 0x4000) &&
- ((lp->media_status ^ media) & 0x0010))
- netdev_info(dev, "coax cable %s\n",
- (lp->media_status & 0x0010 ? "ok" : "problem"));
- if (dev->if_port == 0) {
- if (media & 0x8000) {
- if (media & 0x0800)
- netdev_info(dev, "flipped to 10baseT\n");
- else
- tc589_set_xcvr(dev, 2);
- } else if (media & 0x4000) {
- if (media & 0x0010)
- tc589_set_xcvr(dev, 1);
- else
- netdev_info(dev, "flipped to 10base2\n");
- }
- }
- lp->media_status = media;
- }
-
- EL3WINDOW(1);
- spin_unlock_irqrestore(&lp->lock, flags);
-
-reschedule:
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
-}
-
-static struct net_device_stats *el3_get_stats(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- unsigned long flags;
- struct pcmcia_device *link = lp->p_dev;
-
- if (pcmcia_dev_present(link)) {
- spin_lock_irqsave(&lp->lock, flags);
- update_stats(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- }
- return &dev->stats;
-}
-
-/*
- Update statistics. We change to register window 6, so this should be run
- single-threaded if the device is active. This is expected to be a rare
- operation, and it's simpler for the rest of the driver to assume that
- window 1 is always valid rather than use a special window-state variable.
-
- Caller must hold the lock for this
-*/
-static void update_stats(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
-
- netdev_dbg(dev, "updating the statistics.\n");
- /* Turn off statistics updates while reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- /* Switch to the stats window, and read everything. */
- EL3WINDOW(6);
- dev->stats.tx_carrier_errors += inb(ioaddr + 0);
- dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
- /* Multiple collisions. */ inb(ioaddr + 2);
- dev->stats.collisions += inb(ioaddr + 3);
- dev->stats.tx_window_errors += inb(ioaddr + 4);
- dev->stats.rx_fifo_errors += inb(ioaddr + 5);
- dev->stats.tx_packets += inb(ioaddr + 6);
- /* Rx packets */ inb(ioaddr + 7);
- /* Tx deferrals */ inb(ioaddr + 8);
- /* Rx octets */ inw(ioaddr + 10);
- /* Tx octets */ inw(ioaddr + 12);
-
- /* Back to window 1, and turn statistics back on. */
- EL3WINDOW(1);
- outw(StatsEnable, ioaddr + EL3_CMD);
-}
-
-static int el3_rx(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- int worklimit = 32;
- short rx_status;
-
- netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
- while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
- worklimit > 0) {
- worklimit--;
- if (rx_status & 0x4000) { /* Error, update stats. */
- short error = rx_status & 0x3800;
- dev->stats.rx_errors++;
- switch (error) {
- case 0x0000: dev->stats.rx_over_errors++; break;
- case 0x0800: dev->stats.rx_length_errors++; break;
- case 0x1000: dev->stats.rx_frame_errors++; break;
- case 0x1800: dev->stats.rx_length_errors++; break;
- case 0x2000: dev->stats.rx_frame_errors++; break;
- case 0x2800: dev->stats.rx_crc_errors++; break;
- }
- } else {
- short pkt_len = rx_status & 0x7ff;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 5);
-
- netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
- if (skb != NULL) {
- skb_reserve(skb, 2);
- insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
- (pkt_len+3)>>2);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- } else {
- netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
- pkt_len);
- dev->stats.rx_dropped++;
- }
- }
- /* Pop the top of the Rx FIFO */
- tc589_wait_for_completion(dev, RxDiscard);
- }
- if (worklimit == 0)
- netdev_warn(dev, "too much work in el3_rx!\n");
- return 0;
-}
-
-static void set_rx_mode(struct net_device *dev)
-{
- unsigned int ioaddr = dev->base_addr;
- u16 opts = SetRxFilter | RxStation | RxBroadcast;
-
- if (dev->flags & IFF_PROMISC)
- opts |= RxMulticast | RxProm;
- else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
- opts |= RxMulticast;
- outw(opts, ioaddr + EL3_CMD);
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
- struct el3_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- set_rx_mode(dev);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int el3_close(struct net_device *dev)
-{
- struct el3_private *lp = netdev_priv(dev);
- struct pcmcia_device *link = lp->p_dev;
- unsigned int ioaddr = dev->base_addr;
-
- dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
-
- if (pcmcia_dev_present(link)) {
- /* Turn off statistics ASAP. We update dev->stats below. */
- outw(StatsDisable, ioaddr + EL3_CMD);
-
- /* Disable the receiver and transmitter. */
- outw(RxDisable, ioaddr + EL3_CMD);
- outw(TxDisable, ioaddr + EL3_CMD);
-
- if (dev->if_port == 2)
- /* Turn off thinnet power. Green! */
- outw(StopCoax, ioaddr + EL3_CMD);
- else if (dev->if_port == 1) {
- /* Disable link beat and jabber */
- EL3WINDOW(4);
- outw(0, ioaddr + WN4_MEDIA);
- }
-
- /* Switching back to window 0 disables the IRQ. */
- EL3WINDOW(0);
- /* But we explicitly zero the IRQ line select anyway. */
- outw(0x0f00, ioaddr + WN0_IRQ);
-
- /* Check if the card still exists */
- if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
- update_stats(dev);
- }
-
- link->open--;
- netif_stop_queue(dev);
- del_timer_sync(&lp->media);
-
- return 0;
-}
-
-static const struct pcmcia_device_id tc589_ids[] = {
- PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
- PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
- PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
- PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
- PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"),
- PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"),
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
-
-static struct pcmcia_driver tc589_driver = {
- .owner = THIS_MODULE,
- .name = "3c589_cs",
- .probe = tc589_probe,
- .remove = tc589_detach,
- .id_table = tc589_ids,
- .suspend = tc589_suspend,
- .resume = tc589_resume,
-};
-
-static int __init init_tc589(void)
-{
- return pcmcia_register_driver(&tc589_driver);
-}
-
-static void __exit exit_tc589(void)
-{
- pcmcia_unregister_driver(&tc589_driver);
-}
-
-module_init(init_tc589);
-module_exit(exit_tc589);
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c59x.c b/ANDROID_3.4.5/drivers/net/ethernet/3com/3c59x.c
deleted file mode 100644
index e463d103..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/3c59x.c
+++ /dev/null
@@ -1,3329 +0,0 @@
-/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
-/*
- Written 1996-1999 by Donald Becker.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- This driver is for the 3Com "Vortex" and "Boomerang" series ethercards.
- Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597
- and the EtherLink XL 3c900 and 3c905 cards.
-
- Problem reports and questions should be directed to
- vortex@scyld.com
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
-*/
-
-/*
- * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamachi.c implementation
- * as well as other drivers
- *
- * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k
- * due to dead code elimination. There will be some performance benefits from this due to
- * elimination of all the tests and reduced cache footprint.
- */
-
-
-#define DRV_NAME "3c59x"
-
-
-
-/* A few values that may be tweaked. */
-/* Keep the ring sizes a power of two for efficiency. */
-#define TX_RING_SIZE 16
-#define RX_RING_SIZE 32
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-
-/* "Knobs" that adjust features and parameters. */
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- Setting to > 1512 effectively disables this feature. */
-#ifndef __arm__
-static int rx_copybreak = 200;
-#else
-/* ARM systems perform better by disregarding the bus-master
- transfer capability of these cards. -- rmk */
-static int rx_copybreak = 1513;
-#endif
-/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const int mtu = 1500;
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 32;
-/* Tx timeout interval (millisecs) */
-static int watchdog = 5000;
-
-/* Allow aggregation of Tx interrupts. Saves CPU load at the cost
- * of possible Tx stalls if the system is blocking interrupts
- * somewhere else. Undefine this to disable.
- */
-#define tx_interrupt_mitigation 1
-
-/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
-#define vortex_debug debug
-#ifdef VORTEX_DEBUG
-static int vortex_debug = VORTEX_DEBUG;
-#else
-static int vortex_debug = 1;
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/mii.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-#include <linux/highmem.h>
-#include <linux/eisa.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/gfp.h>
-#include <asm/irq.h> /* For nr_irqs only. */
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
- This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
-
-#include <linux/delay.h>
-
-
-static const char version[] __devinitconst =
- DRV_NAME ": Donald Becker and others.\n";
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
-MODULE_LICENSE("GPL");
-
-
-/* Operational parameter that usually are not changed. */
-
-/* The Vortex size is twice that of the original EtherLinkIII series: the
- runtime register window, window 1, is now always mapped in.
- The Boomerang size is twice as large as the Vortex -- it has additional
- bus master control registers. */
-#define VORTEX_TOTAL_SIZE 0x20
-#define BOOMERANG_TOTAL_SIZE 0x40
-
-/* Set iff a MII transceiver on any interface requires mdio preamble.
- This only set with the original DP83840 on older 3c905 boards, so the extra
- code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required;
-
-#define PFX DRV_NAME ": "
-
-
-
-/*
- Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the 3Com FastEtherLink and FastEtherLink
-XL, 3Com's PCI to 10/100baseT adapters. It also works with the 10Mbs
-versions of the FastEtherLink cards. The supported product IDs are
- 3c590, 3c592, 3c595, 3c597, 3c900, 3c905
-
-The related ISA 3c515 is supported with a separate driver, 3c515.c, included
-with the kernel source or available from
- cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board. The system BIOS should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-
-The EEPROM settings for media type and forced-full-duplex are observed.
-The EEPROM media type should be left at the default "autoselect" unless using
-10base2 or AUI connections which cannot be reliably detected.
-
-III. Driver operation
-
-The 3c59x series use an interface that's very similar to the previous 3c5x9
-series. The primary interface is two programmed-I/O FIFOs, with an
-alternate single-contiguous-region bus-master transfer (see next).
-
-The 3c900 "Boomerang" series uses a full-bus-master interface with separate
-lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
-DEC Tulip and Intel Speedo3. The first chip version retains a compatible
-programmed-I/O interface that has been removed in 'B' and subsequent board
-revisions.
-
-One extension that is advertised in a very large font is that the adapters
-are capable of being bus masters. On the Vortex chip this capability was
-only for a single contiguous region making it far less useful than the full
-bus master capability. There is a significant performance impact of taking
-an extra interrupt or polling for the completion of each transfer, as well
-as difficulty sharing the single transfer engine between the transmit and
-receive threads. Using DMA transfers is a win only with large blocks or
-with the flawed versions of the Intel Orion motherboard PCI controller.
-
-The Boomerang chip's full-bus-master interface is useful, and has the
-currently-unused advantages over other similar chips that queued transmit
-packets may be reordered and receive buffer groups are associated with a
-single frame.
-
-With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
-Rather than a fixed intermediate receive buffer, this scheme allocates
-full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as
-the copying breakpoint: it is chosen to trade-off the memory wasted by
-passing the full-sized skbuff to the queue layer for all frames vs. the
-copying cost of copying a frame to a correctly-sized skbuff.
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control. One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag. The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-IV. Notes
-
-Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development
-3c590, 3c595, and 3c900 boards.
-The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
-the EISA version is called "Demon". According to Terry these names come
-from rides at the local amusement park.
-
-The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes!
-This driver only supports ethernet packets because of the skbuff allocation
-limit of 4K.
-*/
-
-/* This table drives the PCI probe routines. It's mostly boilerplate in all
- of the drivers, and will likely be provided by some future kernel.
-*/
-enum pci_flags_bit {
- PCI_USES_MASTER=4,
-};
-
-enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
- EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
- HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
- INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
- EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000,
- EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, };
-
-enum vortex_chips {
- CH_3C590 = 0,
- CH_3C592,
- CH_3C597,
- CH_3C595_1,
- CH_3C595_2,
-
- CH_3C595_3,
- CH_3C900_1,
- CH_3C900_2,
- CH_3C900_3,
- CH_3C900_4,
-
- CH_3C900_5,
- CH_3C900B_FL,
- CH_3C905_1,
- CH_3C905_2,
- CH_3C905B_TX,
- CH_3C905B_1,
-
- CH_3C905B_2,
- CH_3C905B_FX,
- CH_3C905C,
- CH_3C9202,
- CH_3C980,
- CH_3C9805,
-
- CH_3CSOHO100_TX,
- CH_3C555,
- CH_3C556,
- CH_3C556B,
- CH_3C575,
-
- CH_3C575_1,
- CH_3CCFE575,
- CH_3CCFE575CT,
- CH_3CCFE656,
- CH_3CCFEM656,
-
- CH_3CCFEM656_1,
- CH_3C450,
- CH_3C920,
- CH_3C982A,
- CH_3C982B,
-
- CH_905BT4,
- CH_920B_EMB_WNM,
-};
-
-
-/* note: this array directly indexed by above enums, and MUST
- * be kept in sync with both the enums above, and the PCI device
- * table below
- */
-static struct vortex_chip_info {
- const char *name;
- int flags;
- int drv_flags;
- int io_size;
-} vortex_info_tbl[] __devinitdata = {
- {"3c590 Vortex 10Mbps",
- PCI_USES_MASTER, IS_VORTEX, 32, },
- {"3c592 EISA 10Mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */
- PCI_USES_MASTER, IS_VORTEX, 32, },
- {"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */
- PCI_USES_MASTER, IS_VORTEX, 32, },
- {"3c595 Vortex 100baseTx",
- PCI_USES_MASTER, IS_VORTEX, 32, },
- {"3c595 Vortex 100baseT4",
- PCI_USES_MASTER, IS_VORTEX, 32, },
-
- {"3c595 Vortex 100base-MII",
- PCI_USES_MASTER, IS_VORTEX, 32, },
- {"3c900 Boomerang 10baseT",
- PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
- {"3c900 Boomerang 10Mbps Combo",
- PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
- {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */
- PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
- {"3c900 Cyclone 10Mbps Combo",
- PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
-
- {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */
- PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
- {"3c900B-FL Cyclone 10base-FL",
- PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
- {"3c905 Boomerang 100baseTx",
- PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
- {"3c905 Boomerang 100baseT4",
- PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
- {"3C905B-TX Fast Etherlink XL PCI",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
- {"3c905B Cyclone 100baseTx",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-
- {"3c905B Cyclone 10/100/BNC",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
- {"3c905B-FX Cyclone 100baseFx",
- PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
- {"3c905C Tornado",
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
- {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
- PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
- {"3c980 Cyclone",
- PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-
- {"3c980C Python-T",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
- {"3cSOHO100-TX Hurricane",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
- {"3c555 Laptop Hurricane",
- PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
- {"3c556 Laptop Tornado",
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
- HAS_HWCKSM, 128, },
- {"3c556B Laptop Hurricane",
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
- WNO_XCVR_PWR|HAS_HWCKSM, 128, },
-
- {"3c575 [Megahertz] 10/100 LAN CardBus",
- PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
- {"3c575 Boomerang CardBus",
- PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
- {"3CCFE575BT Cyclone CardBus",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
- INVERT_LED_PWR|HAS_HWCKSM, 128, },
- {"3CCFE575CT Tornado CardBus",
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
- MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
- {"3CCFE656 Cyclone CardBus",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
- INVERT_LED_PWR|HAS_HWCKSM, 128, },
-
- {"3CCFEM656B Cyclone+Winmodem CardBus",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
- INVERT_LED_PWR|HAS_HWCKSM, 128, },
- {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
- MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
- {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
- {"3c920 Tornado",
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
- {"3c982 Hydra Dual Port A",
- PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
-
- {"3c982 Hydra Dual Port B",
- PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
- {"3c905B-T4",
- PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
- {"3c920B-EMB-WNM Tornado",
- PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
-
- {NULL,}, /* NULL terminated list. */
-};
-
-
-static DEFINE_PCI_DEVICE_TABLE(vortex_pci_tbl) = {
- { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
- { 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 },
- { 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 },
- { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 },
- { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 },
-
- { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 },
- { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 },
- { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 },
- { 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
- { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 },
-
- { 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 },
- { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL },
- { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 },
- { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 },
- { 0x10B7, 0x9054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_TX },
- { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 },
-
- { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
- { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
- { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
- { 0x10B7, 0x9202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9202 },
- { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
- { 0x10B7, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9805 },
-
- { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
- { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
- { 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 },
- { 0x10B7, 0x6056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556B },
- { 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 },
-
- { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
- { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
- { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
- { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
- { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
-
- { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 },
- { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
- { 0x10B7, 0x9201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C920 },
- { 0x10B7, 0x1201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982A },
- { 0x10B7, 0x1202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982B },
-
- { 0x10B7, 0x9056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_905BT4 },
- { 0x10B7, 0x9210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_920B_EMB_WNM },
-
- {0,} /* 0 terminated list. */
-};
-MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
-
-
-/* Operational definitions.
- These are not used by other compilation units and thus are not
- exported in a ".h" file.
-
- First the windows. There are eight register windows, with the command
- and status registers available in each.
- */
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-/* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable.
- Note that 11 parameters bits was fine for ethernet, but the new chip
- can handle FDDI length frames (~4500 octets) and now parameters count
- 32-bit 'Dwords' rather than octets. */
-
-enum vortex_cmd {
- TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
- RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
- UpStall = 6<<11, UpUnstall = (6<<11)+1,
- DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
- RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
- FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
- SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
- SetTxThreshold = 18<<11, SetTxStart = 19<<11,
- StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
- StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
- RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
-
-/* Bits in the general status register. */
-enum vortex_status {
- IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004,
- TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
- IntReq = 0x0040, StatsFull = 0x0080,
- DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
- DMAInProgress = 1<<11, /* DMA controller is still busy.*/
- CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/
-};
-
-/* Register window 1 offsets, the window used in normal operation.
- On the Vortex this window is always mapped at offsets 0x10-0x1f. */
-enum Window1 {
- TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
- RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B,
- TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
-};
-enum Window0 {
- Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
- Wn0EepromData = 12, /* Window 0: EEPROM results register. */
- IntrStatus=0x0E, /* Valid in all windows. */
-};
-enum Win0_EEPROM_bits {
- EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
- EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
- EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
-};
-/* EEPROM locations. */
-enum eeprom_offset {
- PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
- EtherLink3ID=7, IFXcvrIO=8, IRQLine=9,
- NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
- DriverTune=13, Checksum=15};
-
-enum Window2 { /* Window 2. */
- Wn2_ResetOptions=12,
-};
-enum Window3 { /* Window 3: MAC/config bits. */
- Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8,
-};
-
-#define BFEXT(value, offset, bitcount) \
- ((((unsigned long)(value)) >> (offset)) & ((1 << (bitcount)) - 1))
-
-#define BFINS(lhs, rhs, offset, bitcount) \
- (((lhs) & ~((((1 << (bitcount)) - 1)) << (offset))) | \
- (((rhs) & ((1 << (bitcount)) - 1)) << (offset)))
-
-#define RAM_SIZE(v) BFEXT(v, 0, 3)
-#define RAM_WIDTH(v) BFEXT(v, 3, 1)
-#define RAM_SPEED(v) BFEXT(v, 4, 2)
-#define ROM_SIZE(v) BFEXT(v, 6, 2)
-#define RAM_SPLIT(v) BFEXT(v, 16, 2)
-#define XCVR(v) BFEXT(v, 20, 4)
-#define AUTOSELECT(v) BFEXT(v, 24, 1)
-
-enum Window4 { /* Window 4: Xcvr/media bits. */
- Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
-};
-enum Win4_Media_bits {
- Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
- Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
- Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
- Media_LnkBeat = 0x0800,
-};
-enum Window7 { /* Window 7: Bus Master control. */
- Wn7_MasterAddr = 0, Wn7_VlanEtherType=4, Wn7_MasterLen = 6,
- Wn7_MasterStatus = 12,
-};
-/* Boomerang bus master control registers. */
-enum MasterCtrl {
- PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
- TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,
-};
-
-/* The Rx and Tx descriptor lists.
- Caution Alpha hackers: these types are 32 bits! Note also the 8 byte
- alignment contraint on tx_ring[] and rx_ring[]. */
-#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */
-#define DN_COMPLETE 0x00010000 /* This packet has been downloaded */
-struct boom_rx_desc {
- __le32 next; /* Last entry points to 0. */
- __le32 status;
- __le32 addr; /* Up to 63 addr/len pairs possible. */
- __le32 length; /* Set LAST_FRAG to indicate last pair. */
-};
-/* Values for the Rx status entry. */
-enum rx_desc_status {
- RxDComplete=0x00008000, RxDError=0x4000,
- /* See boomerang_rx() for actual error bits */
- IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
- IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
-};
-
-#ifdef MAX_SKB_FRAGS
-#define DO_ZEROCOPY 1
-#else
-#define DO_ZEROCOPY 0
-#endif
-
-struct boom_tx_desc {
- __le32 next; /* Last entry points to 0. */
- __le32 status; /* bits 0:12 length, others see below. */
-#if DO_ZEROCOPY
- struct {
- __le32 addr;
- __le32 length;
- } frag[1+MAX_SKB_FRAGS];
-#else
- __le32 addr;
- __le32 length;
-#endif
-};
-
-/* Values for the Tx status entry. */
-enum tx_desc_status {
- CRCDisable=0x2000, TxDComplete=0x8000,
- AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
- TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */
-};
-
-/* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
-
-struct vortex_extra_stats {
- unsigned long tx_deferred;
- unsigned long tx_max_collisions;
- unsigned long tx_multiple_collisions;
- unsigned long tx_single_collisions;
- unsigned long rx_bad_ssd;
-};
-
-struct vortex_private {
- /* The Rx and Tx rings should be quad-word-aligned. */
- struct boom_rx_desc* rx_ring;
- struct boom_tx_desc* tx_ring;
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_ring_dma;
- /* The addresses of transmit- and receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- unsigned int cur_rx, cur_tx; /* The next free ring entry */
- unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- struct vortex_extra_stats xstats; /* NIC-specific extra stats */
- struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
- dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DMA. */
-
- /* PCI configuration space information. */
- struct device *gendev;
- void __iomem *ioaddr; /* IO address space */
- void __iomem *cb_fn_base; /* CardBus function status addr space. */
-
- /* Some values here only for performance evaluation and path-coverage */
- int rx_nocopy, rx_copy, queued_packet, rx_csumhits;
- int card_idx;
-
- /* The remainder are related to chip state, mostly media selection. */
- struct timer_list timer; /* Media selection timer. */
- struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */
- int options; /* User-settable misc. driver options. */
- unsigned int media_override:4, /* Passed-in media type. */
- default_media:4, /* Read from the EEPROM/Wn3_Config. */
- full_duplex:1, autoselect:1,
- bus_master:1, /* Vortex can only do a fragment bus-m. */
- full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
- flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */
- partner_flow_ctrl:1, /* Partner supports flow control */
- has_nway:1,
- enable_wol:1, /* Wake-on-LAN is enabled */
- pm_state_valid:1, /* pci_dev->saved_config_space has sane contents */
- open:1,
- medialock:1,
- must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */
- large_frames:1, /* accept large frames */
- handling_irq:1; /* private in_irq indicator */
- /* {get|set}_wol operations are already serialized by rtnl.
- * no additional locking is required for the enable_wol and acpi_set_WOL()
- */
- int drv_flags;
- u16 status_enable;
- u16 intr_enable;
- u16 available_media; /* From Wn3_Options. */
- u16 capabilities, info1, info2; /* Various, from EEPROM. */
- u16 advertising; /* NWay media advertisement */
- unsigned char phys[2]; /* MII device addresses. */
- u16 deferred; /* Resend these interrupts when we
- * bale from the ISR */
- u16 io_size; /* Size of PCI region (for release_region) */
-
- /* Serialises access to hardware other than MII and variables below.
- * The lock hierarchy is rtnl_lock > {lock, mii_lock} > window_lock. */
- spinlock_t lock;
-
- spinlock_t mii_lock; /* Serialises access to MII */
- struct mii_if_info mii; /* MII lib hooks/info */
- spinlock_t window_lock; /* Serialises access to windowed regs */
- int window; /* Register window */
-};
-
-static void window_set(struct vortex_private *vp, int window)
-{
- if (window != vp->window) {
- iowrite16(SelectWindow + window, vp->ioaddr + EL3_CMD);
- vp->window = window;
- }
-}
-
-#define DEFINE_WINDOW_IO(size) \
-static u ## size \
-window_read ## size(struct vortex_private *vp, int window, int addr) \
-{ \
- unsigned long flags; \
- u ## size ret; \
- spin_lock_irqsave(&vp->window_lock, flags); \
- window_set(vp, window); \
- ret = ioread ## size(vp->ioaddr + addr); \
- spin_unlock_irqrestore(&vp->window_lock, flags); \
- return ret; \
-} \
-static void \
-window_write ## size(struct vortex_private *vp, u ## size value, \
- int window, int addr) \
-{ \
- unsigned long flags; \
- spin_lock_irqsave(&vp->window_lock, flags); \
- window_set(vp, window); \
- iowrite ## size(value, vp->ioaddr + addr); \
- spin_unlock_irqrestore(&vp->window_lock, flags); \
-}
-DEFINE_WINDOW_IO(8)
-DEFINE_WINDOW_IO(16)
-DEFINE_WINDOW_IO(32)
-
-#ifdef CONFIG_PCI
-#define DEVICE_PCI(dev) (((dev)->bus == &pci_bus_type) ? to_pci_dev((dev)) : NULL)
-#else
-#define DEVICE_PCI(dev) NULL
-#endif
-
-#define VORTEX_PCI(vp) \
- ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL))
-
-#ifdef CONFIG_EISA
-#define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL)
-#else
-#define DEVICE_EISA(dev) NULL
-#endif
-
-#define VORTEX_EISA(vp) \
- ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL))
-
-/* The action to take with a media selection timer tick.
- Note that we deviate from the 3Com order by checking 10base2 before AUI.
- */
-enum xcvr_types {
- XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
- XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
-};
-
-static const struct media_table {
- char *name;
- unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
- mask:8, /* The transceiver-present bit in Wn3_Config.*/
- next:8; /* The media type to try next. */
- int wait; /* Time before we check media status. */
-} media_tbl[] = {
- { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
- { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
- { "undefined", 0, 0x80, XCVR_10baseT, 10000},
- { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10},
- { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
- { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10},
- { "MII", 0, 0x41, XCVR_10baseT, 3*HZ },
- { "undefined", 0, 0x01, XCVR_10baseT, 10000},
- { "Autonegotiate", 0, 0x41, XCVR_10baseT, 3*HZ},
- { "MII-External", 0, 0x41, XCVR_10baseT, 3*HZ },
- { "Default", 0, 0xFF, XCVR_10baseT, 10000},
-};
-
-static struct {
- const char str[ETH_GSTRING_LEN];
-} ethtool_stats_keys[] = {
- { "tx_deferred" },
- { "tx_max_collisions" },
- { "tx_multiple_collisions" },
- { "tx_single_collisions" },
- { "rx_bad_ssd" },
-};
-
-/* number of ETHTOOL_GSTATS u64's */
-#define VORTEX_NUM_STATS 5
-
-static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
- int chip_idx, int card_idx);
-static int vortex_up(struct net_device *dev);
-static void vortex_down(struct net_device *dev, int final);
-static int vortex_open(struct net_device *dev);
-static void mdio_sync(struct vortex_private *vp, int bits);
-static int mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *vp, int phy_id, int location, int value);
-static void vortex_timer(unsigned long arg);
-static void rx_oom_timer(unsigned long arg);
-static netdev_tx_t vortex_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static netdev_tx_t boomerang_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static int vortex_rx(struct net_device *dev);
-static int boomerang_rx(struct net_device *dev);
-static irqreturn_t vortex_interrupt(int irq, void *dev_id);
-static irqreturn_t boomerang_interrupt(int irq, void *dev_id);
-static int vortex_close(struct net_device *dev);
-static void dump_tx_ring(struct net_device *dev);
-static void update_stats(void __iomem *ioaddr, struct net_device *dev);
-static struct net_device_stats *vortex_get_stats(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-#ifdef CONFIG_PCI
-static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#endif
-static void vortex_tx_timeout(struct net_device *dev);
-static void acpi_set_WOL(struct net_device *dev);
-static const struct ethtool_ops vortex_ethtool_ops;
-static void set_8021q_mode(struct net_device *dev, int enable);
-
-/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
-/* Option count limit only -- unlimited interfaces are supported. */
-#define MAX_UNITS 8
-static int options[MAX_UNITS] = { [0 ... MAX_UNITS-1] = -1 };
-static int full_duplex[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int hw_checksums[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int flow_ctrl[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int enable_wol[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int use_mmio[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int global_options = -1;
-static int global_full_duplex = -1;
-static int global_enable_wol = -1;
-static int global_use_mmio = -1;
-
-/* Variables to work-around the Compaq PCI BIOS32 problem. */
-static int compaq_ioaddr, compaq_irq, compaq_device_id = 0x5900;
-static struct net_device *compaq_net_device;
-
-static int vortex_cards_found;
-
-module_param(debug, int, 0);
-module_param(global_options, int, 0);
-module_param_array(options, int, NULL, 0);
-module_param(global_full_duplex, int, 0);
-module_param_array(full_duplex, int, NULL, 0);
-module_param_array(hw_checksums, int, NULL, 0);
-module_param_array(flow_ctrl, int, NULL, 0);
-module_param(global_enable_wol, int, 0);
-module_param_array(enable_wol, int, NULL, 0);
-module_param(rx_copybreak, int, 0);
-module_param(max_interrupt_work, int, 0);
-module_param(compaq_ioaddr, int, 0);
-module_param(compaq_irq, int, 0);
-module_param(compaq_device_id, int, 0);
-module_param(watchdog, int, 0);
-module_param(global_use_mmio, int, 0);
-module_param_array(use_mmio, int, NULL, 0);
-MODULE_PARM_DESC(debug, "3c59x debug level (0-6)");
-MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex");
-MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to all NICs if options is unset");
-MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)");
-MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if full_duplex is unset");
-MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)");
-MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)");
-MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)");
-MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if enable_wol is unset");
-MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt");
-MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds");
-MODULE_PARM_DESC(global_use_mmio, "3c59x: same as use_mmio, but applies to all NICs if options is unset");
-MODULE_PARM_DESC(use_mmio, "3c59x: use memory-mapped PCI I/O resource (0-1)");
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void poll_vortex(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- unsigned long flags;
- local_irq_save(flags);
- (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
- local_irq_restore(flags);
-}
-#endif
-
-#ifdef CONFIG_PM
-
-static int vortex_suspend(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct net_device *ndev = pci_get_drvdata(pdev);
-
- if (!ndev || !netif_running(ndev))
- return 0;
-
- netif_device_detach(ndev);
- vortex_down(ndev, 1);
-
- return 0;
-}
-
-static int vortex_resume(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct net_device *ndev = pci_get_drvdata(pdev);
- int err;
-
- if (!ndev || !netif_running(ndev))
- return 0;
-
- err = vortex_up(ndev);
- if (err)
- return err;
-
- netif_device_attach(ndev);
-
- return 0;
-}
-
-static const struct dev_pm_ops vortex_pm_ops = {
- .suspend = vortex_suspend,
- .resume = vortex_resume,
- .freeze = vortex_suspend,
- .thaw = vortex_resume,
- .poweroff = vortex_suspend,
- .restore = vortex_resume,
-};
-
-#define VORTEX_PM_OPS (&vortex_pm_ops)
-
-#else /* !CONFIG_PM */
-
-#define VORTEX_PM_OPS NULL
-
-#endif /* !CONFIG_PM */
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id vortex_eisa_ids[] = {
- { "TCM5920", CH_3C592 },
- { "TCM5970", CH_3C597 },
- { "" }
-};
-MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
-
-static int __init vortex_eisa_probe(struct device *device)
-{
- void __iomem *ioaddr;
- struct eisa_device *edev;
-
- edev = to_eisa_device(device);
-
- if (!request_region(edev->base_addr, VORTEX_TOTAL_SIZE, DRV_NAME))
- return -EBUSY;
-
- ioaddr = ioport_map(edev->base_addr, VORTEX_TOTAL_SIZE);
-
- if (vortex_probe1(device, ioaddr, ioread16(ioaddr + 0xC88) >> 12,
- edev->id.driver_data, vortex_cards_found)) {
- release_region(edev->base_addr, VORTEX_TOTAL_SIZE);
- return -ENODEV;
- }
-
- vortex_cards_found++;
-
- return 0;
-}
-
-static int __devexit vortex_eisa_remove(struct device *device)
-{
- struct eisa_device *edev;
- struct net_device *dev;
- struct vortex_private *vp;
- void __iomem *ioaddr;
-
- edev = to_eisa_device(device);
- dev = eisa_get_drvdata(edev);
-
- if (!dev) {
- pr_err("vortex_eisa_remove called for Compaq device!\n");
- BUG();
- }
-
- vp = netdev_priv(dev);
- ioaddr = vp->ioaddr;
-
- unregister_netdev(dev);
- iowrite16(TotalReset|0x14, ioaddr + EL3_CMD);
- release_region(dev->base_addr, VORTEX_TOTAL_SIZE);
-
- free_netdev(dev);
- return 0;
-}
-
-static struct eisa_driver vortex_eisa_driver = {
- .id_table = vortex_eisa_ids,
- .driver = {
- .name = "3c59x",
- .probe = vortex_eisa_probe,
- .remove = __devexit_p(vortex_eisa_remove)
- }
-};
-
-#endif /* CONFIG_EISA */
-
-/* returns count found (>= 0), or negative on error */
-static int __init vortex_eisa_init(void)
-{
- int eisa_found = 0;
- int orig_cards_found = vortex_cards_found;
-
-#ifdef CONFIG_EISA
- int err;
-
- err = eisa_driver_register (&vortex_eisa_driver);
- if (!err) {
- /*
- * Because of the way EISA bus is probed, we cannot assume
- * any device have been found when we exit from
- * eisa_driver_register (the bus root driver may not be
- * initialized yet). So we blindly assume something was
- * found, and let the sysfs magic happened...
- */
- eisa_found = 1;
- }
-#endif
-
- /* Special code to work-around the Compaq PCI BIOS32 problem. */
- if (compaq_ioaddr) {
- vortex_probe1(NULL, ioport_map(compaq_ioaddr, VORTEX_TOTAL_SIZE),
- compaq_irq, compaq_device_id, vortex_cards_found++);
- }
-
- return vortex_cards_found - orig_cards_found + eisa_found;
-}
-
-/* returns count (>= 0), or negative on error */
-static int __devinit vortex_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int rc, unit, pci_bar;
- struct vortex_chip_info *vci;
- void __iomem *ioaddr;
-
- /* wake up and enable device */
- rc = pci_enable_device(pdev);
- if (rc < 0)
- goto out;
-
- unit = vortex_cards_found;
-
- if (global_use_mmio < 0 && (unit >= MAX_UNITS || use_mmio[unit] < 0)) {
- /* Determine the default if the user didn't override us */
- vci = &vortex_info_tbl[ent->driver_data];
- pci_bar = vci->drv_flags & (IS_CYCLONE | IS_TORNADO) ? 1 : 0;
- } else if (unit < MAX_UNITS && use_mmio[unit] >= 0)
- pci_bar = use_mmio[unit] ? 1 : 0;
- else
- pci_bar = global_use_mmio ? 1 : 0;
-
- ioaddr = pci_iomap(pdev, pci_bar, 0);
- if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */
- ioaddr = pci_iomap(pdev, 0, 0);
- if (!ioaddr) {
- pci_disable_device(pdev);
- rc = -ENOMEM;
- goto out;
- }
-
- rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq,
- ent->driver_data, unit);
- if (rc < 0) {
- pci_iounmap(pdev, ioaddr);
- pci_disable_device(pdev);
- goto out;
- }
-
- vortex_cards_found++;
-
-out:
- return rc;
-}
-
-static const struct net_device_ops boomrang_netdev_ops = {
- .ndo_open = vortex_open,
- .ndo_stop = vortex_close,
- .ndo_start_xmit = boomerang_start_xmit,
- .ndo_tx_timeout = vortex_tx_timeout,
- .ndo_get_stats = vortex_get_stats,
-#ifdef CONFIG_PCI
- .ndo_do_ioctl = vortex_ioctl,
-#endif
- .ndo_set_rx_mode = set_rx_mode,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = poll_vortex,
-#endif
-};
-
-static const struct net_device_ops vortex_netdev_ops = {
- .ndo_open = vortex_open,
- .ndo_stop = vortex_close,
- .ndo_start_xmit = vortex_start_xmit,
- .ndo_tx_timeout = vortex_tx_timeout,
- .ndo_get_stats = vortex_get_stats,
-#ifdef CONFIG_PCI
- .ndo_do_ioctl = vortex_ioctl,
-#endif
- .ndo_set_rx_mode = set_rx_mode,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = poll_vortex,
-#endif
-};
-
-/*
- * Start up the PCI/EISA device which is described by *gendev.
- * Return 0 on success.
- *
- * NOTE: pdev can be NULL, for the case of a Compaq device
- */
-static int __devinit vortex_probe1(struct device *gendev,
- void __iomem *ioaddr, int irq,
- int chip_idx, int card_idx)
-{
- struct vortex_private *vp;
- int option;
- unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
- int i, step;
- struct net_device *dev;
- static int printed_version;
- int retval, print_info;
- struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx];
- const char *print_name = "3c59x";
- struct pci_dev *pdev = NULL;
- struct eisa_device *edev = NULL;
-
- if (!printed_version) {
- pr_info("%s", version);
- printed_version = 1;
- }
-
- if (gendev) {
- if ((pdev = DEVICE_PCI(gendev))) {
- print_name = pci_name(pdev);
- }
-
- if ((edev = DEVICE_EISA(gendev))) {
- print_name = dev_name(&edev->dev);
- }
- }
-
- dev = alloc_etherdev(sizeof(*vp));
- retval = -ENOMEM;
- if (!dev)
- goto out;
-
- SET_NETDEV_DEV(dev, gendev);
- vp = netdev_priv(dev);
-
- option = global_options;
-
- /* The lower four bits are the media type. */
- if (dev->mem_start) {
- /*
- * The 'options' param is passed in as the third arg to the
- * LILO 'ether=' argument for non-modular use
- */
- option = dev->mem_start;
- }
- else if (card_idx < MAX_UNITS) {
- if (options[card_idx] >= 0)
- option = options[card_idx];
- }
-
- if (option > 0) {
- if (option & 0x8000)
- vortex_debug = 7;
- if (option & 0x4000)
- vortex_debug = 2;
- if (option & 0x0400)
- vp->enable_wol = 1;
- }
-
- print_info = (vortex_debug > 1);
- if (print_info)
- pr_info("See Documentation/networking/vortex.txt\n");
-
- pr_info("%s: 3Com %s %s at %p.\n",
- print_name,
- pdev ? "PCI" : "EISA",
- vci->name,
- ioaddr);
-
- dev->base_addr = (unsigned long)ioaddr;
- dev->irq = irq;
- dev->mtu = mtu;
- vp->ioaddr = ioaddr;
- vp->large_frames = mtu > 1500;
- vp->drv_flags = vci->drv_flags;
- vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
- vp->io_size = vci->io_size;
- vp->card_idx = card_idx;
- vp->window = -1;
-
- /* module list only for Compaq device */
- if (gendev == NULL) {
- compaq_net_device = dev;
- }
-
- /* PCI-only startup logic */
- if (pdev) {
- /* EISA resources already marked, so only PCI needs to do this here */
- /* Ignore return value, because Cardbus drivers already allocate for us */
- if (request_region(dev->base_addr, vci->io_size, print_name) != NULL)
- vp->must_free_region = 1;
-
- /* enable bus-mastering if necessary */
- if (vci->flags & PCI_USES_MASTER)
- pci_set_master(pdev);
-
- if (vci->drv_flags & IS_VORTEX) {
- u8 pci_latency;
- u8 new_latency = 248;
-
- /* Check the PCI latency value. On the 3c590 series the latency timer
- must be set to the maximum value to avoid data corruption that occurs
- when the timer expires during a transfer. This bug exists the Vortex
- chip only. */
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < new_latency) {
- pr_info("%s: Overriding PCI latency timer (CFLT) setting of %d, new value is %d.\n",
- print_name, pci_latency, new_latency);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
- }
- }
- }
-
- spin_lock_init(&vp->lock);
- spin_lock_init(&vp->mii_lock);
- spin_lock_init(&vp->window_lock);
- vp->gendev = gendev;
- vp->mii.dev = dev;
- vp->mii.mdio_read = mdio_read;
- vp->mii.mdio_write = mdio_write;
- vp->mii.phy_id_mask = 0x1f;
- vp->mii.reg_num_mask = 0x1f;
-
- /* Makes sure rings are at least 16 byte aligned. */
- vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
- + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
- &vp->rx_ring_dma);
- retval = -ENOMEM;
- if (!vp->rx_ring)
- goto free_region;
-
- vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
- vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
-
- /* if we are a PCI driver, we store info in pdev->driver_data
- * instead of a module list */
- if (pdev)
- pci_set_drvdata(pdev, dev);
- if (edev)
- eisa_set_drvdata(edev, dev);
-
- vp->media_override = 7;
- if (option >= 0) {
- vp->media_override = ((option & 7) == 2) ? 0 : option & 15;
- if (vp->media_override != 7)
- vp->medialock = 1;
- vp->full_duplex = (option & 0x200) ? 1 : 0;
- vp->bus_master = (option & 16) ? 1 : 0;
- }
-
- if (global_full_duplex > 0)
- vp->full_duplex = 1;
- if (global_enable_wol > 0)
- vp->enable_wol = 1;
-
- if (card_idx < MAX_UNITS) {
- if (full_duplex[card_idx] > 0)
- vp->full_duplex = 1;
- if (flow_ctrl[card_idx] > 0)
- vp->flow_ctrl = 1;
- if (enable_wol[card_idx] > 0)
- vp->enable_wol = 1;
- }
-
- vp->mii.force_media = vp->full_duplex;
- vp->options = option;
- /* Read the station address from the EEPROM. */
- {
- int base;
-
- if (vci->drv_flags & EEPROM_8BIT)
- base = 0x230;
- else if (vci->drv_flags & EEPROM_OFFSET)
- base = EEPROM_Read + 0x30;
- else
- base = EEPROM_Read;
-
- for (i = 0; i < 0x40; i++) {
- int timer;
- window_write16(vp, base + i, 0, Wn0EepromCmd);
- /* Pause for at least 162 us. for the read to take place. */
- for (timer = 10; timer >= 0; timer--) {
- udelay(162);
- if ((window_read16(vp, 0, Wn0EepromCmd) &
- 0x8000) == 0)
- break;
- }
- eeprom[i] = window_read16(vp, 0, Wn0EepromData);
- }
- }
- for (i = 0; i < 0x18; i++)
- checksum ^= eeprom[i];
- checksum = (checksum ^ (checksum >> 8)) & 0xff;
- if (checksum != 0x00) { /* Grrr, needless incompatible change 3Com. */
- while (i < 0x21)
- checksum ^= eeprom[i++];
- checksum = (checksum ^ (checksum >> 8)) & 0xff;
- }
- if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
- pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
- for (i = 0; i < 3; i++)
- ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (print_info)
- pr_cont(" %pM", dev->dev_addr);
- /* Unfortunately an all zero eeprom passes the checksum and this
- gets found in the wild in failure cases. Crypto is hard 8) */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- retval = -EINVAL;
- pr_err("*** EEPROM MAC address is invalid.\n");
- goto free_ring; /* With every pack */
- }
- for (i = 0; i < 6; i++)
- window_write8(vp, dev->dev_addr[i], 2, i);
-
- if (print_info)
- pr_cont(", IRQ %d\n", dev->irq);
- /* Tell them about an invalid IRQ. */
- if (dev->irq <= 0 || dev->irq >= nr_irqs)
- pr_warning(" *** Warning: IRQ %d is unlikely to work! ***\n",
- dev->irq);
-
- step = (window_read8(vp, 4, Wn4_NetDiag) & 0x1e) >> 1;
- if (print_info) {
- pr_info(" product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n",
- eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
- step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
- }
-
-
- if (pdev && vci->drv_flags & HAS_CB_FNS) {
- unsigned short n;
-
- vp->cb_fn_base = pci_iomap(pdev, 2, 0);
- if (!vp->cb_fn_base) {
- retval = -ENOMEM;
- goto free_ring;
- }
-
- if (print_info) {
- pr_info("%s: CardBus functions mapped %16.16llx->%p\n",
- print_name,
- (unsigned long long)pci_resource_start(pdev, 2),
- vp->cb_fn_base);
- }
-
- n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
- if (vp->drv_flags & INVERT_LED_PWR)
- n |= 0x10;
- if (vp->drv_flags & INVERT_MII_PWR)
- n |= 0x4000;
- window_write16(vp, n, 2, Wn2_ResetOptions);
- if (vp->drv_flags & WNO_XCVR_PWR) {
- window_write16(vp, 0x0800, 0, 0);
- }
- }
-
- /* Extract our information from the EEPROM data. */
- vp->info1 = eeprom[13];
- vp->info2 = eeprom[15];
- vp->capabilities = eeprom[16];
-
- if (vp->info1 & 0x8000) {
- vp->full_duplex = 1;
- if (print_info)
- pr_info("Full duplex capable\n");
- }
-
- {
- static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
- unsigned int config;
- vp->available_media = window_read16(vp, 3, Wn3_Options);
- if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */
- vp->available_media = 0x40;
- config = window_read32(vp, 3, Wn3_Config);
- if (print_info) {
- pr_debug(" Internal config register is %4.4x, transceivers %#x.\n",
- config, window_read16(vp, 3, Wn3_Options));
- pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
- 8 << RAM_SIZE(config),
- RAM_WIDTH(config) ? "word" : "byte",
- ram_split[RAM_SPLIT(config)],
- AUTOSELECT(config) ? "autoselect/" : "",
- XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
- media_tbl[XCVR(config)].name);
- }
- vp->default_media = XCVR(config);
- if (vp->default_media == XCVR_NWAY)
- vp->has_nway = 1;
- vp->autoselect = AUTOSELECT(config);
- }
-
- if (vp->media_override != 7) {
- pr_info("%s: Media override to transceiver type %d (%s).\n",
- print_name, vp->media_override,
- media_tbl[vp->media_override].name);
- dev->if_port = vp->media_override;
- } else
- dev->if_port = vp->default_media;
-
- if ((vp->available_media & 0x40) || (vci->drv_flags & HAS_NWAY) ||
- dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
- int phy, phy_idx = 0;
- mii_preamble_required++;
- if (vp->drv_flags & EXTRA_PREAMBLE)
- mii_preamble_required++;
- mdio_sync(vp, 32);
- mdio_read(dev, 24, MII_BMSR);
- for (phy = 0; phy < 32 && phy_idx < 1; phy++) {
- int mii_status, phyx;
-
- /*
- * For the 3c905CX we look at index 24 first, because it bogusly
- * reports an external PHY at all indices
- */
- if (phy == 0)
- phyx = 24;
- else if (phy <= 24)
- phyx = phy - 1;
- else
- phyx = phy;
- mii_status = mdio_read(dev, phyx, MII_BMSR);
- if (mii_status && mii_status != 0xffff) {
- vp->phys[phy_idx++] = phyx;
- if (print_info) {
- pr_info(" MII transceiver found at address %d, status %4x.\n",
- phyx, mii_status);
- }
- if ((mii_status & 0x0040) == 0)
- mii_preamble_required++;
- }
- }
- mii_preamble_required--;
- if (phy_idx == 0) {
- pr_warning(" ***WARNING*** No MII transceivers found!\n");
- vp->phys[0] = 24;
- } else {
- vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE);
- if (vp->full_duplex) {
- /* Only advertise the FD media types. */
- vp->advertising &= ~0x02A0;
- mdio_write(dev, vp->phys[0], 4, vp->advertising);
- }
- }
- vp->mii.phy_id = vp->phys[0];
- }
-
- if (vp->capabilities & CapBusMaster) {
- vp->full_bus_master_tx = 1;
- if (print_info) {
- pr_info(" Enabling bus-master transmits and %s receives.\n",
- (vp->info2 & 1) ? "early" : "whole-frame" );
- }
- vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
- vp->bus_master = 0; /* AKPM: vortex only */
- }
-
- /* The 3c59x-specific entries in the device structure. */
- if (vp->full_bus_master_tx) {
- dev->netdev_ops = &boomrang_netdev_ops;
- /* Actually, it still should work with iommu. */
- if (card_idx < MAX_UNITS &&
- ((hw_checksums[card_idx] == -1 && (vp->drv_flags & HAS_HWCKSM)) ||
- hw_checksums[card_idx] == 1)) {
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
- }
- } else
- dev->netdev_ops = &vortex_netdev_ops;
-
- if (print_info) {
- pr_info("%s: scatter/gather %sabled. h/w checksums %sabled\n",
- print_name,
- (dev->features & NETIF_F_SG) ? "en":"dis",
- (dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
- }
-
- dev->ethtool_ops = &vortex_ethtool_ops;
- dev->watchdog_timeo = (watchdog * HZ) / 1000;
-
- if (pdev) {
- vp->pm_state_valid = 1;
- pci_save_state(VORTEX_PCI(vp));
- acpi_set_WOL(dev);
- }
- retval = register_netdev(dev);
- if (retval == 0)
- return 0;
-
-free_ring:
- pci_free_consistent(pdev,
- sizeof(struct boom_rx_desc) * RX_RING_SIZE
- + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
- vp->rx_ring,
- vp->rx_ring_dma);
-free_region:
- if (vp->must_free_region)
- release_region(dev->base_addr, vci->io_size);
- free_netdev(dev);
- pr_err(PFX "vortex_probe1 fails. Returns %d\n", retval);
-out:
- return retval;
-}
-
-static void
-issue_and_wait(struct net_device *dev, int cmd)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- int i;
-
- iowrite16(cmd, ioaddr + EL3_CMD);
- for (i = 0; i < 2000; i++) {
- if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress))
- return;
- }
-
- /* OK, that didn't work. Do it the slow way. One second */
- for (i = 0; i < 100000; i++) {
- if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) {
- if (vortex_debug > 1)
- pr_info("%s: command 0x%04x took %d usecs\n",
- dev->name, cmd, i * 10);
- return;
- }
- udelay(10);
- }
- pr_err("%s: command 0x%04x did not complete! Status=0x%x\n",
- dev->name, cmd, ioread16(ioaddr + EL3_STATUS));
-}
-
-static void
-vortex_set_duplex(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- pr_info("%s: setting %s-duplex.\n",
- dev->name, (vp->full_duplex) ? "full" : "half");
-
- /* Set the full-duplex bit. */
- window_write16(vp,
- ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
- (vp->large_frames ? 0x40 : 0) |
- ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
- 0x100 : 0),
- 3, Wn3_MAC_Ctrl);
-}
-
-static void vortex_check_media(struct net_device *dev, unsigned int init)
-{
- struct vortex_private *vp = netdev_priv(dev);
- unsigned int ok_to_print = 0;
-
- if (vortex_debug > 3)
- ok_to_print = 1;
-
- if (mii_check_media(&vp->mii, ok_to_print, init)) {
- vp->full_duplex = vp->mii.full_duplex;
- vortex_set_duplex(dev);
- } else if (init) {
- vortex_set_duplex(dev);
- }
-}
-
-static int
-vortex_up(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- unsigned int config;
- int i, mii_reg1, mii_reg5, err = 0;
-
- if (VORTEX_PCI(vp)) {
- pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */
- if (vp->pm_state_valid)
- pci_restore_state(VORTEX_PCI(vp));
- err = pci_enable_device(VORTEX_PCI(vp));
- if (err) {
- pr_warning("%s: Could not enable device\n",
- dev->name);
- goto err_out;
- }
- }
-
- /* Before initializing select the active media port. */
- config = window_read32(vp, 3, Wn3_Config);
-
- if (vp->media_override != 7) {
- pr_info("%s: Media override to transceiver %d (%s).\n",
- dev->name, vp->media_override,
- media_tbl[vp->media_override].name);
- dev->if_port = vp->media_override;
- } else if (vp->autoselect) {
- if (vp->has_nway) {
- if (vortex_debug > 1)
- pr_info("%s: using NWAY device table, not %d\n",
- dev->name, dev->if_port);
- dev->if_port = XCVR_NWAY;
- } else {
- /* Find first available media type, starting with 100baseTx. */
- dev->if_port = XCVR_100baseTx;
- while (! (vp->available_media & media_tbl[dev->if_port].mask))
- dev->if_port = media_tbl[dev->if_port].next;
- if (vortex_debug > 1)
- pr_info("%s: first available media type: %s\n",
- dev->name, media_tbl[dev->if_port].name);
- }
- } else {
- dev->if_port = vp->default_media;
- if (vortex_debug > 1)
- pr_info("%s: using default media %s\n",
- dev->name, media_tbl[dev->if_port].name);
- }
-
- init_timer(&vp->timer);
- vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
- vp->timer.data = (unsigned long)dev;
- vp->timer.function = vortex_timer; /* timer handler */
- add_timer(&vp->timer);
-
- init_timer(&vp->rx_oom_timer);
- vp->rx_oom_timer.data = (unsigned long)dev;
- vp->rx_oom_timer.function = rx_oom_timer;
-
- if (vortex_debug > 1)
- pr_debug("%s: Initial media type %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- vp->full_duplex = vp->mii.force_media;
- config = BFINS(config, dev->if_port, 20, 4);
- if (vortex_debug > 6)
- pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config);
- window_write32(vp, config, 3, Wn3_Config);
-
- if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
- mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR);
- mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
- vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
- vp->mii.full_duplex = vp->full_duplex;
-
- vortex_check_media(dev, 1);
- }
- else
- vortex_set_duplex(dev);
-
- issue_and_wait(dev, TxReset);
- /*
- * Don't reset the PHY - that upsets autonegotiation during DHCP operations.
- */
- issue_and_wait(dev, RxReset|0x04);
-
-
- iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
- if (vortex_debug > 1) {
- pr_debug("%s: vortex_up() irq %d media status %4.4x.\n",
- dev->name, dev->irq, window_read16(vp, 4, Wn4_Media));
- }
-
- /* Set the station address and mask in window 2 each time opened. */
- for (i = 0; i < 6; i++)
- window_write8(vp, dev->dev_addr[i], 2, i);
- for (; i < 12; i+=2)
- window_write16(vp, 0, 2, i);
-
- if (vp->cb_fn_base) {
- unsigned short n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
- if (vp->drv_flags & INVERT_LED_PWR)
- n |= 0x10;
- if (vp->drv_flags & INVERT_MII_PWR)
- n |= 0x4000;
- window_write16(vp, n, 2, Wn2_ResetOptions);
- }
-
- if (dev->if_port == XCVR_10base2)
- /* Start the thinnet transceiver. We should really wait 50ms...*/
- iowrite16(StartCoax, ioaddr + EL3_CMD);
- if (dev->if_port != XCVR_NWAY) {
- window_write16(vp,
- (window_read16(vp, 4, Wn4_Media) &
- ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits,
- 4, Wn4_Media);
- }
-
- /* Switch to the stats window, and clear all stats by reading. */
- iowrite16(StatsDisable, ioaddr + EL3_CMD);
- for (i = 0; i < 10; i++)
- window_read8(vp, 6, i);
- window_read16(vp, 6, 10);
- window_read16(vp, 6, 12);
- /* New: On the Vortex we must also clear the BadSSD counter. */
- window_read8(vp, 4, 12);
- /* ..and on the Boomerang we enable the extra statistics bits. */
- window_write16(vp, 0x0040, 4, Wn4_NetDiag);
-
- if (vp->full_bus_master_rx) { /* Boomerang bus master. */
- vp->cur_rx = vp->dirty_rx = 0;
- /* Initialize the RxEarly register as recommended. */
- iowrite16(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
- iowrite32(0x0020, ioaddr + PktStatus);
- iowrite32(vp->rx_ring_dma, ioaddr + UpListPtr);
- }
- if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
- vp->cur_tx = vp->dirty_tx = 0;
- if (vp->drv_flags & IS_BOOMERANG)
- iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
- /* Clear the Rx, Tx rings. */
- for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */
- vp->rx_ring[i].status = 0;
- for (i = 0; i < TX_RING_SIZE; i++)
- vp->tx_skbuff[i] = NULL;
- iowrite32(0, ioaddr + DownListPtr);
- }
- /* Set receiver mode: presumably accept b-case and phys addr only. */
- set_rx_mode(dev);
- /* enable 802.1q tagged frames */
- set_8021q_mode(dev, 1);
- iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
- iowrite16(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- iowrite16(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
- /* Allow status bits to be seen. */
- vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
- (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
- (vp->full_bus_master_rx ? UpComplete : RxComplete) |
- (vp->bus_master ? DMADone : 0);
- vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable |
- (vp->full_bus_master_rx ? 0 : RxComplete) |
- StatsFull | HostError | TxComplete | IntReq
- | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
- iowrite16(vp->status_enable, ioaddr + EL3_CMD);
- /* Ack all pending events, and set active indicator mask. */
- iowrite16(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
- iowrite16(vp->intr_enable, ioaddr + EL3_CMD);
- if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
- iowrite32(0x8000, vp->cb_fn_base + 4);
- netif_start_queue (dev);
-err_out:
- return err;
-}
-
-static int
-vortex_open(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- int i;
- int retval;
-
- /* Use the now-standard shared IRQ implementation. */
- if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
- boomerang_interrupt : vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
- pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
- goto err;
- }
-
- if (vp->full_bus_master_rx) { /* Boomerang bus master. */
- if (vortex_debug > 2)
- pr_debug("%s: Filling in the Rx ring.\n", dev->name);
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb;
- vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1));
- vp->rx_ring[i].status = 0; /* Clear complete bit. */
- vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
-
- skb = __netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN,
- GFP_KERNEL);
- vp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break; /* Bad news! */
-
- skb_reserve(skb, NET_IP_ALIGN); /* Align IP on 16 byte boundaries */
- vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
- }
- if (i != RX_RING_SIZE) {
- int j;
- pr_emerg("%s: no memory for rx ring\n", dev->name);
- for (j = 0; j < i; j++) {
- if (vp->rx_skbuff[j]) {
- dev_kfree_skb(vp->rx_skbuff[j]);
- vp->rx_skbuff[j] = NULL;
- }
- }
- retval = -ENOMEM;
- goto err_free_irq;
- }
- /* Wrap the ring. */
- vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
- }
-
- retval = vortex_up(dev);
- if (!retval)
- goto out;
-
-err_free_irq:
- free_irq(dev->irq, dev);
-err:
- if (vortex_debug > 1)
- pr_err("%s: vortex_open() fails: returning %d\n", dev->name, retval);
-out:
- return retval;
-}
-
-static void
-vortex_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- int next_tick = 60*HZ;
- int ok = 0;
- int media_status;
-
- if (vortex_debug > 2) {
- pr_debug("%s: Media selection timer tick happened, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
- pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
- }
-
- media_status = window_read16(vp, 4, Wn4_Media);
- switch (dev->if_port) {
- case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx:
- if (media_status & Media_LnkBeat) {
- netif_carrier_on(dev);
- ok = 1;
- if (vortex_debug > 1)
- pr_debug("%s: Media %s has link beat, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
- } else {
- netif_carrier_off(dev);
- if (vortex_debug > 1) {
- pr_debug("%s: Media %s has no link beat, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
- }
- }
- break;
- case XCVR_MII: case XCVR_NWAY:
- {
- ok = 1;
- vortex_check_media(dev, 0);
- }
- break;
- default: /* Other media types handled by Tx timeouts. */
- if (vortex_debug > 1)
- pr_debug("%s: Media %s has no indication, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
- ok = 1;
- }
-
- if (dev->flags & IFF_SLAVE || !netif_carrier_ok(dev))
- next_tick = 5*HZ;
-
- if (vp->medialock)
- goto leave_media_alone;
-
- if (!ok) {
- unsigned int config;
-
- spin_lock_irq(&vp->lock);
-
- do {
- dev->if_port = media_tbl[dev->if_port].next;
- } while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
- if (dev->if_port == XCVR_Default) { /* Go back to default. */
- dev->if_port = vp->default_media;
- if (vortex_debug > 1)
- pr_debug("%s: Media selection failing, using default %s port.\n",
- dev->name, media_tbl[dev->if_port].name);
- } else {
- if (vortex_debug > 1)
- pr_debug("%s: Media selection failed, now trying %s port.\n",
- dev->name, media_tbl[dev->if_port].name);
- next_tick = media_tbl[dev->if_port].wait;
- }
- window_write16(vp,
- (media_status & ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits,
- 4, Wn4_Media);
-
- config = window_read32(vp, 3, Wn3_Config);
- config = BFINS(config, dev->if_port, 20, 4);
- window_write32(vp, config, 3, Wn3_Config);
-
- iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
- ioaddr + EL3_CMD);
- if (vortex_debug > 1)
- pr_debug("wrote 0x%08x to Wn3_Config\n", config);
- /* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */
-
- spin_unlock_irq(&vp->lock);
- }
-
-leave_media_alone:
- if (vortex_debug > 2)
- pr_debug("%s: Media selection timer finished, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- mod_timer(&vp->timer, RUN_AT(next_tick));
- if (vp->deferred)
- iowrite16(FakeIntr, ioaddr + EL3_CMD);
-}
-
-static void vortex_tx_timeout(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
-
- pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, ioread8(ioaddr + TxStatus),
- ioread16(ioaddr + EL3_STATUS));
- pr_err(" diagnostics: net %04x media %04x dma %08x fifo %04x\n",
- window_read16(vp, 4, Wn4_NetDiag),
- window_read16(vp, 4, Wn4_Media),
- ioread32(ioaddr + PktStatus),
- window_read16(vp, 4, Wn4_FIFODiag));
- /* Slight code bloat to be user friendly. */
- if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88)
- pr_err("%s: Transmitter encountered 16 collisions --"
- " network cable problem?\n", dev->name);
- if (ioread16(ioaddr + EL3_STATUS) & IntLatch) {
- pr_err("%s: Interrupt posted but not delivered --"
- " IRQ blocked by another device?\n", dev->name);
- /* Bad idea here.. but we might as well handle a few events. */
- {
- /*
- * Block interrupts because vortex_interrupt does a bare spin_lock()
- */
- unsigned long flags;
- local_irq_save(flags);
- if (vp->full_bus_master_tx)
- boomerang_interrupt(dev->irq, dev);
- else
- vortex_interrupt(dev->irq, dev);
- local_irq_restore(flags);
- }
- }
-
- if (vortex_debug > 0)
- dump_tx_ring(dev);
-
- issue_and_wait(dev, TxReset);
-
- dev->stats.tx_errors++;
- if (vp->full_bus_master_tx) {
- pr_debug("%s: Resetting the Tx ring pointer.\n", dev->name);
- if (vp->cur_tx - vp->dirty_tx > 0 && ioread32(ioaddr + DownListPtr) == 0)
- iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc),
- ioaddr + DownListPtr);
- if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE)
- netif_wake_queue (dev);
- if (vp->drv_flags & IS_BOOMERANG)
- iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
- iowrite16(DownUnstall, ioaddr + EL3_CMD);
- } else {
- dev->stats.tx_dropped++;
- netif_wake_queue(dev);
- }
-
- /* Issue Tx Enable */
- iowrite16(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/*
- * Handle uncommon interrupt sources. This is a separate routine to minimize
- * the cache impact.
- */
-static void
-vortex_error(struct net_device *dev, int status)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- int do_tx_reset = 0, reset_mask = 0;
- unsigned char tx_status = 0;
-
- if (vortex_debug > 2) {
- pr_err("%s: vortex_error(), status=0x%x\n", dev->name, status);
- }
-
- if (status & TxComplete) { /* Really "TxError" for us. */
- tx_status = ioread8(ioaddr + TxStatus);
- /* Presumably a tx-timeout. We must merely re-enable. */
- if (vortex_debug > 2 ||
- (tx_status != 0x88 && vortex_debug > 0)) {
- pr_err("%s: Transmit error, Tx status register %2.2x.\n",
- dev->name, tx_status);
- if (tx_status == 0x82) {
- pr_err("Probably a duplex mismatch. See "
- "Documentation/networking/vortex.txt\n");
- }
- dump_tx_ring(dev);
- }
- if (tx_status & 0x14) dev->stats.tx_fifo_errors++;
- if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
- if (tx_status & 0x08) vp->xstats.tx_max_collisions++;
- iowrite8(0, ioaddr + TxStatus);
- if (tx_status & 0x30) { /* txJabber or txUnderrun */
- do_tx_reset = 1;
- } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */
- do_tx_reset = 1;
- reset_mask = 0x0108; /* Reset interface logic, but not download logic */
- } else { /* Merely re-enable the transmitter. */
- iowrite16(TxEnable, ioaddr + EL3_CMD);
- }
- }
-
- if (status & RxEarly) /* Rx early is unused. */
- iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD);
-
- if (status & StatsFull) { /* Empty statistics. */
- static int DoneDidThat;
- if (vortex_debug > 4)
- pr_debug("%s: Updating stats.\n", dev->name);
- update_stats(ioaddr, dev);
- /* HACK: Disable statistics as an interrupt source. */
- /* This occurs when we have the wrong media type! */
- if (DoneDidThat == 0 &&
- ioread16(ioaddr + EL3_STATUS) & StatsFull) {
- pr_warning("%s: Updating statistics failed, disabling "
- "stats as an interrupt source.\n", dev->name);
- iowrite16(SetIntrEnb |
- (window_read16(vp, 5, 10) & ~StatsFull),
- ioaddr + EL3_CMD);
- vp->intr_enable &= ~StatsFull;
- DoneDidThat++;
- }
- }
- if (status & IntReq) { /* Restore all interrupt sources. */
- iowrite16(vp->status_enable, ioaddr + EL3_CMD);
- iowrite16(vp->intr_enable, ioaddr + EL3_CMD);
- }
- if (status & HostError) {
- u16 fifo_diag;
- fifo_diag = window_read16(vp, 4, Wn4_FIFODiag);
- pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n",
- dev->name, fifo_diag);
- /* Adapter failure requires Tx/Rx reset and reinit. */
- if (vp->full_bus_master_tx) {
- int bus_status = ioread32(ioaddr + PktStatus);
- /* 0x80000000 PCI master abort. */
- /* 0x40000000 PCI target abort. */
- if (vortex_debug)
- pr_err("%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);
-
- /* In this case, blow the card away */
- /* Must not enter D3 or we can't legally issue the reset! */
- vortex_down(dev, 0);
- issue_and_wait(dev, TotalReset | 0xff);
- vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */
- } else if (fifo_diag & 0x0400)
- do_tx_reset = 1;
- if (fifo_diag & 0x3000) {
- /* Reset Rx fifo and upload logic */
- issue_and_wait(dev, RxReset|0x07);
- /* Set the Rx filter to the current state. */
- set_rx_mode(dev);
- /* enable 802.1q VLAN tagged frames */
- set_8021q_mode(dev, 1);
- iowrite16(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- iowrite16(AckIntr | HostError, ioaddr + EL3_CMD);
- }
- }
-
- if (do_tx_reset) {
- issue_and_wait(dev, TxReset|reset_mask);
- iowrite16(TxEnable, ioaddr + EL3_CMD);
- if (!vp->full_bus_master_tx)
- netif_wake_queue(dev);
- }
-}
-
-static netdev_tx_t
-vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
-
- /* Put out the doubleword header... */
- iowrite32(skb->len, ioaddr + TX_FIFO);
- if (vp->bus_master) {
- /* Set the bus-master controller to transfer the packet. */
- int len = (skb->len + 3) & ~3;
- vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len,
- PCI_DMA_TODEVICE);
- spin_lock_irq(&vp->window_lock);
- window_set(vp, 7);
- iowrite32(vp->tx_skb_dma, ioaddr + Wn7_MasterAddr);
- iowrite16(len, ioaddr + Wn7_MasterLen);
- spin_unlock_irq(&vp->window_lock);
- vp->tx_skb = skb;
- iowrite16(StartDMADown, ioaddr + EL3_CMD);
- /* netif_wake_queue() will be called at the DMADone interrupt. */
- } else {
- /* ... and the packet rounded to a doubleword. */
- iowrite32_rep(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb);
- if (ioread16(ioaddr + TxFree) > 1536) {
- netif_start_queue (dev); /* AKPM: redundant? */
- } else {
- /* Interrupt us when the FIFO has room for max-sized packet. */
- netif_stop_queue(dev);
- iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
- }
- }
-
-
- /* Clear the Tx status stack. */
- {
- int tx_status;
- int i = 32;
-
- while (--i > 0 && (tx_status = ioread8(ioaddr + TxStatus)) > 0) {
- if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
- if (vortex_debug > 2)
- pr_debug("%s: Tx error, status %2.2x.\n",
- dev->name, tx_status);
- if (tx_status & 0x04) dev->stats.tx_fifo_errors++;
- if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
- if (tx_status & 0x30) {
- issue_and_wait(dev, TxReset);
- }
- iowrite16(TxEnable, ioaddr + EL3_CMD);
- }
- iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */
- }
- }
- return NETDEV_TX_OK;
-}
-
-static netdev_tx_t
-boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- /* Calculate the next Tx descriptor entry. */
- int entry = vp->cur_tx % TX_RING_SIZE;
- struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
- unsigned long flags;
-
- if (vortex_debug > 6) {
- pr_debug("boomerang_start_xmit()\n");
- pr_debug("%s: Trying to send a packet, Tx index %d.\n",
- dev->name, vp->cur_tx);
- }
-
- /*
- * We can't allow a recursion from our interrupt handler back into the
- * tx routine, as they take the same spin lock, and that causes
- * deadlock. Just return NETDEV_TX_BUSY and let the stack try again in
- * a bit
- */
- if (vp->handling_irq)
- return NETDEV_TX_BUSY;
-
- if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) {
- if (vortex_debug > 0)
- pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n",
- dev->name);
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
- }
-
- vp->tx_skbuff[entry] = skb;
-
- vp->tx_ring[entry].next = 0;
-#if DO_ZEROCOPY
- if (skb->ip_summed != CHECKSUM_PARTIAL)
- vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
- else
- vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum);
-
- if (!skb_shinfo(skb)->nr_frags) {
- vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data,
- skb->len, PCI_DMA_TODEVICE));
- vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len | LAST_FRAG);
- } else {
- int i;
-
- vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data,
- skb_headlen(skb), PCI_DMA_TODEVICE));
- vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb_headlen(skb));
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
- vp->tx_ring[entry].frag[i+1].addr =
- cpu_to_le32(pci_map_single(
- VORTEX_PCI(vp),
- (void *)skb_frag_address(frag),
- skb_frag_size(frag), PCI_DMA_TODEVICE));
-
- if (i == skb_shinfo(skb)->nr_frags-1)
- vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(skb_frag_size(frag)|LAST_FRAG);
- else
- vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(skb_frag_size(frag));
- }
- }
-#else
- vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, skb->len, PCI_DMA_TODEVICE));
- vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
- vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
-#endif
-
- spin_lock_irqsave(&vp->lock, flags);
- /* Wait for the stall to complete. */
- issue_and_wait(dev, DownStall);
- prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc));
- if (ioread32(ioaddr + DownListPtr) == 0) {
- iowrite32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr);
- vp->queued_packet++;
- }
-
- vp->cur_tx++;
- if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
- netif_stop_queue (dev);
- } else { /* Clear previous interrupt enable. */
-#if defined(tx_interrupt_mitigation)
- /* Dubious. If in boomeang_interrupt "faster" cyclone ifdef
- * were selected, this would corrupt DN_COMPLETE. No?
- */
- prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
-#endif
- }
- iowrite16(DownUnstall, ioaddr + EL3_CMD);
- spin_unlock_irqrestore(&vp->lock, flags);
- return NETDEV_TX_OK;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-
-/*
- * This is the ISR for the vortex series chips.
- * full_bus_master_tx == 0 && full_bus_master_rx == 0
- */
-
-static irqreturn_t
-vortex_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr;
- int status;
- int work_done = max_interrupt_work;
- int handled = 0;
-
- ioaddr = vp->ioaddr;
- spin_lock(&vp->lock);
-
- status = ioread16(ioaddr + EL3_STATUS);
-
- if (vortex_debug > 6)
- pr_debug("vortex_interrupt(). status=0x%4x\n", status);
-
- if ((status & IntLatch) == 0)
- goto handler_exit; /* No interrupt: shared IRQs cause this */
- handled = 1;
-
- if (status & IntReq) {
- status |= vp->deferred;
- vp->deferred = 0;
- }
-
- if (status == 0xffff) /* h/w no longer present (hotplug)? */
- goto handler_exit;
-
- if (vortex_debug > 4)
- pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
- dev->name, status, ioread8(ioaddr + Timer));
-
- spin_lock(&vp->window_lock);
- window_set(vp, 7);
-
- do {
- if (vortex_debug > 5)
- pr_debug("%s: In interrupt loop, status %4.4x.\n",
- dev->name, status);
- if (status & RxComplete)
- vortex_rx(dev);
-
- if (status & TxAvailable) {
- if (vortex_debug > 5)
- pr_debug(" TX room bit was handled.\n");
- /* There's room in the FIFO for a full-sized packet. */
- iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- netif_wake_queue (dev);
- }
-
- if (status & DMADone) {
- if (ioread16(ioaddr + Wn7_MasterStatus) & 0x1000) {
- iowrite16(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- pci_unmap_single(VORTEX_PCI(vp), vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(vp->tx_skb); /* Release the transferred buffer */
- if (ioread16(ioaddr + TxFree) > 1536) {
- /*
- * AKPM: FIXME: I don't think we need this. If the queue was stopped due to
- * insufficient FIFO room, the TxAvailable test will succeed and call
- * netif_wake_queue()
- */
- netif_wake_queue(dev);
- } else { /* Interrupt when FIFO has room for max-sized packet. */
- iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
- netif_stop_queue(dev);
- }
- }
- }
- /* Check for all uncommon interrupts at once. */
- if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
- if (status == 0xffff)
- break;
- if (status & RxEarly)
- vortex_rx(dev);
- spin_unlock(&vp->window_lock);
- vortex_error(dev, status);
- spin_lock(&vp->window_lock);
- window_set(vp, 7);
- }
-
- if (--work_done < 0) {
- pr_warning("%s: Too much work in interrupt, status %4.4x.\n",
- dev->name, status);
- /* Disable all pending interrupts. */
- do {
- vp->deferred |= status;
- iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable),
- ioaddr + EL3_CMD);
- iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
- } while ((status = ioread16(ioaddr + EL3_CMD)) & IntLatch);
- /* The timer will reenable interrupts. */
- mod_timer(&vp->timer, jiffies + 1*HZ);
- break;
- }
- /* Acknowledge the IRQ. */
- iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
- } while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-
- spin_unlock(&vp->window_lock);
-
- if (vortex_debug > 4)
- pr_debug("%s: exiting interrupt, status %4.4x.\n",
- dev->name, status);
-handler_exit:
- spin_unlock(&vp->lock);
- return IRQ_RETVAL(handled);
-}
-
-/*
- * This is the ISR for the boomerang series chips.
- * full_bus_master_tx == 1 && full_bus_master_rx == 1
- */
-
-static irqreturn_t
-boomerang_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr;
- int status;
- int work_done = max_interrupt_work;
-
- ioaddr = vp->ioaddr;
-
-
- /*
- * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout
- * and boomerang_start_xmit
- */
- spin_lock(&vp->lock);
- vp->handling_irq = 1;
-
- status = ioread16(ioaddr + EL3_STATUS);
-
- if (vortex_debug > 6)
- pr_debug("boomerang_interrupt. status=0x%4x\n", status);
-
- if ((status & IntLatch) == 0)
- goto handler_exit; /* No interrupt: shared IRQs can cause this */
-
- if (status == 0xffff) { /* h/w no longer present (hotplug)? */
- if (vortex_debug > 1)
- pr_debug("boomerang_interrupt(1): status = 0xffff\n");
- goto handler_exit;
- }
-
- if (status & IntReq) {
- status |= vp->deferred;
- vp->deferred = 0;
- }
-
- if (vortex_debug > 4)
- pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
- dev->name, status, ioread8(ioaddr + Timer));
- do {
- if (vortex_debug > 5)
- pr_debug("%s: In interrupt loop, status %4.4x.\n",
- dev->name, status);
- if (status & UpComplete) {
- iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD);
- if (vortex_debug > 5)
- pr_debug("boomerang_interrupt->boomerang_rx\n");
- boomerang_rx(dev);
- }
-
- if (status & DownComplete) {
- unsigned int dirty_tx = vp->dirty_tx;
-
- iowrite16(AckIntr | DownComplete, ioaddr + EL3_CMD);
- while (vp->cur_tx - dirty_tx > 0) {
- int entry = dirty_tx % TX_RING_SIZE;
-#if 1 /* AKPM: the latter is faster, but cyclone-only */
- if (ioread32(ioaddr + DownListPtr) ==
- vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc))
- break; /* It still hasn't been processed. */
-#else
- if ((vp->tx_ring[entry].status & DN_COMPLETE) == 0)
- break; /* It still hasn't been processed. */
-#endif
-
- if (vp->tx_skbuff[entry]) {
- struct sk_buff *skb = vp->tx_skbuff[entry];
-#if DO_ZEROCOPY
- int i;
- for (i=0; i<=skb_shinfo(skb)->nr_frags; i++)
- pci_unmap_single(VORTEX_PCI(vp),
- le32_to_cpu(vp->tx_ring[entry].frag[i].addr),
- le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF,
- PCI_DMA_TODEVICE);
-#else
- pci_unmap_single(VORTEX_PCI(vp),
- le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
-#endif
- dev_kfree_skb_irq(skb);
- vp->tx_skbuff[entry] = NULL;
- } else {
- pr_debug("boomerang_interrupt: no skb!\n");
- }
- /* dev->stats.tx_packets++; Counted below. */
- dirty_tx++;
- }
- vp->dirty_tx = dirty_tx;
- if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) {
- if (vortex_debug > 6)
- pr_debug("boomerang_interrupt: wake queue\n");
- netif_wake_queue (dev);
- }
- }
-
- /* Check for all uncommon interrupts at once. */
- if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq))
- vortex_error(dev, status);
-
- if (--work_done < 0) {
- pr_warning("%s: Too much work in interrupt, status %4.4x.\n",
- dev->name, status);
- /* Disable all pending interrupts. */
- do {
- vp->deferred |= status;
- iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable),
- ioaddr + EL3_CMD);
- iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
- } while ((status = ioread16(ioaddr + EL3_CMD)) & IntLatch);
- /* The timer will reenable interrupts. */
- mod_timer(&vp->timer, jiffies + 1*HZ);
- break;
- }
- /* Acknowledge the IRQ. */
- iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
- if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
- iowrite32(0x8000, vp->cb_fn_base + 4);
-
- } while ((status = ioread16(ioaddr + EL3_STATUS)) & IntLatch);
-
- if (vortex_debug > 4)
- pr_debug("%s: exiting interrupt, status %4.4x.\n",
- dev->name, status);
-handler_exit:
- vp->handling_irq = 0;
- spin_unlock(&vp->lock);
- return IRQ_HANDLED;
-}
-
-static int vortex_rx(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- int i;
- short rx_status;
-
- if (vortex_debug > 5)
- pr_debug("vortex_rx(): status %4.4x, rx_status %4.4x.\n",
- ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus));
- while ((rx_status = ioread16(ioaddr + RxStatus)) > 0) {
- if (rx_status & 0x4000) { /* Error, update stats. */
- unsigned char rx_error = ioread8(ioaddr + RxErrors);
- if (vortex_debug > 2)
- pr_debug(" Rx error: status %2.2x.\n", rx_error);
- dev->stats.rx_errors++;
- if (rx_error & 0x01) dev->stats.rx_over_errors++;
- if (rx_error & 0x02) dev->stats.rx_length_errors++;
- if (rx_error & 0x04) dev->stats.rx_frame_errors++;
- if (rx_error & 0x08) dev->stats.rx_crc_errors++;
- if (rx_error & 0x10) dev->stats.rx_length_errors++;
- } else {
- /* The packet length: up to 4.5K!. */
- int pkt_len = rx_status & 0x1fff;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 5);
- if (vortex_debug > 4)
- pr_debug("Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
- if (skb != NULL) {
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- /* 'skb_put()' points to the start of sk_buff data area. */
- if (vp->bus_master &&
- ! (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)) {
- dma_addr_t dma = pci_map_single(VORTEX_PCI(vp), skb_put(skb, pkt_len),
- pkt_len, PCI_DMA_FROMDEVICE);
- iowrite32(dma, ioaddr + Wn7_MasterAddr);
- iowrite16((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
- iowrite16(StartDMAUp, ioaddr + EL3_CMD);
- while (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)
- ;
- pci_unmap_single(VORTEX_PCI(vp), dma, pkt_len, PCI_DMA_FROMDEVICE);
- } else {
- ioread32_rep(ioaddr + RX_FIFO,
- skb_put(skb, pkt_len),
- (pkt_len + 3) >> 2);
- }
- iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- /* Wait a limited time to go to next packet. */
- for (i = 200; i >= 0; i--)
- if ( ! (ioread16(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- continue;
- } else if (vortex_debug > 0)
- pr_notice("%s: No memory to allocate a sk_buff of size %d.\n",
- dev->name, pkt_len);
- dev->stats.rx_dropped++;
- }
- issue_and_wait(dev, RxDiscard);
- }
-
- return 0;
-}
-
-static int
-boomerang_rx(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- int entry = vp->cur_rx % RX_RING_SIZE;
- void __iomem *ioaddr = vp->ioaddr;
- int rx_status;
- int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
-
- if (vortex_debug > 5)
- pr_debug("boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS));
-
- while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
- if (--rx_work_limit < 0)
- break;
- if (rx_status & RxDError) { /* Error, update stats. */
- unsigned char rx_error = rx_status >> 16;
- if (vortex_debug > 2)
- pr_debug(" Rx error: status %2.2x.\n", rx_error);
- dev->stats.rx_errors++;
- if (rx_error & 0x01) dev->stats.rx_over_errors++;
- if (rx_error & 0x02) dev->stats.rx_length_errors++;
- if (rx_error & 0x04) dev->stats.rx_frame_errors++;
- if (rx_error & 0x08) dev->stats.rx_crc_errors++;
- if (rx_error & 0x10) dev->stats.rx_length_errors++;
- } else {
- /* The packet length: up to 4.5K!. */
- int pkt_len = rx_status & 0x1fff;
- struct sk_buff *skb;
- dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr);
-
- if (vortex_debug > 4)
- pr_debug("Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
-
- /* Check if the packet is long enough to just accept without
- copying to a properly sized skbuff. */
- if (pkt_len < rx_copybreak &&
- (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) {
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
- /* 'skb_put()' points to the start of sk_buff data area. */
- memcpy(skb_put(skb, pkt_len),
- vp->rx_skbuff[entry]->data,
- pkt_len);
- pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
- vp->rx_copy++;
- } else {
- /* Pass up the skbuff already on the Rx ring. */
- skb = vp->rx_skbuff[entry];
- vp->rx_skbuff[entry] = NULL;
- skb_put(skb, pkt_len);
- pci_unmap_single(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
- vp->rx_nocopy++;
- }
- skb->protocol = eth_type_trans(skb, dev);
- { /* Use hardware checksum info. */
- int csum_bits = rx_status & 0xee000000;
- if (csum_bits &&
- (csum_bits == (IPChksumValid | TCPChksumValid) ||
- csum_bits == (IPChksumValid | UDPChksumValid))) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- vp->rx_csumhits++;
- }
- }
- netif_rx(skb);
- dev->stats.rx_packets++;
- }
- entry = (++vp->cur_rx) % RX_RING_SIZE;
- }
- /* Refill the Rx ring buffers. */
- for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {
- struct sk_buff *skb;
- entry = vp->dirty_rx % RX_RING_SIZE;
- if (vp->rx_skbuff[entry] == NULL) {
- skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
- if (skb == NULL) {
- static unsigned long last_jif;
- if (time_after(jiffies, last_jif + 10 * HZ)) {
- pr_warning("%s: memory shortage\n", dev->name);
- last_jif = jiffies;
- }
- if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)
- mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1));
- break; /* Bad news! */
- }
-
- vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
- vp->rx_skbuff[entry] = skb;
- }
- vp->rx_ring[entry].status = 0; /* Clear complete bit. */
- iowrite16(UpUnstall, ioaddr + EL3_CMD);
- }
- return 0;
-}
-
-/*
- * If we've hit a total OOM refilling the Rx ring we poll once a second
- * for some memory. Otherwise there is no way to restart the rx process.
- */
-static void
-rx_oom_timer(unsigned long arg)
-{
- struct net_device *dev = (struct net_device *)arg;
- struct vortex_private *vp = netdev_priv(dev);
-
- spin_lock_irq(&vp->lock);
- if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */
- boomerang_rx(dev);
- if (vortex_debug > 1) {
- pr_debug("%s: rx_oom_timer %s\n", dev->name,
- ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying");
- }
- spin_unlock_irq(&vp->lock);
-}
-
-static void
-vortex_down(struct net_device *dev, int final_down)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
-
- netif_stop_queue (dev);
-
- del_timer_sync(&vp->rx_oom_timer);
- del_timer_sync(&vp->timer);
-
- /* Turn off statistics ASAP. We update dev->stats below. */
- iowrite16(StatsDisable, ioaddr + EL3_CMD);
-
- /* Disable the receiver and transmitter. */
- iowrite16(RxDisable, ioaddr + EL3_CMD);
- iowrite16(TxDisable, ioaddr + EL3_CMD);
-
- /* Disable receiving 802.1q tagged frames */
- set_8021q_mode(dev, 0);
-
- if (dev->if_port == XCVR_10base2)
- /* Turn off thinnet power. Green! */
- iowrite16(StopCoax, ioaddr + EL3_CMD);
-
- iowrite16(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
- update_stats(ioaddr, dev);
- if (vp->full_bus_master_rx)
- iowrite32(0, ioaddr + UpListPtr);
- if (vp->full_bus_master_tx)
- iowrite32(0, ioaddr + DownListPtr);
-
- if (final_down && VORTEX_PCI(vp)) {
- vp->pm_state_valid = 1;
- pci_save_state(VORTEX_PCI(vp));
- acpi_set_WOL(dev);
- }
-}
-
-static int
-vortex_close(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- int i;
-
- if (netif_device_present(dev))
- vortex_down(dev, 1);
-
- if (vortex_debug > 1) {
- pr_debug("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
- dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus));
- pr_debug("%s: vortex close stats: rx_nocopy %d rx_copy %d"
- " tx_queued %d Rx pre-checksummed %d.\n",
- dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits);
- }
-
-#if DO_ZEROCOPY
- if (vp->rx_csumhits &&
- (vp->drv_flags & HAS_HWCKSM) == 0 &&
- (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) {
- pr_warning("%s supports hardware checksums, and we're not using them!\n", dev->name);
- }
-#endif
-
- free_irq(dev->irq, dev);
-
- if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
- for (i = 0; i < RX_RING_SIZE; i++)
- if (vp->rx_skbuff[i]) {
- pci_unmap_single( VORTEX_PCI(vp), le32_to_cpu(vp->rx_ring[i].addr),
- PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(vp->rx_skbuff[i]);
- vp->rx_skbuff[i] = NULL;
- }
- }
- if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
- for (i = 0; i < TX_RING_SIZE; i++) {
- if (vp->tx_skbuff[i]) {
- struct sk_buff *skb = vp->tx_skbuff[i];
-#if DO_ZEROCOPY
- int k;
-
- for (k=0; k<=skb_shinfo(skb)->nr_frags; k++)
- pci_unmap_single(VORTEX_PCI(vp),
- le32_to_cpu(vp->tx_ring[i].frag[k].addr),
- le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF,
- PCI_DMA_TODEVICE);
-#else
- pci_unmap_single(VORTEX_PCI(vp), le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
-#endif
- dev_kfree_skb(skb);
- vp->tx_skbuff[i] = NULL;
- }
- }
- }
-
- return 0;
-}
-
-static void
-dump_tx_ring(struct net_device *dev)
-{
- if (vortex_debug > 0) {
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
-
- if (vp->full_bus_master_tx) {
- int i;
- int stalled = ioread32(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */
-
- pr_err(" Flags; bus-master %d, dirty %d(%d) current %d(%d)\n",
- vp->full_bus_master_tx,
- vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE,
- vp->cur_tx, vp->cur_tx % TX_RING_SIZE);
- pr_err(" Transmit list %8.8x vs. %p.\n",
- ioread32(ioaddr + DownListPtr),
- &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
- issue_and_wait(dev, DownStall);
- for (i = 0; i < TX_RING_SIZE; i++) {
- unsigned int length;
-
-#if DO_ZEROCOPY
- length = le32_to_cpu(vp->tx_ring[i].frag[0].length);
-#else
- length = le32_to_cpu(vp->tx_ring[i].length);
-#endif
- pr_err(" %d: @%p length %8.8x status %8.8x\n",
- i, &vp->tx_ring[i], length,
- le32_to_cpu(vp->tx_ring[i].status));
- }
- if (!stalled)
- iowrite16(DownUnstall, ioaddr + EL3_CMD);
- }
- }
-}
-
-static struct net_device_stats *vortex_get_stats(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- unsigned long flags;
-
- if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */
- spin_lock_irqsave (&vp->lock, flags);
- update_stats(ioaddr, dev);
- spin_unlock_irqrestore (&vp->lock, flags);
- }
- return &dev->stats;
-}
-
-/* Update statistics.
- Unlike with the EL3 we need not worry about interrupts changing
- the window setting from underneath us, but we must still guard
- against a race condition with a StatsUpdate interrupt updating the
- table. This is done by checking that the ASM (!) code generated uses
- atomic updates with '+='.
- */
-static void update_stats(void __iomem *ioaddr, struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- /* Unlike the 3c5x9 we need not turn off stats updates while reading. */
- /* Switch to the stats window, and read everything. */
- dev->stats.tx_carrier_errors += window_read8(vp, 6, 0);
- dev->stats.tx_heartbeat_errors += window_read8(vp, 6, 1);
- dev->stats.tx_window_errors += window_read8(vp, 6, 4);
- dev->stats.rx_fifo_errors += window_read8(vp, 6, 5);
- dev->stats.tx_packets += window_read8(vp, 6, 6);
- dev->stats.tx_packets += (window_read8(vp, 6, 9) &
- 0x30) << 4;
- /* Rx packets */ window_read8(vp, 6, 7); /* Must read to clear */
- /* Don't bother with register 9, an extension of registers 6&7.
- If we do use the 6&7 values the atomic update assumption above
- is invalid. */
- dev->stats.rx_bytes += window_read16(vp, 6, 10);
- dev->stats.tx_bytes += window_read16(vp, 6, 12);
- /* Extra stats for get_ethtool_stats() */
- vp->xstats.tx_multiple_collisions += window_read8(vp, 6, 2);
- vp->xstats.tx_single_collisions += window_read8(vp, 6, 3);
- vp->xstats.tx_deferred += window_read8(vp, 6, 8);
- vp->xstats.rx_bad_ssd += window_read8(vp, 4, 12);
-
- dev->stats.collisions = vp->xstats.tx_multiple_collisions
- + vp->xstats.tx_single_collisions
- + vp->xstats.tx_max_collisions;
-
- {
- u8 up = window_read8(vp, 4, 13);
- dev->stats.rx_bytes += (up & 0x0f) << 16;
- dev->stats.tx_bytes += (up & 0xf0) << 12;
- }
-}
-
-static int vortex_nway_reset(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- return mii_nway_restart(&vp->mii);
-}
-
-static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- return mii_ethtool_gset(&vp->mii, cmd);
-}
-
-static int vortex_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- return mii_ethtool_sset(&vp->mii, cmd);
-}
-
-static u32 vortex_get_msglevel(struct net_device *dev)
-{
- return vortex_debug;
-}
-
-static void vortex_set_msglevel(struct net_device *dev, u32 dbg)
-{
- vortex_debug = dbg;
-}
-
-static int vortex_get_sset_count(struct net_device *dev, int sset)
-{
- switch (sset) {
- case ETH_SS_STATS:
- return VORTEX_NUM_STATS;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-static void vortex_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 *data)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- unsigned long flags;
-
- spin_lock_irqsave(&vp->lock, flags);
- update_stats(ioaddr, dev);
- spin_unlock_irqrestore(&vp->lock, flags);
-
- data[0] = vp->xstats.tx_deferred;
- data[1] = vp->xstats.tx_max_collisions;
- data[2] = vp->xstats.tx_multiple_collisions;
- data[3] = vp->xstats.tx_single_collisions;
- data[4] = vp->xstats.rx_bad_ssd;
-}
-
-
-static void vortex_get_strings(struct net_device *dev, u32 stringset, u8 *data)
-{
- switch (stringset) {
- case ETH_SS_STATS:
- memcpy(data, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
- break;
- default:
- WARN_ON(1);
- break;
- }
-}
-
-static void vortex_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
- if (VORTEX_PCI(vp)) {
- strlcpy(info->bus_info, pci_name(VORTEX_PCI(vp)),
- sizeof(info->bus_info));
- } else {
- if (VORTEX_EISA(vp))
- strlcpy(info->bus_info, dev_name(vp->gendev),
- sizeof(info->bus_info));
- else
- snprintf(info->bus_info, sizeof(info->bus_info),
- "EISA 0x%lx %d", dev->base_addr, dev->irq);
- }
-}
-
-static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- if (!VORTEX_PCI(vp))
- return;
-
- wol->supported = WAKE_MAGIC;
-
- wol->wolopts = 0;
- if (vp->enable_wol)
- wol->wolopts |= WAKE_MAGIC;
-}
-
-static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct vortex_private *vp = netdev_priv(dev);
-
- if (!VORTEX_PCI(vp))
- return -EOPNOTSUPP;
-
- if (wol->wolopts & ~WAKE_MAGIC)
- return -EINVAL;
-
- if (wol->wolopts & WAKE_MAGIC)
- vp->enable_wol = 1;
- else
- vp->enable_wol = 0;
- acpi_set_WOL(dev);
-
- return 0;
-}
-
-static const struct ethtool_ops vortex_ethtool_ops = {
- .get_drvinfo = vortex_get_drvinfo,
- .get_strings = vortex_get_strings,
- .get_msglevel = vortex_get_msglevel,
- .set_msglevel = vortex_set_msglevel,
- .get_ethtool_stats = vortex_get_ethtool_stats,
- .get_sset_count = vortex_get_sset_count,
- .get_settings = vortex_get_settings,
- .set_settings = vortex_set_settings,
- .get_link = ethtool_op_get_link,
- .nway_reset = vortex_nway_reset,
- .get_wol = vortex_get_wol,
- .set_wol = vortex_set_wol,
-};
-
-#ifdef CONFIG_PCI
-/*
- * Must power the device up to do MDIO operations
- */
-static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- int err;
- struct vortex_private *vp = netdev_priv(dev);
- pci_power_t state = 0;
-
- if(VORTEX_PCI(vp))
- state = VORTEX_PCI(vp)->current_state;
-
- /* The kernel core really should have pci_get_power_state() */
-
- if(state != 0)
- pci_set_power_state(VORTEX_PCI(vp), PCI_D0);
- err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL);
- if(state != 0)
- pci_set_power_state(VORTEX_PCI(vp), state);
-
- return err;
-}
-#endif
-
-
-/* Pre-Cyclone chips have no documented multicast filter, so the only
- multicast setting is to receive all multicast frames. At least
- the chip has a very clean way to set the mode, unlike many others. */
-static void set_rx_mode(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- int new_mode;
-
- if (dev->flags & IFF_PROMISC) {
- if (vortex_debug > 3)
- pr_notice("%s: Setting promiscuous mode.\n", dev->name);
- new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
- } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
- new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
- } else
- new_mode = SetRxFilter | RxStation | RxBroadcast;
-
- iowrite16(new_mode, ioaddr + EL3_CMD);
-}
-
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-/* Setup the card so that it can receive frames with an 802.1q VLAN tag.
- Note that this must be done after each RxReset due to some backwards
- compatibility logic in the Cyclone and Tornado ASICs */
-
-/* The Ethernet Type used for 802.1q tagged frames */
-#define VLAN_ETHER_TYPE 0x8100
-
-static void set_8021q_mode(struct net_device *dev, int enable)
-{
- struct vortex_private *vp = netdev_priv(dev);
- int mac_ctrl;
-
- if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) {
- /* cyclone and tornado chipsets can recognize 802.1q
- * tagged frames and treat them correctly */
-
- int max_pkt_size = dev->mtu+14; /* MTU+Ethernet header */
- if (enable)
- max_pkt_size += 4; /* 802.1Q VLAN tag */
-
- window_write16(vp, max_pkt_size, 3, Wn3_MaxPktSize);
-
- /* set VlanEtherType to let the hardware checksumming
- treat tagged frames correctly */
- window_write16(vp, VLAN_ETHER_TYPE, 7, Wn7_VlanEtherType);
- } else {
- /* on older cards we have to enable large frames */
-
- vp->large_frames = dev->mtu > 1500 || enable;
-
- mac_ctrl = window_read16(vp, 3, Wn3_MAC_Ctrl);
- if (vp->large_frames)
- mac_ctrl |= 0x40;
- else
- mac_ctrl &= ~0x40;
- window_write16(vp, mac_ctrl, 3, Wn3_MAC_Ctrl);
- }
-}
-#else
-
-static void set_8021q_mode(struct net_device *dev, int enable)
-{
-}
-
-
-#endif
-
-/* MII transceiver control section.
- Read and write the MII registers using software-generated serial
- MDIO protocol. See the MII specifications or DP83840A data sheet
- for details. */
-
-/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
- met by back-to-back PCI I/O cycles, but we insert a delay to avoid
- "overclocking" issues. */
-static void mdio_delay(struct vortex_private *vp)
-{
- window_read32(vp, 4, Wn4_PhysicalMgmt);
-}
-
-#define MDIO_SHIFT_CLK 0x01
-#define MDIO_DIR_WRITE 0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ 0x02
-#define MDIO_ENB_IN 0x00
-
-/* Generate the preamble required for initial synchronization and
- a few older transceivers. */
-static void mdio_sync(struct vortex_private *vp, int bits)
-{
- /* Establish sync by sending at least 32 logic ones. */
- while (-- bits >= 0) {
- window_write16(vp, MDIO_DATA_WRITE1, 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- window_write16(vp, MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK,
- 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- }
-}
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
- int i;
- struct vortex_private *vp = netdev_priv(dev);
- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- unsigned int retval = 0;
-
- spin_lock_bh(&vp->mii_lock);
-
- if (mii_preamble_required)
- mdio_sync(vp, 32);
-
- /* Shift the read command bits out. */
- for (i = 14; i >= 0; i--) {
- int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- window_write16(vp, dataval | MDIO_SHIFT_CLK,
- 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- }
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- retval = (retval << 1) |
- ((window_read16(vp, 4, Wn4_PhysicalMgmt) &
- MDIO_DATA_READ) ? 1 : 0);
- window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
- 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- }
-
- spin_unlock_bh(&vp->mii_lock);
-
- return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
- struct vortex_private *vp = netdev_priv(dev);
- int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- int i;
-
- spin_lock_bh(&vp->mii_lock);
-
- if (mii_preamble_required)
- mdio_sync(vp, 32);
-
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- window_write16(vp, dataval | MDIO_SHIFT_CLK,
- 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- }
- /* Leave the interface idle. */
- for (i = 1; i >= 0; i--) {
- window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
- 4, Wn4_PhysicalMgmt);
- mdio_delay(vp);
- }
-
- spin_unlock_bh(&vp->mii_lock);
-}
-
-/* ACPI: Advanced Configuration and Power Interface. */
-/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
-static void acpi_set_WOL(struct net_device *dev)
-{
- struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
-
- device_set_wakeup_enable(vp->gendev, vp->enable_wol);
-
- if (vp->enable_wol) {
- /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
- window_write16(vp, 2, 7, 0x0c);
- /* The RxFilter must accept the WOL frames. */
- iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
- iowrite16(RxEnable, ioaddr + EL3_CMD);
-
- if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) {
- pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp)));
-
- vp->enable_wol = 0;
- return;
- }
-
- if (VORTEX_PCI(vp)->current_state < PCI_D3hot)
- return;
-
- /* Change the power state to D3; RxEnable doesn't take effect. */
- pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
- }
-}
-
-
-static void __devexit vortex_remove_one(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct vortex_private *vp;
-
- if (!dev) {
- pr_err("vortex_remove_one called for Compaq device!\n");
- BUG();
- }
-
- vp = netdev_priv(dev);
-
- if (vp->cb_fn_base)
- pci_iounmap(VORTEX_PCI(vp), vp->cb_fn_base);
-
- unregister_netdev(dev);
-
- if (VORTEX_PCI(vp)) {
- pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */
- if (vp->pm_state_valid)
- pci_restore_state(VORTEX_PCI(vp));
- pci_disable_device(VORTEX_PCI(vp));
- }
- /* Should really use issue_and_wait() here */
- iowrite16(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14),
- vp->ioaddr + EL3_CMD);
-
- pci_iounmap(VORTEX_PCI(vp), vp->ioaddr);
-
- pci_free_consistent(pdev,
- sizeof(struct boom_rx_desc) * RX_RING_SIZE
- + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
- vp->rx_ring,
- vp->rx_ring_dma);
- if (vp->must_free_region)
- release_region(dev->base_addr, vp->io_size);
- free_netdev(dev);
-}
-
-
-static struct pci_driver vortex_driver = {
- .name = "3c59x",
- .probe = vortex_init_one,
- .remove = __devexit_p(vortex_remove_one),
- .id_table = vortex_pci_tbl,
- .driver.pm = VORTEX_PM_OPS,
-};
-
-
-static int vortex_have_pci;
-static int vortex_have_eisa;
-
-
-static int __init vortex_init(void)
-{
- int pci_rc, eisa_rc;
-
- pci_rc = pci_register_driver(&vortex_driver);
- eisa_rc = vortex_eisa_init();
-
- if (pci_rc == 0)
- vortex_have_pci = 1;
- if (eisa_rc > 0)
- vortex_have_eisa = 1;
-
- return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV;
-}
-
-
-static void __exit vortex_eisa_cleanup(void)
-{
- struct vortex_private *vp;
- void __iomem *ioaddr;
-
-#ifdef CONFIG_EISA
- /* Take care of the EISA devices */
- eisa_driver_unregister(&vortex_eisa_driver);
-#endif
-
- if (compaq_net_device) {
- vp = netdev_priv(compaq_net_device);
- ioaddr = ioport_map(compaq_net_device->base_addr,
- VORTEX_TOTAL_SIZE);
-
- unregister_netdev(compaq_net_device);
- iowrite16(TotalReset, ioaddr + EL3_CMD);
- release_region(compaq_net_device->base_addr,
- VORTEX_TOTAL_SIZE);
-
- free_netdev(compaq_net_device);
- }
-}
-
-
-static void __exit vortex_cleanup(void)
-{
- if (vortex_have_pci)
- pci_unregister_driver(&vortex_driver);
- if (vortex_have_eisa)
- vortex_eisa_cleanup();
-}
-
-
-module_init(vortex_init);
-module_exit(vortex_cleanup);
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/Kconfig b/ANDROID_3.4.5/drivers/net/ethernet/3com/Kconfig
deleted file mode 100644
index bad4fa68..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/Kconfig
+++ /dev/null
@@ -1,122 +0,0 @@
-#
-# 3Com Ethernet device configuration
-#
-
-config NET_VENDOR_3COM
- bool "3Com devices"
- default y
- depends on ISA || EISA || MCA || PCI || PCMCIA
- ---help---
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about 3Com cards. If you say Y, you will be asked for
- your specific card in the following questions.
-
-if NET_VENDOR_3COM
-
-config EL1
- tristate "3c501 \"EtherLink\" support"
- depends on ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Also, consider buying a
- new card, since the 3c501 is slow, broken, and obsolete: you will
- have problems. Some people suggest to ping ("man ping") a nearby
- machine every minute ("man cron") when using this card.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c501.
-
-config EL3
- tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
- depends on (ISA || EISA || MCA)
- ---help---
- If you have a network (Ethernet) card belonging to the 3Com
- EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
- from <http://www.tldp.org/docs.html#howto>.
-
- If your card is not working you may need to use the DOS
- setup disk to disable Plug & Play mode, and to select the default
- media type.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c509.
-
-config 3C515
- tristate "3c515 ISA \"Fast EtherLink\""
- depends on (ISA || EISA) && ISA_DMA_API
- ---help---
- If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
- network card, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c515.
-
-config PCMCIA_3C574
- tristate "3Com 3c574 PCMCIA support"
- depends on PCMCIA
- ---help---
- Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA
- (PC-card) Fast Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called 3c574_cs. If unsure, say N.
-
-config PCMCIA_3C589
- tristate "3Com 3c589 PCMCIA support"
- depends on PCMCIA
- ---help---
- Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA
- (PC-card) Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called 3c589_cs. If unsure, say N.
-
-config VORTEX
- tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
- depends on (PCI || EISA)
- select NET_CORE
- select MII
- ---help---
- This option enables driver support for a large number of 10Mbps and
- 10/100Mbps EISA, PCI and PCMCIA 3Com network cards:
-
- "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
- "Boomerang" (EtherLink XL 3c900 or 3c905) PCI
- "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus
- "Tornado" (3c905) PCI
- "Hurricane" (3c555/3cSOHO) PCI
-
- If you have such a card, say Y and read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>. More
- specific information is in
- <file:Documentation/networking/vortex.txt> and in the comments at
- the beginning of <file:drivers/net/ethernet/3com/3c59x.c>.
-
- To compile this support as a module, choose M here.
-
-config TYPHOON
- tristate "3cr990 series \"Typhoon\" support"
- depends on PCI
- select CRC32
- ---help---
- This option enables driver support for the 3cr990 series of cards:
-
- 3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97,
- 3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server,
- 3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR
-
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called typhoon.
-
-endif # NET_VENDOR_3COM
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/Makefile b/ANDROID_3.4.5/drivers/net/ethernet/3com/Makefile
deleted file mode 100644
index 1e5382a3..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the 3Com Ethernet device drivers
-#
-
-obj-$(CONFIG_EL1) += 3c501.o
-obj-$(CONFIG_EL3) += 3c509.o
-obj-$(CONFIG_3C515) += 3c515.o
-obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
-obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o
-obj-$(CONFIG_VORTEX) += 3c59x.o
-obj-$(CONFIG_TYPHOON) += typhoon.o
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.c b/ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.c
deleted file mode 100644
index 1234a14b..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.c
+++ /dev/null
@@ -1,2558 +0,0 @@
-/* typhoon.c: A Linux Ethernet device driver for 3Com 3CR990 family of NICs */
-/*
- Written 2002-2004 by David Dillow <dave@thedillows.org>
- Based on code written 1998-2000 by Donald Becker <becker@scyld.com> and
- Linux 2.2.x driver by David P. McLean <davidpmclean@yahoo.com>.
-
- This software may be used and distributed according to the terms of
- the GNU General Public License (GPL), incorporated herein by reference.
- Drivers based on or derived from this code fall under the GPL and must
- retain the authorship, copyright and license notice. This file is not
- a complete program and may only be used when the entire operating
- system is licensed under the GPL.
-
- This software is available on a public web site. It may enable
- cryptographic capabilities of the 3Com hardware, and may be
- exported from the United States under License Exception "TSU"
- pursuant to 15 C.F.R. Section 740.13(e).
-
- This work was funded by the National Library of Medicine under
- the Department of Energy project number 0274DD06D1 and NLM project
- number Y1-LM-2015-01.
-
- This driver is designed for the 3Com 3CR990 Family of cards with the
- 3XP Processor. It has been tested on x86 and sparc64.
-
- KNOWN ISSUES:
- *) Cannot DMA Rx packets to a 2 byte aligned address. Also firmware
- issue. Hopefully 3Com will fix it.
- *) Waiting for a command response takes 8ms due to non-preemptable
- polling. Only significant for getting stats and creating
- SAs, but an ugly wart never the less.
-
- TODO:
- *) Doesn't do IPSEC offloading. Yet. Keep yer pants on, it's coming.
- *) Add more support for ethtool (especially for NIC stats)
- *) Allow disabling of RX checksum offloading
- *) Fix MAC changing to work while the interface is up
- (Need to put commands on the TX ring, which changes
- the locking)
- *) Add in FCS to {rx,tx}_bytes, since the hardware doesn't. See
- http://oss.sgi.com/cgi-bin/mesg.cgi?a=netdev&i=20031215152211.7003fe8e.rddunlap%40osdl.org
-*/
-
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
- * Setting to > 1518 effectively disables this feature.
- */
-static int rx_copybreak = 200;
-
-/* Should we use MMIO or Port IO?
- * 0: Port IO
- * 1: MMIO
- * 2: Try MMIO, fallback to Port IO
- */
-static unsigned int use_mmio = 2;
-
-/* end user-configurable values */
-
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
- */
-static const int multicast_filter_limit = 32;
-
-/* Operational parameters that are set at compile time. */
-
-/* Keep the ring sizes a power of two for compile efficiency.
- * The compiler will convert <unsigned>'%'<2^N> into a bit mask.
- * Making the Tx ring too large decreases the effectiveness of channel
- * bonding and packet priority.
- * There are no ill effects from too-large receive rings.
- *
- * We don't currently use the Hi Tx ring so, don't make it very big.
- *
- * Beware that if we start using the Hi Tx ring, we will need to change
- * typhoon_num_free_tx() and typhoon_tx_complete() to account for that.
- */
-#define TXHI_ENTRIES 2
-#define TXLO_ENTRIES 128
-#define RX_ENTRIES 32
-#define COMMAND_ENTRIES 16
-#define RESPONSE_ENTRIES 32
-
-#define COMMAND_RING_SIZE (COMMAND_ENTRIES * sizeof(struct cmd_desc))
-#define RESPONSE_RING_SIZE (RESPONSE_ENTRIES * sizeof(struct resp_desc))
-
-/* The 3XP will preload and remove 64 entries from the free buffer
- * list, and we need one entry to keep the ring from wrapping, so
- * to keep this a power of two, we use 128 entries.
- */
-#define RXFREE_ENTRIES 128
-#define RXENT_ENTRIES (RXFREE_ENTRIES - 1)
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
-
-#define PKT_BUF_SZ 1536
-#define FIRMWARE_NAME "3com/typhoon.bin"
-
-#define pr_fmt(fmt) KBUILD_MODNAME " " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/if_vlan.h>
-#include <linux/crc32.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/in6.h>
-#include <linux/dma-mapping.h>
-#include <linux/firmware.h>
-
-#include "typhoon.h"
-
-MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FIRMWARE_NAME);
-MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
-MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and "
- "the buffer given back to the NIC. Default "
- "is 200.");
-MODULE_PARM_DESC(use_mmio, "Use MMIO (1) or PIO(0) to access the NIC. "
- "Default is to try MMIO and fallback to PIO.");
-module_param(rx_copybreak, int, 0);
-module_param(use_mmio, int, 0);
-
-#if defined(NETIF_F_TSO) && MAX_SKB_FRAGS > 32
-#warning Typhoon only supports 32 entries in its SG list for TSO, disabling TSO
-#undef NETIF_F_TSO
-#endif
-
-#if TXLO_ENTRIES <= (2 * MAX_SKB_FRAGS)
-#error TX ring too small!
-#endif
-
-struct typhoon_card_info {
- const char *name;
- const int capabilities;
-};
-
-#define TYPHOON_CRYPTO_NONE 0x00
-#define TYPHOON_CRYPTO_DES 0x01
-#define TYPHOON_CRYPTO_3DES 0x02
-#define TYPHOON_CRYPTO_VARIABLE 0x04
-#define TYPHOON_FIBER 0x08
-#define TYPHOON_WAKEUP_NEEDS_RESET 0x10
-
-enum typhoon_cards {
- TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR,
- TYPHOON_SVR95, TYPHOON_SVR97, TYPHOON_TXM, TYPHOON_BSVR,
- TYPHOON_FX95, TYPHOON_FX97, TYPHOON_FX95SVR, TYPHOON_FX97SVR,
- TYPHOON_FXM,
-};
-
-/* directly indexed by enum typhoon_cards, above */
-static struct typhoon_card_info typhoon_card_info[] __devinitdata = {
- { "3Com Typhoon (3C990-TX)",
- TYPHOON_CRYPTO_NONE},
- { "3Com Typhoon (3CR990-TX-95)",
- TYPHOON_CRYPTO_DES},
- { "3Com Typhoon (3CR990-TX-97)",
- TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES},
- { "3Com Typhoon (3C990SVR)",
- TYPHOON_CRYPTO_NONE},
- { "3Com Typhoon (3CR990SVR95)",
- TYPHOON_CRYPTO_DES},
- { "3Com Typhoon (3CR990SVR97)",
- TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES},
- { "3Com Typhoon2 (3C990B-TX-M)",
- TYPHOON_CRYPTO_VARIABLE},
- { "3Com Typhoon2 (3C990BSVR)",
- TYPHOON_CRYPTO_VARIABLE},
- { "3Com Typhoon (3CR990-FX-95)",
- TYPHOON_CRYPTO_DES | TYPHOON_FIBER},
- { "3Com Typhoon (3CR990-FX-97)",
- TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES | TYPHOON_FIBER},
- { "3Com Typhoon (3CR990-FX-95 Server)",
- TYPHOON_CRYPTO_DES | TYPHOON_FIBER},
- { "3Com Typhoon (3CR990-FX-97 Server)",
- TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES | TYPHOON_FIBER},
- { "3Com Typhoon2 (3C990B-FX-97)",
- TYPHOON_CRYPTO_VARIABLE | TYPHOON_FIBER},
-};
-
-/* Notes on the new subsystem numbering scheme:
- * bits 0-1 indicate crypto capabilities: (0) variable, (1) DES, or (2) 3DES
- * bit 4 indicates if this card has secured firmware (we don't support it)
- * bit 8 indicates if this is a (0) copper or (1) fiber card
- * bits 12-16 indicate card type: (0) client and (1) server
- */
-static DEFINE_PCI_DEVICE_TABLE(typhoon_pci_tbl) = {
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,TYPHOON_TX },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_95,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_TX95 },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_97,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_TX97 },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B,
- PCI_ANY_ID, 0x1000, 0, 0, TYPHOON_TXM },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B,
- PCI_ANY_ID, 0x1102, 0, 0, TYPHOON_FXM },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B,
- PCI_ANY_ID, 0x2000, 0, 0, TYPHOON_BSVR },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
- PCI_ANY_ID, 0x1101, 0, 0, TYPHOON_FX95 },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
- PCI_ANY_ID, 0x1102, 0, 0, TYPHOON_FX97 },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
- PCI_ANY_ID, 0x2101, 0, 0, TYPHOON_FX95SVR },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
- PCI_ANY_ID, 0x2102, 0, 0, TYPHOON_FX97SVR },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR95,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR95 },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR97,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR97 },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, typhoon_pci_tbl);
-
-/* Define the shared memory area
- * Align everything the 3XP will normally be using.
- * We'll need to move/align txHi if we start using that ring.
- */
-#define __3xp_aligned ____cacheline_aligned
-struct typhoon_shared {
- struct typhoon_interface iface;
- struct typhoon_indexes indexes __3xp_aligned;
- struct tx_desc txLo[TXLO_ENTRIES] __3xp_aligned;
- struct rx_desc rxLo[RX_ENTRIES] __3xp_aligned;
- struct rx_desc rxHi[RX_ENTRIES] __3xp_aligned;
- struct cmd_desc cmd[COMMAND_ENTRIES] __3xp_aligned;
- struct resp_desc resp[RESPONSE_ENTRIES] __3xp_aligned;
- struct rx_free rxBuff[RXFREE_ENTRIES] __3xp_aligned;
- u32 zeroWord;
- struct tx_desc txHi[TXHI_ENTRIES];
-} __packed;
-
-struct rxbuff_ent {
- struct sk_buff *skb;
- dma_addr_t dma_addr;
-};
-
-struct typhoon {
- /* Tx cache line section */
- struct transmit_ring txLoRing ____cacheline_aligned;
- struct pci_dev * tx_pdev;
- void __iomem *tx_ioaddr;
- u32 txlo_dma_addr;
-
- /* Irq/Rx cache line section */
- void __iomem *ioaddr ____cacheline_aligned;
- struct typhoon_indexes *indexes;
- u8 awaiting_resp;
- u8 duplex;
- u8 speed;
- u8 card_state;
- struct basic_ring rxLoRing;
- struct pci_dev * pdev;
- struct net_device * dev;
- struct napi_struct napi;
- struct basic_ring rxHiRing;
- struct basic_ring rxBuffRing;
- struct rxbuff_ent rxbuffers[RXENT_ENTRIES];
-
- /* general section */
- spinlock_t command_lock ____cacheline_aligned;
- struct basic_ring cmdRing;
- struct basic_ring respRing;
- struct net_device_stats stats;
- struct net_device_stats stats_saved;
- struct typhoon_shared * shared;
- dma_addr_t shared_dma;
- __le16 xcvr_select;
- __le16 wol_events;
- __le32 offload;
-
- /* unused stuff (future use) */
- int capabilities;
- struct transmit_ring txHiRing;
-};
-
-enum completion_wait_values {
- NoWait = 0, WaitNoSleep, WaitSleep,
-};
-
-/* These are the values for the typhoon.card_state variable.
- * These determine where the statistics will come from in get_stats().
- * The sleep image does not support the statistics we need.
- */
-enum state_values {
- Sleeping = 0, Running,
-};
-
-/* PCI writes are not guaranteed to be posted in order, but outstanding writes
- * cannot pass a read, so this forces current writes to post.
- */
-#define typhoon_post_pci_writes(x) \
- do { if(likely(use_mmio)) ioread32(x+TYPHOON_REG_HEARTBEAT); } while(0)
-
-/* We'll wait up to six seconds for a reset, and half a second normally.
- */
-#define TYPHOON_UDELAY 50
-#define TYPHOON_RESET_TIMEOUT_SLEEP (6 * HZ)
-#define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)
-#define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)
-
-#if defined(NETIF_F_TSO)
-#define skb_tso_size(x) (skb_shinfo(x)->gso_size)
-#define TSO_NUM_DESCRIPTORS 2
-#define TSO_OFFLOAD_ON TYPHOON_OFFLOAD_TCP_SEGMENT
-#else
-#define NETIF_F_TSO 0
-#define skb_tso_size(x) 0
-#define TSO_NUM_DESCRIPTORS 0
-#define TSO_OFFLOAD_ON 0
-#endif
-
-static inline void
-typhoon_inc_index(u32 *index, const int count, const int num_entries)
-{
- /* Increment a ring index -- we can use this for all rings execept
- * the Rx rings, as they use different size descriptors
- * otherwise, everything is the same size as a cmd_desc
- */
- *index += count * sizeof(struct cmd_desc);
- *index %= num_entries * sizeof(struct cmd_desc);
-}
-
-static inline void
-typhoon_inc_cmd_index(u32 *index, const int count)
-{
- typhoon_inc_index(index, count, COMMAND_ENTRIES);
-}
-
-static inline void
-typhoon_inc_resp_index(u32 *index, const int count)
-{
- typhoon_inc_index(index, count, RESPONSE_ENTRIES);
-}
-
-static inline void
-typhoon_inc_rxfree_index(u32 *index, const int count)
-{
- typhoon_inc_index(index, count, RXFREE_ENTRIES);
-}
-
-static inline void
-typhoon_inc_tx_index(u32 *index, const int count)
-{
- /* if we start using the Hi Tx ring, this needs updateing */
- typhoon_inc_index(index, count, TXLO_ENTRIES);
-}
-
-static inline void
-typhoon_inc_rx_index(u32 *index, const int count)
-{
- /* sizeof(struct rx_desc) != sizeof(struct cmd_desc) */
- *index += count * sizeof(struct rx_desc);
- *index %= RX_ENTRIES * sizeof(struct rx_desc);
-}
-
-static int
-typhoon_reset(void __iomem *ioaddr, int wait_type)
-{
- int i, err = 0;
- int timeout;
-
- if(wait_type == WaitNoSleep)
- timeout = TYPHOON_RESET_TIMEOUT_NOSLEEP;
- else
- timeout = TYPHOON_RESET_TIMEOUT_SLEEP;
-
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
-
- iowrite32(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET);
- typhoon_post_pci_writes(ioaddr);
- udelay(1);
- iowrite32(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET);
-
- if(wait_type != NoWait) {
- for(i = 0; i < timeout; i++) {
- if(ioread32(ioaddr + TYPHOON_REG_STATUS) ==
- TYPHOON_STATUS_WAITING_FOR_HOST)
- goto out;
-
- if(wait_type == WaitSleep)
- schedule_timeout_uninterruptible(1);
- else
- udelay(TYPHOON_UDELAY);
- }
-
- err = -ETIMEDOUT;
- }
-
-out:
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
-
- /* The 3XP seems to need a little extra time to complete the load
- * of the sleep image before we can reliably boot it. Failure to
- * do this occasionally results in a hung adapter after boot in
- * typhoon_init_one() while trying to read the MAC address or
- * putting the card to sleep. 3Com's driver waits 5ms, but
- * that seems to be overkill. However, if we can sleep, we might
- * as well give it that much time. Otherwise, we'll give it 500us,
- * which should be enough (I've see it work well at 100us, but still
- * saw occasional problems.)
- */
- if(wait_type == WaitSleep)
- msleep(5);
- else
- udelay(500);
- return err;
-}
-
-static int
-typhoon_wait_status(void __iomem *ioaddr, u32 wait_value)
-{
- int i, err = 0;
-
- for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
- if(ioread32(ioaddr + TYPHOON_REG_STATUS) == wait_value)
- goto out;
- udelay(TYPHOON_UDELAY);
- }
-
- err = -ETIMEDOUT;
-
-out:
- return err;
-}
-
-static inline void
-typhoon_media_status(struct net_device *dev, struct resp_desc *resp)
-{
- if(resp->parm1 & TYPHOON_MEDIA_STAT_NO_LINK)
- netif_carrier_off(dev);
- else
- netif_carrier_on(dev);
-}
-
-static inline void
-typhoon_hello(struct typhoon *tp)
-{
- struct basic_ring *ring = &tp->cmdRing;
- struct cmd_desc *cmd;
-
- /* We only get a hello request if we've not sent anything to the
- * card in a long while. If the lock is held, then we're in the
- * process of issuing a command, so we don't need to respond.
- */
- if(spin_trylock(&tp->command_lock)) {
- cmd = (struct cmd_desc *)(ring->ringBase + ring->lastWrite);
- typhoon_inc_cmd_index(&ring->lastWrite, 1);
-
- INIT_COMMAND_NO_RESPONSE(cmd, TYPHOON_CMD_HELLO_RESP);
- wmb();
- iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
- spin_unlock(&tp->command_lock);
- }
-}
-
-static int
-typhoon_process_response(struct typhoon *tp, int resp_size,
- struct resp_desc *resp_save)
-{
- struct typhoon_indexes *indexes = tp->indexes;
- struct resp_desc *resp;
- u8 *base = tp->respRing.ringBase;
- int count, len, wrap_len;
- u32 cleared;
- u32 ready;
-
- cleared = le32_to_cpu(indexes->respCleared);
- ready = le32_to_cpu(indexes->respReady);
- while(cleared != ready) {
- resp = (struct resp_desc *)(base + cleared);
- count = resp->numDesc + 1;
- if(resp_save && resp->seqNo) {
- if(count > resp_size) {
- resp_save->flags = TYPHOON_RESP_ERROR;
- goto cleanup;
- }
-
- wrap_len = 0;
- len = count * sizeof(*resp);
- if(unlikely(cleared + len > RESPONSE_RING_SIZE)) {
- wrap_len = cleared + len - RESPONSE_RING_SIZE;
- len = RESPONSE_RING_SIZE - cleared;
- }
-
- memcpy(resp_save, resp, len);
- if(unlikely(wrap_len)) {
- resp_save += len / sizeof(*resp);
- memcpy(resp_save, base, wrap_len);
- }
-
- resp_save = NULL;
- } else if(resp->cmd == TYPHOON_CMD_READ_MEDIA_STATUS) {
- typhoon_media_status(tp->dev, resp);
- } else if(resp->cmd == TYPHOON_CMD_HELLO_RESP) {
- typhoon_hello(tp);
- } else {
- netdev_err(tp->dev,
- "dumping unexpected response 0x%04x:%d:0x%02x:0x%04x:%08x:%08x\n",
- le16_to_cpu(resp->cmd),
- resp->numDesc, resp->flags,
- le16_to_cpu(resp->parm1),
- le32_to_cpu(resp->parm2),
- le32_to_cpu(resp->parm3));
- }
-
-cleanup:
- typhoon_inc_resp_index(&cleared, count);
- }
-
- indexes->respCleared = cpu_to_le32(cleared);
- wmb();
- return resp_save == NULL;
-}
-
-static inline int
-typhoon_num_free(int lastWrite, int lastRead, int ringSize)
-{
- /* this works for all descriptors but rx_desc, as they are a
- * different size than the cmd_desc -- everyone else is the same
- */
- lastWrite /= sizeof(struct cmd_desc);
- lastRead /= sizeof(struct cmd_desc);
- return (ringSize + lastRead - lastWrite - 1) % ringSize;
-}
-
-static inline int
-typhoon_num_free_cmd(struct typhoon *tp)
-{
- int lastWrite = tp->cmdRing.lastWrite;
- int cmdCleared = le32_to_cpu(tp->indexes->cmdCleared);
-
- return typhoon_num_free(lastWrite, cmdCleared, COMMAND_ENTRIES);
-}
-
-static inline int
-typhoon_num_free_resp(struct typhoon *tp)
-{
- int respReady = le32_to_cpu(tp->indexes->respReady);
- int respCleared = le32_to_cpu(tp->indexes->respCleared);
-
- return typhoon_num_free(respReady, respCleared, RESPONSE_ENTRIES);
-}
-
-static inline int
-typhoon_num_free_tx(struct transmit_ring *ring)
-{
- /* if we start using the Hi Tx ring, this needs updating */
- return typhoon_num_free(ring->lastWrite, ring->lastRead, TXLO_ENTRIES);
-}
-
-static int
-typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd,
- int num_resp, struct resp_desc *resp)
-{
- struct typhoon_indexes *indexes = tp->indexes;
- struct basic_ring *ring = &tp->cmdRing;
- struct resp_desc local_resp;
- int i, err = 0;
- int got_resp;
- int freeCmd, freeResp;
- int len, wrap_len;
-
- spin_lock(&tp->command_lock);
-
- freeCmd = typhoon_num_free_cmd(tp);
- freeResp = typhoon_num_free_resp(tp);
-
- if(freeCmd < num_cmd || freeResp < num_resp) {
- netdev_err(tp->dev, "no descs for cmd, had (needed) %d (%d) cmd, %d (%d) resp\n",
- freeCmd, num_cmd, freeResp, num_resp);
- err = -ENOMEM;
- goto out;
- }
-
- if(cmd->flags & TYPHOON_CMD_RESPOND) {
- /* If we're expecting a response, but the caller hasn't given
- * us a place to put it, we'll provide one.
- */
- tp->awaiting_resp = 1;
- if(resp == NULL) {
- resp = &local_resp;
- num_resp = 1;
- }
- }
-
- wrap_len = 0;
- len = num_cmd * sizeof(*cmd);
- if(unlikely(ring->lastWrite + len > COMMAND_RING_SIZE)) {
- wrap_len = ring->lastWrite + len - COMMAND_RING_SIZE;
- len = COMMAND_RING_SIZE - ring->lastWrite;
- }
-
- memcpy(ring->ringBase + ring->lastWrite, cmd, len);
- if(unlikely(wrap_len)) {
- struct cmd_desc *wrap_ptr = cmd;
- wrap_ptr += len / sizeof(*cmd);
- memcpy(ring->ringBase, wrap_ptr, wrap_len);
- }
-
- typhoon_inc_cmd_index(&ring->lastWrite, num_cmd);
-
- /* "I feel a presence... another warrior is on the mesa."
- */
- wmb();
- iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
- typhoon_post_pci_writes(tp->ioaddr);
-
- if((cmd->flags & TYPHOON_CMD_RESPOND) == 0)
- goto out;
-
- /* Ugh. We'll be here about 8ms, spinning our thumbs, unable to
- * preempt or do anything other than take interrupts. So, don't
- * wait for a response unless you have to.
- *
- * I've thought about trying to sleep here, but we're called
- * from many contexts that don't allow that. Also, given the way
- * 3Com has implemented irq coalescing, we would likely timeout --
- * this has been observed in real life!
- *
- * The big killer is we have to wait to get stats from the card,
- * though we could go to a periodic refresh of those if we don't
- * mind them getting somewhat stale. The rest of the waiting
- * commands occur during open/close/suspend/resume, so they aren't
- * time critical. Creating SAs in the future will also have to
- * wait here.
- */
- got_resp = 0;
- for(i = 0; i < TYPHOON_WAIT_TIMEOUT && !got_resp; i++) {
- if(indexes->respCleared != indexes->respReady)
- got_resp = typhoon_process_response(tp, num_resp,
- resp);
- udelay(TYPHOON_UDELAY);
- }
-
- if(!got_resp) {
- err = -ETIMEDOUT;
- goto out;
- }
-
- /* Collect the error response even if we don't care about the
- * rest of the response
- */
- if(resp->flags & TYPHOON_RESP_ERROR)
- err = -EIO;
-
-out:
- if(tp->awaiting_resp) {
- tp->awaiting_resp = 0;
- smp_wmb();
-
- /* Ugh. If a response was added to the ring between
- * the call to typhoon_process_response() and the clearing
- * of tp->awaiting_resp, we could have missed the interrupt
- * and it could hang in the ring an indeterminate amount of
- * time. So, check for it, and interrupt ourselves if this
- * is the case.
- */
- if(indexes->respCleared != indexes->respReady)
- iowrite32(1, tp->ioaddr + TYPHOON_REG_SELF_INTERRUPT);
- }
-
- spin_unlock(&tp->command_lock);
- return err;
-}
-
-static inline void
-typhoon_tso_fill(struct sk_buff *skb, struct transmit_ring *txRing,
- u32 ring_dma)
-{
- struct tcpopt_desc *tcpd;
- u32 tcpd_offset = ring_dma;
-
- tcpd = (struct tcpopt_desc *) (txRing->ringBase + txRing->lastWrite);
- tcpd_offset += txRing->lastWrite;
- tcpd_offset += offsetof(struct tcpopt_desc, bytesTx);
- typhoon_inc_tx_index(&txRing->lastWrite, 1);
-
- tcpd->flags = TYPHOON_OPT_DESC | TYPHOON_OPT_TCP_SEG;
- tcpd->numDesc = 1;
- tcpd->mss_flags = cpu_to_le16(skb_tso_size(skb));
- tcpd->mss_flags |= TYPHOON_TSO_FIRST | TYPHOON_TSO_LAST;
- tcpd->respAddrLo = cpu_to_le32(tcpd_offset);
- tcpd->bytesTx = cpu_to_le32(skb->len);
- tcpd->status = 0;
-}
-
-static netdev_tx_t
-typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
-{
- struct typhoon *tp = netdev_priv(dev);
- struct transmit_ring *txRing;
- struct tx_desc *txd, *first_txd;
- dma_addr_t skb_dma;
- int numDesc;
-
- /* we have two rings to choose from, but we only use txLo for now
- * If we start using the Hi ring as well, we'll need to update
- * typhoon_stop_runtime(), typhoon_interrupt(), typhoon_num_free_tx(),
- * and TXHI_ENTRIES to match, as well as update the TSO code below
- * to get the right DMA address
- */
- txRing = &tp->txLoRing;
-
- /* We need one descriptor for each fragment of the sk_buff, plus the
- * one for the ->data area of it.
- *
- * The docs say a maximum of 16 fragment descriptors per TCP option
- * descriptor, then make a new packet descriptor and option descriptor
- * for the next 16 fragments. The engineers say just an option
- * descriptor is needed. I've tested up to 26 fragments with a single
- * packet descriptor/option descriptor combo, so I use that for now.
- *
- * If problems develop with TSO, check this first.
- */
- numDesc = skb_shinfo(skb)->nr_frags + 1;
- if (skb_is_gso(skb))
- numDesc++;
-
- /* When checking for free space in the ring, we need to also
- * account for the initial Tx descriptor, and we always must leave
- * at least one descriptor unused in the ring so that it doesn't
- * wrap and look empty.
- *
- * The only time we should loop here is when we hit the race
- * between marking the queue awake and updating the cleared index.
- * Just loop and it will appear. This comes from the acenic driver.
- */
- while(unlikely(typhoon_num_free_tx(txRing) < (numDesc + 2)))
- smp_rmb();
-
- first_txd = (struct tx_desc *) (txRing->ringBase + txRing->lastWrite);
- typhoon_inc_tx_index(&txRing->lastWrite, 1);
-
- first_txd->flags = TYPHOON_TX_DESC | TYPHOON_DESC_VALID;
- first_txd->numDesc = 0;
- first_txd->len = 0;
- first_txd->tx_addr = (u64)((unsigned long) skb);
- first_txd->processFlags = 0;
-
- if(skb->ip_summed == CHECKSUM_PARTIAL) {
- /* The 3XP will figure out if this is UDP/TCP */
- first_txd->processFlags |= TYPHOON_TX_PF_TCP_CHKSUM;
- first_txd->processFlags |= TYPHOON_TX_PF_UDP_CHKSUM;
- first_txd->processFlags |= TYPHOON_TX_PF_IP_CHKSUM;
- }
-
- if(vlan_tx_tag_present(skb)) {
- first_txd->processFlags |=
- TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY;
- first_txd->processFlags |=
- cpu_to_le32(htons(vlan_tx_tag_get(skb)) <<
- TYPHOON_TX_PF_VLAN_TAG_SHIFT);
- }
-
- if (skb_is_gso(skb)) {
- first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
- first_txd->numDesc++;
-
- typhoon_tso_fill(skb, txRing, tp->txlo_dma_addr);
- }
-
- txd = (struct tx_desc *) (txRing->ringBase + txRing->lastWrite);
- typhoon_inc_tx_index(&txRing->lastWrite, 1);
-
- /* No need to worry about padding packet -- the firmware pads
- * it with zeros to ETH_ZLEN for us.
- */
- if(skb_shinfo(skb)->nr_frags == 0) {
- skb_dma = pci_map_single(tp->tx_pdev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
- txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
- txd->len = cpu_to_le16(skb->len);
- txd->frag.addr = cpu_to_le32(skb_dma);
- txd->frag.addrHi = 0;
- first_txd->numDesc++;
- } else {
- int i, len;
-
- len = skb_headlen(skb);
- skb_dma = pci_map_single(tp->tx_pdev, skb->data, len,
- PCI_DMA_TODEVICE);
- txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
- txd->len = cpu_to_le16(len);
- txd->frag.addr = cpu_to_le32(skb_dma);
- txd->frag.addrHi = 0;
- first_txd->numDesc++;
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- void *frag_addr;
-
- txd = (struct tx_desc *) (txRing->ringBase +
- txRing->lastWrite);
- typhoon_inc_tx_index(&txRing->lastWrite, 1);
-
- len = skb_frag_size(frag);
- frag_addr = skb_frag_address(frag);
- skb_dma = pci_map_single(tp->tx_pdev, frag_addr, len,
- PCI_DMA_TODEVICE);
- txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
- txd->len = cpu_to_le16(len);
- txd->frag.addr = cpu_to_le32(skb_dma);
- txd->frag.addrHi = 0;
- first_txd->numDesc++;
- }
- }
-
- /* Kick the 3XP
- */
- wmb();
- iowrite32(txRing->lastWrite, tp->tx_ioaddr + txRing->writeRegister);
-
- /* If we don't have room to put the worst case packet on the
- * queue, then we must stop the queue. We need 2 extra
- * descriptors -- one to prevent ring wrap, and one for the
- * Tx header.
- */
- numDesc = MAX_SKB_FRAGS + TSO_NUM_DESCRIPTORS + 1;
-
- if(typhoon_num_free_tx(txRing) < (numDesc + 2)) {
- netif_stop_queue(dev);
-
- /* A Tx complete IRQ could have gotten between, making
- * the ring free again. Only need to recheck here, since
- * Tx is serialized.
- */
- if(typhoon_num_free_tx(txRing) >= (numDesc + 2))
- netif_wake_queue(dev);
- }
-
- return NETDEV_TX_OK;
-}
-
-static void
-typhoon_set_rx_mode(struct net_device *dev)
-{
- struct typhoon *tp = netdev_priv(dev);
- struct cmd_desc xp_cmd;
- u32 mc_filter[2];
- __le16 filter;
-
- filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
- if(dev->flags & IFF_PROMISC) {
- filter |= TYPHOON_RX_FILTER_PROMISCOUS;
- } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
- (dev->flags & IFF_ALLMULTI)) {
- /* Too many to match, or accept all multicasts. */
- filter |= TYPHOON_RX_FILTER_ALL_MCAST;
- } else if (!netdev_mc_empty(dev)) {
- struct netdev_hw_addr *ha;
-
- memset(mc_filter, 0, sizeof(mc_filter));
- netdev_for_each_mc_addr(ha, dev) {
- int bit = ether_crc(ETH_ALEN, ha->addr) & 0x3f;
- mc_filter[bit >> 5] |= 1 << (bit & 0x1f);
- }
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd,
- TYPHOON_CMD_SET_MULTICAST_HASH);
- xp_cmd.parm1 = TYPHOON_MCAST_HASH_SET;
- xp_cmd.parm2 = cpu_to_le32(mc_filter[0]);
- xp_cmd.parm3 = cpu_to_le32(mc_filter[1]);
- typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
-
- filter |= TYPHOON_RX_FILTER_MCAST_HASH;
- }
-
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
- xp_cmd.parm1 = filter;
- typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
-}
-
-static int
-typhoon_do_get_stats(struct typhoon *tp)
-{
- struct net_device_stats *stats = &tp->stats;
- struct net_device_stats *saved = &tp->stats_saved;
- struct cmd_desc xp_cmd;
- struct resp_desc xp_resp[7];
- struct stats_resp *s = (struct stats_resp *) xp_resp;
- int err;
-
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_STATS);
- err = typhoon_issue_command(tp, 1, &xp_cmd, 7, xp_resp);
- if(err < 0)
- return err;
-
- /* 3Com's Linux driver uses txMultipleCollisions as it's
- * collisions value, but there is some other collision info as well...
- *
- * The extra status reported would be a good candidate for
- * ethtool_ops->get_{strings,stats}()
- */
- stats->tx_packets = le32_to_cpu(s->txPackets) +
- saved->tx_packets;
- stats->tx_bytes = le64_to_cpu(s->txBytes) +
- saved->tx_bytes;
- stats->tx_errors = le32_to_cpu(s->txCarrierLost) +
- saved->tx_errors;
- stats->tx_carrier_errors = le32_to_cpu(s->txCarrierLost) +
- saved->tx_carrier_errors;
- stats->collisions = le32_to_cpu(s->txMultipleCollisions) +
- saved->collisions;
- stats->rx_packets = le32_to_cpu(s->rxPacketsGood) +
- saved->rx_packets;
- stats->rx_bytes = le64_to_cpu(s->rxBytesGood) +
- saved->rx_bytes;
- stats->rx_fifo_errors = le32_to_cpu(s->rxFifoOverruns) +
- saved->rx_fifo_errors;
- stats->rx_errors = le32_to_cpu(s->rxFifoOverruns) +
- le32_to_cpu(s->BadSSD) + le32_to_cpu(s->rxCrcErrors) +
- saved->rx_errors;
- stats->rx_crc_errors = le32_to_cpu(s->rxCrcErrors) +
- saved->rx_crc_errors;
- stats->rx_length_errors = le32_to_cpu(s->rxOversized) +
- saved->rx_length_errors;
- tp->speed = (s->linkStatus & TYPHOON_LINK_100MBPS) ?
- SPEED_100 : SPEED_10;
- tp->duplex = (s->linkStatus & TYPHOON_LINK_FULL_DUPLEX) ?
- DUPLEX_FULL : DUPLEX_HALF;
-
- return 0;
-}
-
-static struct net_device_stats *
-typhoon_get_stats(struct net_device *dev)
-{
- struct typhoon *tp = netdev_priv(dev);
- struct net_device_stats *stats = &tp->stats;
- struct net_device_stats *saved = &tp->stats_saved;
-
- smp_rmb();
- if(tp->card_state == Sleeping)
- return saved;
-
- if(typhoon_do_get_stats(tp) < 0) {
- netdev_err(dev, "error getting stats\n");
- return saved;
- }
-
- return stats;
-}
-
-static void
-typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct typhoon *tp = netdev_priv(dev);
- struct pci_dev *pci_dev = tp->pdev;
- struct cmd_desc xp_cmd;
- struct resp_desc xp_resp[3];
-
- smp_rmb();
- if(tp->card_state == Sleeping) {
- strlcpy(info->fw_version, "Sleep image",
- sizeof(info->fw_version));
- } else {
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
- if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
- strlcpy(info->fw_version, "Unknown runtime",
- sizeof(info->fw_version));
- } else {
- u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
- snprintf(info->fw_version, sizeof(info->fw_version),
- "%02x.%03x.%03x", sleep_ver >> 24,
- (sleep_ver >> 12) & 0xfff, sleep_ver & 0xfff);
- }
- }
-
- strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info));
-}
-
-static int
-typhoon_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct typhoon *tp = netdev_priv(dev);
-
- cmd->supported = SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
- SUPPORTED_Autoneg;
-
- switch (tp->xcvr_select) {
- case TYPHOON_XCVR_10HALF:
- cmd->advertising = ADVERTISED_10baseT_Half;
- break;
- case TYPHOON_XCVR_10FULL:
- cmd->advertising = ADVERTISED_10baseT_Full;
- break;
- case TYPHOON_XCVR_100HALF:
- cmd->advertising = ADVERTISED_100baseT_Half;
- break;
- case TYPHOON_XCVR_100FULL:
- cmd->advertising = ADVERTISED_100baseT_Full;
- break;
- case TYPHOON_XCVR_AUTONEG:
- cmd->advertising = ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_Autoneg;
- break;
- }
-
- if(tp->capabilities & TYPHOON_FIBER) {
- cmd->supported |= SUPPORTED_FIBRE;
- cmd->advertising |= ADVERTISED_FIBRE;
- cmd->port = PORT_FIBRE;
- } else {
- cmd->supported |= SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_TP;
- cmd->advertising |= ADVERTISED_TP;
- cmd->port = PORT_TP;
- }
-
- /* need to get stats to make these link speed/duplex valid */
- typhoon_do_get_stats(tp);
- ethtool_cmd_speed_set(cmd, tp->speed);
- cmd->duplex = tp->duplex;
- cmd->phy_address = 0;
- cmd->transceiver = XCVR_INTERNAL;
- if(tp->xcvr_select == TYPHOON_XCVR_AUTONEG)
- cmd->autoneg = AUTONEG_ENABLE;
- else
- cmd->autoneg = AUTONEG_DISABLE;
- cmd->maxtxpkt = 1;
- cmd->maxrxpkt = 1;
-
- return 0;
-}
-
-static int
-typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct typhoon *tp = netdev_priv(dev);
- u32 speed = ethtool_cmd_speed(cmd);
- struct cmd_desc xp_cmd;
- __le16 xcvr;
- int err;
-
- err = -EINVAL;
- if (cmd->autoneg == AUTONEG_ENABLE) {
- xcvr = TYPHOON_XCVR_AUTONEG;
- } else {
- if (cmd->duplex == DUPLEX_HALF) {
- if (speed == SPEED_10)
- xcvr = TYPHOON_XCVR_10HALF;
- else if (speed == SPEED_100)
- xcvr = TYPHOON_XCVR_100HALF;
- else
- goto out;
- } else if (cmd->duplex == DUPLEX_FULL) {
- if (speed == SPEED_10)
- xcvr = TYPHOON_XCVR_10FULL;
- else if (speed == SPEED_100)
- xcvr = TYPHOON_XCVR_100FULL;
- else
- goto out;
- } else
- goto out;
- }
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_XCVR_SELECT);
- xp_cmd.parm1 = xcvr;
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto out;
-
- tp->xcvr_select = xcvr;
- if(cmd->autoneg == AUTONEG_ENABLE) {
- tp->speed = 0xff; /* invalid */
- tp->duplex = 0xff; /* invalid */
- } else {
- tp->speed = speed;
- tp->duplex = cmd->duplex;
- }
-
-out:
- return err;
-}
-
-static void
-typhoon_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct typhoon *tp = netdev_priv(dev);
-
- wol->supported = WAKE_PHY | WAKE_MAGIC;
- wol->wolopts = 0;
- if(tp->wol_events & TYPHOON_WAKE_LINK_EVENT)
- wol->wolopts |= WAKE_PHY;
- if(tp->wol_events & TYPHOON_WAKE_MAGIC_PKT)
- wol->wolopts |= WAKE_MAGIC;
- memset(&wol->sopass, 0, sizeof(wol->sopass));
-}
-
-static int
-typhoon_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct typhoon *tp = netdev_priv(dev);
-
- if(wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
- return -EINVAL;
-
- tp->wol_events = 0;
- if(wol->wolopts & WAKE_PHY)
- tp->wol_events |= TYPHOON_WAKE_LINK_EVENT;
- if(wol->wolopts & WAKE_MAGIC)
- tp->wol_events |= TYPHOON_WAKE_MAGIC_PKT;
-
- return 0;
-}
-
-static void
-typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
-{
- ering->rx_max_pending = RXENT_ENTRIES;
- ering->tx_max_pending = TXLO_ENTRIES - 1;
-
- ering->rx_pending = RXENT_ENTRIES;
- ering->tx_pending = TXLO_ENTRIES - 1;
-}
-
-static const struct ethtool_ops typhoon_ethtool_ops = {
- .get_settings = typhoon_get_settings,
- .set_settings = typhoon_set_settings,
- .get_drvinfo = typhoon_get_drvinfo,
- .get_wol = typhoon_get_wol,
- .set_wol = typhoon_set_wol,
- .get_link = ethtool_op_get_link,
- .get_ringparam = typhoon_get_ringparam,
-};
-
-static int
-typhoon_wait_interrupt(void __iomem *ioaddr)
-{
- int i, err = 0;
-
- for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
- if(ioread32(ioaddr + TYPHOON_REG_INTR_STATUS) &
- TYPHOON_INTR_BOOTCMD)
- goto out;
- udelay(TYPHOON_UDELAY);
- }
-
- err = -ETIMEDOUT;
-
-out:
- iowrite32(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
- return err;
-}
-
-#define shared_offset(x) offsetof(struct typhoon_shared, x)
-
-static void
-typhoon_init_interface(struct typhoon *tp)
-{
- struct typhoon_interface *iface = &tp->shared->iface;
- dma_addr_t shared_dma;
-
- memset(tp->shared, 0, sizeof(struct typhoon_shared));
-
- /* The *Hi members of iface are all init'd to zero by the memset().
- */
- shared_dma = tp->shared_dma + shared_offset(indexes);
- iface->ringIndex = cpu_to_le32(shared_dma);
-
- shared_dma = tp->shared_dma + shared_offset(txLo);
- iface->txLoAddr = cpu_to_le32(shared_dma);
- iface->txLoSize = cpu_to_le32(TXLO_ENTRIES * sizeof(struct tx_desc));
-
- shared_dma = tp->shared_dma + shared_offset(txHi);
- iface->txHiAddr = cpu_to_le32(shared_dma);
- iface->txHiSize = cpu_to_le32(TXHI_ENTRIES * sizeof(struct tx_desc));
-
- shared_dma = tp->shared_dma + shared_offset(rxBuff);
- iface->rxBuffAddr = cpu_to_le32(shared_dma);
- iface->rxBuffSize = cpu_to_le32(RXFREE_ENTRIES *
- sizeof(struct rx_free));
-
- shared_dma = tp->shared_dma + shared_offset(rxLo);
- iface->rxLoAddr = cpu_to_le32(shared_dma);
- iface->rxLoSize = cpu_to_le32(RX_ENTRIES * sizeof(struct rx_desc));
-
- shared_dma = tp->shared_dma + shared_offset(rxHi);
- iface->rxHiAddr = cpu_to_le32(shared_dma);
- iface->rxHiSize = cpu_to_le32(RX_ENTRIES * sizeof(struct rx_desc));
-
- shared_dma = tp->shared_dma + shared_offset(cmd);
- iface->cmdAddr = cpu_to_le32(shared_dma);
- iface->cmdSize = cpu_to_le32(COMMAND_RING_SIZE);
-
- shared_dma = tp->shared_dma + shared_offset(resp);
- iface->respAddr = cpu_to_le32(shared_dma);
- iface->respSize = cpu_to_le32(RESPONSE_RING_SIZE);
-
- shared_dma = tp->shared_dma + shared_offset(zeroWord);
- iface->zeroAddr = cpu_to_le32(shared_dma);
-
- tp->indexes = &tp->shared->indexes;
- tp->txLoRing.ringBase = (u8 *) tp->shared->txLo;
- tp->txHiRing.ringBase = (u8 *) tp->shared->txHi;
- tp->rxLoRing.ringBase = (u8 *) tp->shared->rxLo;
- tp->rxHiRing.ringBase = (u8 *) tp->shared->rxHi;
- tp->rxBuffRing.ringBase = (u8 *) tp->shared->rxBuff;
- tp->cmdRing.ringBase = (u8 *) tp->shared->cmd;
- tp->respRing.ringBase = (u8 *) tp->shared->resp;
-
- tp->txLoRing.writeRegister = TYPHOON_REG_TX_LO_READY;
- tp->txHiRing.writeRegister = TYPHOON_REG_TX_HI_READY;
-
- tp->txlo_dma_addr = le32_to_cpu(iface->txLoAddr);
- tp->card_state = Sleeping;
-
- tp->offload = TYPHOON_OFFLOAD_IP_CHKSUM | TYPHOON_OFFLOAD_TCP_CHKSUM;
- tp->offload |= TYPHOON_OFFLOAD_UDP_CHKSUM | TSO_OFFLOAD_ON;
- tp->offload |= TYPHOON_OFFLOAD_VLAN;
-
- spin_lock_init(&tp->command_lock);
-
- /* Force the writes to the shared memory area out before continuing. */
- wmb();
-}
-
-static void
-typhoon_init_rings(struct typhoon *tp)
-{
- memset(tp->indexes, 0, sizeof(struct typhoon_indexes));
-
- tp->txLoRing.lastWrite = 0;
- tp->txHiRing.lastWrite = 0;
- tp->rxLoRing.lastWrite = 0;
- tp->rxHiRing.lastWrite = 0;
- tp->rxBuffRing.lastWrite = 0;
- tp->cmdRing.lastWrite = 0;
- tp->respRing.lastWrite = 0;
-
- tp->txLoRing.lastRead = 0;
- tp->txHiRing.lastRead = 0;
-}
-
-static const struct firmware *typhoon_fw;
-
-static int
-typhoon_request_firmware(struct typhoon *tp)
-{
- const struct typhoon_file_header *fHdr;
- const struct typhoon_section_header *sHdr;
- const u8 *image_data;
- u32 numSections;
- u32 section_len;
- u32 remaining;
- int err;
-
- if (typhoon_fw)
- return 0;
-
- err = request_firmware(&typhoon_fw, FIRMWARE_NAME, &tp->pdev->dev);
- if (err) {
- netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
- FIRMWARE_NAME);
- return err;
- }
-
- image_data = (u8 *) typhoon_fw->data;
- remaining = typhoon_fw->size;
- if (remaining < sizeof(struct typhoon_file_header))
- goto invalid_fw;
-
- fHdr = (struct typhoon_file_header *) image_data;
- if (memcmp(fHdr->tag, "TYPHOON", 8))
- goto invalid_fw;
-
- numSections = le32_to_cpu(fHdr->numSections);
- image_data += sizeof(struct typhoon_file_header);
- remaining -= sizeof(struct typhoon_file_header);
-
- while (numSections--) {
- if (remaining < sizeof(struct typhoon_section_header))
- goto invalid_fw;
-
- sHdr = (struct typhoon_section_header *) image_data;
- image_data += sizeof(struct typhoon_section_header);
- section_len = le32_to_cpu(sHdr->len);
-
- if (remaining < section_len)
- goto invalid_fw;
-
- image_data += section_len;
- remaining -= section_len;
- }
-
- return 0;
-
-invalid_fw:
- netdev_err(tp->dev, "Invalid firmware image\n");
- release_firmware(typhoon_fw);
- typhoon_fw = NULL;
- return -EINVAL;
-}
-
-static int
-typhoon_download_firmware(struct typhoon *tp)
-{
- void __iomem *ioaddr = tp->ioaddr;
- struct pci_dev *pdev = tp->pdev;
- const struct typhoon_file_header *fHdr;
- const struct typhoon_section_header *sHdr;
- const u8 *image_data;
- void *dpage;
- dma_addr_t dpage_dma;
- __sum16 csum;
- u32 irqEnabled;
- u32 irqMasked;
- u32 numSections;
- u32 section_len;
- u32 len;
- u32 load_addr;
- u32 hmac;
- int i;
- int err;
-
- image_data = (u8 *) typhoon_fw->data;
- fHdr = (struct typhoon_file_header *) image_data;
-
- /* Cannot just map the firmware image using pci_map_single() as
- * the firmware is vmalloc()'d and may not be physically contiguous,
- * so we allocate some consistent memory to copy the sections into.
- */
- err = -ENOMEM;
- dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma);
- if(!dpage) {
- netdev_err(tp->dev, "no DMA mem for firmware\n");
- goto err_out;
- }
-
- irqEnabled = ioread32(ioaddr + TYPHOON_REG_INTR_ENABLE);
- iowrite32(irqEnabled | TYPHOON_INTR_BOOTCMD,
- ioaddr + TYPHOON_REG_INTR_ENABLE);
- irqMasked = ioread32(ioaddr + TYPHOON_REG_INTR_MASK);
- iowrite32(irqMasked | TYPHOON_INTR_BOOTCMD,
- ioaddr + TYPHOON_REG_INTR_MASK);
-
- err = -ETIMEDOUT;
- if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- netdev_err(tp->dev, "card ready timeout\n");
- goto err_out_irq;
- }
-
- numSections = le32_to_cpu(fHdr->numSections);
- load_addr = le32_to_cpu(fHdr->startAddr);
-
- iowrite32(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
- iowrite32(load_addr, ioaddr + TYPHOON_REG_DOWNLOAD_BOOT_ADDR);
- hmac = le32_to_cpu(fHdr->hmacDigest[0]);
- iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_0);
- hmac = le32_to_cpu(fHdr->hmacDigest[1]);
- iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_1);
- hmac = le32_to_cpu(fHdr->hmacDigest[2]);
- iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_2);
- hmac = le32_to_cpu(fHdr->hmacDigest[3]);
- iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_3);
- hmac = le32_to_cpu(fHdr->hmacDigest[4]);
- iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_4);
- typhoon_post_pci_writes(ioaddr);
- iowrite32(TYPHOON_BOOTCMD_RUNTIME_IMAGE, ioaddr + TYPHOON_REG_COMMAND);
-
- image_data += sizeof(struct typhoon_file_header);
-
- /* The ioread32() in typhoon_wait_interrupt() will force the
- * last write to the command register to post, so
- * we don't need a typhoon_post_pci_writes() after it.
- */
- for(i = 0; i < numSections; i++) {
- sHdr = (struct typhoon_section_header *) image_data;
- image_data += sizeof(struct typhoon_section_header);
- load_addr = le32_to_cpu(sHdr->startAddr);
- section_len = le32_to_cpu(sHdr->len);
-
- while(section_len) {
- len = min_t(u32, section_len, PAGE_SIZE);
-
- if(typhoon_wait_interrupt(ioaddr) < 0 ||
- ioread32(ioaddr + TYPHOON_REG_STATUS) !=
- TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
- netdev_err(tp->dev, "segment ready timeout\n");
- goto err_out_irq;
- }
-
- /* Do an pseudo IPv4 checksum on the data -- first
- * need to convert each u16 to cpu order before
- * summing. Fortunately, due to the properties of
- * the checksum, we can do this once, at the end.
- */
- csum = csum_fold(csum_partial_copy_nocheck(image_data,
- dpage, len,
- 0));
-
- iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
- iowrite32(le16_to_cpu((__force __le16)csum),
- ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
- iowrite32(load_addr,
- ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
- iowrite32(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI);
- iowrite32(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
- typhoon_post_pci_writes(ioaddr);
- iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
- ioaddr + TYPHOON_REG_COMMAND);
-
- image_data += len;
- load_addr += len;
- section_len -= len;
- }
- }
-
- if(typhoon_wait_interrupt(ioaddr) < 0 ||
- ioread32(ioaddr + TYPHOON_REG_STATUS) !=
- TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
- netdev_err(tp->dev, "final segment ready timeout\n");
- goto err_out_irq;
- }
-
- iowrite32(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND);
-
- if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
- netdev_err(tp->dev, "boot ready timeout, status 0x%0x\n",
- ioread32(ioaddr + TYPHOON_REG_STATUS));
- goto err_out_irq;
- }
-
- err = 0;
-
-err_out_irq:
- iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK);
- iowrite32(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE);
-
- pci_free_consistent(pdev, PAGE_SIZE, dpage, dpage_dma);
-
-err_out:
- return err;
-}
-
-static int
-typhoon_boot_3XP(struct typhoon *tp, u32 initial_status)
-{
- void __iomem *ioaddr = tp->ioaddr;
-
- if(typhoon_wait_status(ioaddr, initial_status) < 0) {
- netdev_err(tp->dev, "boot ready timeout\n");
- goto out_timeout;
- }
-
- iowrite32(0, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_HI);
- iowrite32(tp->shared_dma, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_LO);
- typhoon_post_pci_writes(ioaddr);
- iowrite32(TYPHOON_BOOTCMD_REG_BOOT_RECORD,
- ioaddr + TYPHOON_REG_COMMAND);
-
- if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_RUNNING) < 0) {
- netdev_err(tp->dev, "boot finish timeout (status 0x%x)\n",
- ioread32(ioaddr + TYPHOON_REG_STATUS));
- goto out_timeout;
- }
-
- /* Clear the Transmit and Command ready registers
- */
- iowrite32(0, ioaddr + TYPHOON_REG_TX_HI_READY);
- iowrite32(0, ioaddr + TYPHOON_REG_CMD_READY);
- iowrite32(0, ioaddr + TYPHOON_REG_TX_LO_READY);
- typhoon_post_pci_writes(ioaddr);
- iowrite32(TYPHOON_BOOTCMD_BOOT, ioaddr + TYPHOON_REG_COMMAND);
-
- return 0;
-
-out_timeout:
- return -ETIMEDOUT;
-}
-
-static u32
-typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing,
- volatile __le32 * index)
-{
- u32 lastRead = txRing->lastRead;
- struct tx_desc *tx;
- dma_addr_t skb_dma;
- int dma_len;
- int type;
-
- while(lastRead != le32_to_cpu(*index)) {
- tx = (struct tx_desc *) (txRing->ringBase + lastRead);
- type = tx->flags & TYPHOON_TYPE_MASK;
-
- if(type == TYPHOON_TX_DESC) {
- /* This tx_desc describes a packet.
- */
- unsigned long ptr = tx->tx_addr;
- struct sk_buff *skb = (struct sk_buff *) ptr;
- dev_kfree_skb_irq(skb);
- } else if(type == TYPHOON_FRAG_DESC) {
- /* This tx_desc describes a memory mapping. Free it.
- */
- skb_dma = (dma_addr_t) le32_to_cpu(tx->frag.addr);
- dma_len = le16_to_cpu(tx->len);
- pci_unmap_single(tp->pdev, skb_dma, dma_len,
- PCI_DMA_TODEVICE);
- }
-
- tx->flags = 0;
- typhoon_inc_tx_index(&lastRead, 1);
- }
-
- return lastRead;
-}
-
-static void
-typhoon_tx_complete(struct typhoon *tp, struct transmit_ring *txRing,
- volatile __le32 * index)
-{
- u32 lastRead;
- int numDesc = MAX_SKB_FRAGS + 1;
-
- /* This will need changing if we start to use the Hi Tx ring. */
- lastRead = typhoon_clean_tx(tp, txRing, index);
- if(netif_queue_stopped(tp->dev) && typhoon_num_free(txRing->lastWrite,
- lastRead, TXLO_ENTRIES) > (numDesc + 2))
- netif_wake_queue(tp->dev);
-
- txRing->lastRead = lastRead;
- smp_wmb();
-}
-
-static void
-typhoon_recycle_rx_skb(struct typhoon *tp, u32 idx)
-{
- struct typhoon_indexes *indexes = tp->indexes;
- struct rxbuff_ent *rxb = &tp->rxbuffers[idx];
- struct basic_ring *ring = &tp->rxBuffRing;
- struct rx_free *r;
-
- if((ring->lastWrite + sizeof(*r)) % (RXFREE_ENTRIES * sizeof(*r)) ==
- le32_to_cpu(indexes->rxBuffCleared)) {
- /* no room in ring, just drop the skb
- */
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- return;
- }
-
- r = (struct rx_free *) (ring->ringBase + ring->lastWrite);
- typhoon_inc_rxfree_index(&ring->lastWrite, 1);
- r->virtAddr = idx;
- r->physAddr = cpu_to_le32(rxb->dma_addr);
-
- /* Tell the card about it */
- wmb();
- indexes->rxBuffReady = cpu_to_le32(ring->lastWrite);
-}
-
-static int
-typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx)
-{
- struct typhoon_indexes *indexes = tp->indexes;
- struct rxbuff_ent *rxb = &tp->rxbuffers[idx];
- struct basic_ring *ring = &tp->rxBuffRing;
- struct rx_free *r;
- struct sk_buff *skb;
- dma_addr_t dma_addr;
-
- rxb->skb = NULL;
-
- if((ring->lastWrite + sizeof(*r)) % (RXFREE_ENTRIES * sizeof(*r)) ==
- le32_to_cpu(indexes->rxBuffCleared))
- return -ENOMEM;
-
- skb = netdev_alloc_skb(tp->dev, PKT_BUF_SZ);
- if(!skb)
- return -ENOMEM;
-
-#if 0
- /* Please, 3com, fix the firmware to allow DMA to a unaligned
- * address! Pretty please?
- */
- skb_reserve(skb, 2);
-#endif
-
- dma_addr = pci_map_single(tp->pdev, skb->data,
- PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-
- /* Since no card does 64 bit DAC, the high bits will never
- * change from zero.
- */
- r = (struct rx_free *) (ring->ringBase + ring->lastWrite);
- typhoon_inc_rxfree_index(&ring->lastWrite, 1);
- r->virtAddr = idx;
- r->physAddr = cpu_to_le32(dma_addr);
- rxb->skb = skb;
- rxb->dma_addr = dma_addr;
-
- /* Tell the card about it */
- wmb();
- indexes->rxBuffReady = cpu_to_le32(ring->lastWrite);
- return 0;
-}
-
-static int
-typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * ready,
- volatile __le32 * cleared, int budget)
-{
- struct rx_desc *rx;
- struct sk_buff *skb, *new_skb;
- struct rxbuff_ent *rxb;
- dma_addr_t dma_addr;
- u32 local_ready;
- u32 rxaddr;
- int pkt_len;
- u32 idx;
- __le32 csum_bits;
- int received;
-
- received = 0;
- local_ready = le32_to_cpu(*ready);
- rxaddr = le32_to_cpu(*cleared);
- while(rxaddr != local_ready && budget > 0) {
- rx = (struct rx_desc *) (rxRing->ringBase + rxaddr);
- idx = rx->addr;
- rxb = &tp->rxbuffers[idx];
- skb = rxb->skb;
- dma_addr = rxb->dma_addr;
-
- typhoon_inc_rx_index(&rxaddr, 1);
-
- if(rx->flags & TYPHOON_RX_ERROR) {
- typhoon_recycle_rx_skb(tp, idx);
- continue;
- }
-
- pkt_len = le16_to_cpu(rx->frameLen);
-
- if(pkt_len < rx_copybreak &&
- (new_skb = netdev_alloc_skb(tp->dev, pkt_len + 2)) != NULL) {
- skb_reserve(new_skb, 2);
- pci_dma_sync_single_for_cpu(tp->pdev, dma_addr,
- PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
- skb_copy_to_linear_data(new_skb, skb->data, pkt_len);
- pci_dma_sync_single_for_device(tp->pdev, dma_addr,
- PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
- skb_put(new_skb, pkt_len);
- typhoon_recycle_rx_skb(tp, idx);
- } else {
- new_skb = skb;
- skb_put(new_skb, pkt_len);
- pci_unmap_single(tp->pdev, dma_addr, PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
- typhoon_alloc_rx_skb(tp, idx);
- }
- new_skb->protocol = eth_type_trans(new_skb, tp->dev);
- csum_bits = rx->rxStatus & (TYPHOON_RX_IP_CHK_GOOD |
- TYPHOON_RX_UDP_CHK_GOOD | TYPHOON_RX_TCP_CHK_GOOD);
- if(csum_bits ==
- (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_TCP_CHK_GOOD) ||
- csum_bits ==
- (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_UDP_CHK_GOOD)) {
- new_skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else
- skb_checksum_none_assert(new_skb);
-
- if (rx->rxStatus & TYPHOON_RX_VLAN)
- __vlan_hwaccel_put_tag(new_skb,
- ntohl(rx->vlanTag) & 0xffff);
- netif_receive_skb(new_skb);
-
- received++;
- budget--;
- }
- *cleared = cpu_to_le32(rxaddr);
-
- return received;
-}
-
-static void
-typhoon_fill_free_ring(struct typhoon *tp)
-{
- u32 i;
-
- for(i = 0; i < RXENT_ENTRIES; i++) {
- struct rxbuff_ent *rxb = &tp->rxbuffers[i];
- if(rxb->skb)
- continue;
- if(typhoon_alloc_rx_skb(tp, i) < 0)
- break;
- }
-}
-
-static int
-typhoon_poll(struct napi_struct *napi, int budget)
-{
- struct typhoon *tp = container_of(napi, struct typhoon, napi);
- struct typhoon_indexes *indexes = tp->indexes;
- int work_done;
-
- rmb();
- if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared)
- typhoon_process_response(tp, 0, NULL);
-
- if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead)
- typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared);
-
- work_done = 0;
-
- if(indexes->rxHiCleared != indexes->rxHiReady) {
- work_done += typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
- &indexes->rxHiCleared, budget);
- }
-
- if(indexes->rxLoCleared != indexes->rxLoReady) {
- work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady,
- &indexes->rxLoCleared, budget - work_done);
- }
-
- if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) {
- /* rxBuff ring is empty, try to fill it. */
- typhoon_fill_free_ring(tp);
- }
-
- if (work_done < budget) {
- napi_complete(napi);
- iowrite32(TYPHOON_INTR_NONE,
- tp->ioaddr + TYPHOON_REG_INTR_MASK);
- typhoon_post_pci_writes(tp->ioaddr);
- }
-
- return work_done;
-}
-
-static irqreturn_t
-typhoon_interrupt(int irq, void *dev_instance)
-{
- struct net_device *dev = dev_instance;
- struct typhoon *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->ioaddr;
- u32 intr_status;
-
- intr_status = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
- if(!(intr_status & TYPHOON_INTR_HOST_INT))
- return IRQ_NONE;
-
- iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
-
- if (napi_schedule_prep(&tp->napi)) {
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
- typhoon_post_pci_writes(ioaddr);
- __napi_schedule(&tp->napi);
- } else {
- netdev_err(dev, "Error, poll already scheduled\n");
- }
- return IRQ_HANDLED;
-}
-
-static void
-typhoon_free_rx_rings(struct typhoon *tp)
-{
- u32 i;
-
- for(i = 0; i < RXENT_ENTRIES; i++) {
- struct rxbuff_ent *rxb = &tp->rxbuffers[i];
- if(rxb->skb) {
- pci_unmap_single(tp->pdev, rxb->dma_addr, PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(rxb->skb);
- rxb->skb = NULL;
- }
- }
-}
-
-static int
-typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events)
-{
- struct pci_dev *pdev = tp->pdev;
- void __iomem *ioaddr = tp->ioaddr;
- struct cmd_desc xp_cmd;
- int err;
-
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_ENABLE_WAKE_EVENTS);
- xp_cmd.parm1 = events;
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0) {
- netdev_err(tp->dev, "typhoon_sleep(): wake events cmd err %d\n",
- err);
- return err;
- }
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_GOTO_SLEEP);
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0) {
- netdev_err(tp->dev, "typhoon_sleep(): sleep cmd err %d\n", err);
- return err;
- }
-
- if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_SLEEPING) < 0)
- return -ETIMEDOUT;
-
- /* Since we cannot monitor the status of the link while sleeping,
- * tell the world it went away.
- */
- netif_carrier_off(tp->dev);
-
- pci_enable_wake(tp->pdev, state, 1);
- pci_disable_device(pdev);
- return pci_set_power_state(pdev, state);
-}
-
-static int
-typhoon_wakeup(struct typhoon *tp, int wait_type)
-{
- struct pci_dev *pdev = tp->pdev;
- void __iomem *ioaddr = tp->ioaddr;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
- /* Post 2.x.x versions of the Sleep Image require a reset before
- * we can download the Runtime Image. But let's not make users of
- * the old firmware pay for the reset.
- */
- iowrite32(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND);
- if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0 ||
- (tp->capabilities & TYPHOON_WAKEUP_NEEDS_RESET))
- return typhoon_reset(ioaddr, wait_type);
-
- return 0;
-}
-
-static int
-typhoon_start_runtime(struct typhoon *tp)
-{
- struct net_device *dev = tp->dev;
- void __iomem *ioaddr = tp->ioaddr;
- struct cmd_desc xp_cmd;
- int err;
-
- typhoon_init_rings(tp);
- typhoon_fill_free_ring(tp);
-
- err = typhoon_download_firmware(tp);
- if(err < 0) {
- netdev_err(tp->dev, "cannot load runtime on 3XP\n");
- goto error_out;
- }
-
- if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
- netdev_err(tp->dev, "cannot boot 3XP\n");
- err = -EIO;
- goto error_out;
- }
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAX_PKT_SIZE);
- xp_cmd.parm1 = cpu_to_le16(PKT_BUF_SZ);
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
- xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
- xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- /* Disable IRQ coalescing -- we can reenable it when 3Com gives
- * us some more information on how to control it.
- */
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_IRQ_COALESCE_CTRL);
- xp_cmd.parm1 = 0;
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_XCVR_SELECT);
- xp_cmd.parm1 = tp->xcvr_select;
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_VLAN_TYPE_WRITE);
- xp_cmd.parm1 = cpu_to_le16(ETH_P_8021Q);
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_OFFLOAD_TASKS);
- xp_cmd.parm2 = tp->offload;
- xp_cmd.parm3 = tp->offload;
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- typhoon_set_rx_mode(dev);
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_TX_ENABLE);
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_RX_ENABLE);
- err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
- if(err < 0)
- goto error_out;
-
- tp->card_state = Running;
- smp_wmb();
-
- iowrite32(TYPHOON_INTR_ENABLE_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE);
- iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_MASK);
- typhoon_post_pci_writes(ioaddr);
-
- return 0;
-
-error_out:
- typhoon_reset(ioaddr, WaitNoSleep);
- typhoon_free_rx_rings(tp);
- typhoon_init_rings(tp);
- return err;
-}
-
-static int
-typhoon_stop_runtime(struct typhoon *tp, int wait_type)
-{
- struct typhoon_indexes *indexes = tp->indexes;
- struct transmit_ring *txLo = &tp->txLoRing;
- void __iomem *ioaddr = tp->ioaddr;
- struct cmd_desc xp_cmd;
- int i;
-
- /* Disable interrupts early, since we can't schedule a poll
- * when called with !netif_running(). This will be posted
- * when we force the posting of the command.
- */
- iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE);
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_RX_DISABLE);
- typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
-
- /* Wait 1/2 sec for any outstanding transmits to occur
- * We'll cleanup after the reset if this times out.
- */
- for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
- if(indexes->txLoCleared == cpu_to_le32(txLo->lastWrite))
- break;
- udelay(TYPHOON_UDELAY);
- }
-
- if(i == TYPHOON_WAIT_TIMEOUT)
- netdev_err(tp->dev, "halt timed out waiting for Tx to complete\n");
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_TX_DISABLE);
- typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
-
- /* save the statistics so when we bring the interface up again,
- * the values reported to userspace are correct.
- */
- tp->card_state = Sleeping;
- smp_wmb();
- typhoon_do_get_stats(tp);
- memcpy(&tp->stats_saved, &tp->stats, sizeof(struct net_device_stats));
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_HALT);
- typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
-
- if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_HALTED) < 0)
- netdev_err(tp->dev, "timed out waiting for 3XP to halt\n");
-
- if(typhoon_reset(ioaddr, wait_type) < 0) {
- netdev_err(tp->dev, "unable to reset 3XP\n");
- return -ETIMEDOUT;
- }
-
- /* cleanup any outstanding Tx packets */
- if(indexes->txLoCleared != cpu_to_le32(txLo->lastWrite)) {
- indexes->txLoCleared = cpu_to_le32(txLo->lastWrite);
- typhoon_clean_tx(tp, &tp->txLoRing, &indexes->txLoCleared);
- }
-
- return 0;
-}
-
-static void
-typhoon_tx_timeout(struct net_device *dev)
-{
- struct typhoon *tp = netdev_priv(dev);
-
- if(typhoon_reset(tp->ioaddr, WaitNoSleep) < 0) {
- netdev_warn(dev, "could not reset in tx timeout\n");
- goto truly_dead;
- }
-
- /* If we ever start using the Hi ring, it will need cleaning too */
- typhoon_clean_tx(tp, &tp->txLoRing, &tp->indexes->txLoCleared);
- typhoon_free_rx_rings(tp);
-
- if(typhoon_start_runtime(tp) < 0) {
- netdev_err(dev, "could not start runtime in tx timeout\n");
- goto truly_dead;
- }
-
- netif_wake_queue(dev);
- return;
-
-truly_dead:
- /* Reset the hardware, and turn off carrier to avoid more timeouts */
- typhoon_reset(tp->ioaddr, NoWait);
- netif_carrier_off(dev);
-}
-
-static int
-typhoon_open(struct net_device *dev)
-{
- struct typhoon *tp = netdev_priv(dev);
- int err;
-
- err = typhoon_request_firmware(tp);
- if (err)
- goto out;
-
- err = typhoon_wakeup(tp, WaitSleep);
- if(err < 0) {
- netdev_err(dev, "unable to wakeup device\n");
- goto out_sleep;
- }
-
- err = request_irq(dev->irq, typhoon_interrupt, IRQF_SHARED,
- dev->name, dev);
- if(err < 0)
- goto out_sleep;
-
- napi_enable(&tp->napi);
-
- err = typhoon_start_runtime(tp);
- if(err < 0) {
- napi_disable(&tp->napi);
- goto out_irq;
- }
-
- netif_start_queue(dev);
- return 0;
-
-out_irq:
- free_irq(dev->irq, dev);
-
-out_sleep:
- if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- netdev_err(dev, "unable to reboot into sleep img\n");
- typhoon_reset(tp->ioaddr, NoWait);
- goto out;
- }
-
- if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
- netdev_err(dev, "unable to go back to sleep\n");
-
-out:
- return err;
-}
-
-static int
-typhoon_close(struct net_device *dev)
-{
- struct typhoon *tp = netdev_priv(dev);
-
- netif_stop_queue(dev);
- napi_disable(&tp->napi);
-
- if(typhoon_stop_runtime(tp, WaitSleep) < 0)
- netdev_err(dev, "unable to stop runtime\n");
-
- /* Make sure there is no irq handler running on a different CPU. */
- free_irq(dev->irq, dev);
-
- typhoon_free_rx_rings(tp);
- typhoon_init_rings(tp);
-
- if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0)
- netdev_err(dev, "unable to boot sleep image\n");
-
- if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
- netdev_err(dev, "unable to put card to sleep\n");
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int
-typhoon_resume(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct typhoon *tp = netdev_priv(dev);
-
- /* If we're down, resume when we are upped.
- */
- if(!netif_running(dev))
- return 0;
-
- if(typhoon_wakeup(tp, WaitNoSleep) < 0) {
- netdev_err(dev, "critical: could not wake up in resume\n");
- goto reset;
- }
-
- if(typhoon_start_runtime(tp) < 0) {
- netdev_err(dev, "critical: could not start runtime in resume\n");
- goto reset;
- }
-
- netif_device_attach(dev);
- return 0;
-
-reset:
- typhoon_reset(tp->ioaddr, NoWait);
- return -EBUSY;
-}
-
-static int
-typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct typhoon *tp = netdev_priv(dev);
- struct cmd_desc xp_cmd;
-
- /* If we're down, we're already suspended.
- */
- if(!netif_running(dev))
- return 0;
-
- /* TYPHOON_OFFLOAD_VLAN is always on now, so this doesn't work */
- if(tp->wol_events & TYPHOON_WAKE_MAGIC_PKT)
- netdev_warn(dev, "cannot do WAKE_MAGIC with VLAN offloading\n");
-
- netif_device_detach(dev);
-
- if(typhoon_stop_runtime(tp, WaitNoSleep) < 0) {
- netdev_err(dev, "unable to stop runtime\n");
- goto need_resume;
- }
-
- typhoon_free_rx_rings(tp);
- typhoon_init_rings(tp);
-
- if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- netdev_err(dev, "unable to boot sleep image\n");
- goto need_resume;
- }
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
- xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
- xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
- if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
- netdev_err(dev, "unable to set mac address in suspend\n");
- goto need_resume;
- }
-
- INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
- xp_cmd.parm1 = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
- if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
- netdev_err(dev, "unable to set rx filter in suspend\n");
- goto need_resume;
- }
-
- if(typhoon_sleep(tp, pci_choose_state(pdev, state), tp->wol_events) < 0) {
- netdev_err(dev, "unable to put card to sleep\n");
- goto need_resume;
- }
-
- return 0;
-
-need_resume:
- typhoon_resume(pdev);
- return -EBUSY;
-}
-#endif
-
-static int __devinit
-typhoon_test_mmio(struct pci_dev *pdev)
-{
- void __iomem *ioaddr = pci_iomap(pdev, 1, 128);
- int mode = 0;
- u32 val;
-
- if(!ioaddr)
- goto out;
-
- if(ioread32(ioaddr + TYPHOON_REG_STATUS) !=
- TYPHOON_STATUS_WAITING_FOR_HOST)
- goto out_unmap;
-
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE);
-
- /* Ok, see if we can change our interrupt status register by
- * sending ourselves an interrupt. If so, then MMIO works.
- * The 50usec delay is arbitrary -- it could probably be smaller.
- */
- val = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
- if((val & TYPHOON_INTR_SELF) == 0) {
- iowrite32(1, ioaddr + TYPHOON_REG_SELF_INTERRUPT);
- ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
- udelay(50);
- val = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
- if(val & TYPHOON_INTR_SELF)
- mode = 1;
- }
-
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
- iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
- iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE);
- ioread32(ioaddr + TYPHOON_REG_INTR_STATUS);
-
-out_unmap:
- pci_iounmap(pdev, ioaddr);
-
-out:
- if(!mode)
- pr_info("%s: falling back to port IO\n", pci_name(pdev));
- return mode;
-}
-
-static const struct net_device_ops typhoon_netdev_ops = {
- .ndo_open = typhoon_open,
- .ndo_stop = typhoon_close,
- .ndo_start_xmit = typhoon_start_tx,
- .ndo_set_rx_mode = typhoon_set_rx_mode,
- .ndo_tx_timeout = typhoon_tx_timeout,
- .ndo_get_stats = typhoon_get_stats,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-};
-
-static int __devinit
-typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- struct net_device *dev;
- struct typhoon *tp;
- int card_id = (int) ent->driver_data;
- void __iomem *ioaddr;
- void *shared;
- dma_addr_t shared_dma;
- struct cmd_desc xp_cmd;
- struct resp_desc xp_resp[3];
- int err = 0;
- const char *err_msg;
-
- dev = alloc_etherdev(sizeof(*tp));
- if(dev == NULL) {
- err_msg = "unable to alloc new net device";
- err = -ENOMEM;
- goto error_out;
- }
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- err = pci_enable_device(pdev);
- if(err < 0) {
- err_msg = "unable to enable device";
- goto error_out_dev;
- }
-
- err = pci_set_mwi(pdev);
- if(err < 0) {
- err_msg = "unable to set MWI";
- goto error_out_disable;
- }
-
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if(err < 0) {
- err_msg = "No usable DMA configuration";
- goto error_out_mwi;
- }
-
- /* sanity checks on IO and MMIO BARs
- */
- if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
- err_msg = "region #1 not a PCI IO resource, aborting";
- err = -ENODEV;
- goto error_out_mwi;
- }
- if(pci_resource_len(pdev, 0) < 128) {
- err_msg = "Invalid PCI IO region size, aborting";
- err = -ENODEV;
- goto error_out_mwi;
- }
- if(!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
- err_msg = "region #1 not a PCI MMIO resource, aborting";
- err = -ENODEV;
- goto error_out_mwi;
- }
- if(pci_resource_len(pdev, 1) < 128) {
- err_msg = "Invalid PCI MMIO region size, aborting";
- err = -ENODEV;
- goto error_out_mwi;
- }
-
- err = pci_request_regions(pdev, KBUILD_MODNAME);
- if(err < 0) {
- err_msg = "could not request regions";
- goto error_out_mwi;
- }
-
- /* map our registers
- */
- if(use_mmio != 0 && use_mmio != 1)
- use_mmio = typhoon_test_mmio(pdev);
-
- ioaddr = pci_iomap(pdev, use_mmio, 128);
- if (!ioaddr) {
- err_msg = "cannot remap registers, aborting";
- err = -EIO;
- goto error_out_regions;
- }
-
- /* allocate pci dma space for rx and tx descriptor rings
- */
- shared = pci_alloc_consistent(pdev, sizeof(struct typhoon_shared),
- &shared_dma);
- if(!shared) {
- err_msg = "could not allocate DMA memory";
- err = -ENOMEM;
- goto error_out_remap;
- }
-
- dev->irq = pdev->irq;
- tp = netdev_priv(dev);
- tp->shared = shared;
- tp->shared_dma = shared_dma;
- tp->pdev = pdev;
- tp->tx_pdev = pdev;
- tp->ioaddr = ioaddr;
- tp->tx_ioaddr = ioaddr;
- tp->dev = dev;
-
- /* Init sequence:
- * 1) Reset the adapter to clear any bad juju
- * 2) Reload the sleep image
- * 3) Boot the sleep image
- * 4) Get the hardware address.
- * 5) Put the card to sleep.
- */
- if (typhoon_reset(ioaddr, WaitSleep) < 0) {
- err_msg = "could not reset 3XP";
- err = -EIO;
- goto error_out_dma;
- }
-
- /* Now that we've reset the 3XP and are sure it's not going to
- * write all over memory, enable bus mastering, and save our
- * state for resuming after a suspend.
- */
- pci_set_master(pdev);
- pci_save_state(pdev);
-
- typhoon_init_interface(tp);
- typhoon_init_rings(tp);
-
- if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
- err_msg = "cannot boot 3XP sleep image";
- err = -EIO;
- goto error_out_reset;
- }
-
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS);
- if(typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp) < 0) {
- err_msg = "cannot read MAC address";
- err = -EIO;
- goto error_out_reset;
- }
-
- *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
- *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
-
- if(!is_valid_ether_addr(dev->dev_addr)) {
- err_msg = "Could not obtain valid ethernet address, aborting";
- goto error_out_reset;
- }
-
- /* Read the Sleep Image version last, so the response is valid
- * later when we print out the version reported.
- */
- INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
- if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
- err_msg = "Could not get Sleep Image version";
- goto error_out_reset;
- }
-
- tp->capabilities = typhoon_card_info[card_id].capabilities;
- tp->xcvr_select = TYPHOON_XCVR_AUTONEG;
-
- /* Typhoon 1.0 Sleep Images return one response descriptor to the
- * READ_VERSIONS command. Those versions are OK after waking up
- * from sleep without needing a reset. Typhoon 1.1+ Sleep Images
- * seem to need a little extra help to get started. Since we don't
- * know how to nudge it along, just kick it.
- */
- if(xp_resp[0].numDesc != 0)
- tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET;
-
- if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) {
- err_msg = "cannot put adapter to sleep";
- err = -EIO;
- goto error_out_reset;
- }
-
- /* The chip-specific entries in the device structure. */
- dev->netdev_ops = &typhoon_netdev_ops;
- netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
- dev->watchdog_timeo = TX_TIMEOUT;
-
- SET_ETHTOOL_OPS(dev, &typhoon_ethtool_ops);
-
- /* We can handle scatter gather, up to 16 entries, and
- * we can do IP checksumming (only version 4, doh...)
- *
- * There's no way to turn off the RX VLAN offloading and stripping
- * on the current 3XP firmware -- it does not respect the offload
- * settings -- so we only allow the user to toggle the TX processing.
- */
- dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
- NETIF_F_HW_VLAN_TX;
- dev->features = dev->hw_features |
- NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM;
-
- if(register_netdev(dev) < 0) {
- err_msg = "unable to register netdev";
- goto error_out_reset;
- }
-
- pci_set_drvdata(pdev, dev);
-
- netdev_info(dev, "%s at %s 0x%llx, %pM\n",
- typhoon_card_info[card_id].name,
- use_mmio ? "MMIO" : "IO",
- (unsigned long long)pci_resource_start(pdev, use_mmio),
- dev->dev_addr);
-
- /* xp_resp still contains the response to the READ_VERSIONS command.
- * For debugging, let the user know what version he has.
- */
- if(xp_resp[0].numDesc == 0) {
- /* This is the Typhoon 1.0 type Sleep Image, last 16 bits
- * of version is Month/Day of build.
- */
- u16 monthday = le32_to_cpu(xp_resp[0].parm2) & 0xffff;
- netdev_info(dev, "Typhoon 1.0 Sleep Image built %02u/%02u/2000\n",
- monthday >> 8, monthday & 0xff);
- } else if(xp_resp[0].numDesc == 2) {
- /* This is the Typhoon 1.1+ type Sleep Image
- */
- u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
- u8 *ver_string = (u8 *) &xp_resp[1];
- ver_string[25] = 0;
- netdev_info(dev, "Typhoon 1.1+ Sleep Image version %02x.%03x.%03x %s\n",
- sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
- sleep_ver & 0xfff, ver_string);
- } else {
- netdev_warn(dev, "Unknown Sleep Image version (%u:%04x)\n",
- xp_resp[0].numDesc, le32_to_cpu(xp_resp[0].parm2));
- }
-
- return 0;
-
-error_out_reset:
- typhoon_reset(ioaddr, NoWait);
-
-error_out_dma:
- pci_free_consistent(pdev, sizeof(struct typhoon_shared),
- shared, shared_dma);
-error_out_remap:
- pci_iounmap(pdev, ioaddr);
-error_out_regions:
- pci_release_regions(pdev);
-error_out_mwi:
- pci_clear_mwi(pdev);
-error_out_disable:
- pci_disable_device(pdev);
-error_out_dev:
- free_netdev(dev);
-error_out:
- pr_err("%s: %s\n", pci_name(pdev), err_msg);
- return err;
-}
-
-static void __devexit
-typhoon_remove_one(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct typhoon *tp = netdev_priv(dev);
-
- unregister_netdev(dev);
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- typhoon_reset(tp->ioaddr, NoWait);
- pci_iounmap(pdev, tp->ioaddr);
- pci_free_consistent(pdev, sizeof(struct typhoon_shared),
- tp->shared, tp->shared_dma);
- pci_release_regions(pdev);
- pci_clear_mwi(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
- free_netdev(dev);
-}
-
-static struct pci_driver typhoon_driver = {
- .name = KBUILD_MODNAME,
- .id_table = typhoon_pci_tbl,
- .probe = typhoon_init_one,
- .remove = __devexit_p(typhoon_remove_one),
-#ifdef CONFIG_PM
- .suspend = typhoon_suspend,
- .resume = typhoon_resume,
-#endif
-};
-
-static int __init
-typhoon_init(void)
-{
- return pci_register_driver(&typhoon_driver);
-}
-
-static void __exit
-typhoon_cleanup(void)
-{
- if (typhoon_fw)
- release_firmware(typhoon_fw);
- pci_unregister_driver(&typhoon_driver);
-}
-
-module_init(typhoon_init);
-module_exit(typhoon_cleanup);
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.h b/ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.h
deleted file mode 100644
index 88187fc8..00000000
--- a/ANDROID_3.4.5/drivers/net/ethernet/3com/typhoon.h
+++ /dev/null
@@ -1,624 +0,0 @@
-/* typhoon.h: chip info for the 3Com 3CR990 family of controllers */
-/*
- Written 2002-2003 by David Dillow <dave@thedillows.org>
-
- This software may be used and distributed according to the terms of
- the GNU General Public License (GPL), incorporated herein by reference.
- Drivers based on or derived from this code fall under the GPL and must
- retain the authorship, copyright and license notice. This file is not
- a complete program and may only be used when the entire operating
- system is licensed under the GPL.
-
- This software is available on a public web site. It may enable
- cryptographic capabilities of the 3Com hardware, and may be
- exported from the United States under License Exception "TSU"
- pursuant to 15 C.F.R. Section 740.13(e).
-
- This work was funded by the National Library of Medicine under
- the Department of Energy project number 0274DD06D1 and NLM project
- number Y1-LM-2015-01.
-*/
-
-/* All Typhoon ring positions are specificed in bytes, and point to the
- * first "clean" entry in the ring -- ie the next entry we use for whatever
- * purpose.
- */
-
-/* The Typhoon basic ring
- * ringBase: where this ring lives (our virtual address)
- * lastWrite: the next entry we'll use
- */
-struct basic_ring {
- u8 *ringBase;
- u32 lastWrite;
-};
-
-/* The Typoon transmit ring -- same as a basic ring, plus:
- * lastRead: where we're at in regard to cleaning up the ring
- * writeRegister: register to use for writing (different for Hi & Lo rings)
- */
-struct transmit_ring {
- u8 *ringBase;
- u32 lastWrite;
- u32 lastRead;
- int writeRegister;
-};
-
-/* The host<->Typhoon ring index structure
- * This indicates the current positions in the rings
- *
- * All values must be in little endian format for the 3XP
- *
- * rxHiCleared: entry we've cleared to in the Hi receive ring
- * rxLoCleared: entry we've cleared to in the Lo receive ring
- * rxBuffReady: next entry we'll put a free buffer in
- * respCleared: entry we've cleared to in the response ring
- *
- * txLoCleared: entry the NIC has cleared to in the Lo transmit ring
- * txHiCleared: entry the NIC has cleared to in the Hi transmit ring
- * rxLoReady: entry the NIC has filled to in the Lo receive ring
- * rxBuffCleared: entry the NIC has cleared in the free buffer ring
- * cmdCleared: entry the NIC has cleared in the command ring
- * respReady: entry the NIC has filled to in the response ring
- * rxHiReady: entry the NIC has filled to in the Hi receive ring
- */
-struct typhoon_indexes {
- /* The first four are written by the host, and read by the NIC */
- volatile __le32 rxHiCleared;
- volatile __le32 rxLoCleared;
- volatile __le32 rxBuffReady;
- volatile __le32 respCleared;
-
- /* The remaining are written by the NIC, and read by the host */
- volatile __le32 txLoCleared;
- volatile __le32 txHiCleared;
- volatile __le32 rxLoReady;
- volatile __le32 rxBuffCleared;
- volatile __le32 cmdCleared;
- volatile __le32 respReady;
- volatile __le32 rxHiReady;
-} __packed;
-
-/* The host<->Typhoon interface
- * Our means of communicating where things are
- *
- * All values must be in little endian format for the 3XP
- *
- * ringIndex: 64 bit bus address of the index structure
- * txLoAddr: 64 bit bus address of the Lo transmit ring
- * txLoSize: size (in bytes) of the Lo transmit ring
- * txHi*: as above for the Hi priority transmit ring
- * rxLo*: as above for the Lo priority receive ring
- * rxBuff*: as above for the free buffer ring
- * cmd*: as above for the command ring
- * resp*: as above for the response ring
- * zeroAddr: 64 bit bus address of a zero word (for DMA)
- * rxHi*: as above for the Hi Priority receive ring
- *
- * While there is room for 64 bit addresses, current versions of the 3XP
- * only do 32 bit addresses, so the *Hi for each of the above will always
- * be zero.
- */
-struct typhoon_interface {
- __le32 ringIndex;
- __le32 ringIndexHi;
- __le32 txLoAddr;
- __le32 txLoAddrHi;
- __le32 txLoSize;
- __le32 txHiAddr;
- __le32 txHiAddrHi;
- __le32 txHiSize;
- __le32 rxLoAddr;
- __le32 rxLoAddrHi;
- __le32 rxLoSize;
- __le32 rxBuffAddr;
- __le32 rxBuffAddrHi;
- __le32 rxBuffSize;
- __le32 cmdAddr;
- __le32 cmdAddrHi;
- __le32 cmdSize;
- __le32 respAddr;
- __le32 respAddrHi;
- __le32 respSize;
- __le32 zeroAddr;
- __le32 zeroAddrHi;
- __le32 rxHiAddr;
- __le32 rxHiAddrHi;
- __le32 rxHiSize;
-} __packed;
-
-/* The Typhoon transmit/fragment descriptor
- *
- * A packet is described by a packet descriptor, followed by option descriptors,
- * if any, then one or more fragment descriptors.
- *
- * Packet descriptor:
- * flags: Descriptor type
- * len:i zero, or length of this packet
- * addr*: 8 bytes of opaque data to the firmware -- for skb pointer
- * processFlags: Determine offload tasks to perform on this packet.
- *
- * Fragment descriptor:
- * flags: Descriptor type
- * len:i length of this fragment
- * addr: low bytes of DMA address for this part of the packet
- * addrHi: hi bytes of DMA address for this part of the packet
- * processFlags: must be zero
- *
- * TYPHOON_DESC_VALID is not mentioned in their docs, but their Linux
- * driver uses it.
- */
-struct tx_desc {
- u8 flags;
-#define TYPHOON_TYPE_MASK 0x07
-#define TYPHOON_FRAG_DESC 0x00
-#define TYPHOON_TX_DESC 0x01
-#define TYPHOON_CMD_DESC 0x02
-#define TYPHOON_OPT_DESC 0x03
-#define TYPHOON_RX_DESC 0x04
-#define TYPHOON_RESP_DESC 0x05
-#define TYPHOON_OPT_TYPE_MASK 0xf0
-#define TYPHOON_OPT_IPSEC 0x00
-#define TYPHOON_OPT_TCP_SEG 0x10
-#define TYPHOON_CMD_RESPOND 0x40
-#define TYPHOON_RESP_ERROR 0x40
-#define TYPHOON_RX_ERROR 0x40
-#define TYPHOON_DESC_VALID 0x80
- u8 numDesc;
- __le16 len;
- union {
- struct {
- __le32 addr;
- __le32 addrHi;
- } frag;
- u64 tx_addr; /* opaque for hardware, for TX_DESC */
- };
- __le32 processFlags;
-#define TYPHOON_TX_PF_NO_CRC cpu_to_le32(0x00000001)
-#define TYPHOON_TX_PF_IP_CHKSUM cpu_to_le32(0x00000002)
-#define TYPHOON_TX_PF_TCP_CHKSUM cpu_to_le32(0x00000004)
-#define TYPHOON_TX_PF_TCP_SEGMENT cpu_to_le32(0x00000008)
-#define TYPHOON_TX_PF_INSERT_VLAN cpu_to_le32(0x00000010)
-#define TYPHOON_TX_PF_IPSEC cpu_to_le32(0x00000020)
-#define TYPHOON_TX_PF_VLAN_PRIORITY cpu_to_le32(0x00000040)
-#define TYPHOON_TX_PF_UDP_CHKSUM cpu_to_le32(0x00000080)
-#define TYPHOON_TX_PF_PAD_FRAME cpu_to_le32(0x00000100)
-#define TYPHOON_TX_PF_RESERVED cpu_to_le32(0x00000e00)
-#define TYPHOON_TX_PF_VLAN_MASK cpu_to_le32(0x0ffff000)
-#define TYPHOON_TX_PF_INTERNAL cpu_to_le32(0xf0000000)
-#define TYPHOON_TX_PF_VLAN_TAG_SHIFT 12
-} __packed;
-
-/* The TCP Segmentation offload option descriptor
- *
- * flags: descriptor type
- * numDesc: must be 1
- * mss_flags: bits 0-11 (little endian) are MSS, 12 is first TSO descriptor
- * 13 is list TSO descriptor, set both if only one TSO
- * respAddrLo: low bytes of address of the bytesTx field of this descriptor
- * bytesTx: total number of bytes in this TSO request
- * status: 0 on completion
- */
-struct tcpopt_desc {
- u8 flags;
- u8 numDesc;
- __le16 mss_flags;
-#define TYPHOON_TSO_FIRST cpu_to_le16(0x1000)
-#define TYPHOON_TSO_LAST cpu_to_le16(0x2000)
- __le32 respAddrLo;
- __le32 bytesTx;
- __le32 status;
-} __packed;
-
-/* The IPSEC Offload descriptor
- *
- * flags: descriptor type
- * numDesc: must be 1
- * ipsecFlags: bit 0: 0 -- generate IV, 1 -- use supplied IV
- * sa1, sa2: Security Association IDs for this packet
- * reserved: set to 0
- */
-struct ipsec_desc {
- u8 flags;
- u8 numDesc;
- __le16 ipsecFlags;
-#define TYPHOON_IPSEC_GEN_IV cpu_to_le16(0x0000)
-#define TYPHOON_IPSEC_USE_IV cpu_to_le16(0x0001)
- __le32 sa1;
- __le32 sa2;
- __le32 reserved;
-} __packed;
-
-/* The Typhoon receive descriptor (Updated by NIC)
- *
- * flags: Descriptor type, error indication
- * numDesc: Always zero
- * frameLen: the size of the packet received
- * addr: low 32 bytes of the virtual addr passed in for this buffer
- * addrHi: high 32 bytes of the virtual addr passed in for this buffer
- * rxStatus: Error if set in flags, otherwise result of offload processing
- * filterResults: results of filtering on packet, not used
- * ipsecResults: Results of IPSEC processing
- * vlanTag: the 801.2q TCI from the packet
- */
-struct rx_desc {
- u8 flags;
- u8 numDesc;
- __le16 frameLen;
- u32 addr; /* opaque, comes from virtAddr */
- u32 addrHi; /* opaque, comes from virtAddrHi */
- __le32 rxStatus;
-#define TYPHOON_RX_ERR_INTERNAL cpu_to_le32(0x00000000)
-#define TYPHOON_RX_ERR_FIFO_UNDERRUN cpu_to_le32(0x00000001)
-#define TYPHOON_RX_ERR_BAD_SSD cpu_to_le32(0x00000002)
-#define TYPHOON_RX_ERR_RUNT cpu_to_le32(0x00000003)
-#define TYPHOON_RX_ERR_CRC cpu_to_le32(0x00000004)
-#define TYPHOON_RX_ERR_OVERSIZE cpu_to_le32(0x00000005)
-#define TYPHOON_RX_ERR_ALIGN cpu_to_le32(0x00000006)
-#define TYPHOON_RX_ERR_DRIBBLE cpu_to_le32(0x00000007)
-#define TYPHOON_RX_PROTO_MASK cpu_to_le32(0x00000003)
-#define TYPHOON_RX_PROTO_UNKNOWN cpu_to_le32(0x00000000)
-#define TYPHOON_RX_PROTO_IP cpu_to_le32(0x00000001)
-#define TYPHOON_RX_PROTO_IPX cpu_to_le32(0x00000002)
-#define TYPHOON_RX_VLAN cpu_to_le32(0x00000004)
-#define TYPHOON_RX_IP_FRAG cpu_to_le32(0x00000008)
-#define TYPHOON_RX_IPSEC cpu_to_le32(0x00000010)
-#define TYPHOON_RX_IP_CHK_FAIL cpu_to_le32(0x00000020)
-#define TYPHOON_RX_TCP_CHK_FAIL cpu_to_le32(0x00000040)
-#define TYPHOON_RX_UDP_CHK_FAIL cpu_to_le32(0x00000080)
-#define TYPHOON_RX_IP_CHK_GOOD cpu_to_le32(0x00000100)
-#define TYPHOON_RX_TCP_CHK_GOOD cpu_to_le32(0x00000200)
-#define TYPHOON_RX_UDP_CHK_GOOD cpu_to_le32(0x00000400)
- __le16 filterResults;
-#define TYPHOON_RX_FILTER_MASK cpu_to_le16(0x7fff)
-#define TYPHOON_RX_FILTERED cpu_to_le16(0x8000)
- __le16 ipsecResults;
-#define TYPHOON_RX_OUTER_AH_GOOD cpu_to_le16(0x0001)
-#define TYPHOON_RX_OUTER_ESP_GOOD cpu_to_le16(0x0002)
-#define TYPHOON_RX_INNER_AH_GOOD cpu_to_le16(0x0004)
-#define TYPHOON_RX_INNER_ESP_GOOD cpu_to_le16(0x0008)
-#define TYPHOON_RX_OUTER_AH_FAIL cpu_to_le16(0x0010)
-#define TYPHOON_RX_OUTER_ESP_FAIL cpu_to_le16(0x0020)
-#define TYPHOON_RX_INNER_AH_FAIL cpu_to_le16(0x0040)
-#define TYPHOON_RX_INNER_ESP_FAIL cpu_to_le16(0x0080)
-#define TYPHOON_RX_UNKNOWN_SA cpu_to_le16(0x0100)
-#define TYPHOON_RX_ESP_FORMAT_ERR cpu_to_le16(0x0200)
- __be32 vlanTag;
-} __packed;
-
-/* The Typhoon free buffer descriptor, used to give a buffer to the NIC
- *
- * physAddr: low 32 bits of the bus address of the buffer
- * physAddrHi: high 32 bits of the bus address of the buffer, always zero
- * virtAddr: low 32 bits of the skb address
- * virtAddrHi: high 32 bits of the skb address, always zero
- *
- * the virt* address is basically two 32 bit cookies, just passed back
- * from the NIC
- */
-struct rx_free {
- __le32 physAddr;
- __le32 physAddrHi;
- u32 virtAddr;
- u32 virtAddrHi;
-} __packed;
-
-/* The Typhoon command descriptor, used for commands and responses
- *
- * flags: descriptor type
- * numDesc: number of descriptors following in this command/response,
- * ie, zero for a one descriptor command
- * cmd: the command
- * seqNo: sequence number (unused)
- * parm1: use varies by command
- * parm2: use varies by command
- * parm3: use varies by command
- */
-struct cmd_desc {
- u8 flags;
- u8 numDesc;
- __le16 cmd;
-#define TYPHOON_CMD_TX_ENABLE cpu_to_le16(0x0001)
-#define TYPHOON_CMD_TX_DISABLE cpu_to_le16(0x0002)
-#define TYPHOON_CMD_RX_ENABLE cpu_to_le16(0x0003)
-#define TYPHOON_CMD_RX_DISABLE cpu_to_le16(0x0004)
-#define TYPHOON_CMD_SET_RX_FILTER cpu_to_le16(0x0005)
-#define TYPHOON_CMD_READ_STATS cpu_to_le16(0x0007)
-#define TYPHOON_CMD_XCVR_SELECT cpu_to_le16(0x0013)
-#define TYPHOON_CMD_SET_MAX_PKT_SIZE cpu_to_le16(0x001a)
-#define TYPHOON_CMD_READ_MEDIA_STATUS cpu_to_le16(0x001b)
-#define TYPHOON_CMD_GOTO_SLEEP cpu_to_le16(0x0023)
-#define TYPHOON_CMD_SET_MULTICAST_HASH cpu_to_le16(0x0025)
-#define TYPHOON_CMD_SET_MAC_ADDRESS cpu_to_le16(0x0026)
-#define TYPHOON_CMD_READ_MAC_ADDRESS cpu_to_le16(0x0027)
-#define TYPHOON_CMD_VLAN_TYPE_WRITE cpu_to_le16(0x002b)
-#define TYPHOON_CMD_CREATE_SA cpu_to_le16(0x0034)
-#define TYPHOON_CMD_DELETE_SA cpu_to_le16(0x0035)
-#define TYPHOON_CMD_READ_VERSIONS cpu_to_le16(0x0043)
-#define TYPHOON_CMD_IRQ_COALESCE_CTRL cpu_to_le16(0x0045)
-#define TYPHOON_CMD_ENABLE_WAKE_EVENTS cpu_to_le16(0x0049)
-#define TYPHOON_CMD_SET_OFFLOAD_TASKS cpu_to_le16(0x004f)
-#define TYPHOON_CMD_HELLO_RESP cpu_to_le16(0x0057)
-#define TYPHOON_CMD_HALT cpu_to_le16(0x005d)
-#define TYPHOON_CMD_READ_IPSEC_INFO cpu_to_le16(0x005e)
-#define TYPHOON_CMD_GET_IPSEC_ENABLE cpu_to_le16(0x0067)
-#define TYPHOON_CMD_GET_CMD_LVL cpu_to_le16(0x0069)
- u16 seqNo;
- __le16 parm1;
- __le32 parm2;
- __le32 parm3;
-} __packed;
-
-/* The Typhoon response descriptor, see command descriptor for details
- */
-struct resp_desc {
- u8 flags;
- u8 numDesc;
- __le16 cmd;
- __le16 seqNo;
- __le16 parm1;
- __le32 parm2;
- __le32 parm3;
-} __packed;
-
-#define INIT_COMMAND_NO_RESPONSE(x, command) \
- do { struct cmd_desc *_ptr = (x); \
- memset(_ptr, 0, sizeof(struct cmd_desc)); \
- _ptr->flags = TYPHOON_CMD_DESC | TYPHOON_DESC_VALID; \
- _ptr->cmd = command; \
- } while(0)
-
-/* We set seqNo to 1 if we're expecting a response from this command */
-#define INIT_COMMAND_WITH_RESPONSE(x, command) \
- do { struct cmd_desc *_ptr = (x); \
- memset(_ptr, 0, sizeof(struct cmd_desc)); \
- _ptr->flags = TYPHOON_CMD_RESPOND | TYPHOON_CMD_DESC; \
- _ptr->flags |= TYPHOON_DESC_VALID; \
- _ptr->cmd = command; \
- _ptr->seqNo = 1; \
- } while(0)
-
-/* TYPHOON_CMD_SET_RX_FILTER filter bits (cmd.parm1)
- */
-#define TYPHOON_RX_FILTER_DIRECTED cpu_to_le16(0x0001)
-#define TYPHOON_RX_FILTER_ALL_MCAST cpu_to_le16(0x0002)
-#define TYPHOON_RX_FILTER_BROADCAST cpu_to_le16(0x0004)
-#define TYPHOON_RX_FILTER_PROMISCOUS cpu_to_le16(0x0008)
-#define TYPHOON_RX_FILTER_MCAST_HASH cpu_to_le16(0x0010)
-
-/* TYPHOON_CMD_READ_STATS response format
- */
-struct stats_resp {
- u8 flags;
- u8 numDesc;
- __le16 cmd;
- __le16 seqNo;
- __le16 unused;
- __le32 txPackets;
- __le64 txBytes;
- __le32 txDeferred;
- __le32 txLateCollisions;
- __le32 txCollisions;
- __le32 txCarrierLost;
- __le32 txMultipleCollisions;
- __le32 txExcessiveCollisions;
- __le32 txFifoUnderruns;
- __le32 txMulticastTxOverflows;
- __le32 txFiltered;
- __le32 rxPacketsGood;
- __le64 rxBytesGood;
- __le32 rxFifoOverruns;
- __le32 BadSSD;
- __le32 rxCrcErrors;
- __le32 rxOversized;
- __le32 rxBroadcast;
- __le32 rxMulticast;
- __le32 rxOverflow;
- __le32 rxFiltered;
- __le32 linkStatus;
-#define TYPHOON_LINK_STAT_MASK cpu_to_le32(0x00000001)
-#define TYPHOON_LINK_GOOD cpu_to_le32(0x00000001)
-#define TYPHOON_LINK_BAD cpu_to_le32(0x00000000)
-#define TYPHOON_LINK_SPEED_MASK cpu_to_le32(0x00000002)
-#define TYPHOON_LINK_100MBPS cpu_to_le32(0x00000002)
-#define TYPHOON_LINK_10MBPS cpu_to_le32(0x00000000)
-#define TYPHOON_LINK_DUPLEX_MASK cpu_to_le32(0x00000004)
-#define TYPHOON_LINK_FULL_DUPLEX cpu_to_le32(0x00000004)
-#define TYPHOON_LINK_HALF_DUPLEX cpu_to_le32(0x00000000)
- __le32 unused2;
- __le32 unused3;
-} __packed;
-
-/* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
- */
-#define TYPHOON_XCVR_10HALF cpu_to_le16(0x0000)
-#define TYPHOON_XCVR_10FULL cpu_to_le16(0x0001)
-#define TYPHOON_XCVR_100HALF cpu_to_le16(0x0002)
-#define TYPHOON_XCVR_100FULL cpu_to_le16(0x0003)
-#define TYPHOON_XCVR_AUTONEG cpu_to_le16(0x0004)
-
-/* TYPHOON_CMD_READ_MEDIA_STATUS (resp.parm1)
- */
-#define TYPHOON_MEDIA_STAT_CRC_STRIP_DISABLE cpu_to_le16(0x0004)
-#define TYPHOON_MEDIA_STAT_COLLISION_DETECT cpu_to_le16(0x0010)
-#define TYPHOON_MEDIA_STAT_CARRIER_SENSE cpu_to_le16(0x0020)
-#define TYPHOON_MEDIA_STAT_POLARITY_REV cpu_to_le16(0x0400)
-#define TYPHOON_MEDIA_STAT_NO_LINK cpu_to_le16(0x0800)
-
-/* TYPHOON_CMD_SET_MULTICAST_HASH enable values (cmd.parm1)
- */
-#define TYPHOON_MCAST_HASH_DISABLE cpu_to_le16(0x0000)
-#define TYPHOON_MCAST_HASH_ENABLE cpu_to_le16(0x0001)
-#define TYPHOON_MCAST_HASH_SET cpu_to_le16(0x0002)
-
-/* TYPHOON_CMD_CREATE_SA descriptor and settings
- */
-struct sa_descriptor {
- u8 flags;
- u8 numDesc;
- u16 cmd;
- u16 seqNo;
- u16 mode;
-#define TYPHOON_SA_MODE_NULL cpu_to_le16(0x0000)
-#define TYPHOON_SA_MODE_AH cpu_to_le16(0x0001)
-#define TYPHOON_SA_MODE_ESP cpu_to_le16(0x0002)
- u8 hashFlags;
-#define TYPHOON_SA_HASH_ENABLE 0x01
-#define TYPHOON_SA_HASH_SHA1 0x02
-#define TYPHOON_SA_HASH_MD5 0x04
- u8 direction;
-#define TYPHOON_SA_DIR_RX 0x00
-#define TYPHOON_SA_DIR_TX 0x01
- u8 encryptionFlags;
-#define TYPHOON_SA_ENCRYPT_ENABLE 0x01
-#define TYPHOON_SA_ENCRYPT_DES 0x02
-#define TYPHOON_SA_ENCRYPT_3DES 0x00
-#define TYPHOON_SA_ENCRYPT_3DES_2KEY 0x00
-#define TYPHOON_SA_ENCRYPT_3DES_3KEY 0x04
-#define TYPHOON_SA_ENCRYPT_CBC 0x08
-#define TYPHOON_SA_ENCRYPT_ECB 0x00
- u8 specifyIndex;
-#define TYPHOON_SA_SPECIFY_INDEX 0x01
-#define TYPHOON_SA_GENERATE_INDEX 0x00
- u32 SPI;
- u32 destAddr;
- u32 destMask;
- u8 integKey[20];
- u8 confKey[24];
- u32 index;
- u32 unused;
- u32 unused2;
-} __packed;
-
-/* TYPHOON_CMD_SET_OFFLOAD_TASKS bits (cmd.parm2 (Tx) & cmd.parm3 (Rx))
- * This is all for IPv4.
- */
-#define TYPHOON_OFFLOAD_TCP_CHKSUM cpu_to_le32(0x00000002)
-#define TYPHOON_OFFLOAD_UDP_CHKSUM cpu_to_le32(0x00000004)
-#define TYPHOON_OFFLOAD_IP_CHKSUM cpu_to_le32(0x00000008)
-#define TYPHOON_OFFLOAD_IPSEC cpu_to_le32(0x00000010)
-#define TYPHOON_OFFLOAD_BCAST_THROTTLE cpu_to_le32(0x00000020)
-#define TYPHOON_OFFLOAD_DHCP_PREVENT cpu_to_le32(0x00000040)
-#define TYPHOON_OFFLOAD_VLAN cpu_to_le32(0x00000080)
-#define TYPHOON_OFFLOAD_FILTERING cpu_to_le32(0x00000100)
-#define TYPHOON_OFFLOAD_TCP_SEGMENT cpu_to_le32(0x00000200)
-
-/* TYPHOON_CMD_ENABLE_WAKE_EVENTS bits (cmd.parm1)
- */
-#define TYPHOON_WAKE_MAGIC_PKT cpu_to_le16(0x01)
-#define TYPHOON_WAKE_LINK_EVENT cpu_to_le16(0x02)
-#define TYPHOON_WAKE_ICMP_ECHO cpu_to_le16(0x04)
-#define TYPHOON_WAKE_ARP cpu_to_le16(0x08)
-
-/* These are used to load the firmware image on the NIC
- */
-struct typhoon_file_header {
- u8 tag[8];
- __le32 version;
- __le32 numSections;
- __le32 startAddr;
- __le32 hmacDigest[5];
-} __packed;
-
-struct typhoon_section_header {
- __le32 len;
- u16 checksum;
- u16 reserved;
- __le32 startAddr;
-} __packed;
-
-/* The Typhoon Register offsets
- */
-#define TYPHOON_REG_SOFT_RESET 0x00
-#define TYPHOON_REG_INTR_STATUS 0x04
-#define TYPHOON_REG_INTR_ENABLE 0x08
-#define TYPHOON_REG_INTR_MASK 0x0c
-#define TYPHOON_REG_SELF_INTERRUPT 0x10
-#define TYPHOON_REG_HOST2ARM7 0x14
-#define TYPHOON_REG_HOST2ARM6 0x18
-#define TYPHOON_REG_HOST2ARM5 0x1c
-#define TYPHOON_REG_HOST2ARM4 0x20
-#define TYPHOON_REG_HOST2ARM3 0x24
-#define TYPHOON_REG_HOST2ARM2 0x28
-#define TYPHOON_REG_HOST2ARM1 0x2c
-#define TYPHOON_REG_HOST2ARM0 0x30
-#define TYPHOON_REG_ARM2HOST3 0x34
-#define TYPHOON_REG_ARM2HOST2 0x38
-#define TYPHOON_REG_ARM2HOST1 0x3c
-#define TYPHOON_REG_ARM2HOST0 0x40
-
-#define TYPHOON_REG_BOOT_DATA_LO TYPHOON_REG_HOST2ARM5
-#define TYPHOON_REG_BOOT_DATA_HI TYPHOON_REG_HOST2ARM4
-#define TYPHOON_REG_BOOT_DEST_ADDR TYPHOON_REG_HOST2ARM3
-#define TYPHOON_REG_BOOT_CHECKSUM TYPHOON_REG_HOST2ARM2
-#define TYPHOON_REG_BOOT_LENGTH TYPHOON_REG_HOST2ARM1
-
-#define TYPHOON_REG_DOWNLOAD_BOOT_ADDR TYPHOON_REG_HOST2ARM1
-#define TYPHOON_REG_DOWNLOAD_HMAC_0 TYPHOON_REG_HOST2ARM2
-#define TYPHOON_REG_DOWNLOAD_HMAC_1 TYPHOON_REG_HOST2ARM3
-#define TYPHOON_REG_DOWNLOAD_HMAC_2 TYPHOON_REG_HOST2ARM4
-#define TYPHOON_REG_DOWNLOAD_HMAC_3 TYPHOON_REG_HOST2ARM5
-#define TYPHOON_REG_DOWNLOAD_HMAC_4 TYPHOON_REG_HOST2ARM6
-
-#define TYPHOON_REG_BOOT_RECORD_ADDR_HI TYPHOON_REG_HOST2ARM2
-#define TYPHOON_REG_BOOT_RECORD_ADDR_LO TYPHOON_REG_HOST2ARM1
-
-#define TYPHOON_REG_TX_LO_READY TYPHOON_REG_HOST2ARM3
-#define TYPHOON_REG_CMD_READY TYPHOON_REG_HOST2ARM2
-#define TYPHOON_REG_TX_HI_READY TYPHOON_REG_HOST2ARM1
-
-#define TYPHOON_REG_COMMAND TYPHOON_REG_HOST2ARM0
-#define TYPHOON_REG_HEARTBEAT TYPHOON_REG_ARM2HOST3
-#define TYPHOON_REG_STATUS TYPHOON_REG_ARM2HOST0
-
-/* 3XP Reset values (TYPHOON_REG_SOFT_RESET)
- */
-#define TYPHOON_RESET_ALL 0x7f
-#define TYPHOON_RESET_NONE 0x00
-
-/* 3XP irq bits (TYPHOON_REG_INTR{STATUS,ENABLE,MASK})
- *
- * Some of these came from OpenBSD, as the 3Com docs have it wrong
- * (INTR_SELF) or don't list it at all (INTR_*_ABORT)
- *
- * Enabling irqs on the Heartbeat reg (ArmToHost3) gets you an irq
- * about every 8ms, so don't do it.
- */
-#define TYPHOON_INTR_HOST_INT 0x00000001
-#define TYPHOON_INTR_ARM2HOST0 0x00000002
-#define TYPHOON_INTR_ARM2HOST1 0x00000004
-#define TYPHOON_INTR_ARM2HOST2 0x00000008
-#define TYPHOON_INTR_ARM2HOST3 0x00000010
-#define TYPHOON_INTR_DMA0 0x00000020
-#define TYPHOON_INTR_DMA1 0x00000040
-#define TYPHOON_INTR_DMA2 0x00000080
-#define TYPHOON_INTR_DMA3 0x00000100
-#define TYPHOON_INTR_MASTER_ABORT 0x00000200
-#define TYPHOON_INTR_TARGET_ABORT 0x00000400
-#define TYPHOON_INTR_SELF 0x00000800
-#define TYPHOON_INTR_RESERVED 0xfffff000
-
-#define TYPHOON_INTR_BOOTCMD TYPHOON_INTR_ARM2HOST0
-
-#define TYPHOON_INTR_ENABLE_ALL 0xffffffef
-#define TYPHOON_INTR_ALL 0xffffffff
-#define TYPHOON_INTR_NONE 0x00000000
-
-/* The commands for the 3XP chip (TYPHOON_REG_COMMAND)
- */
-#define TYPHOON_BOOTCMD_BOOT 0x00
-#define TYPHOON_BOOTCMD_WAKEUP 0xfa
-#define TYPHOON_BOOTCMD_DNLD_COMPLETE 0xfb
-#define TYPHOON_BOOTCMD_SEG_AVAILABLE 0xfc
-#define TYPHOON_BOOTCMD_RUNTIME_IMAGE 0xfd
-#define TYPHOON_BOOTCMD_REG_BOOT_RECORD 0xff
-
-/* 3XP Status values (TYPHOON_REG_STATUS)
- */
-#define TYPHOON_STATUS_WAITING_FOR_BOOT 0x07
-#define TYPHOON_STATUS_SECOND_INIT 0x08
-#define TYPHOON_STATUS_RUNNING 0x09
-#define TYPHOON_STATUS_WAITING_FOR_HOST 0x0d
-#define TYPHOON_STATUS_WAITING_FOR_SEGMENT 0x10
-#define TYPHOON_STATUS_SLEEPING 0x11
-#define TYPHOON_STATUS_HALTED 0x14