fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / 3c515.c
index fc86a35..c307ce6 100644 (file)
        Annapolis MD 21403
 
 
-       2000/2/2- Added support for kernel-level ISAPnP 
+       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@redhat.com)
 
 */
@@ -34,7 +34,7 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " becker@scyld.com and others\n";
 /* "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 const int rx_copybreak = 200;
+static int rx_copybreak = 200;
 
 /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
 static const int mtu = 1500;
@@ -57,7 +57,6 @@ static int max_interrupt_work = 20;
 #define RX_RING_SIZE   16
 #define PKT_BUF_SZ             1536    /* Size of each temporary Rx buffer. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/isapnp.h>
 #include <linux/kernel.h>
@@ -72,9 +71,9 @@ static int max_interrupt_work = 20;
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/ethtool.h>
+#include <linux/bitops.h>
 
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
@@ -86,15 +85,7 @@ static int max_interrupt_work = 20;
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
 MODULE_LICENSE("GPL");
-
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-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");
+MODULE_VERSION(DRV_VERSION);
 
 /* "Knobs" for adjusting internal parameters. */
 /* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
@@ -196,9 +187,9 @@ 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, 
+       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,
@@ -347,15 +338,15 @@ static struct media_table {
                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}, 
+} 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},
 };
 
@@ -373,7 +364,7 @@ static int nopnp;
 #endif /* __ISAPNP__ */
 
 static struct net_device *corkscrew_scan(int unit);
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+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);
@@ -382,16 +373,15 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
 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,
-                                   struct pt_regs *regs);
+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 struct ethtool_ops netdev_ethtool_ops;
-\f
+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.
@@ -409,6 +399,16 @@ 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);
@@ -471,7 +471,7 @@ static int check_device(unsigned ioaddr)
 
 static void cleanup_card(struct net_device *dev)
 {
-       struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        list_del_init(&vp->list);
        if (dev->dma)
                free_dma(dev->dma);
@@ -537,10 +537,9 @@ static struct net_device *corkscrew_scan(int unit)
                        printk(KERN_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 */
-                       corkscrew_setup(dev, ioaddr, idev, cards_found++);
                        SET_NETDEV_DEV(dev, &idev->dev);
                        pnp_cards++;
-                       err = register_netdev(dev);
+                       err = corkscrew_setup(dev, ioaddr, idev, cards_found++);
                        if (!err)
                                return dev;
                        cleanup_card(dev);
@@ -556,8 +555,7 @@ no_pnp:
 
                printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
                     inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
-               corkscrew_setup(dev, ioaddr, NULL, cards_found++);
-               err = register_netdev(dev);
+               err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
                if (!err)
                        return dev;
                cleanup_card(dev);
@@ -566,10 +564,10 @@ no_pnp:
        return NULL;
 }
 
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+static int corkscrew_setup(struct net_device *dev, int ioaddr,
                            struct pnp_dev *idev, int card_number)
 {
-       struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        unsigned int eeprom[0x40], checksum = 0;        /* EEPROM contents */
        int i;
        int irq;
@@ -613,7 +611,7 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
        printk(KERN_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++) {
@@ -689,14 +687,15 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
        dev->get_stats = &corkscrew_get_stats;
        dev->set_multicast_list = &set_rx_mode;
        dev->ethtool_ops = &netdev_ethtool_ops;
+
+       return register_netdev(dev);
 }
-\f
+
 
 static int corkscrew_open(struct net_device *dev)
 {
        int ioaddr = dev->base_addr;
-       struct corkscrew_private *vp =
-           (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        union wn3_config config;
        int i;
 
@@ -715,7 +714,7 @@ static int corkscrew_open(struct net_device *dev)
        } 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)) 
+               while (!(vp->available_media & media_tbl[dev->if_port].mask))
                        dev->if_port = media_tbl[dev->if_port].next;
 
                if (corkscrew_debug > 1)
@@ -760,7 +759,7 @@ static int corkscrew_open(struct net_device *dev)
                                   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, SA_SHIRQ,
+       } else if (request_irq(dev->irq, &corkscrew_interrupt, IRQF_SHARED,
                               vp->product_name, dev)) {
                return -EAGAIN;
        }
@@ -821,7 +820,7 @@ static int corkscrew_open(struct net_device *dev)
                                break;  /* Bad news!  */
                        skb->dev = dev; /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[i].addr = isa_virt_to_bus(skb->tail);
+                       vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
                }
                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);
@@ -831,7 +830,7 @@ static int corkscrew_open(struct net_device *dev)
                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] = 0;
+                       vp->tx_skbuff[i] = NULL;
                outl(0, ioaddr + DownListPtr);
        }
        /* Set receiver mode: presumably accept b-case and phys addr only. */
@@ -861,7 +860,7 @@ static void corkscrew_timer(unsigned long data)
 {
 #ifdef AUTOMEDIA
        struct net_device *dev = (struct net_device *) data;
-       struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
        unsigned long flags;
        int ok = 0;
@@ -871,7 +870,7 @@ static void corkscrew_timer(unsigned long data)
                       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;
@@ -911,7 +910,7 @@ static void corkscrew_timer(unsigned long data)
                                    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)
@@ -940,7 +939,7 @@ static void corkscrew_timer(unsigned long data)
                }
                EL3WINDOW(old_window);
        }
-       
+
        spin_unlock_irqrestore(&vp->lock, flags);
        if (corkscrew_debug > 1)
                printk("%s: Media selection timer finished, %s.\n",
@@ -953,8 +952,7 @@ static void corkscrew_timer(unsigned long data)
 static void corkscrew_timeout(struct net_device *dev)
 {
        int i;
-       struct corkscrew_private *vp =
-           (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
 
        printk(KERN_WARNING
@@ -993,8 +991,7 @@ static void corkscrew_timeout(struct net_device *dev)
 static int corkscrew_start_xmit(struct sk_buff *skb,
                                struct net_device *dev)
 {
-       struct corkscrew_private *vp =
-           (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
 
        /* Block a timer-based transmit from overlapping. */
@@ -1005,7 +1002,8 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                /* Calculate the next Tx descriptor entry. */
                int entry = vp->cur_tx % TX_RING_SIZE;
                struct boom_tx_desc *prev_entry;
-               unsigned long flags, i;
+               unsigned long flags;
+               int i;
 
                if (vp->tx_full)        /* No room to transmit with */
                        return 1;
@@ -1027,7 +1025,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                outw(DownStall, ioaddr + EL3_CMD);
                /* Wait for the stall to complete. */
                for (i = 20; i >= 0; i--)
-                       if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) 
+                       if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
                                break;
                if (prev_entry)
                        prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]);
@@ -1103,7 +1101,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                                        int j;
                                        outw(TxReset, ioaddr + EL3_CMD);
                                        for (j = 20; j >= 0; j--)
-                                               if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) 
+                                               if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
                                                        break;
                                }
                                outw(TxEnable, ioaddr + EL3_CMD);
@@ -1117,22 +1115,20 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
 /* 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,
-                                   struct pt_regs *regs)
+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;
+       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);
-       lp = (struct corkscrew_private *) dev->priv;
 
        spin_lock(&lp->lock);
-       
+
        status = inw(ioaddr + EL3_STATUS);
 
        if (corkscrew_debug > 4)
@@ -1174,7 +1170,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
                                        break;  /* It still hasn't been processed. */
                                if (lp->tx_skbuff[entry]) {
                                        dev_kfree_skb_irq(lp->tx_skbuff[entry]);
-                                       lp->tx_skbuff[entry] = 0;
+                                       lp->tx_skbuff[entry] = NULL;
                                }
                                dirty_tx++;
                        }
@@ -1251,7 +1247,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
                outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
 
        } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-       
+
        spin_unlock(&lp->lock);
 
        if (corkscrew_debug > 4)
@@ -1261,7 +1257,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
 
 static int corkscrew_rx(struct net_device *dev)
 {
-       struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
        int i;
        short rx_status;
@@ -1310,7 +1306,7 @@ static int corkscrew_rx(struct net_device *dev)
                                vp->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)) 
+                                       if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                                                break;
                                continue;
                        } else if (corkscrew_debug)
@@ -1328,8 +1324,7 @@ static int corkscrew_rx(struct net_device *dev)
 
 static int boomerang_rx(struct net_device *dev)
 {
-       struct corkscrew_private *vp =
-           (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        int entry = vp->cur_rx % RX_RING_SIZE;
        int ioaddr = dev->base_addr;
        int rx_status;
@@ -1409,7 +1404,7 @@ static int boomerang_rx(struct net_device *dev)
                                break;  /* Bad news!  */
                        skb->dev = dev; /* Mark as being used by this device. */
                        skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       vp->rx_ring[entry].addr = isa_virt_to_bus(skb->tail);
+                       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. */
@@ -1419,8 +1414,7 @@ static int boomerang_rx(struct net_device *dev)
 
 static int corkscrew_close(struct net_device *dev)
 {
-       struct corkscrew_private *vp =
-           (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
        int i;
 
@@ -1458,7 +1452,7 @@ static int corkscrew_close(struct net_device *dev)
                for (i = 0; i < RX_RING_SIZE; i++)
                        if (vp->rx_skbuff[i]) {
                                dev_kfree_skb(vp->rx_skbuff[i]);
-                               vp->rx_skbuff[i] = 0;
+                               vp->rx_skbuff[i] = NULL;
                        }
        }
        if (vp->full_bus_master_tx) {   /* Free Boomerang bus master Tx buffers. */
@@ -1466,7 +1460,7 @@ static int corkscrew_close(struct net_device *dev)
                for (i = 0; i < TX_RING_SIZE; i++)
                        if (vp->tx_skbuff[i]) {
                                dev_kfree_skb(vp->tx_skbuff[i]);
-                               vp->tx_skbuff[i] = 0;
+                               vp->tx_skbuff[i] = NULL;
                        }
        }
 
@@ -1475,7 +1469,7 @@ static int corkscrew_close(struct net_device *dev)
 
 static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
 {
-       struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
+       struct corkscrew_private *vp = netdev_priv(dev);
        unsigned long flags;
 
        if (netif_running(dev)) {
@@ -1495,8 +1489,7 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
        */
 static void update_stats(int ioaddr, struct net_device *dev)
 {
-       struct corkscrew_private *vp =
-           (struct corkscrew_private *) dev->priv;
+       struct corkscrew_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. */
@@ -1566,13 +1559,13 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
        corkscrew_debug = level;
 }
 
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
        .get_drvinfo            = netdev_get_drvinfo,
        .get_msglevel           = netdev_get_msglevel,
        .set_msglevel           = netdev_set_msglevel,
 };
 
-\f
+
 #ifdef MODULE
 void cleanup_module(void)
 {
@@ -1589,7 +1582,7 @@ void cleanup_module(void)
        }
 }
 #endif                         /* MODULE */
-\f
+
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c"