Merge 'upstream' branch of rsync://rsync.kernel.org/pub/scm/linux/kernel/git/jgarzik...
authorLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 27 Jun 2005 21:55:50 +0000 (14:55 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 27 Jun 2005 21:55:50 +0000 (14:55 -0700)
44 files changed:
drivers/net/3c523.c
drivers/net/Kconfig
drivers/net/b44.c
drivers/net/cs89x0.c
drivers/net/cs89x0.h
drivers/net/e100.c
drivers/net/e1000/e1000.h
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_main.c
drivers/net/forcedeth.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/gianfar_ethtool.c
drivers/net/pcnet32.c
drivers/net/sb1000.c
drivers/net/skfp/Makefile
drivers/net/skfp/drvfbi.c
drivers/net/skfp/ess.c
drivers/net/skfp/fplustm.c
drivers/net/skfp/h/cmtdef.h
drivers/net/skfp/h/hwmtm.h
drivers/net/skfp/hwmtm.c
drivers/net/skfp/pcmplc.c
drivers/net/skfp/pmf.c
drivers/net/skfp/skfddi.c
drivers/net/skfp/smt.c
drivers/net/skfp/smtdef.c
drivers/net/skfp/smtparse.c [deleted file]
drivers/net/smc91x.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tulip/tulip_core.c
drivers/net/via-rhine.c
drivers/net/wan/farsync.c
drivers/net/wireless/airo.c
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.h
drivers/net/wireless/prism54/isl_38xx.c
drivers/usb/net/pegasus.c
drivers/usb/net/pegasus.h
drivers/usb/net/rtl8150.c
include/linux/pci_ids.h
include/net/ieee80211.h [new file with mode: 0644]

index 1247a25f109381e214a6256d2f6d22b59ce4fe6b..9e1fe2e0478c3e783492e435c276e00f2d3935f1 100644 (file)
@@ -1274,6 +1274,7 @@ module_param_array(irq, int, NULL, 0);
 module_param_array(io, int, NULL, 0);
 MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
 MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
index 47e158fa5aacca87700c975cb8903b52b7a0ff07..2b55687f6ee9d678a468f7a1ffdb632a5b865694 100644 (file)
@@ -1320,7 +1320,7 @@ config FORCEDETH
 
 config CS89x0
        tristate "CS89x0 support"
-       depends on NET_PCI && (ISA || ARCH_IXDP2X01)
+       depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
        ---help---
          Support for CS89x0 chipset based Ethernet cards. If you have a
          network (Ethernet) card of this type, say Y and read the
index 3fe8ba992c38b32b8fd5b55e8f503e6231afbfaf..f1bd45e3da31cd0ea482fd0db6995ae319977415 100644 (file)
@@ -1285,6 +1285,9 @@ static int b44_open(struct net_device *dev)
        b44_init_hw(bp);
        bp->flags |= B44_FLAG_INIT_COMPLETE;
 
+       netif_carrier_off(dev);
+       b44_check_phy(bp);
+
        spin_unlock_irq(&bp->lock);
 
        init_timer(&bp->timer);
index 25e4495de79eed0d44654cdc41dba03cab03162a..b96d6fb1929ededc702ec46d90858034ea4c660f 100644 (file)
@@ -174,6 +174,13 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0};
 #include <asm/irq.h>
 static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
+#elif defined(CONFIG_ARCH_PNX0105)
+#include <asm/irq.h>
+#include <asm/arch/gpio.h>
+#define CIRRUS_DEFAULT_BASE    IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000)      /* = Physical address 0x48200000 */
+#define CIRRUS_DEFAULT_IRQ     VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
+static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
+static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
 #else
 static unsigned int netcard_portlist[] __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
@@ -431,6 +438,30 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
 #endif
         }
 
+#ifdef CONFIG_ARCH_PNX0105
+       initialize_ebi();
+
+       /* Map GPIO registers for the pins connected to the CS8900a. */
+       if (map_cirrus_gpio() < 0)
+               return -ENODEV;
+
+       reset_cirrus();
+
+       /* Map event-router registers. */
+       if (map_event_router() < 0)
+               return -ENODEV;
+
+       enable_cirrus_irq();
+
+       unmap_cirrus_gpio();
+       unmap_event_router();
+
+       dev->base_addr = ioaddr;
+
+       for (i = 0 ; i < 3 ; i++)
+               readreg(dev, 0);
+#endif
+
        /* Grab the region so we can find another board if autoIRQ fails. */
        /* WTF is going on here? */
        if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
@@ -672,7 +703,7 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
        } else {
                i = lp->isa_config & INT_NO_MASK;
                if (lp->chip_type == CS8900) {
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
                        i = cs8900_irq_map[0];
 #else
                        /* Translate the IRQ using the IRQ mapping table. */
@@ -1145,7 +1176,7 @@ net_open(struct net_device *dev)
        int i;
        int ret;
 
-#ifndef CONFIG_SH_HICOSH4 /* uses irq#1, so this won't work */
+#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */
        if (dev->irq < 2) {
                /* Allow interrupts to be generated by the chip */
 /* Cirrus' release had this: */
@@ -1176,7 +1207,7 @@ net_open(struct net_device *dev)
        else
 #endif
        {
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
                if (((1 << dev->irq) & lp->irq_map) == 0) {
                        printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1261,6 +1292,9 @@ net_open(struct net_device *dev)
        case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
         default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
         }
+#ifdef CONFIG_ARCH_PNX0105
+       result = A_CNF_10B_T;
+#endif
         if (!result) {
                 printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
         release_irq:
index b0ef7ad2baad1980bdacb0a323df09afb8c04ef7..bd3ad8e6cce9c46e02a5da048fb78a1ce7f954cd 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
 /* IXDP2401/IXDP2801 uses dword-aligned register addressing */
 #define CS89x0_PORT(reg) ((reg) * 2)
 #else
index cfaa6b2bf345e7f2dbe504c1c95e18a006cb23cc..1e56c8eea35fdfa41f39b0e0372cd9ee15873c65 100644 (file)
@@ -1093,11 +1093,16 @@ static int e100_phy_init(struct nic *nic)
        }
 
        if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && 
-               (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && 
-               (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)))
-               /* enable/disable MDI/MDI-X auto-switching */
-               mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
-                       nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
+          (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {
+               /* enable/disable MDI/MDI-X auto-switching.
+                  MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */
+               if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||
+                  (nic->mac == mac_82551_10) || (nic->mii.force_media) || 
+                  !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)) 
+                       mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);
+               else
+                       mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);
+       }
 
        return 0;
 }
@@ -1666,8 +1671,10 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
        if(stat_ack & stat_ack_rnr)
                nic->ru_running = RU_SUSPENDED;
 
-       e100_disable_irq(nic);
-       netif_rx_schedule(netdev);
+       if(likely(netif_rx_schedule_prep(netdev))) {
+               e100_disable_irq(nic);
+               __netif_rx_schedule(netdev);
+       }
 
        return IRQ_HANDLED;
 }
@@ -2335,11 +2342,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                goto err_out_iounmap;
        }
 
-       e100_phy_init(nic);
-
        if((err = e100_eeprom_load(nic)))
                goto err_out_free;
 
+       e100_phy_init(nic);
+
        memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
        if(!is_valid_ether_addr(netdev->dev_addr)) {
                DPRINTK(PROBE, ERR, "Invalid MAC address from "
index af1e82c5b808d89371b7ad99ff100bb3b5ea666b..092757bc721f0ade1821465d73bedba39348ee89 100644 (file)
@@ -140,7 +140,7 @@ struct e1000_adapter;
 #define E1000_RX_BUFFER_WRITE  16      /* Must be power of 2 */
 
 #define AUTO_ALL_MODES            0
-#define E1000_EEPROM_82544_APM    0x0400
+#define E1000_EEPROM_82544_APM    0x0004
 #define E1000_EEPROM_APME         0x0400
 
 #ifndef E1000_MASTER_SLAVE
@@ -159,7 +159,7 @@ struct e1000_adapter;
  * so a DMA handle can be stored along with the buffer */
 struct e1000_buffer {
        struct sk_buff *skb;
-       uint64_t dma;
+       dma_addr_t dma;
        unsigned long time_stamp;
        uint16_t length;
        uint16_t next_to_watch;
index 237247f74df48f0ae0c8e4c9998e7b8f6be9223d..f133ff0b0b947c6ad6a76635ff5f159f6cad83bd 100644 (file)
@@ -105,7 +105,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
 static int
 e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        if(hw->media_type == e1000_media_type_copper) {
@@ -141,9 +141,9 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
                                     SUPPORTED_FIBRE |
                                     SUPPORTED_Autoneg);
 
-               ecmd->advertising = (SUPPORTED_1000baseT_Full |
-                                    SUPPORTED_FIBRE |
-                                    SUPPORTED_Autoneg);
+               ecmd->advertising = (ADVERTISED_1000baseT_Full |
+                                    ADVERTISED_FIBRE |
+                                    ADVERTISED_Autoneg);
 
                ecmd->port = PORT_FIBRE;
 
@@ -179,13 +179,24 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 static int
 e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        if(ecmd->autoneg == AUTONEG_ENABLE) {
                hw->autoneg = 1;
-               hw->autoneg_advertised = 0x002F;
-               ecmd->advertising = 0x002F;
+               if(hw->media_type == e1000_media_type_fiber)
+                       hw->autoneg_advertised = ADVERTISED_1000baseT_Full |
+                                    ADVERTISED_FIBRE |
+                                    ADVERTISED_Autoneg;
+               else 
+                       hw->autoneg_advertised = ADVERTISED_10baseT_Half |
+                                                 ADVERTISED_10baseT_Full |
+                                                 ADVERTISED_100baseT_Half |
+                                                 ADVERTISED_100baseT_Full |
+                                                 ADVERTISED_1000baseT_Full|
+                                                 ADVERTISED_Autoneg |
+                                                 ADVERTISED_TP;
+               ecmd->advertising = hw->autoneg_advertised;
        } else
                if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
                        return -EINVAL;
@@ -206,7 +217,7 @@ static void
 e1000_get_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *pause)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        pause->autoneg = 
@@ -226,7 +237,7 @@ static int
 e1000_set_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *pause)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        
        adapter->fc_autoneg = pause->autoneg;
@@ -259,14 +270,14 @@ e1000_set_pauseparam(struct net_device *netdev,
 static uint32_t
 e1000_get_rx_csum(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        return adapter->rx_csum;
 }
 
 static int
 e1000_set_rx_csum(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        adapter->rx_csum = data;
 
        if(netif_running(netdev)) {
@@ -286,7 +297,7 @@ e1000_get_tx_csum(struct net_device *netdev)
 static int
 e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        if(adapter->hw.mac_type < e1000_82543) {
                if (!data)
@@ -306,8 +317,8 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
 static int
 e1000_set_tso(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
-       if ((adapter->hw.mac_type < e1000_82544) ||
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       if((adapter->hw.mac_type < e1000_82544) ||
            (adapter->hw.mac_type == e1000_82547)) 
                return data ? -EINVAL : 0;
 
@@ -322,14 +333,14 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
 static uint32_t
 e1000_get_msglevel(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        return adapter->msg_enable;
 }
 
 static void
 e1000_set_msglevel(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        adapter->msg_enable = data;
 }
 
@@ -344,7 +355,7 @@ static void
 e1000_get_regs(struct net_device *netdev,
               struct ethtool_regs *regs, void *p)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint32_t *regs_buff = p;
        uint16_t phy_data;
@@ -432,7 +443,7 @@ e1000_get_regs(struct net_device *netdev,
 static int
 e1000_get_eeprom_len(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        return adapter->hw.eeprom.word_size * 2;
 }
 
@@ -440,7 +451,7 @@ static int
 e1000_get_eeprom(struct net_device *netdev,
                       struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        int first_word, last_word;
@@ -486,7 +497,7 @@ static int
 e1000_set_eeprom(struct net_device *netdev,
                       struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        void *ptr;
@@ -547,7 +558,7 @@ static void
 e1000_get_drvinfo(struct net_device *netdev,
                        struct ethtool_drvinfo *drvinfo)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        strncpy(drvinfo->driver,  e1000_driver_name, 32);
        strncpy(drvinfo->version, e1000_driver_version, 32);
@@ -563,7 +574,7 @@ static void
 e1000_get_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        e1000_mac_type mac_type = adapter->hw.mac_type;
        struct e1000_desc_ring *txdr = &adapter->tx_ring;
        struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -584,7 +595,7 @@ static int
 e1000_set_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        e1000_mac_type mac_type = adapter->hw.mac_type;
        struct e1000_desc_ring *txdr = &adapter->tx_ring;
        struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -651,6 +662,9 @@ err_setup_rx:
                E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W));             \
                value = E1000_READ_REG(&adapter->hw, R);                       \
                if(value != (test[pat] & W & M)) {                             \
+                       DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \
+                               "0x%08X expected 0x%08X\n",                    \
+                               E1000_##R, value, (test[pat] & W & M));        \
                        *data = (adapter->hw.mac_type < e1000_82543) ?         \
                                E1000_82542_##R : E1000_##R;                   \
                        return 1;                                              \
@@ -663,7 +677,9 @@ err_setup_rx:
        uint32_t value;                                                        \
        E1000_WRITE_REG(&adapter->hw, R, W & M);                               \
        value = E1000_READ_REG(&adapter->hw, R);                               \
-       if ((W & M) != (value & M)) {                                          \
+       if((W & M) != (value & M)) {                                          \
+               DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
+                       "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \
                *data = (adapter->hw.mac_type < e1000_82543) ?                 \
                        E1000_82542_##R : E1000_##R;                           \
                return 1;                                                      \
@@ -673,18 +689,33 @@ err_setup_rx:
 static int
 e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
 {
-       uint32_t value;
-       uint32_t i;
+       uint32_t value, before, after;
+       uint32_t i, toggle;
 
        /* The status register is Read Only, so a write should fail.
         * Some bits that get toggled are ignored.
         */
-       value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
-       E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
-       if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
+        switch (adapter->hw.mac_type) {
+       case e1000_82573:
+               toggle = 0x7FFFF033;
+               break;
+       default:
+               toggle = 0xFFFFF833;
+               break;
+       }
+
+       before = E1000_READ_REG(&adapter->hw, STATUS);
+       value = (E1000_READ_REG(&adapter->hw, STATUS) & toggle);
+       E1000_WRITE_REG(&adapter->hw, STATUS, toggle);
+       after = E1000_READ_REG(&adapter->hw, STATUS) & toggle;
+       if(value != after) {
+               DPRINTK(DRV, ERR, "failed STATUS register test got: "
+                       "0x%08X expected: 0x%08X\n", after, value);
                *data = 1;
                return 1;
        }
+       /* restore previous status */
+       E1000_WRITE_REG(&adapter->hw, STATUS, before);
 
        REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
        REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
@@ -766,7 +797,7 @@ e1000_test_intr(int irq,
                struct pt_regs *regs)
 {
        struct net_device *netdev = (struct net_device *) data;
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
 
@@ -1214,6 +1245,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
        case e1000_82541_rev_2:
        case e1000_82547:
        case e1000_82547_rev_2:
+       case e1000_82573:
                return e1000_integrated_phy_loopback(adapter);
                break;
 
@@ -1422,7 +1454,7 @@ static void
 e1000_diag_test(struct net_device *netdev,
                   struct ethtool_test *eth_test, uint64_t *data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        boolean_t if_running = netif_running(netdev);
 
        if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
@@ -1482,7 +1514,7 @@ e1000_diag_test(struct net_device *netdev,
 static void
 e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        switch(adapter->hw.device_id) {
@@ -1527,7 +1559,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 static int
 e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
        switch(adapter->hw.device_id) {
@@ -1588,22 +1620,31 @@ e1000_led_blink_callback(unsigned long data)
 static int
 e1000_phys_id(struct net_device *netdev, uint32_t data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
 
-       if(!adapter->blink_timer.function) {
-               init_timer(&adapter->blink_timer);
-               adapter->blink_timer.function = e1000_led_blink_callback;
-               adapter->blink_timer.data = (unsigned long) adapter;
+       if(adapter->hw.mac_type < e1000_82573) {
+               if(!adapter->blink_timer.function) {
+                       init_timer(&adapter->blink_timer);
+                       adapter->blink_timer.function = e1000_led_blink_callback;
+                       adapter->blink_timer.data = (unsigned long) adapter;
+               }
+               e1000_setup_led(&adapter->hw);
+               mod_timer(&adapter->blink_timer, jiffies);
+               msleep_interruptible(data * 1000);
+               del_timer_sync(&adapter->blink_timer);
+       }
+       else {
+               E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
+                       E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | 
+                       (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
+                       (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
+                       (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+               msleep_interruptible(data * 1000);
        }
 
-       e1000_setup_led(&adapter->hw);
-       mod_timer(&adapter->blink_timer, jiffies);
-
-       msleep_interruptible(data * 1000);
-       del_timer_sync(&adapter->blink_timer);
        e1000_led_off(&adapter->hw);
        clear_bit(E1000_LED_ON, &adapter->led_status);
        e1000_cleanup_led(&adapter->hw);
@@ -1614,7 +1655,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
 static int
 e1000_nway_reset(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        if(netif_running(netdev)) {
                e1000_down(adapter);
                e1000_up(adapter);
@@ -1632,7 +1673,7 @@ static void
 e1000_get_ethtool_stats(struct net_device *netdev, 
                struct ethtool_stats *stats, uint64_t *data)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int i;
 
        e1000_update_stats(adapter);
index 723589b28be5d7a1716e89858ae1fe6303d9dd63..045f5426ab9a68c6af41690f450839d77dca0110 100644 (file)
@@ -354,18 +354,27 @@ e1000_set_media_type(struct e1000_hw *hw)
         hw->media_type = e1000_media_type_internal_serdes;
         break;
     default:
-        if(hw->mac_type >= e1000_82543) {
+        switch (hw->mac_type) {
+        case e1000_82542_rev2_0:
+        case e1000_82542_rev2_1:
+            hw->media_type = e1000_media_type_fiber;
+            break;
+        case e1000_82573:
+            /* The STATUS_TBIMODE bit is reserved or reused for the this
+             * device.
+             */
+            hw->media_type = e1000_media_type_copper;
+            break;
+        default:
             status = E1000_READ_REG(hw, STATUS);
-            if(status & E1000_STATUS_TBIMODE) {
+            if (status & E1000_STATUS_TBIMODE) {
                 hw->media_type = e1000_media_type_fiber;
                 /* tbi_compatibility not valid on fiber */
                 hw->tbi_compatibility_en = FALSE;
             } else {
                 hw->media_type = e1000_media_type_copper;
             }
-        } else {
-            /* This is an 82542 (fiber only) */
-            hw->media_type = e1000_media_type_fiber;
+            break;
         }
     }
 }
@@ -1189,9 +1198,9 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
         ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
         if(ret_val)
             return ret_val;
-        }
+    }
 
-   return E1000_SUCCESS;
+    return E1000_SUCCESS;
 }
 
 
index a0263ee96c6b0ee9133cc0ebdbee7ce08bfe5d75..93e9f8788751e462f31d2f2edb17212f7aa7e954 100644 (file)
@@ -66,6 +66,7 @@ typedef enum {
     e1000_eeprom_spi,
     e1000_eeprom_microwire,
     e1000_eeprom_flash,
+    e1000_eeprom_none, /* No NVM support */
     e1000_num_eeprom_types
 } e1000_eeprom_type;
 
index 137226d98d4760f8d1a72b536ffa530effcbd541..cb7f051a60ad6a29b914b1af36fa3090c249bbf0 100644 (file)
@@ -29,6 +29,8 @@
 #include "e1000.h"
 
 /* Change Log
+ * 6.0.58       4/20/05
+ *   o Accepted ethtool cleanup patch from Stephen Hemminger 
  * 6.0.44+     2/15/05
  *   o applied Anton's patch to resolve tx hang in hardware
  *   o Applied Andrew Mortons patch - e1000 stops working after resume
@@ -41,9 +43,9 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-#define DRV_VERSION "6.0.54-k2"DRIVERNAPI
+#define DRV_VERSION            "6.0.60-k2"DRIVERNAPI
 char e1000_driver_version[] = DRV_VERSION;
-char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
+char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
  *
@@ -517,7 +519,7 @@ e1000_probe(struct pci_dev *pdev,
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
        pci_set_drvdata(pdev, netdev);
-       adapter = netdev->priv;
+       adapter = netdev_priv(netdev);
        adapter->netdev = netdev;
        adapter->pdev = pdev;
        adapter->hw.back = adapter;
@@ -738,7 +740,7 @@ static void __devexit
 e1000_remove(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t manc, swsm;
 
        flush_scheduled_work();
@@ -871,7 +873,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
 static int
 e1000_open(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int err;
 
        /* allocate transmit descriptors */
@@ -919,7 +921,7 @@ err_setup_tx:
 static int
 e1000_close(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        e1000_down(adapter);
 
@@ -1599,7 +1601,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
 static int
 e1000_set_mac(struct net_device *netdev, void *p)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
 
        if(!is_valid_ether_addr(addr->sa_data))
@@ -1634,7 +1636,7 @@ e1000_set_mac(struct net_device *netdev, void *p)
 static void
 e1000_set_multi(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        struct dev_mc_list *mc_ptr;
        unsigned long flags;
@@ -2213,7 +2215,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
 static int
 e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
        unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
        unsigned int tx_flags = 0;
@@ -2344,7 +2346,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 static void
 e1000_tx_timeout(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        /* Do the reset outside of interrupt context */
        schedule_work(&adapter->tx_timeout_task);
@@ -2353,7 +2355,7 @@ e1000_tx_timeout(struct net_device *netdev)
 static void
 e1000_tx_timeout_task(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        e1000_down(adapter);
        e1000_up(adapter);
@@ -2370,7 +2372,7 @@ e1000_tx_timeout_task(struct net_device *netdev)
 static struct net_device_stats *
 e1000_get_stats(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
 
        e1000_update_stats(adapter);
        return &adapter->net_stats;
@@ -2387,7 +2389,7 @@ e1000_get_stats(struct net_device *netdev)
 static int
 e1000_change_mtu(struct net_device *netdev, int new_mtu)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 
        if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
@@ -2598,7 +2600,7 @@ static irqreturn_t
 e1000_intr(int irq, void *data, struct pt_regs *regs)
 {
        struct net_device *netdev = data;
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        uint32_t icr = E1000_READ_REG(hw, ICR);
 #ifndef CONFIG_E1000_NAPI
@@ -2661,7 +2663,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
 static int
 e1000_clean(struct net_device *netdev, int *budget)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        int work_to_do = min(*budget, netdev->quota);
        int tx_cleaned;
        int work_done = 0;
@@ -2672,8 +2674,8 @@ e1000_clean(struct net_device *netdev, int *budget)
        *budget -= work_done;
        netdev->quota -= work_done;
        
-       /* If no Tx and no Rx work done, exit the polling mode */
        if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+       /* If no Tx and not enough Rx work done, exit the polling mode */
                netif_rx_complete(netdev);
                e1000_irq_enable(adapter);
                return 0;
@@ -2769,13 +2771,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
                        i = tx_ring->next_to_clean;
                        eop = tx_ring->buffer_info[i].next_to_watch;
                        eop_desc = E1000_TX_DESC(*tx_ring, eop);
-                       DPRINTK(TX_ERR, ERR, "Detected Tx Unit Hang\n"
+                       DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
                                        "  TDH                  <%x>\n"
                                        "  TDT                  <%x>\n"
                                        "  next_to_use          <%x>\n"
                                        "  next_to_clean        <%x>\n"
                                        "buffer_info[next_to_clean]\n"
-                                       "  dma                  <%llx>\n"
+                                       "  dma                  <%zx>\n"
                                        "  time_stamp           <%lx>\n"
                                        "  next_to_watch        <%x>\n"
                                        "  jiffies              <%lx>\n"
@@ -2994,7 +2996,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
 
        i = rx_ring->next_to_clean;
        rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-       staterr = rx_desc->wb.middle.status_error;
+       staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
 
        while(staterr & E1000_RXD_STAT_DD) {
                buffer_info = &rx_ring->buffer_info[i];
@@ -3065,16 +3067,16 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
 #ifdef CONFIG_E1000_NAPI
                if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
                        vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
-                               le16_to_cpu(rx_desc->wb.middle.vlan &
-                                       E1000_RXD_SPC_VLAN_MASK));
+                               le16_to_cpu(rx_desc->wb.middle.vlan) &
+                               E1000_RXD_SPC_VLAN_MASK);
                } else {
                        netif_receive_skb(skb);
                }
 #else /* CONFIG_E1000_NAPI */
                if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
                        vlan_hwaccel_rx(skb, adapter->vlgrp,
-                               le16_to_cpu(rx_desc->wb.middle.vlan &
-                                       E1000_RXD_SPC_VLAN_MASK));
+                               le16_to_cpu(rx_desc->wb.middle.vlan) &
+                               E1000_RXD_SPC_VLAN_MASK);
                } else {
                        netif_rx(skb);
                }
@@ -3087,7 +3089,7 @@ next_desc:
                if(unlikely(++i == rx_ring->count)) i = 0;
 
                rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
-               staterr = rx_desc->wb.middle.status_error;
+               staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
        }
        rx_ring->next_to_clean = i;
        adapter->alloc_rx_buf(adapter);
@@ -3371,11 +3373,12 @@ e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 static int
 e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        struct mii_ioctl_data *data = if_mii(ifr);
        int retval;
        uint16_t mii_reg;
        uint16_t spddplx;
+       unsigned long flags;
 
        if(adapter->hw.media_type != e1000_media_type_copper)
                return -EOPNOTSUPP;
@@ -3385,22 +3388,29 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                data->phy_id = adapter->hw.phy_addr;
                break;
        case SIOCGMIIREG:
-               if (!capable(CAP_NET_ADMIN))
+               if(!capable(CAP_NET_ADMIN))
                        return -EPERM;
-               if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
-                                  &data->val_out))
+               spin_lock_irqsave(&adapter->stats_lock, flags);
+               if(e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+                                  &data->val_out)) {
+                       spin_unlock_irqrestore(&adapter->stats_lock, flags);
                        return -EIO;
+               }
+               spin_unlock_irqrestore(&adapter->stats_lock, flags);
                break;
        case SIOCSMIIREG:
-               if (!capable(CAP_NET_ADMIN))
+               if(!capable(CAP_NET_ADMIN))
                        return -EPERM;
-               if (data->reg_num & ~(0x1F))
+               if(data->reg_num & ~(0x1F))
                        return -EFAULT;
                mii_reg = data->val_in;
-               if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
-                                       mii_reg))
+               spin_lock_irqsave(&adapter->stats_lock, flags);
+               if(e1000_write_phy_reg(&adapter->hw, data->reg_num,
+                                       mii_reg)) {
+                       spin_unlock_irqrestore(&adapter->stats_lock, flags);
                        return -EIO;
-               if (adapter->hw.phy_type == e1000_phy_m88) {
+               }
+               if(adapter->hw.phy_type == e1000_phy_m88) {
                        switch (data->reg_num) {
                        case PHY_CTRL:
                                if(mii_reg & MII_CR_POWER_DOWN)
@@ -3420,8 +3430,12 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                                                   HALF_DUPLEX;
                                        retval = e1000_set_spd_dplx(adapter,
                                                                    spddplx);
-                                       if(retval)
+                                       if(retval) {
+                                               spin_unlock_irqrestore(
+                                                       &adapter->stats_lock, 
+                                                       flags);
                                                return retval;
+                                       }
                                }
                                if(netif_running(adapter->netdev)) {
                                        e1000_down(adapter);
@@ -3431,8 +3445,11 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                                break;
                        case M88E1000_PHY_SPEC_CTRL:
                        case M88E1000_EXT_PHY_SPEC_CTRL:
-                               if (e1000_phy_reset(&adapter->hw))
+                               if(e1000_phy_reset(&adapter->hw)) {
+                                       spin_unlock_irqrestore(
+                                               &adapter->stats_lock, flags);
                                        return -EIO;
+                               }
                                break;
                        }
                } else {
@@ -3448,6 +3465,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
                                break;
                        }
                }
+               spin_unlock_irqrestore(&adapter->stats_lock, flags);
                break;
        default:
                return -EOPNOTSUPP;
@@ -3504,7 +3522,7 @@ e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
 static void
 e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t ctrl, rctl;
 
        e1000_irq_disable(adapter);
@@ -3544,7 +3562,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 static void
 e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
        if((adapter->hw.mng_cookie.status &
                E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
@@ -3560,7 +3578,7 @@ e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 static void
 e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
 
        e1000_irq_disable(adapter);
@@ -3601,6 +3619,13 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
 {
        adapter->hw.autoneg = 0;
 
+       /* Fiber NICs only allow 1000 gbps Full duplex */
+       if((adapter->hw.media_type == e1000_media_type_fiber) &&
+               spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+               DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
+               return -EINVAL;
+       }
+
        switch(spddplx) {
        case SPEED_10 + DUPLEX_HALF:
                adapter->hw.forced_speed_duplex = e1000_10_half;
@@ -3647,7 +3672,7 @@ static int
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm;
        uint32_t wufc = adapter->wol;
 
@@ -3740,12 +3765,12 @@ static int
 e1000_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev->priv;
-       uint32_t manc, ret, swsm;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       uint32_t manc, ret_val, swsm;
 
        pci_set_power_state(pdev, 0);
        pci_restore_state(pdev);
-       ret = pci_enable_device(pdev);
+       ret_val = pci_enable_device(pdev);
        pci_set_master(pdev);
 
        pci_enable_wake(pdev, 3, 0);
@@ -3788,7 +3813,7 @@ e1000_resume(struct pci_dev *pdev)
 static void
 e1000_netpoll(struct net_device *netdev)
 {
-       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
        disable_irq(adapter->pdev->irq);
        e1000_intr(adapter->pdev->irq, netdev, NULL);
        enable_irq(adapter->pdev->irq);
index 4ebcd052e15093b0c6e59c5880d974cf06f108dc..64f0f697c958ad399317fe7cc628bf93d9f73018 100644 (file)
@@ -82,6 +82,9 @@
  *     0.31: 14 Nov 2004: ethtool support for getting/setting link
  *                        capabilities.
  *     0.32: 16 Apr 2005: RX_ERROR4 handling added.
+ *     0.33: 16 May 2005: Support for MCP51 added.
+ *     0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
+ *     0.35: 26 Jun 2005: Support for MCP55 added.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -93,7 +96,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.32"
+#define FORCEDETH_VERSION              "0.35"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
@@ -2005,7 +2008,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        /* handle different descriptor versions */
        if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
                pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||    
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
                np->desc_ver = DESC_VER_1;
        else
                np->desc_ver = DESC_VER_2;
@@ -2215,56 +2220,84 @@ static struct pci_device_id pci_tbl[] = {
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* CK804 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* CK804 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* MCP04 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* MCP04 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP51 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP51 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP55 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP55 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {0,},
 };
index b43b2b11aacd752318c279264ee0e4e1a9865419..6518334b92801a41745718b09a74805e3e7b8004 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * drivers/net/gianfar.c
  *
  * Gianfar Ethernet Driver
  *  B-V +1.62
  *
  *  Theory of operation
- *  This driver is designed for the Triple-speed Ethernet
- *  controllers on the Freescale 8540/8560 integrated processors,
- *  as well as the Fast Ethernet Controller on the 8540.  
- *  
+ *  This driver is designed for the non-CPM ethernet controllers
+ *  on the 85xx and 83xx family of integrated processors
+ *
  *  The driver is initialized through platform_device.  Structures which
  *  define the configuration needed by the board are defined in a
  *  board structure in arch/ppc/platforms (though I do not
  *
  *  The Gianfar Ethernet Controller uses a ring of buffer
  *  descriptors.  The beginning is indicated by a register
- *  pointing to the physical address of the start of the ring. 
- *  The end is determined by a "wrap" bit being set in the 
+ *  pointing to the physical address of the start of the ring.
+ *  The end is determined by a "wrap" bit being set in the
  *  last descriptor of the ring.
  *
  *  When a packet is received, the RXF bit in the
- *  IEVENT register is set, triggering an interrupt when the 
+ *  IEVENT register is set, triggering an interrupt when the
  *  corresponding bit in the IMASK register is also set (if
  *  interrupt coalescing is active, then the interrupt may not
  *  happen immediately, but will wait until either a set number
@@ -52,7 +51,7 @@
  *  interrupt handler will signal there is work to be done, and
  *  exit.  Without NAPI, the packet(s) will be handled
  *  immediately.  Both methods will start at the last known empty
- *  descriptor, and process every subsequent descriptor until there 
+ *  descriptor, and process every subsequent descriptor until there
  *  are none left with data (NAPI will stop after a set number of
  *  packets to give time to other tasks, but will eventually
  *  process all the packets).  The data arrives inside a
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/if_vlan.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/device.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -123,7 +126,7 @@ static int gfar_set_mac_address(struct net_device *dev);
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
 static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void gfar_phy_change(void *data);
@@ -139,9 +142,12 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
 #ifdef CONFIG_GFAR_NAPI
 static int gfar_poll(struct net_device *dev, int *budget);
 #endif
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
 static void gfar_phy_startup_timer(unsigned long data);
+static void gfar_vlan_rx_register(struct net_device *netdev,
+                               struct vlan_group *grp);
+static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 
 extern struct ethtool_ops gfar_ethtool_ops;
 
@@ -149,6 +155,13 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
 MODULE_LICENSE("GPL");
 
+int gfar_uses_fcb(struct gfar_private *priv)
+{
+       if (priv->vlan_enable || priv->rx_csum_enable)
+               return 1;
+       else
+               return 0;
+}
 static int gfar_probe(struct device *device)
 {
        u32 tempval;
@@ -159,7 +172,6 @@ static int gfar_probe(struct device *device)
        struct resource *r;
        int idx;
        int err = 0;
-       int dev_ethtool_ops = 0;
 
        einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
 
@@ -265,15 +277,69 @@ static int gfar_probe(struct device *device)
        dev->mtu = 1500;
        dev->set_multicast_list = gfar_set_multi;
 
-       /* Index into the array of possible ethtool
-        * ops to catch all 4 possibilities */
-       if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) == 0)
-               dev_ethtool_ops += 1;
+       dev->ethtool_ops = &gfar_ethtool_ops;
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+               priv->rx_csum_enable = 1;
+               dev->features |= NETIF_F_IP_CSUM;
+       } else
+               priv->rx_csum_enable = 0;
+
+       priv->vlgrp = NULL;
 
-       if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE) == 0)
-               dev_ethtool_ops += 2;
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+               dev->vlan_rx_register = gfar_vlan_rx_register;
+               dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
 
-       dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];
+               dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+               priv->vlan_enable = 1;
+       }
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+               priv->extended_hash = 1;
+               priv->hash_width = 9;
+
+               priv->hash_regs[0] = &priv->regs->igaddr0;
+               priv->hash_regs[1] = &priv->regs->igaddr1;
+               priv->hash_regs[2] = &priv->regs->igaddr2;
+               priv->hash_regs[3] = &priv->regs->igaddr3;
+               priv->hash_regs[4] = &priv->regs->igaddr4;
+               priv->hash_regs[5] = &priv->regs->igaddr5;
+               priv->hash_regs[6] = &priv->regs->igaddr6;
+               priv->hash_regs[7] = &priv->regs->igaddr7;
+               priv->hash_regs[8] = &priv->regs->gaddr0;
+               priv->hash_regs[9] = &priv->regs->gaddr1;
+               priv->hash_regs[10] = &priv->regs->gaddr2;
+               priv->hash_regs[11] = &priv->regs->gaddr3;
+               priv->hash_regs[12] = &priv->regs->gaddr4;
+               priv->hash_regs[13] = &priv->regs->gaddr5;
+               priv->hash_regs[14] = &priv->regs->gaddr6;
+               priv->hash_regs[15] = &priv->regs->gaddr7;
+
+       } else {
+               priv->extended_hash = 0;
+               priv->hash_width = 8;
+
+               priv->hash_regs[0] = &priv->regs->gaddr0;
+                priv->hash_regs[1] = &priv->regs->gaddr1;
+               priv->hash_regs[2] = &priv->regs->gaddr2;
+               priv->hash_regs[3] = &priv->regs->gaddr3;
+               priv->hash_regs[4] = &priv->regs->gaddr4;
+               priv->hash_regs[5] = &priv->regs->gaddr5;
+               priv->hash_regs[6] = &priv->regs->gaddr6;
+               priv->hash_regs[7] = &priv->regs->gaddr7;
+       }
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
+               priv->padding = DEFAULT_PADDING;
+       else
+               priv->padding = 0;
+
+       dev->hard_header_len += priv->padding;
+
+       if (dev->features & NETIF_F_IP_CSUM)
+               dev->hard_header_len += GMAC_FCB_LEN;
 
        priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
 #ifdef CONFIG_GFAR_BUFSTASH
@@ -289,6 +355,9 @@ static int gfar_probe(struct device *device)
        priv->rxcount = DEFAULT_RXCOUNT;
        priv->rxtime = DEFAULT_RXTIME;
 
+       /* Enable most messages by default */
+       priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
        err = register_netdev(dev);
 
        if (err) {
@@ -360,8 +429,9 @@ static int init_phy(struct net_device *dev)
                        GFP_KERNEL);
 
        if(NULL == mii_info) {
-               printk(KERN_ERR "%s: Could not allocate mii_info\n", 
-                               dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate mii_info\n",
+                                       dev->name);
                return -ENOMEM;
        }
 
@@ -410,7 +480,8 @@ static int init_phy(struct net_device *dev)
        curphy = get_phy_info(priv->mii_info);
 
        if (curphy == NULL) {
-               printk(KERN_ERR "%s: No PHY found\n", dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: No PHY found\n", dev->name);
                err = -1;
                goto no_phy;
        }
@@ -421,7 +492,7 @@ static int init_phy(struct net_device *dev)
        if(curphy->init) {
                err = curphy->init(priv->mii_info);
 
-               if (err) 
+               if (err)
                        goto phy_init_fail;
        }
 
@@ -446,14 +517,14 @@ static void init_registers(struct net_device *dev)
        gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);
 
        /* Init hash registers to zero */
-       gfar_write(&priv->regs->iaddr0, 0);
-       gfar_write(&priv->regs->iaddr1, 0);
-       gfar_write(&priv->regs->iaddr2, 0);
-       gfar_write(&priv->regs->iaddr3, 0);
-       gfar_write(&priv->regs->iaddr4, 0);
-       gfar_write(&priv->regs->iaddr5, 0);
-       gfar_write(&priv->regs->iaddr6, 0);
-       gfar_write(&priv->regs->iaddr7, 0);
+       gfar_write(&priv->regs->igaddr0, 0);
+       gfar_write(&priv->regs->igaddr1, 0);
+       gfar_write(&priv->regs->igaddr2, 0);
+       gfar_write(&priv->regs->igaddr3, 0);
+       gfar_write(&priv->regs->igaddr4, 0);
+       gfar_write(&priv->regs->igaddr5, 0);
+       gfar_write(&priv->regs->igaddr6, 0);
+       gfar_write(&priv->regs->igaddr7, 0);
 
        gfar_write(&priv->regs->gaddr0, 0);
        gfar_write(&priv->regs->gaddr1, 0);
@@ -464,9 +535,6 @@ static void init_registers(struct net_device *dev)
        gfar_write(&priv->regs->gaddr6, 0);
        gfar_write(&priv->regs->gaddr7, 0);
 
-       /* Zero out rctrl */
-       gfar_write(&priv->regs->rctrl, 0x00000000);
-
        /* Zero out the rmon mib registers if it has them */
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
                memset((void *) &(priv->regs->rmon), 0,
@@ -497,20 +565,14 @@ static void init_registers(struct net_device *dev)
        gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
 }
 
-void stop_gfar(struct net_device *dev)
+
+/* Halt the receive and transmit queues */
+void gfar_halt(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar *regs = priv->regs;
-       unsigned long flags;
        u32 tempval;
 
-       /* Lock it down */
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Tell the kernel the link is down */
-       priv->mii_info->link = 0;
-       adjust_link(dev);
-
        /* Mask all interrupts */
        gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
@@ -533,13 +595,29 @@ void stop_gfar(struct net_device *dev)
        tempval = gfar_read(&regs->maccfg1);
        tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
        gfar_write(&regs->maccfg1, tempval);
+}
+
+void stop_gfar(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar *regs = priv->regs;
+       unsigned long flags;
+
+       /* Lock it down */
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Tell the kernel the link is down */
+       priv->mii_info->link = 0;
+       adjust_link(dev);
+
+       gfar_halt(dev);
 
        if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
                /* Clear any pending interrupts */
                mii_clear_phy_interrupt(priv->mii_info);
 
                /* Disable PHY Interrupts */
-               mii_configure_phy_interrupt(priv->mii_info, 
+               mii_configure_phy_interrupt(priv->mii_info,
                                MII_INTERRUPT_DISABLED);
        }
 
@@ -566,7 +644,7 @@ void stop_gfar(struct net_device *dev)
                        sizeof(struct txbd8)*priv->tx_ring_size
                        + sizeof(struct rxbd8)*priv->rx_ring_size,
                        priv->tx_bd_base,
-                       gfar_read(&regs->tbase));
+                       gfar_read(&regs->tbase0));
 }
 
 /* If there are any tx skbs or rx skbs still around, free them.
@@ -620,6 +698,34 @@ void free_skb_resources(struct gfar_private *priv)
        }
 }
 
+void gfar_start(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar *regs = priv->regs;
+       u32 tempval;
+
+       /* Enable Rx and Tx in MACCFG1 */
+       tempval = gfar_read(&regs->maccfg1);
+       tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+       gfar_write(&regs->maccfg1, tempval);
+
+       /* Initialize DMACTRL to have WWR and WOP */
+       tempval = gfar_read(&priv->regs->dmactrl);
+       tempval |= DMACTRL_INIT_SETTINGS;
+       gfar_write(&priv->regs->dmactrl, tempval);
+
+       /* Clear THLT, so that the DMA starts polling now */
+       gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+
+       /* Make sure we aren't stopped */
+       tempval = gfar_read(&priv->regs->dmactrl);
+       tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
+       gfar_write(&priv->regs->dmactrl, tempval);
+
+       /* Unmask the interrupts we look for */
+       gfar_write(&regs->imask, IMASK_DEFAULT);
+}
+
 /* Bring the controller up and running */
 int startup_gfar(struct net_device *dev)
 {
@@ -630,33 +736,34 @@ int startup_gfar(struct net_device *dev)
        int i;
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar *regs = priv->regs;
-       u32 tempval;
        int err = 0;
+       u32 rctrl = 0;
 
        gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
        /* Allocate memory for the buffer descriptors */
-       vaddr = (unsigned long) dma_alloc_coherent(NULL, 
+       vaddr = (unsigned long) dma_alloc_coherent(NULL,
                        sizeof (struct txbd8) * priv->tx_ring_size +
                        sizeof (struct rxbd8) * priv->rx_ring_size,
                        &addr, GFP_KERNEL);
 
        if (vaddr == 0) {
-               printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
-                      dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
+                                       dev->name);
                return -ENOMEM;
        }
 
        priv->tx_bd_base = (struct txbd8 *) vaddr;
 
        /* enet DMA only understands physical addresses */
-       gfar_write(&regs->tbase, addr);
+       gfar_write(&regs->tbase0, addr);
 
        /* Start the rx descriptor ring where the tx ring leaves off */
        addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
        vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
        priv->rx_bd_base = (struct rxbd8 *) vaddr;
-       gfar_write(&regs->rbase, addr);
+       gfar_write(&regs->rbase0, addr);
 
        /* Setup the skbuff rings */
        priv->tx_skbuff =
@@ -664,8 +771,9 @@ int startup_gfar(struct net_device *dev)
                                        priv->tx_ring_size, GFP_KERNEL);
 
        if (priv->tx_skbuff == NULL) {
-               printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
-                      dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
+                                       dev->name);
                err = -ENOMEM;
                goto tx_skb_fail;
        }
@@ -678,8 +786,9 @@ int startup_gfar(struct net_device *dev)
                                        priv->rx_ring_size, GFP_KERNEL);
 
        if (priv->rx_skbuff == NULL) {
-               printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
-                      dev->name);
+               if (netif_msg_ifup(priv))
+                       printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
+                                       dev->name);
                err = -ENOMEM;
                goto rx_skb_fail;
        }
@@ -726,12 +835,13 @@ int startup_gfar(struct net_device *dev)
        /* If the device has multiple interrupts, register for
         * them.  Otherwise, only register for the one */
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-               /* Install our interrupt handlers for Error, 
+               /* Install our interrupt handlers for Error,
                 * Transmit, and Receive */
                if (request_irq(priv->interruptError, gfar_error,
                                0, "enet_error", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d\n",
-                              dev->name, priv->interruptError);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d\n",
+                                       dev->name, priv->interruptError);
 
                        err = -1;
                        goto err_irq_fail;
@@ -739,8 +849,9 @@ int startup_gfar(struct net_device *dev)
 
                if (request_irq(priv->interruptTransmit, gfar_transmit,
                                0, "enet_tx", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d\n",
-                              dev->name, priv->interruptTransmit);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d\n",
+                                       dev->name, priv->interruptTransmit);
 
                        err = -1;
 
@@ -749,8 +860,9 @@ int startup_gfar(struct net_device *dev)
 
                if (request_irq(priv->interruptReceive, gfar_receive,
                                0, "enet_rx", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
-                              dev->name, priv->interruptReceive);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
+                                               dev->name, priv->interruptReceive);
 
                        err = -1;
                        goto rx_irq_fail;
@@ -758,8 +870,9 @@ int startup_gfar(struct net_device *dev)
        } else {
                if (request_irq(priv->interruptTransmit, gfar_interrupt,
                                0, "gfar_interrupt", dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d\n",
-                              dev->name, priv->interruptError);
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d\n",
+                                       dev->name, priv->interruptError);
 
                        err = -1;
                        goto err_irq_fail;
@@ -787,28 +900,22 @@ int startup_gfar(struct net_device *dev)
        else
                gfar_write(&regs->rxic, 0);
 
-       init_waitqueue_head(&priv->rxcleanupq);
+       if (priv->rx_csum_enable)
+               rctrl |= RCTRL_CHECKSUMMING;
 
-       /* Enable Rx and Tx in MACCFG1 */
-       tempval = gfar_read(&regs->maccfg1);
-       tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
-       gfar_write(&regs->maccfg1, tempval);
+       if (priv->extended_hash)
+               rctrl |= RCTRL_EXTHASH;
 
-       /* Initialize DMACTRL to have WWR and WOP */
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval |= DMACTRL_INIT_SETTINGS;
-       gfar_write(&priv->regs->dmactrl, tempval);
+       if (priv->vlan_enable)
+               rctrl |= RCTRL_VLAN;
 
-       /* Clear THLT, so that the DMA starts polling now */
-       gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+       /* Init rctrl based on our settings */
+       gfar_write(&priv->regs->rctrl, rctrl);
 
-       /* Make sure we aren't stopped */
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+       if (dev->features & NETIF_F_IP_CSUM)
+               gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
 
-       /* Unmask the interrupts we look for */
-       gfar_write(&regs->imask, IMASK_DEFAULT);
+       gfar_start(dev);
 
        return 0;
 
@@ -824,7 +931,7 @@ tx_skb_fail:
                        sizeof(struct txbd8)*priv->tx_ring_size
                        + sizeof(struct rxbd8)*priv->rx_ring_size,
                        priv->tx_bd_base,
-                       gfar_read(&regs->tbase));
+                       gfar_read(&regs->tbase0));
 
        if (priv->mii_info->phyinfo->close)
                priv->mii_info->phyinfo->close(priv->mii_info);
@@ -857,11 +964,62 @@ static int gfar_enet_open(struct net_device *dev)
        return err;
 }
 
+static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
+{
+       struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
+
+       memset(fcb, 0, GMAC_FCB_LEN);
+
+       /* Flag the bd so the controller looks for the FCB */
+       bdp->status |= TXBD_TOE;
+
+       return fcb;
+}
+
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+{
+       int len;
+
+       /* If we're here, it's a IP packet with a TCP or UDP
+        * payload.  We set it to checksum, using a pseudo-header
+        * we provide
+        */
+       fcb->ip = 1;
+       fcb->tup = 1;
+       fcb->ctu = 1;
+       fcb->nph = 1;
+
+       /* Notify the controller what the protocol is */
+       if (skb->nh.iph->protocol == IPPROTO_UDP)
+               fcb->udp = 1;
+
+       /* l3os is the distance between the start of the
+        * frame (skb->data) and the start of the IP hdr.
+        * l4os is the distance between the start of the
+        * l3 hdr and the l4 hdr */
+       fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
+       fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+
+       len = skb->nh.iph->tot_len - fcb->l4os;
+
+       /* Provide the pseudoheader csum */
+       fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+                       skb->nh.iph->daddr, len,
+                       skb->nh.iph->protocol, 0);
+}
+
+void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
+{
+       fcb->vln = 1;
+       fcb->vlctl = vlan_tx_tag_get(skb);
+}
+
 /* This is called by the kernel when a frame is ready for transmission. */
 /* It is pointed to by the dev->hard_start_xmit function pointer */
 static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       struct txfcb *fcb = NULL;
        struct txbd8 *txbdp;
 
        /* Update transmit stats */
@@ -876,9 +1034,24 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Clear all but the WRAP status flags */
        txbdp->status &= TXBD_WRAP;
 
+       /* Set up checksumming */
+       if ((dev->features & NETIF_F_IP_CSUM) 
+                       && (CHECKSUM_HW == skb->ip_summed)) {
+               fcb = gfar_add_fcb(skb, txbdp);
+               gfar_tx_checksum(skb, fcb);
+       }
+
+       if (priv->vlan_enable &&
+                       unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
+               if (NULL == fcb)
+                       fcb = gfar_add_fcb(skb, txbdp);
+
+               gfar_tx_vlan(skb, fcb);
+       }
+
        /* Set buffer length and pointer */
        txbdp->length = skb->len;
-       txbdp->bufPtr = dma_map_single(NULL, skb->data, 
+       txbdp->bufPtr = dma_map_single(NULL, skb->data,
                        skb->len, DMA_TO_DEVICE);
 
        /* Save the skb pointer so we can free it later */
@@ -972,15 +1145,78 @@ int gfar_set_mac_address(struct net_device *dev)
 }
 
 
+/* Enables and disables VLAN insertion/extraction */
+static void gfar_vlan_rx_register(struct net_device *dev,
+               struct vlan_group *grp)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       u32 tempval;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->vlgrp = grp;
+
+       if (grp) {
+               /* Enable VLAN tag insertion */
+               tempval = gfar_read(&priv->regs->tctrl);
+               tempval |= TCTRL_VLINS;
+
+               gfar_write(&priv->regs->tctrl, tempval);
+               
+               /* Enable VLAN tag extraction */
+               tempval = gfar_read(&priv->regs->rctrl);
+               tempval |= RCTRL_VLEX;
+               gfar_write(&priv->regs->rctrl, tempval);
+       } else {
+               /* Disable VLAN tag insertion */
+               tempval = gfar_read(&priv->regs->tctrl);
+               tempval &= ~TCTRL_VLINS;
+               gfar_write(&priv->regs->tctrl, tempval);
+
+               /* Disable VLAN tag extraction */
+               tempval = gfar_read(&priv->regs->rctrl);
+               tempval &= ~RCTRL_VLEX;
+               gfar_write(&priv->regs->rctrl, tempval);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (priv->vlgrp)
+               priv->vlgrp->vlan_devices[vid] = NULL;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
        int tempsize, tempval;
        struct gfar_private *priv = netdev_priv(dev);
        int oldsize = priv->rx_buffer_size;
-       int frame_size = new_mtu + 18;
+       int frame_size = new_mtu + ETH_HLEN;
+
+       if (priv->vlan_enable)
+               frame_size += VLAN_ETH_HLEN;
+
+       if (gfar_uses_fcb(priv))
+               frame_size += GMAC_FCB_LEN;
+
+       frame_size += priv->padding;
 
        if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
-               printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name);
+               if (netif_msg_drv(priv))
+                       printk(KERN_ERR "%s: Invalid MTU setting\n",
+                                       dev->name);
                return -EINVAL;
        }
 
@@ -1120,7 +1356,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
        skb->dev = dev;
 
        bdp->bufPtr = dma_map_single(NULL, skb->data,
-                       priv->rx_buffer_size + RXBUF_ALIGNMENT, 
+                       priv->rx_buffer_size + RXBUF_ALIGNMENT,
                        DMA_FROM_DEVICE);
 
        bdp->length = 0;
@@ -1190,11 +1426,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
 
                __netif_rx_schedule(dev);
        } else {
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
-                      dev->name, gfar_read(&priv->regs->ievent),
-                      gfar_read(&priv->regs->imask));
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
+                               dev->name, gfar_read(&priv->regs->ievent),
+                               gfar_read(&priv->regs->imask));
        }
 #else
 
@@ -1209,15 +1444,43 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
        else
                gfar_write(&priv->regs->rxic, 0);
 
-       /* Just in case we need to wake the ring param changer */
-       priv->rxclean = 1;
-
        spin_unlock(&priv->lock);
 #endif
 
        return IRQ_HANDLED;
 }
 
+static inline int gfar_rx_vlan(struct sk_buff *skb,
+               struct vlan_group *vlgrp, unsigned short vlctl)
+{
+#ifdef CONFIG_GFAR_NAPI
+       return vlan_hwaccel_receive_skb(skb, vlgrp, vlctl);
+#else
+       return vlan_hwaccel_rx(skb, vlgrp, vlctl);
+#endif
+}
+
+static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
+{
+       /* If valid headers were found, and valid sums
+        * were verified, then we tell the kernel that no
+        * checksumming is necessary.  Otherwise, it is */
+       if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       else
+               skb->ip_summed = CHECKSUM_NONE;
+}
+
+
+static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
+{
+       struct rxfcb *fcb = (struct rxfcb *)skb->data;
+
+       /* Remove the FCB from the skb */
+       skb_pull(skb, GMAC_FCB_LEN);
+
+       return fcb;
+}
 
 /* gfar_process_frame() -- handle one incoming packet if skb
  * isn't NULL.  */
@@ -1225,35 +1488,51 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
                int length)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       struct rxfcb *fcb = NULL;
 
        if (skb == NULL) {
-#ifdef BRIEF_GFAR_ERRORS
-               printk(KERN_WARNING "%s: Missing skb!!.\n",
-                               dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
                priv->stats.rx_dropped++;
                priv->extra_stats.rx_skbmissing++;
        } else {
+               int ret;
+
                /* Prep the skb for the packet */
                skb_put(skb, length);
 
+               /* Grab the FCB if there is one */
+               if (gfar_uses_fcb(priv))
+                       fcb = gfar_get_fcb(skb);
+
+               /* Remove the padded bytes, if there are any */
+               if (priv->padding)
+                       skb_pull(skb, priv->padding);
+
+               if (priv->rx_csum_enable)
+                       gfar_rx_checksum(skb, fcb);
+
                /* Tell the skb what kind of packet this is */
                skb->protocol = eth_type_trans(skb, dev);
 
                /* Send the packet up the stack */
-               if (RECEIVE(skb) == NET_RX_DROP) {
+               if (unlikely(priv->vlgrp && fcb->vln))
+                       ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
+               else
+                       ret = RECEIVE(skb);
+
+               if (NET_RX_DROP == ret)
                        priv->extra_stats.kernel_dropped++;
-               }
        }
 
        return 0;
 }
 
 /* gfar_clean_rx_ring() -- Processes each frame in the rx ring
- *   until the budget/quota has been reached. Returns the number 
+ *   until the budget/quota has been reached. Returns the number
  *   of frames handled
  */
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 {
        struct rxbd8 *bdp;
        struct sk_buff *skb;
@@ -1355,9 +1634,6 @@ static int gfar_poll(struct net_device *dev, int *budget)
                                   mk_ic_value(priv->rxcount, priv->rxtime));
                else
                        gfar_write(&priv->regs->rxic, 0);
-
-               /* Signal to the ring size changer that it's safe to go */
-               priv->rxclean = 1;
        }
 
        return (rx_work_limit < 0) ? 1 : 0;
@@ -1393,10 +1669,8 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                if (events & IEVENT_CRL)
                        priv->stats.tx_aborted_errors++;
                if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
-                       printk(KERN_WARNING "%s: tx underrun. dropped packet\n",
-                              dev->name);
-#endif
+                       if (netif_msg_tx_err(priv))
+                               printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
                        priv->stats.tx_dropped++;
                        priv->extra_stats.tx_underrun++;
 
@@ -1415,36 +1689,30 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
 #endif
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
-                      gfar_read(&priv->regs->rstat));
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+                                       dev->name,
+                                       gfar_read(&priv->regs->rstat));
        }
        if (events & IEVENT_BABR) {
                priv->stats.rx_errors++;
                priv->extra_stats.rx_babr++;
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: babbling error\n", dev->name);
        }
        if (events & IEVENT_EBERR) {
                priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
-       }
-       if (events & IEVENT_RXC) {
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: EBERR\n", dev->name);
        }
+       if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
+                       printk(KERN_DEBUG "%s: control frame\n", dev->name);
 
        if (events & IEVENT_BABT) {
                priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: babt error\n", dev->name);
        }
 
        return IRQ_HANDLED;
@@ -1510,7 +1778,7 @@ static void gfar_phy_timer(unsigned long data)
  * If, after GFAR_AN_TIMEOUT seconds, it has not
  * finished, we switch to forced.
  * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to 
+ * request the interrupt, or switch the timer over to
  * using gfar_phy_timer to check status */
 static void gfar_phy_startup_timer(unsigned long data)
 {
@@ -1535,8 +1803,9 @@ static void gfar_phy_startup_timer(unsigned long data)
 
                /* Forcing failed!  Give up */
                if(result) {
-                       printk(KERN_ERR "%s: Forcing failed!\n",
-                                       mii_info->dev->name);
+                       if (netif_msg_link(priv))
+                               printk(KERN_ERR "%s: Forcing failed!\n",
+                                               mii_info->dev->name);
                        return;
                }
        }
@@ -1546,16 +1815,17 @@ static void gfar_phy_startup_timer(unsigned long data)
 
        /* Grab the PHY interrupt, if necessary/possible */
        if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
-               if (request_irq(priv->einfo->interruptPHY, 
+               if (request_irq(priv->einfo->interruptPHY,
                                        phy_interrupt,
-                                       SA_SHIRQ, 
-                                       "phy_interrupt", 
+                                       SA_SHIRQ,
+                                       "phy_interrupt",
                                        mii_info->dev) < 0) {
-                       printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
-                                       mii_info->dev->name,
+                       if (netif_msg_intr(priv))
+                               printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
+                                               mii_info->dev->name,
                                        priv->einfo->interruptPHY);
                } else {
-                       mii_configure_phy_interrupt(priv->mii_info, 
+                       mii_configure_phy_interrupt(priv->mii_info,
                                        MII_INTERRUPT_ENABLED);
                        return;
                }
@@ -1592,15 +1862,17 @@ static void adjust_link(struct net_device *dev)
                                tempval &= ~(MACCFG2_FULL_DUPLEX);
                                gfar_write(&regs->maccfg2, tempval);
 
-                               printk(KERN_INFO "%s: Half Duplex\n",
-                                      dev->name);
+                               if (netif_msg_link(priv))
+                                       printk(KERN_INFO "%s: Half Duplex\n",
+                                                       dev->name);
                        } else {
                                tempval = gfar_read(&regs->maccfg2);
                                tempval |= MACCFG2_FULL_DUPLEX;
                                gfar_write(&regs->maccfg2, tempval);
 
-                               printk(KERN_INFO "%s: Full Duplex\n",
-                                      dev->name);
+                               if (netif_msg_link(priv))
+                                       printk(KERN_INFO "%s: Full Duplex\n",
+                                                       dev->name);
                        }
 
                        priv->oldduplex = mii_info->duplex;
@@ -1622,27 +1894,32 @@ static void adjust_link(struct net_device *dev)
                                gfar_write(&regs->maccfg2, tempval);
                                break;
                        default:
-                               printk(KERN_WARNING
-                                      "%s: Ack!  Speed (%d) is not 10/100/1000!\n",
-                                      dev->name, mii_info->speed);
+                               if (netif_msg_link(priv))
+                                       printk(KERN_WARNING
+                                                       "%s: Ack!  Speed (%d) is not 10/100/1000!\n",
+                                                       dev->name, mii_info->speed);
                                break;
                        }
 
-                       printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
-                              mii_info->speed);
+                       if (netif_msg_link(priv))
+                               printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
+                                               mii_info->speed);
 
                        priv->oldspeed = mii_info->speed;
                }
 
                if (!priv->oldlink) {
-                       printk(KERN_INFO "%s: Link is up\n", dev->name);
+                       if (netif_msg_link(priv))
+                               printk(KERN_INFO "%s: Link is up\n", dev->name);
                        priv->oldlink = 1;
                        netif_carrier_on(dev);
                        netif_schedule(dev);
                }
        } else {
                if (priv->oldlink) {
-                       printk(KERN_INFO "%s: Link is down\n", dev->name);
+                       if (netif_msg_link(priv))
+                               printk(KERN_INFO "%s: Link is down\n",
+                                               dev->name);
                        priv->oldlink = 0;
                        priv->oldspeed = 0;
                        priv->oldduplex = -1;
@@ -1664,8 +1941,9 @@ static void gfar_set_multi(struct net_device *dev)
        u32 tempval;
 
        if(dev->flags & IFF_PROMISC) {
-               printk(KERN_INFO "%s: Entering promiscuous mode.\n",
-                               dev->name);
+               if (netif_msg_drv(priv))
+                       printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+                                       dev->name);
                /* Set RCTRL to PROM */
                tempval = gfar_read(&regs->rctrl);
                tempval |= RCTRL_PROM;
@@ -1679,6 +1957,14 @@ static void gfar_set_multi(struct net_device *dev)
        
        if(dev->flags & IFF_ALLMULTI) {
                /* Set the hash to rx all multicast frames */
+               gfar_write(&regs->igaddr0, 0xffffffff);
+               gfar_write(&regs->igaddr1, 0xffffffff);
+               gfar_write(&regs->igaddr2, 0xffffffff);
+               gfar_write(&regs->igaddr3, 0xffffffff);
+               gfar_write(&regs->igaddr4, 0xffffffff);
+               gfar_write(&regs->igaddr5, 0xffffffff);
+               gfar_write(&regs->igaddr6, 0xffffffff);
+               gfar_write(&regs->igaddr7, 0xffffffff);
                gfar_write(&regs->gaddr0, 0xffffffff);
                gfar_write(&regs->gaddr1, 0xffffffff);
                gfar_write(&regs->gaddr2, 0xffffffff);
@@ -1689,6 +1975,14 @@ static void gfar_set_multi(struct net_device *dev)
                gfar_write(&regs->gaddr7, 0xffffffff);
        } else {
                /* zero out the hash */
+               gfar_write(&regs->igaddr0, 0x0);
+               gfar_write(&regs->igaddr1, 0x0);
+               gfar_write(&regs->igaddr2, 0x0);
+               gfar_write(&regs->igaddr3, 0x0);
+               gfar_write(&regs->igaddr4, 0x0);
+               gfar_write(&regs->igaddr5, 0x0);
+               gfar_write(&regs->igaddr6, 0x0);
+               gfar_write(&regs->igaddr7, 0x0);
                gfar_write(&regs->gaddr0, 0x0);
                gfar_write(&regs->gaddr1, 0x0);
                gfar_write(&regs->gaddr2, 0x0);
@@ -1727,16 +2021,15 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
 {
        u32 tempval;
        struct gfar_private *priv = netdev_priv(dev);
-       struct gfar *regs = priv->regs;
-       u32 *hash = &regs->gaddr0;
        u32 result = ether_crc(MAC_ADDR_LEN, addr);
-       u8 whichreg = ((result >> 29) & 0x7);
-       u8 whichbit = ((result >> 24) & 0x1f);
+       int width = priv->hash_width;
+       u8 whichbit = (result >> (32 - width)) & 0x1f;
+       u8 whichreg = result >> (32 - width + 5);
        u32 value = (1 << (31-whichbit));
 
-       tempval = gfar_read(&hash[whichreg]);
+       tempval = gfar_read(priv->hash_regs[whichreg]);
        tempval |= value;
-       gfar_write(&hash[whichreg], tempval);
+       gfar_write(priv->hash_regs[whichreg], tempval);
 
        return;
 }
@@ -1754,10 +2047,9 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
        gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
 
        /* Hmm... */
-#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS)
-       printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
-              dev->name, events, gfar_read(&priv->regs->imask));
-#endif
+       if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
+               printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
+                               dev->name, events, gfar_read(&priv->regs->imask));
 
        /* Update the error counters */
        if (events & IEVENT_TXE) {
@@ -1768,19 +2060,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
                if (events & IEVENT_CRL)
                        priv->stats.tx_aborted_errors++;
                if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
-                       printk(KERN_DEBUG "%s: underrun.  packet dropped.\n",
-                              dev->name);
-#endif
+                       if (netif_msg_tx_err(priv))
+                               printk(KERN_DEBUG "%s: underrun.  packet dropped.\n",
+                                               dev->name);
                        priv->stats.tx_dropped++;
                        priv->extra_stats.tx_underrun++;
 
                        /* Reactivate the Tx Queues */
                        gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
                }
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
-#endif
+               if (netif_msg_tx_err(priv))
+                       printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
        }
        if (events & IEVENT_BSY) {
                priv->stats.rx_errors++;
@@ -1793,35 +2083,31 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
                gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
 #endif
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
-                      gfar_read(&priv->regs->rstat));
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+                                       dev->name,
+                                       gfar_read(&priv->regs->rstat));
        }
        if (events & IEVENT_BABR) {
                priv->stats.rx_errors++;
                priv->extra_stats.rx_babr++;
 
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: babbling error\n", dev->name);
        }
        if (events & IEVENT_EBERR) {
                priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
+               if (netif_msg_rx_err(priv))
+                       printk(KERN_DEBUG "%s: EBERR\n", dev->name);
        }
-       if (events & IEVENT_RXC)
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+       if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
+               if (netif_msg_rx_status(priv))
+                       printk(KERN_DEBUG "%s: control frame\n", dev->name);
 
        if (events & IEVENT_BABT) {
                priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
-               printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+               if (netif_msg_tx_err(priv))
+                       printk(KERN_DEBUG "%s: babt error\n", dev->name);
        }
        return IRQ_HANDLED;
 }
index c2f783a6a9fab85ea221643aeb31c40462e52c87..28af087d9fbba24d0005fd66c34f765005565610 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * drivers/net/gianfar.h
  *
  * Gianfar Ethernet Driver
 /* The maximum number of packets to be handled in one call of gfar_poll */
 #define GFAR_DEV_WEIGHT 64
 
+/* Length for FCB */
+#define GMAC_FCB_LEN 8
+
+/* Default padding amount */
+#define DEFAULT_PADDING 2
+
 /* Number of bytes to align the rx bufs to */
 #define RXBUF_ALIGNMENT 64
 
@@ -91,7 +97,7 @@ extern const char gfar_driver_version[];
 #define JUMBO_FRAME_SIZE 9600
 
 /* Latency of interface clock in nanoseconds */
-/* Interface clock latency , in this case, means the 
+/* Interface clock latency , in this case, means the
  * time described by a value of 1 in the interrupt
  * coalescing registers' time fields.  Since those fields
  * refer to the time it takes for 64 clocks to pass, the
@@ -166,9 +172,28 @@ extern const char gfar_driver_version[];
                                mk_ic_icft(count) | \
                                mk_ic_ictt(time))
 
+#define RCTRL_PAL_MASK         0x001f0000
+#define RCTRL_VLEX             0x00002000
+#define RCTRL_FILREN           0x00001000
+#define RCTRL_GHTX             0x00000400
+#define RCTRL_IPCSEN           0x00000200
+#define RCTRL_TUCSEN           0x00000100
+#define RCTRL_PRSDEP_MASK      0x000000c0
+#define RCTRL_PRSDEP_INIT      0x000000c0
 #define RCTRL_PROM             0x00000008
+#define RCTRL_CHECKSUMMING     (RCTRL_IPCSEN \
+               | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
+#define RCTRL_EXTHASH          (RCTRL_GHTX)
+#define RCTRL_VLAN             (RCTRL_PRSDEP_INIT)
+
+
 #define RSTAT_CLEAR_RHALT       0x00800000
 
+#define TCTRL_IPCSEN           0x00004000
+#define TCTRL_TUCSEN           0x00002000
+#define TCTRL_VLINS            0x00001000
+#define TCTRL_INIT_CSUM                (TCTRL_TUCSEN | TCTRL_IPCSEN)
+
 #define IEVENT_INIT_CLEAR      0xffffffff
 #define IEVENT_BABR            0x80000000
 #define IEVENT_RXC             0x40000000
@@ -187,12 +212,16 @@ extern const char gfar_driver_version[];
 #define IEVENT_RXB0            0x00008000
 #define IEVENT_GRSC            0x00000100
 #define IEVENT_RXF0            0x00000080
+#define IEVENT_FIR             0x00000008
+#define IEVENT_FIQ             0x00000004
+#define IEVENT_DPE             0x00000002
+#define IEVENT_PERR            0x00000001
 #define IEVENT_RX_MASK          (IEVENT_RXB0 | IEVENT_RXF0)
 #define IEVENT_TX_MASK          (IEVENT_TXB | IEVENT_TXF)
 #define IEVENT_ERR_MASK         \
 (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
  IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN)
+ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
 
 #define IMASK_INIT_CLEAR       0x00000000
 #define IMASK_BABR              0x80000000
@@ -212,10 +241,15 @@ extern const char gfar_driver_version[];
 #define IMASK_RXB0              0x00008000
 #define IMASK_GTSC              0x00000100
 #define IMASK_RXFEN0           0x00000080
+#define IMASK_FIR              0x00000008
+#define IMASK_FIQ              0x00000004
+#define IMASK_DPE              0x00000002
+#define IMASK_PERR             0x00000001
 #define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
 #define IMASK_DEFAULT  (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
                IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
-               IMASK_XFUN | IMASK_RXC | IMASK_BABT)
+               IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
+               | IMASK_PERR)
 
 
 /* Attribute fields */
@@ -254,6 +288,18 @@ extern const char gfar_driver_version[];
 #define TXBD_RETRYLIMIT                0x0040
 #define        TXBD_RETRYCOUNTMASK     0x003c
 #define TXBD_UNDERRUN          0x0002
+#define TXBD_TOE               0x0002
+
+/* Tx FCB param bits */
+#define TXFCB_VLN              0x80
+#define TXFCB_IP               0x40
+#define TXFCB_IP6              0x20
+#define TXFCB_TUP              0x10
+#define TXFCB_UDP              0x08
+#define TXFCB_CIP              0x04
+#define TXFCB_CTU              0x02
+#define TXFCB_NPH              0x01
+#define TXFCB_DEFAULT          (TXFCB_IP|TXFCB_TUP|TXFCB_CTU|TXFCB_NPH)
 
 /* RxBD status field bits */
 #define RXBD_EMPTY             0x8000
@@ -273,6 +319,18 @@ extern const char gfar_driver_version[];
 #define RXBD_TRUNCATED         0x0001
 #define RXBD_STATS             0x01ff
 
+/* Rx FCB status field bits */
+#define RXFCB_VLN              0x8000
+#define RXFCB_IP               0x4000
+#define RXFCB_IP6              0x2000
+#define RXFCB_TUP              0x1000
+#define RXFCB_CIP              0x0800
+#define RXFCB_CTU              0x0400
+#define RXFCB_EIP              0x0200
+#define RXFCB_ETU              0x0100
+#define RXFCB_PERR_MASK                0x000c
+#define RXFCB_PERR_BADL3       0x0008
+
 struct txbd8
 {
        u16     status; /* Status Fields */
@@ -280,6 +338,22 @@ struct txbd8
        u32     bufPtr; /* Buffer Pointer */
 };
 
+struct txfcb {
+       u8      vln:1,
+               ip:1,
+               ip6:1,
+               tup:1,
+               udp:1,
+               cip:1,
+               ctu:1,
+               nph:1;
+       u8      reserved;
+       u8      l4os;   /* Level 4 Header Offset */
+       u8      l3os;   /* Level 3 Header Offset */
+       u16     phcs;   /* Pseudo-header Checksum */
+       u16     vlctl;  /* VLAN control word */
+};
+
 struct rxbd8
 {
        u16     status; /* Status Fields */
@@ -287,6 +361,21 @@ struct rxbd8
        u32     bufPtr; /* Buffer Pointer */
 };
 
+struct rxfcb {
+       u16     vln:1,
+               ip:1,
+               ip6:1,
+               tup:1,
+               cip:1,
+               ctu:1,
+               eip:1,
+               etu:1;
+       u8      rq;     /* Receive Queue index */
+       u8      pro;    /* Layer 4 Protocol */
+       u16     reserved;
+       u16     vlctl;  /* VLAN control word */
+};
+
 struct rmon_mib
 {
        u32     tr64;   /* 0x.680 - Transmit and Receive 64-byte Frame Counter */
@@ -371,90 +460,191 @@ struct gfar_stats {
 
 
 struct gfar {
-       u8      res1[16];
-       u32     ievent;                 /* 0x.010 - Interrupt Event Register */
-       u32     imask;                  /* 0x.014 - Interrupt Mask Register */
-       u32     edis;                   /* 0x.018 - Error Disabled Register */
+       u32     tsec_id;        /* 0x.000 - Controller ID register */
+       u8      res1[12];
+       u32     ievent;         /* 0x.010 - Interrupt Event Register */
+       u32     imask;          /* 0x.014 - Interrupt Mask Register */
+       u32     edis;           /* 0x.018 - Error Disabled Register */
        u8      res2[4];
-       u32     ecntrl;                 /* 0x.020 - Ethernet Control Register */
-       u32     minflr;                 /* 0x.024 - Minimum Frame Length Register */
-       u32     ptv;                    /* 0x.028 - Pause Time Value Register */
-       u32     dmactrl;                /* 0x.02c - DMA Control Register */
-       u32     tbipa;                  /* 0x.030 - TBI PHY Address Register */
+       u32     ecntrl;         /* 0x.020 - Ethernet Control Register */
+       u32     minflr;         /* 0x.024 - Minimum Frame Length Register */
+       u32     ptv;            /* 0x.028 - Pause Time Value Register */
+       u32     dmactrl;        /* 0x.02c - DMA Control Register */
+       u32     tbipa;          /* 0x.030 - TBI PHY Address Register */
        u8      res3[88];
-       u32     fifo_tx_thr;            /* 0x.08c - FIFO transmit threshold register */
+       u32     fifo_tx_thr;    /* 0x.08c - FIFO transmit threshold register */
        u8      res4[8];
-       u32     fifo_tx_starve;         /* 0x.098 - FIFO transmit starve register */
+       u32     fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
        u32     fifo_tx_starve_shutoff; /* 0x.09c - FIFO transmit starve shutoff register */
-       u8      res5[96];
-       u32     tctrl;                  /* 0x.100 - Transmit Control Register */
-       u32     tstat;                  /* 0x.104 - Transmit Status Register */
-       u8      res6[4];
-       u32     tbdlen;                 /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
-       u32     txic;                   /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
-       u8      res7[16];
-       u32     ctbptr;                 /* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */
-       u8      res8[92];
-       u32     tbptr;                  /* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */
-       u8      res9[124];
-       u32     tbase;                  /* 0x.204 - Transmit Descriptor Base Address Register */
-       u8      res10[168];
-       u32     ostbd;                  /* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */
-       u32     ostbdp;                 /* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */
-       u8      res11[72];
-       u32     rctrl;                  /* 0x.300 - Receive Control Register */
-       u32     rstat;                  /* 0x.304 - Receive Status Register */
-       u8      res12[4];
-       u32     rbdlen;                 /* 0x.30c - RxBD Data Length Register */
-       u32     rxic;                   /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
-       u8      res13[16];
-       u32     crbptr;                 /* 0x.324 - Current Receive Buffer Descriptor Pointer */
-       u8      res14[24];
-       u32     mrblr;                  /* 0x.340 - Maximum Receive Buffer Length Register */
-       u8      res15[64];
-       u32     rbptr;                  /* 0x.384 - Receive Buffer Descriptor Pointer */
-       u8      res16[124];
-       u32     rbase;                  /* 0x.404 - Receive Descriptor Base Address */
-       u8      res17[248];
-       u32     maccfg1;                /* 0x.500 - MAC Configuration 1 Register */
-       u32     maccfg2;                /* 0x.504 - MAC Configuration 2 Register */
-       u32     ipgifg;                 /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
-       u32     hafdup;                 /* 0x.50c - Half Duplex Register */
-       u32     maxfrm;                 /* 0x.510 - Maximum Frame Length Register */
+       u8      res5[4];
+       u32     fifo_rx_pause;  /* 0x.0a4 - FIFO receive pause threshold register */
+       u32     fifo_rx_alarm;  /* 0x.0a8 - FIFO receive alarm threshold register */
+       u8      res6[84];
+       u32     tctrl;          /* 0x.100 - Transmit Control Register */
+       u32     tstat;          /* 0x.104 - Transmit Status Register */
+       u32     dfvlan;         /* 0x.108 - Default VLAN Control word */
+       u32     tbdlen;         /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
+       u32     txic;           /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
+       u32     tqueue;         /* 0x.114 - Transmit queue control register */
+       u8      res7[40];
+       u32     tr03wt;         /* 0x.140 - TxBD Rings 0-3 round-robin weightings */
+       u32     tr47wt;         /* 0x.144 - TxBD Rings 4-7 round-robin weightings */
+       u8      res8[52];
+       u32     tbdbph;         /* 0x.17c - Tx data buffer pointer high */
+       u8      res9a[4];
+       u32     tbptr0;         /* 0x.184 - TxBD Pointer for ring 0 */
+       u8      res9b[4];
+       u32     tbptr1;         /* 0x.18c - TxBD Pointer for ring 1 */
+       u8      res9c[4];
+       u32     tbptr2;         /* 0x.194 - TxBD Pointer for ring 2 */
+       u8      res9d[4];
+       u32     tbptr3;         /* 0x.19c - TxBD Pointer for ring 3 */
+       u8      res9e[4];
+       u32     tbptr4;         /* 0x.1a4 - TxBD Pointer for ring 4 */
+       u8      res9f[4];
+       u32     tbptr5;         /* 0x.1ac - TxBD Pointer for ring 5 */
+       u8      res9g[4];
+       u32     tbptr6;         /* 0x.1b4 - TxBD Pointer for ring 6 */
+       u8      res9h[4];
+       u32     tbptr7;         /* 0x.1bc - TxBD Pointer for ring 7 */
+       u8      res9[64];
+       u32     tbaseh;         /* 0x.200 - TxBD base address high */
+       u32     tbase0;         /* 0x.204 - TxBD Base Address of ring 0 */
+       u8      res10a[4];
+       u32     tbase1;         /* 0x.20c - TxBD Base Address of ring 1 */
+       u8      res10b[4];
+       u32     tbase2;         /* 0x.214 - TxBD Base Address of ring 2 */
+       u8      res10c[4];
+       u32     tbase3;         /* 0x.21c - TxBD Base Address of ring 3 */
+       u8      res10d[4];
+       u32     tbase4;         /* 0x.224 - TxBD Base Address of ring 4 */
+       u8      res10e[4];
+       u32     tbase5;         /* 0x.22c - TxBD Base Address of ring 5 */
+       u8      res10f[4];
+       u32     tbase6;         /* 0x.234 - TxBD Base Address of ring 6 */
+       u8      res10g[4];
+       u32     tbase7;         /* 0x.23c - TxBD Base Address of ring 7 */
+       u8      res10[192];
+       u32     rctrl;          /* 0x.300 - Receive Control Register */
+       u32     rstat;          /* 0x.304 - Receive Status Register */
+       u8      res12[8];
+       u32     rxic;           /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
+       u32     rqueue;         /* 0x.314 - Receive queue control register */
+       u8      res13[24];
+       u32     rbifx;          /* 0x.330 - Receive bit field extract control register */
+       u32     rqfar;          /* 0x.334 - Receive queue filing table address register */
+       u32     rqfcr;          /* 0x.338 - Receive queue filing table control register */
+       u32     rqfpr;          /* 0x.33c - Receive queue filing table property register */
+       u32     mrblr;          /* 0x.340 - Maximum Receive Buffer Length Register */
+       u8      res14[56];
+       u32     rbdbph;         /* 0x.37c - Rx data buffer pointer high */
+       u8      res15a[4];
+       u32     rbptr0;         /* 0x.384 - RxBD pointer for ring 0 */
+       u8      res15b[4];
+       u32     rbptr1;         /* 0x.38c - RxBD pointer for ring 1 */
+       u8      res15c[4];
+       u32     rbptr2;         /* 0x.394 - RxBD pointer for ring 2 */
+       u8      res15d[4];
+       u32     rbptr3;         /* 0x.39c - RxBD pointer for ring 3 */
+       u8      res15e[4];
+       u32     rbptr4;         /* 0x.3a4 - RxBD pointer for ring 4 */
+       u8      res15f[4];
+       u32     rbptr5;         /* 0x.3ac - RxBD pointer for ring 5 */
+       u8      res15g[4];
+       u32     rbptr6;         /* 0x.3b4 - RxBD pointer for ring 6 */
+       u8      res15h[4];
+       u32     rbptr7;         /* 0x.3bc - RxBD pointer for ring 7 */
+       u8      res16[64];
+       u32     rbaseh;         /* 0x.400 - RxBD base address high */
+       u32     rbase0;         /* 0x.404 - RxBD base address of ring 0 */
+       u8      res17a[4];
+       u32     rbase1;         /* 0x.40c - RxBD base address of ring 1 */
+       u8      res17b[4];
+       u32     rbase2;         /* 0x.414 - RxBD base address of ring 2 */
+       u8      res17c[4];
+       u32     rbase3;         /* 0x.41c - RxBD base address of ring 3 */
+       u8      res17d[4];
+       u32     rbase4;         /* 0x.424 - RxBD base address of ring 4 */
+       u8      res17e[4];
+       u32     rbase5;         /* 0x.42c - RxBD base address of ring 5 */
+       u8      res17f[4];
+       u32     rbase6;         /* 0x.434 - RxBD base address of ring 6 */
+       u8      res17g[4];
+       u32     rbase7;         /* 0x.43c - RxBD base address of ring 7 */
+       u8      res17[192];
+       u32     maccfg1;        /* 0x.500 - MAC Configuration 1 Register */
+       u32     maccfg2;        /* 0x.504 - MAC Configuration 2 Register */
+       u32     ipgifg;         /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
+       u32     hafdup;         /* 0x.50c - Half Duplex Register */
+       u32     maxfrm;         /* 0x.510 - Maximum Frame Length Register */
        u8      res18[12];
-       u32     miimcfg;                /* 0x.520 - MII Management Configuration Register */
-       u32     miimcom;                /* 0x.524 - MII Management Command Register */
-       u32     miimadd;                /* 0x.528 - MII Management Address Register */
-       u32     miimcon;                /* 0x.52c - MII Management Control Register */
-       u32     miimstat;               /* 0x.530 - MII Management Status Register */
-       u32     miimind;                /* 0x.534 - MII Management Indicator Register */
+       u32     miimcfg;        /* 0x.520 - MII Management Configuration Register */
+       u32     miimcom;        /* 0x.524 - MII Management Command Register */
+       u32     miimadd;        /* 0x.528 - MII Management Address Register */
+       u32     miimcon;        /* 0x.52c - MII Management Control Register */
+       u32     miimstat;       /* 0x.530 - MII Management Status Register */
+       u32     miimind;        /* 0x.534 - MII Management Indicator Register */
        u8      res19[4];
-       u32     ifstat;                 /* 0x.53c - Interface Status Register */
-       u32     macstnaddr1;            /* 0x.540 - Station Address Part 1 Register */
-       u32     macstnaddr2;            /* 0x.544 - Station Address Part 2 Register */
-       u8      res20[312];
-       struct rmon_mib rmon;
-       u8      res21[192];
-       u32     iaddr0;                 /* 0x.800 - Indivdual address register 0 */
-       u32     iaddr1;                 /* 0x.804 - Indivdual address register 1 */
-       u32     iaddr2;                 /* 0x.808 - Indivdual address register 2 */
-       u32     iaddr3;                 /* 0x.80c - Indivdual address register 3 */
-       u32     iaddr4;                 /* 0x.810 - Indivdual address register 4 */
-       u32     iaddr5;                 /* 0x.814 - Indivdual address register 5 */
-       u32     iaddr6;                 /* 0x.818 - Indivdual address register 6 */
-       u32     iaddr7;                 /* 0x.81c - Indivdual address register 7 */
+       u32     ifstat;         /* 0x.53c - Interface Status Register */
+       u32     macstnaddr1;    /* 0x.540 - Station Address Part 1 Register */
+       u32     macstnaddr2;    /* 0x.544 - Station Address Part 2 Register */
+       u32     mac01addr1;     /* 0x.548 - MAC exact match address 1, part 1 */
+       u32     mac01addr2;     /* 0x.54c - MAC exact match address 1, part 2 */
+       u32     mac02addr1;     /* 0x.550 - MAC exact match address 2, part 1 */
+       u32     mac02addr2;     /* 0x.554 - MAC exact match address 2, part 2 */
+       u32     mac03addr1;     /* 0x.558 - MAC exact match address 3, part 1 */
+       u32     mac03addr2;     /* 0x.55c - MAC exact match address 3, part 2 */
+       u32     mac04addr1;     /* 0x.560 - MAC exact match address 4, part 1 */
+       u32     mac04addr2;     /* 0x.564 - MAC exact match address 4, part 2 */
+       u32     mac05addr1;     /* 0x.568 - MAC exact match address 5, part 1 */
+       u32     mac05addr2;     /* 0x.56c - MAC exact match address 5, part 2 */
+       u32     mac06addr1;     /* 0x.570 - MAC exact match address 6, part 1 */
+       u32     mac06addr2;     /* 0x.574 - MAC exact match address 6, part 2 */
+       u32     mac07addr1;     /* 0x.578 - MAC exact match address 7, part 1 */
+       u32     mac07addr2;     /* 0x.57c - MAC exact match address 7, part 2 */
+       u32     mac08addr1;     /* 0x.580 - MAC exact match address 8, part 1 */
+       u32     mac08addr2;     /* 0x.584 - MAC exact match address 8, part 2 */
+       u32     mac09addr1;     /* 0x.588 - MAC exact match address 9, part 1 */
+       u32     mac09addr2;     /* 0x.58c - MAC exact match address 9, part 2 */
+       u32     mac10addr1;     /* 0x.590 - MAC exact match address 10, part 1*/
+       u32     mac10addr2;     /* 0x.594 - MAC exact match address 10, part 2*/
+       u32     mac11addr1;     /* 0x.598 - MAC exact match address 11, part 1*/
+       u32     mac11addr2;     /* 0x.59c - MAC exact match address 11, part 2*/
+       u32     mac12addr1;     /* 0x.5a0 - MAC exact match address 12, part 1*/
+       u32     mac12addr2;     /* 0x.5a4 - MAC exact match address 12, part 2*/
+       u32     mac13addr1;     /* 0x.5a8 - MAC exact match address 13, part 1*/
+       u32     mac13addr2;     /* 0x.5ac - MAC exact match address 13, part 2*/
+       u32     mac14addr1;     /* 0x.5b0 - MAC exact match address 14, part 1*/
+       u32     mac14addr2;     /* 0x.5b4 - MAC exact match address 14, part 2*/
+       u32     mac15addr1;     /* 0x.5b8 - MAC exact match address 15, part 1*/
+       u32     mac15addr2;     /* 0x.5bc - MAC exact match address 15, part 2*/
+       u8      res20[192];
+       struct rmon_mib rmon;   /* 0x.680-0x.73c */
+       u32     rrej;           /* 0x.740 - Receive filer rejected packet counter */
+       u8      res21[188];
+       u32     igaddr0;        /* 0x.800 - Indivdual/Group address register 0*/
+       u32     igaddr1;        /* 0x.804 - Indivdual/Group address register 1*/
+       u32     igaddr2;        /* 0x.808 - Indivdual/Group address register 2*/
+       u32     igaddr3;        /* 0x.80c - Indivdual/Group address register 3*/
+       u32     igaddr4;        /* 0x.810 - Indivdual/Group address register 4*/
+       u32     igaddr5;        /* 0x.814 - Indivdual/Group address register 5*/
+       u32     igaddr6;        /* 0x.818 - Indivdual/Group address register 6*/
+       u32     igaddr7;        /* 0x.81c - Indivdual/Group address register 7*/
        u8      res22[96];
-       u32     gaddr0;                 /* 0x.880 - Global address register 0 */
-       u32     gaddr1;                 /* 0x.884 - Global address register 1 */
-       u32     gaddr2;                 /* 0x.888 - Global address register 2 */
-       u32     gaddr3;                 /* 0x.88c - Global address register 3 */
-       u32     gaddr4;                 /* 0x.890 - Global address register 4 */
-       u32     gaddr5;                 /* 0x.894 - Global address register 5 */
-       u32     gaddr6;                 /* 0x.898 - Global address register 6 */
-       u32     gaddr7;                 /* 0x.89c - Global address register 7 */
-       u8      res23[856];
-       u32     attr;                   /* 0x.bf8 - Attributes Register */
-       u32     attreli;                /* 0x.bfc - Attributes Extract Length and Extract Index Register */
+       u32     gaddr0;         /* 0x.880 - Group address register 0 */
+       u32     gaddr1;         /* 0x.884 - Group address register 1 */
+       u32     gaddr2;         /* 0x.888 - Group address register 2 */
+       u32     gaddr3;         /* 0x.88c - Group address register 3 */
+       u32     gaddr4;         /* 0x.890 - Group address register 4 */
+       u32     gaddr5;         /* 0x.894 - Group address register 5 */
+       u32     gaddr6;         /* 0x.898 - Group address register 6 */
+       u32     gaddr7;         /* 0x.89c - Group address register 7 */
+       u8      res23a[352];
+       u32     fifocfg;        /* 0x.a00 - FIFO interface config register */
+       u8      res23b[252];
+       u8      res23c[248];
+       u32     attr;           /* 0x.bf8 - Attributes Register */
+       u32     attreli;        /* 0x.bfc - Attributes Extract Length and Extract Index Register */
        u8      res24[1024];
 
 };
@@ -496,6 +686,8 @@ struct gfar_private {
        struct txbd8 *cur_tx;           /* Next free ring entry */
        struct txbd8 *dirty_tx;         /* The Ring entry to be freed. */
        struct gfar *regs;      /* Pointer to the GFAR memory mapped Registers */
+       u32 *hash_regs[16];
+       int hash_width;
        struct gfar *phyregs;
        struct work_struct tq;
        struct timer_list phy_info_timer;
@@ -506,9 +698,12 @@ struct gfar_private {
        unsigned int rx_stash_size;
        unsigned int tx_ring_size;
        unsigned int rx_ring_size;
-       wait_queue_head_t rxcleanupq;
-       unsigned int rxclean;
 
+       unsigned char vlan_enable:1,
+               rx_csum_enable:1,
+               extended_hash:1;
+       unsigned short padding;
+       struct vlan_group *vlgrp;
        /* Info structure initialized by board setup code */
        unsigned int interruptTransmit;
        unsigned int interruptReceive;
@@ -519,6 +714,8 @@ struct gfar_private {
        int oldspeed;
        int oldduplex;
        int oldlink;
+
+       uint32_t msg_enable;
 };
 
 extern inline u32 gfar_read(volatile unsigned *addr)
index 28046e9e88ba1f369030c33f29e49395bdb9dc2a..a451de629197b13e1204f59b2707fef1d425e91d 100644 (file)
 
 extern int startup_gfar(struct net_device *dev);
 extern void stop_gfar(struct net_device *dev);
-extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_start(struct net_device *dev);
+extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
                     u64 * buf);
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
 
 static char stat_gstrings[][ETH_GSTRING_LEN] = {
        "rx-dropped-by-kernel",
@@ -118,57 +120,56 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
        "tx-fragmented-frames",
 };
 
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+               memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+       else
+               memcpy(buf, stat_gstrings,
+                               GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+}
+
 /* Fill in an array of 64-bit statistics from various sources.
  * This array will be appended to the end of the ethtool_stats
  * structure, and returned to user space
  */
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
 {
        int i;
        struct gfar_private *priv = netdev_priv(dev);
-       u32 *rmon = (u32 *) & priv->regs->rmon;
        u64 *extra = (u64 *) & priv->extra_stats;
-       struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-       for (i = 0; i < GFAR_RMON_LEN; i++) {
-               stats->rmon[i] = (u64) (rmon[i]);
-       }
-
-       for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-               stats->extra[i] = extra[i];
-       }
-}
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+               u32 *rmon = (u32 *) & priv->regs->rmon;
+               struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-/* Returns the number of stats (and their corresponding strings) */
-int gfar_stats_count(struct net_device *dev)
-{
-       return GFAR_STATS_LEN;
-}
+               for (i = 0; i < GFAR_RMON_LEN; i++)
+                       stats->rmon[i] = (u64) (rmon[i]);
 
-void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
-{
-       memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+               for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+                       stats->extra[i] = extra[i];
+       } else
+               for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+                       buf[i] = extra[i];
 }
 
-void gfar_fill_stats_normon(struct net_device *dev, 
-               struct ethtool_stats *dummy, u64 * buf)
+/* Returns the number of stats (and their corresponding strings) */
+static int gfar_stats_count(struct net_device *dev)
 {
-       int i;
        struct gfar_private *priv = netdev_priv(dev);
-       u64 *extra = (u64 *) & priv->extra_stats;
 
-       for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-               buf[i] = extra[i];
-       }
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+               return GFAR_STATS_LEN;
+       else
+               return GFAR_EXTRA_STATS_LEN;
 }
 
-
-int gfar_stats_count_normon(struct net_device *dev)
-{
-       return GFAR_EXTRA_STATS_LEN;
-}
 /* Fills in the drvinfo structure with some basic info */
-void gfar_gdrvinfo(struct net_device *dev, struct
+static void gfar_gdrvinfo(struct net_device *dev, struct
              ethtool_drvinfo *drvinfo)
 {
        strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,7 @@ void gfar_gdrvinfo(struct net_device *dev, struct
 }
 
 /* Return the current settings in the ethtool_cmd structure */
-int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct gfar_private *priv = netdev_priv(dev);
        uint gigabit_support = 
@@ -216,13 +217,13 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 }
 
 /* Return the length of the register structure */
-int gfar_reglen(struct net_device *dev)
+static int gfar_reglen(struct net_device *dev)
 {
        return sizeof (struct gfar);
 }
 
 /* Return a dump of the GFAR register space */
-void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
 {
        int i;
        struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb
                buf[i] = theregs[i];
 }
 
-/* Fill in a buffer with the strings which correspond to the
- * stats */
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
-{
-       memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
-}
-
 /* Convert microseconds to ethernet clock ticks, which changes
  * depending on what speed the controller is running at */
 static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
 
 /* Get the coalescing parameters, and put them in the cvals
  * structure.  */
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+               return -EOPNOTSUPP;
 
        cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
        cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
  * Both cvals->*_usecs and cvals->*_frames have to be > 0
  * in order for coalescing to be active
  */
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+               return -EOPNOTSUPP;
+
        /* Set up rx coalescing */
        if ((cvals->rx_coalesce_usecs == 0) ||
            (cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 /* Fills in rvals with the current ring parameters.  Currently,
  * rx, rx_mini, and rx_jumbo rings are the same size, as mini and
  * jumbo are ignored by the driver */
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
@@ -401,9 +401,8 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
  * necessary so that we don't mess things up while we're in
  * motion.  We wait for the ring to be clean before reallocating
  * the rings. */
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
-       u32 tempval;
        struct gfar_private *priv = netdev_priv(dev);
        int err = 0;
 
@@ -425,37 +424,54 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
                return -EINVAL;
        }
 
-       /* Stop the controller so we don't rx any more frames */
-       /* But first, make sure we clear the bits */
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+       if (dev->flags & IFF_UP) {
+               unsigned long flags;
 
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval |= (DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+               /* Halt TX and RX, and process the frames which
+                * have already been received */
+               spin_lock_irqsave(&priv->lock, flags);
+               gfar_halt(dev);
+               gfar_clean_rx_ring(dev, priv->rx_ring_size);
+               spin_unlock_irqrestore(&priv->lock, flags);
 
-       while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
-               cpu_relax();
+               /* Now we take down the rings to rebuild them */
+               stop_gfar(dev);
+       }
 
-       /* Note that rx is not clean right now */
-       priv->rxclean = 0;
+       /* Change the size */
+       priv->rx_ring_size = rvals->rx_pending;
+       priv->tx_ring_size = rvals->tx_pending;
 
-       if (dev->flags & IFF_UP) {
-               /* Tell the driver to process the rest of the frames */
-               gfar_receive(0, (void *) dev, NULL);
+       /* Rebuild the rings with the new size */
+       if (dev->flags & IFF_UP)
+               err = startup_gfar(dev);
 
-               /* Now wait for it to be done */
-               wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+       return err;
+}
 
-               /* Ok, all packets have been handled.  Now we bring it down,
-                * change the ring size, and bring it up */
+static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       int err = 0;
 
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return -EOPNOTSUPP;
+
+       if (dev->flags & IFF_UP) {
+               unsigned long flags;
+
+               /* Halt TX and RX, and process the frames which
+                * have already been received */
+               spin_lock_irqsave(&priv->lock, flags);
+               gfar_halt(dev);
+               gfar_clean_rx_ring(dev, priv->rx_ring_size);
+               spin_unlock_irqrestore(&priv->lock, flags);
+
+               /* Now we take down the rings to rebuild them */
                stop_gfar(dev);
        }
 
-       priv->rx_ring_size = rvals->rx_pending;
-       priv->tx_ring_size = rvals->tx_pending;
+       priv->rx_csum_enable = data;
 
        if (dev->flags & IFF_UP)
                err = startup_gfar(dev);
@@ -463,6 +479,61 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
        return err;
 }
 
+static uint32_t gfar_get_rx_csum(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return 0;
+
+       return priv->rx_csum_enable;
+}
+
+static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+       unsigned long flags;
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return -EOPNOTSUPP;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       gfar_halt(dev);
+
+       if (data)
+               dev->features |= NETIF_F_IP_CSUM;
+       else
+               dev->features &= ~NETIF_F_IP_CSUM;
+
+       gfar_start(dev);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static uint32_t gfar_get_tx_csum(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return 0;
+
+       return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static uint32_t gfar_get_msglevel(struct net_device *dev)
+{       
+       struct gfar_private *priv = netdev_priv(dev);
+       return priv->msg_enable;
+}       
+        
+static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
+{       
+       struct gfar_private *priv = netdev_priv(dev);
+       priv->msg_enable = data;
+}
+
+
 struct ethtool_ops gfar_ethtool_ops = {
        .get_settings = gfar_gsettings,
        .get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@ struct ethtool_ops gfar_ethtool_ops = {
        .get_strings = gfar_gstrings,
        .get_stats_count = gfar_stats_count,
        .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings_normon,
-       .get_stats_count = gfar_stats_count_normon,
-       .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops gfar_nocoalesce_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings,
-       .get_stats_count = gfar_stats_count,
-       .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_coalesce = gfar_gcoalesce,
-       .set_coalesce = gfar_scoalesce,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings_normon,
-       .get_stats_count = gfar_stats_count_normon,
-       .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops *gfar_op_array[] = {
-       &gfar_ethtool_ops,
-       &gfar_normon_ethtool_ops,
-       &gfar_nocoalesce_ethtool_ops,
-       &gfar_normon_nocoalesce_ethtool_ops
+       .get_rx_csum = gfar_get_rx_csum,
+       .get_tx_csum = gfar_get_tx_csum,
+       .set_rx_csum = gfar_set_rx_csum,
+       .set_tx_csum = gfar_set_tx_csum,
+       .get_msglevel = gfar_get_msglevel,
+       .set_msglevel = gfar_set_msglevel,
 };
index 13f114876965ba1d26f3bc2c604037d409213fa5..3213f3e50487cee1076d9d69407ea520108bbd07 100644 (file)
@@ -850,7 +850,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
     if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
     data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
 
-    schedule_timeout(data * HZ);
+    msleep_interruptible(data * 1000);
     del_timer_sync(&lp->blink_timer);
 
     /* Restore the original value of the bcrs */
index e15369c8d1651dbd9d20ffa1724f29f47ce9e2e6..d6388e1533f09778578a0eee49dad0d3dbed8af2 100644 (file)
@@ -90,7 +90,6 @@ static int sb1000_close(struct net_device *dev);
 
 
 /* SB1000 hardware routines to be used during open/configuration phases */
-static inline void nicedelay(unsigned long usecs);
 static inline int card_wait_for_busy_clear(const int ioaddr[],
        const char* name);
 static inline int card_wait_for_ready(const int ioaddr[], const char* name,
@@ -254,13 +253,6 @@ static struct pnp_driver sb1000_driver = {
 
 static const int TimeOutJiffies = (875 * HZ) / 100;
 
-static inline void nicedelay(unsigned long usecs)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(HZ);
-       return;
-}
-
 /* Card Wait For Busy Clear (cannot be used during an interrupt) */
 static inline int
 card_wait_for_busy_clear(const int ioaddr[], const char* name)
@@ -475,7 +467,7 @@ sb1000_reset(const int ioaddr[], const char* name)
        udelay(1000);
        outb(0x0, port);
        inb(port);
-       nicedelay(60000);
+       ssleep(1);
        outb(0x4, port);
        inb(port);
        udelay(1000);
@@ -537,7 +529,7 @@ sb1000_activate(const int ioaddr[], const char* name)
        const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00};
        const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00};
 
-       nicedelay(50000);
+       ssleep(1);
        if ((status = card_send_command(ioaddr, name, Command0, st)))
                return status;
        if ((status = card_send_command(ioaddr, name, Command1, st)))
@@ -944,7 +936,7 @@ sb1000_open(struct net_device *dev)
        /* initialize sb1000 */
        if ((status = sb1000_reset(ioaddr, name)))
                return status;
-       nicedelay(200000);
+       ssleep(1);
        if ((status = sb1000_check_CRC(ioaddr, name)))
                return status;
 
index 5f4bb1a67400d8690fd3ad4231349c28c3fd0236..cb23580fcffa5894d1f10db8dce271575c7a1781 100644 (file)
@@ -6,8 +6,8 @@ obj-$(CONFIG_SKFP) += skfp.o
 
 skfp-objs :=  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
               ecm.o       pcmplc.o   pmf.o      queue.o    rmt.o     \
-             smtdef.o    smtinit.o  smttimer.o srf.o      smtparse.o\
-             hwt.o      drvfbi.o   ess.o
+             smtdef.o    smtinit.o  smttimer.o srf.o      hwt.o     \
+             drvfbi.o   ess.o
 
 # NOTE:
 #   Compiling this driver produces some warnings (and some more are 
index 052e841ba187176fcb89d43f2775120e16f651e8..5b475833f64562d23177c5f2393a9a94c6327956 100644 (file)
@@ -105,8 +105,8 @@ extern int AIX_vpdReadByte() ;
 #endif
 
 
-/* Prototypes of local functions. */
-void smt_stop_watchdog(struct s_smc *smc);
+/* Prototype of a local function. */
+static void smt_stop_watchdog(struct s_smc *smc);
 
 #ifdef MCA
 static int read_card_id() ;
@@ -631,7 +631,7 @@ void plc_clear_irq(struct s_smc *smc, int p)
  *     LED_Y_OFF       just switch yellow LED off
  *     LED_Y_ON        just switch yello LED on
  */
-void led_indication(struct s_smc *smc, int led_event)
+static void led_indication(struct s_smc *smc, int led_event)
 {
        /* use smc->hw.mac_ring_is_up == TRUE 
         * as indication for Ring Operational
@@ -764,122 +764,6 @@ void llc_recover_tx(struct s_smc *smc)
 #endif
 }
 
-/*--------------------------- DMA init ----------------------------*/
-#ifdef ISA
-
-/*
- * init DMA
- */
-void init_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-
-       /*
-        * set cascade mode,
-        * clear mask bit (enable DMA cannal)
-        */
-       if (dma > 3) {
-               outp(0xd6,(dma & 0x03) | 0xc0) ;
-               outp(0xd4, dma & 0x03) ;
-       }
-       else {
-               outp(0x0b,(dma & 0x03) | 0xc0) ;
-               outp(0x0a,dma & 0x03) ;
-       }
-}
-
-/*
- * disable DMA
- */
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-
-       /*
-        * set mask bit (disable DMA cannal)
-        */
-       if (dma > 3) {
-               outp(0xd4,(dma & 0x03) | 0x04) ;
-       }
-       else {
-               outp(0x0a,(dma & 0x03) | 0x04) ;
-       }
-}
-
-#endif /* ISA */
-
-#ifdef EISA
-
-/*arrays with io addresses of dma controller length and address registers*/
-static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
-static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
-static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
-
-void init_dma(struct s_smc *smc, int dma)
-{
-       /*
-        * extended mode register
-        * 32 bit IO
-        * type c
-        * TC output
-        * disable stop
-        */
-
-       /* mode read (write) demand */
-       smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
-       smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
-
-       /* 32 bit IO's, burst DMA mode (type "C") */
-       smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
-
-       outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
-
-       /* disable chaining */
-       outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
-
-       /*load dma controller addresses for fast access during set dma*/
-       smc->hw.dma_base_word_count = cntr[smc->hw.dma];
-       smc->hw.dma_base_address = base[smc->hw.dma];
-       smc->hw.dma_base_address_page = page[smc->hw.dma];
-
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-
-       outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
-}
-#endif /* EISA */
-
-#ifdef MCA
-void init_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-#endif
-
-#ifdef PCI
-void init_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
-       SK_UNUSED(smc) ;
-       SK_UNUSED(dma) ;
-}
-#endif
-
 #ifdef MULT_OEM
 static int is_equal_num(char comp1[], char comp2[], int num)
 {
@@ -1407,7 +1291,7 @@ void smt_start_watchdog(struct s_smc *smc)
 #endif /* DEBUG */
 }
 
-void smt_stop_watchdog(struct s_smc *smc)
+static void smt_stop_watchdog(struct s_smc *smc)
 {
        SK_UNUSED(smc) ;        /* Make LINT happy. */
 #ifndef        DEBUG
@@ -1422,104 +1306,6 @@ void smt_stop_watchdog(struct s_smc *smc)
 }
 
 #ifdef PCI
-static char get_rom_byte(struct s_smc *smc, u_short addr)
-{
-       GET_PAGE(addr) ;
-       return (READ_PROM(ADDR(B2_FDP))) ;
-}
-
-/*
- * ROM image defines
- */
-#define        ROM_SIG_1       0
-#define ROM_SIG_2      1
-#define PCI_DATA_1     0x18
-#define PCI_DATA_2     0x19
-
-/*
- * PCI data structure defines
- */
-#define        VPD_DATA_1      0x08
-#define        VPD_DATA_2      0x09
-#define IMAGE_LEN_1    0x10
-#define IMAGE_LEN_2    0x11
-#define        CODE_TYPE       0x14
-#define        INDICATOR       0x15
-
-/*
- *     BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
- *     mac_drv_vpd_read(smc,buf,size,image)
- *
- * function    DOWNCALL        (FDDIWARE)
- *             reads the VPD data of the FPROM and writes it into the
- *             buffer
- *
- * para        buf     points to the buffer for the VPD data
- *     size    size of the VPD data buffer
- *     image   boot image; code type of the boot image
- *             image = 0       Intel x86, PC-AT compatible
- *                     1       OPENBOOT standard for PCI
- *                     2-FF    reserved
- *
- * returns     len     number of VPD data bytes read form the FPROM
- *             <0      number of read bytes
- *             >0      error: data invalid
- *
- *     END_MANUAL_ENTRY
- */
-int mac_drv_vpd_read(struct s_smc *smc, char *buf, int size, char image)
-{
-       u_short ibase ;
-       u_short pci_base ;
-       u_short vpd ;
-       int     len ;
-
-       len = 0 ;
-       ibase = 0 ;
-       /*
-        * as long images defined
-        */
-       while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
-               (u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
-               /*
-                * get the pointer to the PCI data structure
-                */
-               pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
-                               (get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
-
-               if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
-                       /*
-                        * we have the right image, read the VPD data
-                        */
-                       vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
-                               (get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
-                       if (vpd == ibase) {
-                               break ;         /* no VPD data */
-                       }
-                       for (len = 0; len < size; len++,buf++,vpd++) {
-                               *buf = get_rom_byte(smc,vpd) ;
-                       }
-                       break ;
-               }
-               else {
-                       /*
-                        * try the next image
-                        */
-                       if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
-                               break ;         /* this was the last image */
-                       }
-                       ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
-                               (get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
-               }
-       }
-
-       return(len) ;
-}
-
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value)
-{
-       smc->hw.pci_fix_value = fix_value ;
-}
 
 void mac_do_pci_fix(struct s_smc *smc)
 {
index fd39b4b2ef7da93caae56bc36691be161b9eaf5b..62b01328c496c4e3678bf8b5b7fe7e1950470895 100644 (file)
@@ -102,7 +102,7 @@ void ess_timer_poll(struct s_smc *smc);
 void ess_para_change(struct s_smc *smc);
 int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
                          int fs);
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
 
 
 /*
@@ -375,7 +375,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
  * determines the synchronous bandwidth, set the TSYNC register and the
  * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
  */
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
 {
        /*
         * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
index 76e78442fc2470a340628c71c9a1cb79e4903c9a..a2ed47f1cc709ec5b7243b5f04ffe2b5de8d96db 100644 (file)
@@ -1114,30 +1114,6 @@ void mac_clear_multicast(struct s_smc *smc)
        }
 }
 
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;2)
-
-       int mac_set_func_addr(smc,f_addr)
-       struct s_smc *smc ;
-       u_long f_addr ;
-
-Function       DOWNCALL        (SMT, fplustm.c)
-               Set a Token-Ring functional address, the address will
-               be activated after calling mac_update_multicast()
-
-Para   f_addr  functional bits in non-canonical format
-
-Returns        0: always success
-
-       END_MANUAL_ENTRY()
- */
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr)
-{
-       smc->hw.fp.func_addr = f_addr ;
-       return(0) ;
-}
-
-
 /*
        BEGIN_MANUAL_ENTRY(if,func;others;2)
 
@@ -1202,52 +1178,6 @@ int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
        return(0) ;
 }
 
-/*
-       BEGIN_MANUAL_ENTRY(if,func;others;2)
-
-       void mac_del_multicast(smc,addr,can)
-       struct s_smc *smc ;
-       struct fddi_addr *addr ;
-       int can ;
-
-Function       DOWNCALL        (SMT, fplustm.c)
-               Delete an entry from the multicast table
-
-Para   addr    pointer to a multicast address
-       can     = 0:    the multicast address has the physical format
-               = 1:    the multicast address has the canonical format
-               | 0x80  permanent
-
-       END_MANUAL_ENTRY()
- */
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
-{
-       SK_LOC_DECL(struct fddi_addr,own) ;
-       struct s_fpmc   *tb ;
-
-       if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
-               return ;
-       /*
-        * permanent addresses must be deleted with perm bit
-        * and vice versa
-        */
-       if (( tb->perm &&  (can & 0x80)) ||
-           (!tb->perm && !(can & 0x80))) {
-               /*
-                * delete it
-                */
-               if (tb->n) {
-                       tb->n-- ;
-                       if (tb->perm) {
-                               smc->hw.fp.smt_slots_used-- ;
-                       }
-                       else {
-                               smc->hw.fp.os_slots_used-- ;
-                       }
-               }
-       }
-}
-
 /*
  * mode
  */
index 603982debc71e0690ae5d1254caf166d27d3de87..f2f771d8be76b3a207ff8282b91fd2a8f7331703 100644 (file)
@@ -507,7 +507,6 @@ void pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
                      int *remote, int *mac);
 void plc_config_mux(struct s_smc *smc, int mux);
 void sm_lem_evaluate(struct s_smc *smc);
-void smt_clear_una_dna(struct s_smc *smc);
 void mac_update_counter(struct s_smc *smc);
 void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off);
 void sm_ma_control(struct s_smc *smc, int mode);
@@ -541,11 +540,9 @@ void smt_timer_poll(struct s_smc *smc);
 u_long smt_get_time(void);
 u_long smt_get_tid(struct s_smc *smc);
 void smt_timer_done(struct s_smc *smc);
-void smt_set_defaults(struct s_smc *smc);
 void smt_fixup_mib(struct s_smc *smc);
 void smt_reset_defaults(struct s_smc *smc, int level);
 void smt_agent_task(struct s_smc *smc);
-void smt_please_reconnect(struct s_smc *smc, int reconn_time);
 int smt_check_para(struct s_smc *smc, struct smt_header *sm,
                   const u_short list[]);
 void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr);
@@ -568,7 +565,6 @@ int pcm_get_s_port(struct s_smc *smc);
 int pcm_rooted_station(struct s_smc *smc);
 int cfm_get_mac_input(struct s_smc *smc);
 int cfm_get_mac_output(struct s_smc *smc);
-int port_to_mib(struct s_smc *smc, int p);
 int cem_build_path(struct s_smc *smc, char *to, int path_index);
 int sm_mac_get_tx_state(struct s_smc *smc);
 char *get_pcmstate(struct s_smc *smc, int np);
@@ -580,8 +576,6 @@ void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local);
 void smt_set_timestamp(struct s_smc *smc, u_char *p);
 void mac_set_rx_mode(struct s_smc *smc,        int mode);
 int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr);
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
 void mac_update_multicast(struct s_smc *smc);
 void mac_clear_multicast(struct s_smc *smc);
 void set_formac_tsync(struct s_smc *smc, long sync_bw);
@@ -599,7 +593,6 @@ void plc_irq(struct s_smc *smc,     int np, unsigned int cmd);
 int smt_set_mac_opvalues(struct s_smc *smc);
 
 #ifdef TAG_MODE
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value);
 void mac_do_pci_fix(struct s_smc *smc);
 void mac_drv_clear_tx_queue(struct s_smc *smc);
 void mac_drv_repair_descr(struct s_smc *smc);
index 4e360af07d779a73daf6b6f2f656e583225affd6..1a606d4bfe5e98253ff3b7f241de99887804ebee 100644 (file)
@@ -261,31 +261,6 @@ struct os_debug {
 #define        HWM_GET_CURR_TXD(smc,queue)     (struct s_smt_fp_txd volatile *)\
                                        (smc)->hw.fp.tx_q[queue].tx_curr_put
 
-/*
- *     BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
- *     void HWM_TX_CHECK(smc,frame_status,low_water)
- *
- * function    MACRO           (hardware module, hwmtm.h)
- *             This macro is invoked by the OS-specific before it left it's
- *             driver_send function. This macro calls mac_drv_clear_txd
- *             if the free TxDs of the current transmit queue is equal or
- *             lower than the given low water mark.
- *
- * para        frame_status    status of the frame, see design description
- *     low_water       low water mark of free TxD's
- *
- *     END_MANUAL_ENTRY
- */
-#ifndef HWM_NO_FLOW_CTL
-#define        HWM_TX_CHECK(smc,frame_status,low_water) {\
-       if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
-               mac_drv_clear_txd(smc) ;\
-       }\
-}
-#else
-#define        HWM_TX_CHECK(smc,frame_status,low_water)        mac_drv_clear_txd(smc)
-#endif
-
 /*
  *     BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
  *     int HWM_GET_RX_FRAG_LEN(rxd)
index 18d429021edbbbe188b1dee75b79806804987a7f..438f424e63611ca73f372aa74207713507d34bb5 100644 (file)
@@ -86,6 +86,7 @@ static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue);
 static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue);
 static SMbuf* get_llc_rx(struct s_smc *smc);
 static SMbuf* get_txd_mb(struct s_smc *smc);
+static void mac_drv_clear_txd(struct s_smc *smc);
 
 /*
        -------------------------------------------------------------
@@ -146,7 +147,6 @@ extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
 */
 void process_receive(struct s_smc *smc);
 void fddi_isr(struct s_smc *smc);
-void mac_drv_clear_txd(struct s_smc *smc);
 void smt_free_mbuf(struct s_smc *smc, SMbuf *mb);
 void init_driver_fplus(struct s_smc *smc);
 void mac_drv_rx_mode(struct s_smc *smc, int mode);
@@ -158,7 +158,6 @@ void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
 void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
                 int frame_status);
 
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len);
 int mac_drv_init(struct s_smc *smc);
 int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
                int frame_status);
@@ -1448,35 +1447,6 @@ void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
        NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
 }
 
-#ifndef        NDIS_OS2
-/*
- *     BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
- *     int mac_drv_rx_frag(smc,virt,len)
- *
- * function    DOWNCALL        (hwmtm.c)
- *             mac_drv_rx_frag fills the fragment with a part of the frame.
- *
- * para        virt    the virtual address of the fragment
- *     len     the length in bytes of the fragment
- *
- * return 0:   success code, no errors possible
- *
- *     END_MANUAL_ENTRY
- */
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len)
-{
-       NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
-
-       DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
-       memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
-       smc->os.hwm.r.mb_pos += len ;
-
-       NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
-       return(0) ;
-}
-#endif
-
-
 /*
  *     BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
  *
@@ -1978,7 +1948,7 @@ void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc)
  *
  *     END_MANUAL_ENTRY
  */
-void mac_drv_clear_txd(struct s_smc *smc)
+static void mac_drv_clear_txd(struct s_smc *smc)
 {
        struct s_smt_tx_queue *queue ;
        struct s_smt_fp_txd volatile *t1 ;
index 571f055c096bacca88967d49c88ba6446c426131..cd0aa4c151b092effd4dc5fb33d9c6473a85ef03 100644 (file)
@@ -1861,13 +1861,6 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd)
 #endif
 }
 
-void pcm_set_lct_short(struct s_smc *smc, int n)
-{
-       if (n <= 0 || n > 1000)
-               return ;
-       smc->s.lct_short = n ;
-}
-
 #ifdef DEBUG
 /*
  * fill state struct
index f2b446d8b0bffc90407dbdaf3f85afc738956097..efc639c013fde5b0fc82d2e1fc2cb99ca13009d2 100644 (file)
@@ -36,12 +36,13 @@ static int smt_authorize(struct s_smc *smc, struct smt_header *sm);
 static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm);
 static const struct s_p_tab* smt_get_ptab(u_short para);
 static int smt_mib_phys(struct s_smc *smc);
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
-                int set);
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+                       int local, int set);
 void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
                  int index, int local);
 static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req,
                                     int set, int local);
+static int port_to_mib(struct s_smc *smc, int p);
 
 #define MOFFSS(e)      ((int)&(((struct fddi_mib *)0)->e))
 #define MOFFSA(e)      ((int) (((struct fddi_mib *)0)->e))
@@ -1078,8 +1079,8 @@ wrong_error:
 /*
  * set parameter
  */
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
-                int set)
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+                       int local, int set)
 {
 #define IFSET(x)       if (set) (x)
 
@@ -1549,7 +1550,7 @@ static int smt_mib_phys(struct s_smc *smc)
 #endif
 }
 
-int port_to_mib(struct s_smc *smc, int p)
+static int port_to_mib(struct s_smc *smc, int p)
 {
 #ifdef CONCENTRATOR
        SK_UNUSED(smc) ;
index c88aad6edd7456bc0af36d49644875b15b3c18e9..4b5ed2c63177ff991716885c843c4fe331e26eaf 100644 (file)
@@ -149,7 +149,6 @@ extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
 extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
 extern void mac_drv_clear_rx_queue(struct s_smc *smc);
 extern void enable_tx_irq(struct s_smc *smc, u_short queue);
-extern void mac_drv_clear_txd(struct s_smc *smc);
 
 static struct pci_device_id skfddi_pci_tbl[] = {
        { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
index c3a0d2f10b2b237da4684fa2bc83851d958f808b..f17c05cbe44bf84a79eab3b4d3900369f9f8a706 100644 (file)
@@ -110,7 +110,7 @@ static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount
 static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed,
                          int len);
 
-void smt_clear_una_dna(struct s_smc *smc);
+static void smt_clear_una_dna(struct s_smc *smc);
 static void smt_clear_old_una_dna(struct s_smc *smc);
 #ifdef CONCENTRATOR
 static int entity_to_index(void);
@@ -118,7 +118,7 @@ static int entity_to_index(void);
 static void update_dac(struct s_smc *smc, int report);
 static int div_ratio(u_long upper, u_long lower);
 #ifdef  USE_CAN_ADDR
-void   hwm_conv_can(struct s_smc *smc, char *data, int len);
+static void    hwm_conv_can(struct s_smc *smc, char *data, int len);
 #else
 #define                hwm_conv_can(smc,data,len)
 #endif
@@ -216,24 +216,6 @@ void smt_agent_task(struct s_smc *smc)
        DB_SMT("SMT agent task\n",0,0) ;
 }
 
-void smt_please_reconnect(struct s_smc *smc, int reconn_time)
-/* struct s_smc        *smc;  Pointer to SMT context */
-/* int reconn_time;    Wait for reconnect time in seconds */
-{
-       /*
-        * The please reconnect variable is used as a timer.
-        * It is decremented each time smt_event is called.
-        * This happens every second or when smt_force_irq is called.
-        * Note: smt_force_irq () is called on some packet receives and
-        *       when a multicast address is changed. Since nothing
-        *       is received during the disconnect and the multicast
-        *       address changes can be viewed as not very often and
-        *       the timer runs out close to its given value
-        *       (reconn_time).
-        */
-       smc->sm.please_reconnect = reconn_time ;
-}
-
 #ifndef SMT_REAL_TOKEN_CT
 void smt_emulate_token_ct(struct s_smc *smc, int mac_index)
 {
@@ -1574,7 +1556,7 @@ static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long see
  * clear DNA and UNA
  * called from CFM if configuration changes
  */
-void smt_clear_una_dna(struct s_smc *smc)
+static void smt_clear_una_dna(struct s_smc *smc)
 {
        smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
        smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
@@ -2057,31 +2039,11 @@ int smt_action(struct s_smc *smc, int class, int code, int index)
        return(0) ;
 }
 
-/*
- * change tneg
- *     set T_Req in MIB (Path Attribute)
- *     calculate new values for MAC
- *     if change required
- *             disconnect
- *             set reconnect
- *     end
- */
-void smt_change_t_neg(struct s_smc *smc, u_long tneg)
-{
-       smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
-
-       if (smt_set_mac_opvalues(smc)) {
-               RS_SET(smc,RS_EVENT) ;
-               smc->sm.please_reconnect = 1 ;
-               queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
-       }
-}
-
 /*
  * canonical conversion of <len> bytes beginning form *data
  */
 #ifdef  USE_CAN_ADDR
-void hwm_conv_can(struct s_smc *smc, char *data, int len)
+static void hwm_conv_can(struct s_smc *smc, char *data, int len)
 {
        int i ;
 
index 5a0c8db816d8194042ee3f2b667b9cafed8fb3d7..4e07ff7073f1141f209c0773f16c0972261c260a 100644 (file)
@@ -76,11 +76,6 @@ void smt_reset_defaults(struct s_smc *smc, int level);
 static void smt_init_mib(struct s_smc *smc, int level);
 static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper);
 
-void smt_set_defaults(struct s_smc *smc)
-{
-       smt_reset_defaults(smc,0) ;
-}
-
 #define MS2BCLK(x)     ((x)*12500L)
 #define US2BCLK(x)     ((x)*1250L)
 
diff --git a/drivers/net/skfp/smtparse.c b/drivers/net/skfp/smtparse.c
deleted file mode 100644 (file)
index d5779e4..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/******************************************************************************
- *
- *     (C)Copyright 1998,1999 SysKonnect,
- *     a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- *     See the file "skfddi.c" for further information.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-
-/*
-       parser for SMT parameters
-*/
-
-#include "h/types.h"
-#include "h/fddi.h"
-#include "h/smc.h"
-#include "h/smt_p.h"
-
-#define KERNEL
-#include "h/smtstate.h"
-
-#ifndef        lint
-static const char ID_sccs[] = "@(#)smtparse.c  1.12 98/10/06 (C) SK " ;
-#endif
-
-#ifdef sun
-#define _far
-#endif
-
-/*
- * convert to BCLK units
- */
-#define MS2BCLK(x)      ((x)*12500L)
-#define US2BCLK(x)      ((x/10)*125L)
-
-/*
- * parameter table
- */
-static struct s_ptab {
-       char    *pt_name ;
-       u_short pt_num ;
-       u_short pt_type ;
-       u_long  pt_min ;
-       u_long  pt_max ;
-} ptab[] = {
-       { "PMFPASSWD",0,        0 } ,
-       { "USERDATA",1,         0 } ,
-       { "LERCUTOFFA",2,       1,      4,      15      } ,
-       { "LERCUTOFFB",3,       1,      4,      15      } ,
-       { "LERALARMA",4,        1,      4,      15      } ,
-       { "LERALARMB",5,        1,      4,      15      } ,
-       { "TMAX",6,             1,      5,      165     } ,
-       { "TMIN",7,             1,      5,      165     } ,
-       { "TREQ",8,             1,      5,      165     } ,
-       { "TVX",9,              1,      2500,   10000   } ,
-#ifdef ESS
-       { "SBAPAYLOAD",10,      1,      0,      1562    } ,
-       { "SBAOVERHEAD",11,     1,      50,     5000    } ,
-       { "MAXTNEG",12,         1,      5,      165     } ,
-       { "MINSEGMENTSIZE",13,  1,      0,      4478    } ,
-       { "SBACATEGORY",14,     1,      0,      0xffff  } ,
-       { "SYNCHTXMODE",15,     0 } ,
-#endif
-#ifdef SBA
-       { "SBACOMMAND",16,      0 } ,
-       { "SBAAVAILABLE",17,    1,      0,      100     } ,
-#endif
-       { NULL }
-} ;
-
-/* Define maximum string size for values and keybuffer */
-#define MAX_VAL        40
-
-/*
- * local function declarations
- */
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
-                       u_long mx, int scale);
-static int parse_word(char *buf, char _far *text);
-
-#ifdef SIM
-#define DB_MAIN(a,b,c) printf(a,b,c)
-#else
-#define DB_MAIN(a,b,c)
-#endif
-
-/*
- * BEGIN_MANUAL_ENTRY()
- *
- *     int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
-               char _far *value)
- *
- *     parse SMT parameter
- *     *keyword
- *             pointer to keyword, must be \0, \n or \r terminated
- *     *value  pointer to value, either char * or u_long *
- *             if char *
- *                     pointer to value, must be \0, \n or \r terminated
- *             if u_long *
- *                     contains binary value
- *
- *     type    0: integer
- *             1: string
- *     return
- *             0       parameter parsed ok
- *             != 0    error
- *     NOTE:
- *             function can be called with DS != SS
- *
- *
- * END_MANUAL_ENTRY()
- */
-int smt_parse_arg(struct s_smc *smc, char _far *keyword, int type,
-                 char _far *value)
-{
-       char            keybuf[MAX_VAL+1];
-       char            valbuf[MAX_VAL+1];
-       char            c ;
-       char            *p ;
-       char            *v ;
-       char            *d ;
-       u_long          val = 0 ;
-       struct s_ptab   *pt ;
-       int             st ;
-       int             i ;
-
-       /*
-        * parse keyword
-        */
-       if ((st = parse_word(keybuf,keyword)))
-               return(st) ;
-       /*
-        * parse value if given as string
-        */
-       if (type == 1) {
-               if ((st = parse_word(valbuf,value)))
-                       return(st) ;
-       }
-       /*
-        * search in table
-        */
-       st = 0 ;
-       for (pt = ptab ; (v = pt->pt_name) ; pt++) {
-               for (p = keybuf ; (c = *p) ; p++,v++) {
-                       if (c != *v)
-                               break ;
-               }
-               if (!c && !*v)
-                       break ;
-       }
-       if (!v)
-               return(-1) ;
-#if    0
-       printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
-#endif
-       /*
-        * set value in MIB
-        */
-       if (pt->pt_type)
-               val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
-       switch (pt->pt_num) {
-       case 0 :
-               v = valbuf ;
-               d = (char *) smc->mib.fddiPRPMFPasswd ;
-               for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
-                       *d++ = *v++ ;
-               DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
-               break ;
-       case 1 :
-               v = valbuf ;
-               d = (char *) smc->mib.fddiSMTUserData ;
-               for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
-                       *d++ = *v++ ;
-               DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
-               break ;
-       case 2 :
-               smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
-               break ;
-       case 3 :
-               smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
-               break ;
-       case 4 :
-               smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
-               break ;
-       case 5 :
-               smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
-               DB_MAIN("SET %s = %d\n",
-                       pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
-               break ;
-       case 6 :                        /* TMAX */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
-                       (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 7 :                        /* TMIN */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.m[MAC0].fddiMACT_Min =
-                       (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 8 :                        /* TREQ */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.a[PATH0].fddiPATHMaxT_Req =
-                       (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 9 :                        /* TVX */
-               DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
-               smc->mib.a[PATH0].fddiPATHTVXLowerBound =
-                       (u_long) -US2BCLK((long)val) ;
-               break ;
-#ifdef ESS
-       case 10 :                       /* SBAPAYLOAD */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               if (smc->mib.fddiESSPayload != val) {
-                       smc->ess.raf_act_timer_poll = TRUE ;
-                       smc->mib.fddiESSPayload = val ;
-               }
-               break ;
-       case 11 :                       /* SBAOVERHEAD */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSOverhead = val ;
-               break ;
-       case 12 :                       /* MAXTNEG */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
-               break ;
-       case 13 :                       /* MINSEGMENTSIZE */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSMinSegmentSize = val ;
-               break ;
-       case 14 :                       /* SBACATEGORY */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiESSCategory =
-                       (smc->mib.fddiESSCategory & 0xffff) |
-                       ((u_long)(val << 16)) ;
-               break ;
-       case 15 :                       /* SYNCHTXMODE */
-               /* do not use memcmp(valbuf,"ALL",3) because DS != SS */
-               if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
-                       smc->mib.fddiESSSynchTxMode = TRUE ;
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-               }
-               /* if (!memcmp(valbuf,"SPLIT",5)) { */
-               if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
-                       valbuf[3] == 'I' && valbuf[4] == 'T') {
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-                       smc->mib.fddiESSSynchTxMode = FALSE ;
-               }
-               break ;
-#endif
-#ifdef SBA
-       case 16 :                       /* SBACOMMAND */
-               /* if (!memcmp(valbuf,"START",5)) { */
-               if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
-                       valbuf[3] == 'R' && valbuf[4] == 'T') {
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-                       smc->mib.fddiSBACommand = SB_START ;
-               }
-               /* if (!memcmp(valbuf,"STOP",4)) { */
-               if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
-                       valbuf[3] == 'P') {
-                       DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
-                       smc->mib.fddiSBACommand = SB_STOP ;
-               }
-               break ;
-       case 17 :                       /* SBAAVAILABLE */
-               DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
-               smc->mib.fddiSBAAvailable = (u_char) val ;
-               break ;
-#endif
-       }
-       return(0) ;
-}
-
-static int parse_word(char *buf, char _far *text)
-{
-       char            c ;
-       char            *p ;
-       int             p_len ;
-       int             quote ;
-       int             i ;
-       int             ok ;
-
-       /*
-        * skip leading white space
-        */
-       p = buf ;
-       for (i = 0 ; i < MAX_VAL ; i++)
-               *p++ = 0 ;
-       p = buf ;
-       p_len = 0 ;
-       ok = 0 ;
-       while ( (c = *text++) && (c != '\n') && (c != '\r')) {
-               if ((c != ' ') && (c != '\t')) {
-                       ok = 1 ;
-                       break ;
-               }
-       }
-       if (!ok)
-               return(-1) ;
-       if (c == '"') {
-               quote = 1 ;
-       }
-       else {
-               quote = 0 ;
-               text-- ;
-       }
-       /*
-        * parse valbuf
-        */
-       ok = 0 ;
-       while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
-               && (c != '\r')) {
-               switch (quote) {
-               case 0 :
-                       if ((c == ' ') || (c == '\t') || (c == '=')) {
-                               ok = 1 ;
-                               break ;
-                       }
-                       *p++ = c ;
-                       p_len++ ;
-                       break ;
-               case 2 :
-                       *p++ = c ;
-                       p_len++ ;
-                       quote = 1 ;
-                       break ;
-               case 1 :
-                       switch (c) {
-                       case '"' :
-                               ok = 1 ;
-                               break ;
-                       case '\\' :
-                               quote = 2 ;
-                               break ;
-                       default :
-                               *p++ = c ;
-                               p_len++ ;
-                       }
-               }
-       }
-       *p++ = 0 ;
-       for (p = buf ; (c = *p) ; p++) {
-               if (c >= 'a' && c <= 'z')
-                       *p = c + 'A' - 'a' ;
-       }
-       return(0) ;
-}
-
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
-                       u_long mx, int scale)
-{
-       u_long  x = 0 ;
-       char    c ;
-
-       if (type == 0) {                /* integer */
-               u_long _far     *l ;
-               u_long          u1 ;
-
-               l = (u_long _far *) value ;
-               u1 = *l ;
-               /*
-                * if the value is negative take the lower limit
-                */
-               if ((long)u1 < 0) {
-                       if (- ((long)u1) > (long) mx) {
-                               u1 = 0 ;
-                       }
-                       else {
-                               u1 = (u_long) - ((long)u1) ;
-                       }
-               }
-               x = u1 ;
-       }
-       else {                          /* string */
-               int     sign = 0 ;
-
-               if (*v == '-') {
-                       sign = 1 ;
-               }
-               while ((c = *v++) && (c >= '0') && (c <= '9')) {
-                       x = x * 10 + c - '0' ;
-               }
-               if (scale == 10) {
-                       x *= 10 ;
-                       if (c == '.') {
-                               if ((c = *v++) && (c >= '0') && (c <= '9')) {
-                                       x += c - '0' ;
-                               }
-                       }
-               }
-               if (sign)
-                       x = (u_long) - ((long)x) ;
-       }
-       /*
-        * if the value is negative
-        *      and the absolute value is outside the limits
-        *              take the lower limit
-        *      else
-        *              take the absoute value
-        */
-       if ((long)x < 0) {
-               if (- ((long)x) > (long) mx) {
-                       x = 0 ;
-               }
-               else {
-                       x = (u_long) - ((long)x) ;
-               }
-       }
-       if (x < mn)
-               return(mn) ;
-       else if (x > mx)
-               return(mx) ;
-       return(x) ;
-}
-
-#if 0
-struct s_smc   SMC ;
-main()
-{
-       char    *p ;
-       char    *v ;
-       char    buf[100] ;
-       int     toggle = 0 ;
-
-       while (gets(buf)) {
-               p = buf ;
-               while (*p && ((*p == ' ') || (*p == '\t')))
-                       p++ ;
-
-               while (*p && ((*p != ' ') && (*p != '\t')))
-                       p++ ;
-
-               v = p ;
-               while (*v && ((*v == ' ') || (*v == '\t')))
-                       v++ ;
-               if ((*v >= '0') && (*v <= '9')) {
-                       toggle = !toggle ;
-                       if (toggle) {
-                               u_long  l ;
-                               l = atol(v) ;
-                               smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
-                       }
-                       else
-                               smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
-               }
-               else {
-                       smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
-               }
-       }
-       exit(0) ;
-}
-#endif
-
index fd80048f7f7ac6f98e09bf6e0456448e7688ccea..cfb9d3cdb04a593713df0fabcf2f8359bdbc1b4d 100644 (file)
@@ -315,15 +315,25 @@ static void smc_reset(struct net_device *dev)
        struct smc_local *lp = netdev_priv(dev);
        void __iomem *ioaddr = lp->base;
        unsigned int ctl, cfg;
+       struct sk_buff *pending_skb;
 
        DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
-       /* Disable all interrupts */
+       /* Disable all interrupts, block TX tasklet */
        spin_lock(&lp->lock);
        SMC_SELECT_BANK(2);
        SMC_SET_INT_MASK(0);
+       pending_skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
        spin_unlock(&lp->lock);
 
+       /* free any pending tx skb */
+       if (pending_skb) {
+               dev_kfree_skb(pending_skb);
+               lp->stats.tx_errors++;
+               lp->stats.tx_aborted_errors++;
+       }
+
        /*
         * This resets the registers mostly to defaults, but doesn't
         * affect EEPROM.  That seems unnecessary
@@ -389,14 +399,6 @@ static void smc_reset(struct net_device *dev)
        SMC_SELECT_BANK(2);
        SMC_SET_MMU_CMD(MC_RESET);
        SMC_WAIT_MMU_BUSY();
-
-       /* clear anything saved */
-       if (lp->pending_tx_skb != NULL) {
-               dev_kfree_skb (lp->pending_tx_skb);
-               lp->pending_tx_skb = NULL;
-               lp->stats.tx_errors++;
-               lp->stats.tx_aborted_errors++;
-       }
 }
 
 /*
@@ -440,6 +442,7 @@ static void smc_shutdown(struct net_device *dev)
 {
        struct smc_local *lp = netdev_priv(dev);
        void __iomem *ioaddr = lp->base;
+       struct sk_buff *pending_skb;
 
        DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
 
@@ -447,7 +450,11 @@ static void smc_shutdown(struct net_device *dev)
        spin_lock(&lp->lock);
        SMC_SELECT_BANK(2);
        SMC_SET_INT_MASK(0);
+       pending_skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
        spin_unlock(&lp->lock);
+       if (pending_skb)
+               dev_kfree_skb(pending_skb);
 
        /* and tell the card to stay away from that nasty outside world */
        SMC_SELECT_BANK(0);
@@ -627,7 +634,12 @@ static void smc_hardware_send_pkt(unsigned long data)
        }
 
        skb = lp->pending_tx_skb;
+       if (unlikely(!skb)) {
+               smc_special_unlock(&lp->lock);
+               return;
+       }
        lp->pending_tx_skb = NULL;
+
        packet_no = SMC_GET_AR();
        if (unlikely(packet_no & AR_FAILED)) {
                printk("%s: Memory allocation failed.\n", dev->name);
@@ -702,7 +714,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
 
        BUG_ON(lp->pending_tx_skb != NULL);
-       lp->pending_tx_skb = skb;
 
        /*
         * The MMU wants the number of pages to be the number of 256 bytes
@@ -718,7 +729,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
        if (unlikely(numPages > 7)) {
                printk("%s: Far too big packet error.\n", dev->name);
-               lp->pending_tx_skb = NULL;
                lp->stats.tx_errors++;
                lp->stats.tx_dropped++;
                dev_kfree_skb(skb);
@@ -745,6 +755,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        smc_special_unlock(&lp->lock);
 
+       lp->pending_tx_skb = skb;
        if (!poll_count) {
                /* oh well, wait until the chip finds memory later */
                netif_stop_queue(dev);
@@ -1062,7 +1073,7 @@ static void smc_phy_powerdown(struct net_device *dev)
           above). linkwatch_event() also wants the netlink semaphore.
        */
        while(lp->work_pending)
-               schedule();
+               yield();
 
        bmcr = smc_phy_read(dev, phy, MII_BMCR);
        smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
@@ -1606,14 +1617,8 @@ static int smc_close(struct net_device *dev)
 
        /* clear everything */
        smc_shutdown(dev);
-
+       tasklet_kill(&lp->tx_task);
        smc_phy_powerdown(dev);
-
-       if (lp->pending_tx_skb) {
-               dev_kfree_skb(lp->pending_tx_skb);
-               lp->pending_tx_skb = NULL;
-       }
-
        return 0;
 }
 
index 6e5ade99a38f88adf555dd5baf29c314bc87b176..97712c3c4e07f4ccfa34b18377e065f781e5726d 100644 (file)
@@ -455,8 +455,7 @@ static int streamer_reset(struct net_device *dev)
        writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
        t = jiffies;
        /* Hold soft reset bit for a while */
-       current->state = TASK_UNINTERRUPTIBLE;
-       schedule_timeout(HZ);
+       ssleep(1);
        
        writew(readw(streamer_mmio + BCTL) & ~BCTL_SOFTRESET,
               streamer_mmio + BCTL);
@@ -512,8 +511,7 @@ static int streamer_reset(struct net_device *dev)
        writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
 
        while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ/10);
+               msleep_interruptible(100);
                if (jiffies - t > 40 * HZ) {
                        printk(KERN_ERR
                               "IBM PCI tokenring card not responding\n");
index cfc346e72d6234ae37ee11b794791ee99fcec24e..08e0f80f89d5356b59370e064f6f4ce78178840d 100644 (file)
@@ -242,6 +242,7 @@ static struct pci_device_id tulip_pci_tbl[] = {
        { 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },      /* ALi 1563 integrated ethernet */
        { 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X },      /* ALi 1563 integrated ethernet */
        { 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
+       { 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
        { } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -1756,11 +1757,19 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
 
-       if (dev && netif_running (dev) && netif_device_present (dev)) {
-               netif_device_detach (dev);
-               tulip_down (dev);
-               /* pci_power_off(pdev, -1); */
-       }
+       if (!dev)
+               return -EINVAL;
+
+       if (netif_running(dev))
+               tulip_down(dev);
+
+       netif_device_detach(dev);
+       free_irq(dev->irq, dev);
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
        return 0;
 }
 
@@ -1768,15 +1777,26 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
 static int tulip_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
+       int retval;
 
-       if (dev && netif_running (dev) && !netif_device_present (dev)) {
-#if 1
-               pci_enable_device (pdev);
-#endif
-               /* pci_power_on(pdev); */
-               tulip_up (dev);
-               netif_device_attach (dev);
+       if (!dev)
+               return -EINVAL;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       pci_enable_device(pdev);
+
+       if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
+               printk (KERN_ERR "tulip: request_irq failed in resume\n");
+               return retval;
        }
+
+       netif_device_attach(dev);
+
+       if (netif_running(dev))
+               tulip_up(dev);
+
        return 0;
 }
 
index 6200cfc4244e0ba783f24acb0eeabe3f63e4d041..be1c1047b9bac2a11d68cf95d568fa6b2d923379 100644 (file)
@@ -1398,7 +1398,7 @@ static void rhine_tx(struct net_device *dev)
        while (rp->dirty_tx != rp->cur_tx) {
                txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
                if (debug > 6)
-                       printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
+                       printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n",
                               entry, txstatus);
                if (txstatus & DescOwn)
                        break;
@@ -1469,7 +1469,7 @@ static void rhine_rx(struct net_device *dev)
                int data_size = desc_status >> 16;
 
                if (debug > 4)
-                       printk(KERN_DEBUG " rhine_rx() status is %8.8x.\n",
+                       printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
                               desc_status);
                if (--boguscnt < 0)
                        break;
@@ -1487,7 +1487,7 @@ static void rhine_rx(struct net_device *dev)
                        } else if (desc_status & RxErr) {
                                /* There was a error. */
                                if (debug > 2)
-                                       printk(KERN_DEBUG " rhine_rx() Rx "
+                                       printk(KERN_DEBUG "rhine_rx() Rx "
                                               "error was %8.8x.\n",
                                               desc_status);
                                rp->stats.rx_errors++;
index 7575b799ce5368751c76323e61107d8766df2400..7217d44e885404ca310571dc246121ba0ab9d4b5 100644 (file)
@@ -981,6 +981,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd)
        /* Wait for any previous command to complete */
        while (mbval > NAK) {
                spin_unlock_irqrestore(&card->card_lock, flags);
+               set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(1);
                spin_lock_irqsave(&card->card_lock, flags);
 
index 180968899cada12a0c3c91e8ca8d5cbc3e23e5a2..c12648d8192b7dd7df2ffbbe7bbb68ccd87a30cb 100644 (file)
@@ -900,7 +900,7 @@ typedef struct aironet_ioctl {
        unsigned char __user *data;     // d-data
 } aironet_ioctl;
 
-static char *swversion = "2.1";
+static char swversion[] = "2.1";
 #endif /* CISCO_EXT */
 
 #define NUM_MODULES       2
index b1078baa1d5e3851804b12509222407283b753d2..aabcdc2be05ea925fee9d685bbc4d38bcd8c5e0f 100644 (file)
  * under either the MPL or the GPL.  */
 
 /*
- * v0.01 -> v0.02 - 21/3/2001 - Jean II
- *     o Allow to use regular ethX device name instead of dldwdX
- *     o Warning on IBSS with ESSID=any for firmware 6.06
- *     o Put proper range.throughput values (optimistic)
- *     o IWSPY support (IOCTL and stat gather in Rx path)
- *     o Allow setting frequency in Ad-Hoc mode
- *     o Disable WEP setting if !has_wep to work on old firmware
- *     o Fix txpower range
- *     o Start adding support for Samsung/Compaq firmware
- *
- * v0.02 -> v0.03 - 23/3/2001 - Jean II
- *     o Start adding Symbol support - need to check all that
- *     o Fix Prism2/Symbol WEP to accept 128 bits keys
- *     o Add Symbol WEP (add authentication type)
- *     o Add Prism2/Symbol rate
- *     o Add PM timeout (holdover duration)
- *     o Enable "iwconfig eth0 key off" and friends (toggle flags)
- *     o Enable "iwconfig eth0 power unicast/all" (toggle flags)
- *     o Try with an Intel card. It report firmware 1.01, behave like
- *       an antiquated firmware, however on windows it says 2.00. Yuck !
- *     o Workaround firmware bug in allocate buffer (Intel 1.01)
- *     o Finish external renaming to orinoco...
- *     o Testing with various Wavelan firmwares
- *
- * v0.03 -> v0.04 - 30/3/2001 - Jean II
- *     o Update to Wireless 11 -> add retry limit/lifetime support
- *     o Tested with a D-Link DWL 650 card, fill in firmware support
- *     o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
- *     o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-(
- *       It works on D-Link *only* after a tcpdump. Weird...
- *       And still doesn't work on Intel card. Grrrr...
- *     o Update the mode after a setport3
- *     o Add preamble setting for Symbol cards (not yet enabled)
- *     o Don't complain as much about Symbol cards...
- *
- * v0.04 -> v0.04b - 22/4/2001 - David Gibson
- *      o Removed the 'eth' parameter - always use ethXX as the
- *        interface name instead of dldwdXX.  The other was racy
- *        anyway.
- *     o Clean up RID definitions in hermes.h, other cleanups
- *
- * v0.04b -> v0.04c - 24/4/2001 - Jean II
- *     o Tim Hurley <timster AT seiki.bliztech.com> reported a D-Link card
- *       with vendor 02 and firmware 0.08. Added in the capabilities...
- *     o Tested Lucent firmware 7.28, everything works...
- *
- * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt
- *     o Spin-off Pcmcia code. This file is renamed orinoco.c,
- *       and orinoco_cs.c now contains only the Pcmcia specific stuff
- *     o Add Airport driver support on top of orinoco.c (see airport.c)
- *
- * v0.05 -> v0.05a - 4/5/2001 - Jean II
- *     o Revert to old Pcmcia code to fix breakage of Ben's changes...
- *
- * v0.05a -> v0.05b - 4/5/2001 - Jean II
- *     o add module parameter 'ignore_cis_vcc' for D-Link @ 5V
- *     o D-Link firmware doesn't support multicast. We just print a few
- *       error messages, but otherwise everything works...
- *     o For David : set/getport3 works fine, just upgrade iwpriv...
- *
- * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt
- *     o Adapt airport.c to latest changes in orinoco.c
- *     o Remove deferred power enabling code
- *
- * v0.05c -> v0.05d - 5/5/2001 - Jean II
- *     o Workaround to SNAP decapsulate frame from Linksys AP
- *       original patch from : Dong Liu <dliu AT research.bell-labs.com>
- *       (note : the memcmp bug was mine - fixed)
- *     o Remove set_retry stuff, no firmware support it (bloat--).
- *
- * v0.05d -> v0.06 - 25/5/2001 - Jean II
- *             Original patch from "Hong Lin" <alin AT redhat.com>,
- *             "Ian Kinner" <ikinner AT redhat.com>
- *             and "David Smith" <dsmith AT redhat.com>
- *     o Init of priv->tx_rate_ctrl in firmware specific section.
- *     o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh !
- *     o Spectrum card always need cor_reset (for every reset)
- *     o Fix cor_reset to not lose bit 7 in the register
- *     o flush_stale_links to remove zombie Pcmcia instances
- *     o Ack previous hermes event before reset
- *             Me (with my little hands)
- *     o Allow orinoco.c to call cor_reset via priv->card_reset_handler
- *     o Add priv->need_card_reset to toggle this feature
- *     o Fix various buglets when setting WEP in Symbol firmware
- *       Now, encryption is fully functional on Symbol cards. Youpi !
- *
- * v0.06 -> v0.06b - 25/5/2001 - Jean II
- *     o IBSS on Symbol use port_mode = 4. Please don't ask...
- *
- * v0.06b -> v0.06c - 29/5/2001 - Jean II
- *     o Show first spy address in /proc/net/wireless for IBSS mode as well
- *
- * v0.06c -> v0.06d - 6/7/2001 - David Gibson
- *      o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus'
- *        wishes to reduce the number of unnecessary messages.
- *     o Removed bogus message on CRC error.
- *     o Merged fixes for v0.08 Prism 2 firmware from William Waghorn
- *       <willwaghorn AT yahoo.co.uk>
- *     o Slight cleanup/re-arrangement of firmware detection code.
- *
- * v0.06d -> v0.06e - 1/8/2001 - David Gibson
- *     o Removed some redundant global initializers (orinoco_cs.c).
- *     o Added some module metadata
- *
- * v0.06e -> v0.06f - 14/8/2001 - David Gibson
- *     o Wording fix to license
- *     o Added a 'use_alternate_encaps' module parameter for APs which need an
- *       oui of 00:00:00.  We really need a better way of handling this, but
- *       the module flag is better than nothing for now.
- *
- * v0.06f -> v0.07 - 20/8/2001 - David Gibson
- *     o Removed BAP error retries from hermes_bap_seek().  For Tx we now
- *       let the upper layers handle the retry, we retry explicitly in the
- *       Rx path, but don't make as much noise about it.
- *     o Firmware detection cleanups.
- *
- * v0.07 -> v0.07a - 1/10/3001 - Jean II
- *     o Add code to read Symbol firmware revision, inspired by latest code
- *       in Spectrum24 by Lee John Keyser-Allen - Thanks Lee !
- *     o Thanks to Jared Valentine <hidden AT xmission.com> for "providing" me
- *       a 3Com card with a recent firmware, fill out Symbol firmware
- *       capabilities of latest rev (2.20), as well as older Symbol cards.
- *     o Disable Power Management in newer Symbol firmware, the API 
- *       has changed (documentation needed).
- *
- * v0.07a -> v0.08 - 3/10/2001 - David Gibson
- *     o Fixed a possible buffer overrun found by the Stanford checker (in
- *       dldwd_ioctl_setiwencode()).  Can only be called by root anyway, so not
- *       a big problem.
- *     o Turned has_big_wep on for Intersil cards.  That's not true for all of
- *       them but we should at least let the capable ones try.
- *     o Wait for BUSY to clear at the beginning of hermes_bap_seek().  I
- *       realized that my assumption that the driver's serialization
- *       would prevent the BAP being busy on entry was possibly false, because
- *       things other than seeks may make the BAP busy.
- *     o Use "alternate" (oui 00:00:00) encapsulation by default.
- *       Setting use_old_encaps will mimic the old behaviour, but I think we
- *       will be able to eliminate this.
- *     o Don't try to make __initdata const (the version string).  This can't
- *       work because of the way the __initdata sectioning works.
- *     o Added MODULE_LICENSE tags.
- *     o Support for PLX (transparent PCMCIA->PCI bridge) cards.
- *     o Changed to using the new type-fascist min/max.
- *
- * v0.08 -> v0.08a - 9/10/2001 - David Gibson
- *     o Inserted some missing acknowledgements/info into the Changelog.
- *     o Fixed some bugs in the normalization of signal level reporting.
- *     o Fixed bad bug in WEP key handling on Intersil and Symbol firmware,
- *       which led to an instant crash on big-endian machines.
- *
- * v0.08a -> v0.08b - 20/11/2001 - David Gibson
- *     o Lots of cleanup and bugfixes in orinoco_plx.c
- *     o Cleanup to handling of Tx rate setting.
- *     o Removed support for old encapsulation method.
- *     o Removed old "dldwd" names.
- *     o Split RID constants into a new file hermes_rid.h
- *     o Renamed RID constants to match linux-wlan-ng and prism2.o
- *     o Bugfixes in hermes.c
- *     o Poke the PLX's INTCSR register, so it actually starts
- *       generating interrupts.  These cards might actually work now.
- *     o Update to wireless extensions v12 (Jean II)
- *     o Support for tallies and inquire command (Jean II)
- *     o Airport updates for newer PPC kernels (BenH)
- *
- * v0.08b -> v0.09 - 21/12/2001 - David Gibson
- *     o Some new PCI IDs for PLX cards.
- *     o Removed broken attempt to do ALLMULTI reception.  Just use
- *       promiscuous mode instead
- *     o Preliminary work for list-AP (Jean II)
- *     o Airport updates from (BenH)
- *     o Eliminated racy hw_ready stuff
- *     o Fixed generation of fake events in irq handler.  This should
- *       finally kill the EIO problems (Jean II & dgibson)
- *     o Fixed breakage of bitrate set/get on Agere firmware (Jean II)
- *
- * v0.09 -> v0.09a - 2/1/2002 - David Gibson
- *     o Fixed stupid mistake in multicast list handling, triggering
- *       a BUG()
- *
- * v0.09a -> v0.09b - 16/1/2002 - David Gibson
- *     o Fixed even stupider mistake in new interrupt handling, which
- *       seriously broke things on big-endian machines.
- *     o Removed a bunch of redundant includes and exports.
- *     o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c
- *     o Don't attempt to do hardware level multicast reception on
- *       Intersil firmware, just go promisc instead.
- *     o Typo fixed in hermes_issue_cmd()
- *     o Eliminated WIRELESS_SPY #ifdefs
- *     o Status code reported on Tx exceptions
- *     o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC
- *       interrupts, which should fix the timeouts we're seeing.
- *
- * v0.09b -> v0.10 - 25 Feb 2002 - David Gibson
- *     o Removed nested structures used for header parsing, so the
- *       driver should now work without hackery on ARM
- *     o Fix for WEP handling on Intersil (Hawk Newton)
- *     o Eliminated the /proc/hermes/ethXX/regs debugging file.  It
- *       was never very useful.
- *     o Make Rx errors less noisy.
- *
- * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
- *     o Laid the groundwork in hermes.[ch] for devices which map
- *       into PCI memory space rather than IO space.
- *     o Fixed bug in multicast handling (cleared multicast list when
- *       leaving promiscuous mode).
- *     o Relegated Tx error messages to debug.
- *     o Cleaned up / corrected handling of allocation lengths.
- *     o Set OWNSSID in IBSS mode for WinXP interoperability (jimc).
- *     o Change to using alloc_etherdev() for structure allocations. 
- *     o Check for and drop undersized packets.
- *     o Fixed a race in stopping/waking the queue.  This should fix
- *       the timeout problems (Pavel Roskin)
- *     o Reverted to netif_wake_queue() on the ALLOC event.
- *     o Fixes for recent Symbol firmwares which lack AP density
- *       (Pavel Roskin).
- *
- * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
- *     o Handle different register spacing, necessary for Prism 2.5
- *       PCI adaptors (Steve Hill).
- *     o Cleaned up initialization of card structures in orinoco_cs
- *       and airport.  Removed card->priv field.
- *     o Make response structure optional for hermes_docmd_wait()
- *       Pavel Roskin)
- *     o Added PCI id for Nortel emobility to orinoco_plx.c.
- *     o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin)
- *     o Cleanups to firmware capability detection.
- *     o Arrange for orinoco_pci.c to override firmware detection.
- *       We should be able to support the PCI Intersil cards now.
- *     o Cleanup handling of reset_cor and hard_reset (Pavel Roskin).
- *     o Remove erroneous use of USER_BAP in the TxExc handler (Jouni
- *       Malinen).
- *     o Makefile changes for better integration into David Hinds
- *       pcmcia-cs package.
- *
- * v0.11a -> v0.11b - 1 May 2002 - David Gibson
- *     o Better error reporting in orinoco_plx_init_one()
- *     o Fixed multiple bad kfree() bugs introduced by the
- *       alloc_orinocodev() changes.
- *
- * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
- *     o Support changing the MAC address.
- *     o Correct display of Intersil firmware revision numbers.
- *     o Entirely revised locking scheme.  Should be both simpler and
- *        better.
- *     o Merged some common code in orinoco_plx, orinoco_pci and
- *       airport by creating orinoco_default_{open,stop,reset}()
- *       which are used as the dev->open, dev->stop, priv->reset
- *       callbacks if none are specified when alloc_orinocodev() is
- *       called.
- *     o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
- *       They didn't do anything.
- *
- * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
- *     o Some rearrangement of code.
- *     o Numerous fixups to locking and rest handling, particularly
- *       for PCMCIA.
- *     o This allows open and stop net_device methods to be in
- *       orinoco.c now, rather than in the init modules.
- *     o In orinoco_cs.c link->priv now points to the struct
- *       net_device not to the struct orinoco_private.
- *     o Added a check for undersized SNAP frames, which could cause
- *       crashes.
- *
- * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
- *     o Fix hw->num_init testing code, so num_init is actually
- *       incremented.
- *     o Fix very stupid bug in orinoco_cs which broke compile with
- *       CONFIG_SMP.
- *     o Squashed a warning.
- *
- * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
- *     o Change to C9X style designated initializers.
- *     o Add support for 3Com AirConnect PCI.
- *     o No longer ignore the hard_reset argument to
- *       alloc_orinocodev().  Oops.
- *
- * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
- *     o Revert the broken 0.12* locking scheme and go to a new yet
- *       simpler scheme.
- *     o Do firmware resets only in orinoco_init() and when waking
- *       the card from hard sleep.
- *
- * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
- *     o Re-introduced full resets (via schedule_task()) on Tx
- *       timeout.
- *
- * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
- *     o Minor cleanups to info frame handling.  Add basic support
- *       for linkstatus info frames.
- *     o Include required kernel headers in orinoco.h, to avoid
- *       compile problems.
- *
- * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
- *     o Implemented hard reset for Airport cards
- *     o Experimental suspend/resume implementation for orinoco_pci
- *     o Abolished /proc debugging support, replaced with a debugging
- *       iwpriv.  Now it's ugly and simple instead of ugly and complex.
- *     o Bugfix in hermes.c if the firmware returned a record length
- *       of 0, we could go clobbering memory.
- *     o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
- *       was set, which was usually true on PCMCIA hot removes.
- *     o Track LINKSTATUS messages, silently drop Tx packets before
- *       we are connected (avoids confusing the firmware), and only
- *       give LINKSTATUS printk()s if the status has changed.
- *
- * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
- *     o Cleanup: use dev instead of priv in various places.
- *     o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
- *       if we're in the middle of a (driver initiated) hard reset.
- *     o Bug fix: ETH_ZLEN is supposed to include the header
- *       (Dionysus Blazakis & Manish Karir)
- *     o Convert to using workqueues instead of taskqueues (and
- *       backwards compatibility macros for pre 2.5.41 kernels).
- *     o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
- *       airport.c
- *     o New orinoco_tmd.c init module from Joerg Dorchain for
- *       TMD7160 based PCI to PCMCIA bridges (similar to
- *       orinoco_plx.c).
- *
- * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
- *     o Make hw_unavailable a counter, rather than just a flag, this
- *       is necessary to avoid some races (such as a card being
- *       removed in the middle of orinoco_reset().
- *     o Restore Release/RequestConfiguration in the PCMCIA event handler
- *       when dealing with a driver initiated hard reset.  This is
- *       necessary to prevent hangs due to a spurious interrupt while
- *       the reset is in progress.
- *     o Clear the 802.11 header when transmitting, even though we
- *       don't use it.  This fixes a long standing bug on some
- *       firmwares, which seem to get confused if that isn't done.
- *     o Be less eager to de-encapsulate SNAP frames, only do so if
- *       the OUI is 00:00:00 or 00:00:f8, leave others alone.  The old
- *       behaviour broke CDP (Cisco Discovery Protocol).
- *     o Use dev instead of priv for free_irq() as well as
- *       request_irq() (oops).
- *     o Attempt to reset rather than giving up if we get too many
- *       IRQs.
- *     o Changed semantics of __orinoco_down() so it can be called
- *       safely with hw_unavailable set.  It also now clears the
- *       linkstatus (since we're going to have to reassociate).
- *
- * v0.13d -> v0.13e - 12 May 2003 - David Gibson
- *     o Support for post-2.5.68 return values from irq handler.
- *     o Fixed bug where underlength packets would be double counted
- *       in the rx_dropped statistics.
- *     o Provided a module parameter to suppress linkstatus messages.
- *
- * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
- *     o Replaced priv->connected logic with netif_carrier_on/off()
- *       calls.
- *     o Remove has_ibss_any and never set the CREATEIBSS RID when
- *       the ESSID is empty.  Too many firmwares break if we do.
- *     o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
- *       __devinitdata from PCI ID tables, use free_netdev().
- *     o Enabled shared-key authentication for Agere firmware (from
- *       Robert J. Moore <Robert.J.Moore AT allanbank.com>
- *     o Move netif_wake_queue() (back) to the Tx completion from the
- *       ALLOC event.  This seems to prevent/mitigate the rolling
- *       error -110 problems at least on some Intersil firmwares.
- *       Theoretically reduces performance, but I can't measure it.
- *       Patch from Andrew Tridgell <tridge AT samba.org>
- *
- * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
- *     o Correctly turn off shared-key authentication when requested
- *       (bugfix from Robert J. Moore).
- *     o Correct airport sleep interfaces for current 2.6 kernels.
- *     o Add code for key change without disabling/enabling the MAC
- *       port.  This is supposed to allow 802.1x to work sanely, but
- *       doesn't seem to yet.
- *
  * TODO
- *     o New wireless extensions API (patch from Moustafa
- *       Youssef, updated by Jim Carter and Pavel Roskin).
  *     o Handle de-encapsulation within network layer, provide 802.11
  *       headers (patch from Thomas 'Dent' Mirlacher)
- *     o RF monitor mode support
  *     o Fix possible races in SPY handling.
  *     o Disconnect wireless extensions from fundamental configuration.
  *     o (maybe) Software WEP support (patch from Stano Meduna).
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -496,6 +126,10 @@ static int ignore_disconnect; /* = 0 */
 module_param(ignore_disconnect, int, 0644);
 MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
 
+static int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
 /********************************************************************/
 /* Compile time configuration and compatibility stuff               */
 /********************************************************************/
@@ -511,6 +145,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
 /* Internal constants                                               */
 /********************************************************************/
 
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
+
 #define ORINOCO_MIN_MTU                256
 #define ORINOCO_MAX_MTU                (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
 
@@ -537,6 +175,11 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
                                 | HERMES_EV_WTERR | HERMES_EV_INFO \
                                 | HERMES_EV_INFDROP )
 
+#define MAX_RID_LEN 1024
+
+static const struct iw_handler_def orinoco_handler_def;
+static struct ethtool_ops orinoco_ethtool_ops;
+
 /********************************************************************/
 /* Data tables                                                      */
 /********************************************************************/
@@ -571,26 +214,45 @@ static struct {
 /* Data types                                                       */
 /********************************************************************/
 
-struct header_struct {
-       /* 802.3 */
-       u8 dest[ETH_ALEN];
-       u8 src[ETH_ALEN];
-       u16 len;
-       /* 802.2 */
+/* Used in Event handling.
+ * We avoid nested structres as they break on ARM -- Moustafa */
+struct hermes_tx_descriptor_802_11 {
+       /* hermes_tx_descriptor */
+       u16 status;
+       u16 reserved1;
+       u16 reserved2;
+       u32 sw_support;
+       u8 retry_count;
+       u8 tx_rate;
+       u16 tx_control;
+
+       /* ieee802_11_hdr */
+       u16 frame_ctl;
+       u16 duration_id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       u16 seq_ctl;
+       u8 addr4[ETH_ALEN];
+       u16 data_len;
+
+       /* ethhdr */
+       unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
+       unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
+       unsigned short  h_proto;                /* packet type ID field */
+
+       /* p8022_hdr */
        u8 dsap;
        u8 ssap;
        u8 ctrl;
-       /* SNAP */
        u8 oui[3];
+
        u16 ethertype;
 } __attribute__ ((packed));
 
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-
-#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
-
+/* Rx frame header except compatibility 802.3 header */
 struct hermes_rx_descriptor {
+       /* Control */
        u16 status;
        u32 time;
        u8 silence;
@@ -598,13 +260,24 @@ struct hermes_rx_descriptor {
        u8 rate;
        u8 rxflow;
        u32 reserved;
+
+       /* 802.11 header */
+       u16 frame_ctl;
+       u16 duration_id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       u16 seq_ctl;
+       u8 addr4[ETH_ALEN];
+
+       /* Data length */
+       u16 data_len;
 } __attribute__ ((packed));
 
 /********************************************************************/
 /* Function prototypes                                              */
 /********************************************************************/
 
-static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int __orinoco_program_rids(struct net_device *dev);
 static void __orinoco_set_multicast_list(struct net_device *dev);
 
@@ -628,6 +301,10 @@ static inline void set_port_type(struct orinoco_private *priv)
                        priv->createibss = 1;
                }
                break;
+       case IW_MODE_MONITOR:
+               priv->port_type = 3;
+               priv->createibss = 0;
+               break;
        default:
                printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
                       priv->ndev->name);
@@ -814,7 +491,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                return 1;
        }
 
-       if (! netif_carrier_ok(dev)) {
+       if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
                /* Oops, the firmware hasn't established a connection,
                    silently drop the packet (this seems to be the
                    safest approach). */
@@ -951,26 +628,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
        struct orinoco_private *priv = netdev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        u16 fid = hermes_read_regn(hw, TXCOMPLFID);
-       struct hermes_tx_descriptor desc;
+       struct hermes_tx_descriptor_802_11 hdr;
        int err = 0;
 
        if (fid == DUMMY_FID)
                return; /* Nothing's really happened */
 
-       err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
+       /* Read the frame header */
+       err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+                              sizeof(struct hermes_tx_descriptor) +
+                              sizeof(struct ieee80211_hdr),
+                              fid, 0);
+
+       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+       stats->tx_errors++;
+
        if (err) {
                printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
                       "(FID=%04X error %d)\n",
                       dev->name, fid, err);
-       } else {
-               DEBUG(1, "%s: Tx error, status %d\n",
-                     dev->name, le16_to_cpu(desc.status));
+               return;
        }
        
-       stats->tx_errors++;
+       DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+             err, fid);
+    
+       /* We produce a TXDROP event only for retry or lifetime
+        * exceeded, because that's the only status that really mean
+        * that this particular node went away.
+        * Other errors means that *we* screwed up. - Jean II */
+       hdr.status = le16_to_cpu(hdr.status);
+       if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+               union iwreq_data        wrqu;
+
+               /* Copy 802.11 dest address.
+                * We use the 802.11 header because the frame may
+                * not be 802.3 or may be mangled...
+                * In Ad-Hoc mode, it will be the node address.
+                * In managed mode, it will be most likely the AP addr
+                * User space will figure out how to convert it to
+                * whatever it needs (IP address or else).
+                * - Jean II */
+               memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+               wrqu.addr.sa_family = ARPHRD_ETHER;
+
+               /* Send event to user space */
+               wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+       }
 
        netif_wake_queue(dev);
-       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
 static void orinoco_tx_timeout(struct net_device *dev)
@@ -1047,18 +753,127 @@ static void orinoco_stat_gather(struct net_device *dev,
        }
 }
 
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ *     dev             network device
+ *     rxfid           received FID
+ *     desc            rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+                              struct hermes_rx_descriptor *desc)
+{
+       u32 hdrlen = 30;        /* return full header by default */
+       u32 datalen = 0;
+       u16 fc;
+       int err;
+       int len;
+       struct sk_buff *skb;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       hermes_t *hw = &priv->hw;
+
+       len = le16_to_cpu(desc->data_len);
+
+       /* Determine the size of the header and the data */
+       fc = le16_to_cpu(desc->frame_ctl);
+       switch (fc & IEEE80211_FCTL_FTYPE) {
+       case IEEE80211_FTYPE_DATA:
+               if ((fc & IEEE80211_FCTL_TODS)
+                   && (fc & IEEE80211_FCTL_FROMDS))
+                       hdrlen = 30;
+               else
+                       hdrlen = 24;
+               datalen = len;
+               break;
+       case IEEE80211_FTYPE_MGMT:
+               hdrlen = 24;
+               datalen = len;
+               break;
+       case IEEE80211_FTYPE_CTL:
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_PSPOLL:
+               case IEEE80211_STYPE_RTS:
+               case IEEE80211_STYPE_CFEND:
+               case IEEE80211_STYPE_CFENDACK:
+                       hdrlen = 16;
+                       break;
+               case IEEE80211_STYPE_CTS:
+               case IEEE80211_STYPE_ACK:
+                       hdrlen = 10;
+                       break;
+               }
+               break;
+       default:
+               /* Unknown frame type */
+               break;
+       }
+
+       /* sanity check the length */
+       if (datalen > IEEE80211_DATA_LEN + 12) {
+               printk(KERN_DEBUG "%s: oversized monitor frame, "
+                      "data length = %d\n", dev->name, datalen);
+               err = -EIO;
+               stats->rx_length_errors++;
+               goto update_stats;
+       }
+
+       skb = dev_alloc_skb(hdrlen + datalen);
+       if (!skb) {
+               printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+                      dev->name);
+               err = -ENOMEM;
+               goto drop;
+       }
+
+       /* Copy the 802.11 header to the skb */
+       memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+       skb->mac.raw = skb->data;
+
+       /* If any, copy the data from the card to the skb */
+       if (datalen > 0) {
+               err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+                                      ALIGN(datalen, 2), rxfid,
+                                      HERMES_802_2_OFFSET);
+               if (err) {
+                       printk(KERN_ERR "%s: error %d reading monitor frame\n",
+                              dev->name, err);
+                       goto drop;
+               }
+       }
+
+       skb->dev = dev;
+       skb->ip_summed = CHECKSUM_NONE;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = __constant_htons(ETH_P_802_2);
+       
+       dev->last_rx = jiffies;
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len;
+
+       netif_rx(skb);
+       return;
+
+ drop:
+       dev_kfree_skb_irq(skb);
+ update_stats:
+       stats->rx_errors++;
+       stats->rx_dropped++;
+}
+
 static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        struct iw_statistics *wstats = &priv->wstats;
        struct sk_buff *skb = NULL;
-       u16 rxfid, status;
-       int length, data_len, data_off;
-       char *p;
+       u16 rxfid, status, fc;
+       int length;
        struct hermes_rx_descriptor desc;
-       struct header_struct hdr;
-       struct ethhdr *eh;
+       struct ethhdr *hdr;
        int err;
 
        rxfid = hermes_read_regn(hw, RXFID);
@@ -1068,53 +883,46 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
        if (err) {
                printk(KERN_ERR "%s: error %d reading Rx descriptor. "
                       "Frame dropped.\n", dev->name, err);
-               stats->rx_errors++;
-               goto drop;
+               goto update_stats;
        }
 
        status = le16_to_cpu(desc.status);
 
-       if (status & HERMES_RXSTAT_ERR) {
-               if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
-                       wstats->discard.code++;
-                       DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
-                              dev->name);
-               } else {
-                       stats->rx_crc_errors++;
-                       DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
-               }
-               stats->rx_errors++;
-               goto drop;
+       if (status & HERMES_RXSTAT_BADCRC) {
+               DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+                     dev->name);
+               stats->rx_crc_errors++;
+               goto update_stats;
        }
 
-       /* For now we ignore the 802.11 header completely, assuming
-           that the card's firmware has handled anything vital */
+       /* Handle frames in monitor mode */
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               orinoco_rx_monitor(dev, rxfid, &desc);
+               return;
+       }
 
-       err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
-                              rxfid, HERMES_802_3_OFFSET);
-       if (err) {
-               printk(KERN_ERR "%s: error %d reading frame header. "
-                      "Frame dropped.\n", dev->name, err);
-               stats->rx_errors++;
-               goto drop;
+       if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+               DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+                     dev->name);
+               wstats->discard.code++;
+               goto update_stats;
        }
 
-       length = ntohs(hdr.len);
-       
+       length = le16_to_cpu(desc.data_len);
+       fc = le16_to_cpu(desc.frame_ctl);
+
        /* Sanity checks */
        if (length < 3) { /* No for even an 802.2 LLC header */
                /* At least on Symbol firmware with PCF we get quite a
                    lot of these legitimately - Poll frames with no
                    data. */
-               stats->rx_dropped++;
-               goto drop;
+               return;
        }
        if (length > IEEE802_11_DATA_LEN) {
                printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
                       dev->name, length);
                stats->rx_length_errors++;
-               stats->rx_errors++;
-               goto drop;
+               goto update_stats;
        }
 
        /* We need space for the packet data itself, plus an ethernet
@@ -1126,60 +934,53 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
        if (!skb) {
                printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
                       dev->name);
-               goto drop;
+               goto update_stats;
        }
 
-       skb_reserve(skb, 2); /* This way the IP header is aligned */
+       /* We'll prepend the header, so reserve space for it.  The worst
+          case is no decapsulation, when 802.3 header is prepended and
+          nothing is removed.  2 is for aligning the IP header.  */
+       skb_reserve(skb, ETH_HLEN + 2);
+
+       err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+                              ALIGN(length, 2), rxfid,
+                              HERMES_802_2_OFFSET);
+       if (err) {
+               printk(KERN_ERR "%s: error %d reading frame. "
+                      "Frame dropped.\n", dev->name, err);
+               goto drop;
+       }
 
        /* Handle decapsulation
         * In most cases, the firmware tell us about SNAP frames.
         * For some reason, the SNAP frames sent by LinkSys APs
         * are not properly recognised by most firmwares.
         * So, check ourselves */
-       if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
-           ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-           is_ethersnap(&hdr)) {
+       if (length >= ENCAPS_OVERHEAD &&
+           (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+            ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+            is_ethersnap(skb->data))) {
                /* These indicate a SNAP within 802.2 LLC within
                   802.11 frame which we'll need to de-encapsulate to
                   the original EthernetII frame. */
-
-               if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
-                       stats->rx_length_errors++;
-                       goto drop;
-               }
-
-               /* Remove SNAP header, reconstruct EthernetII frame */
-               data_len = length - ENCAPS_OVERHEAD;
-               data_off = HERMES_802_3_OFFSET + sizeof(hdr);
-
-               eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
-
-               memcpy(eh, &hdr, 2 * ETH_ALEN);
-               eh->h_proto = hdr.ethertype;
+               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
        } else {
-               /* All other cases indicate a genuine 802.3 frame.  No
-                  decapsulation needed.  We just throw the whole
-                  thing in, and hope the protocol layer can deal with
-                  it as 802.3 */
-               data_len = length;
-               data_off = HERMES_802_3_OFFSET;
-               /* FIXME: we re-read from the card data we already read here */
-       }
-
-       p = skb_put(skb, data_len);
-       err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2),
-                              rxfid, data_off);
-       if (err) {
-               printk(KERN_ERR "%s: error %d reading frame. "
-                      "Frame dropped.\n", dev->name, err);
-               stats->rx_errors++;
-               goto drop;
+               /* 802.3 frame - prepend 802.3 header as is */
+               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+               hdr->h_proto = htons(length);
        }
+       memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
+       if (fc & IEEE80211_FCTL_FROMDS)
+               memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
+       else
+               memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
 
        dev->last_rx = jiffies;
        skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;
+       if (fc & IEEE80211_FCTL_TODS)
+               skb->pkt_type = PACKET_OTHERHOST;
        
        /* Process the wireless stats if needed */
        orinoco_stat_gather(dev, skb, &desc);
@@ -1192,11 +993,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
        return;
 
  drop: 
+       dev_kfree_skb_irq(skb);
+ update_stats:
+       stats->rx_errors++;
        stats->rx_dropped++;
-
-       if (skb)
-               dev_kfree_skb_irq(skb);
-       return;
 }
 
 /********************************************************************/
@@ -1240,6 +1040,99 @@ static void print_linkstatus(struct net_device *dev, u16 status)
               dev->name, s, status);
 }
 
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       int err;
+       unsigned long flags;
+       struct join_req {
+               u8 bssid[ETH_ALEN];
+               u16 channel;
+       } __attribute__ ((packed)) req;
+       const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+       struct prism2_scan_apinfo *atom;
+       int offset = 4;
+       u8 *buf;
+       u16 len;
+
+       /* Allocate buffer for scan results */
+       buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+       if (! buf)
+               return;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               goto out;
+
+       /* Sanity checks in case user changed something in the meantime */
+       if (! priv->bssid_fixed)
+               goto out;
+
+       if (strlen(priv->desired_essid) == 0)
+               goto out;
+
+       /* Read scan results from the firmware */
+       err = hermes_read_ltv(hw, USER_BAP,
+                             HERMES_RID_SCANRESULTSTABLE,
+                             MAX_SCAN_LEN, &len, buf);
+       if (err) {
+               printk(KERN_ERR "%s: Cannot read scan results\n",
+                      dev->name);
+               goto out;
+       }
+
+       len = HERMES_RECLEN_TO_BYTES(len);
+
+       /* Go through the scan results looking for the channel of the AP
+        * we were requested to join */
+       for (; offset + atom_len <= len; offset += atom_len) {
+               atom = (struct prism2_scan_apinfo *) (buf + offset);
+               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
+                       goto found;
+       }
+
+       DEBUG(1, "%s: Requested AP not found in scan results\n",
+             dev->name);
+       goto out;
+
+ found:
+       memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+       req.channel = atom->channel;    /* both are little-endian */
+       err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+                                 &req);
+       if (err)
+               printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+       kfree(buf);
+       orinoco_unlock(priv, &flags);
+}
+
+/* Send new BSSID to userspace */
+static void orinoco_send_wevents(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       union iwreq_data wrqu;
+       int err;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return;
+
+       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+                             ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+       if (err != 0)
+               return;
+
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+       /* Send event to user space */
+       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+       orinoco_unlock(priv, &flags);
+}
+
 static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = netdev_priv(dev);
@@ -1307,6 +1200,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                u16 newstatus;
                int connected;
 
+               if (priv->iw_mode == IW_MODE_MONITOR)
+                       break;
+
                if (len != sizeof(linkstatus)) {
                        printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
                               dev->name, len);
@@ -1319,6 +1215,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
                newstatus = le16_to_cpu(linkstatus.linkstatus);
 
+               /* Symbol firmware uses "out of range" to signal that
+                * the hostscan frame can be requested.  */
+               if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+                   priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+                   priv->has_hostscan && priv->scan_inprogress) {
+                       hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+                       break;
+               }
+
                connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
                        || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
                        || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1328,12 +1233,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                else if (!ignore_disconnect)
                        netif_carrier_off(dev);
 
-               if (newstatus != priv->last_linkstatus)
+               if (newstatus != priv->last_linkstatus) {
+                       priv->last_linkstatus = newstatus;
                        print_linkstatus(dev, newstatus);
+                       /* The info frame contains only one word which is the
+                        * status (see hermes.h). The status is pretty boring
+                        * in itself, that's why we export the new BSSID...
+                        * Jean II */
+                       schedule_work(&priv->wevent_work);
+               }
+       }
+       break;
+       case HERMES_INQ_SCAN:
+               if (!priv->scan_inprogress && priv->bssid_fixed &&
+                   priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+                       schedule_work(&priv->join_work);
+                       break;
+               }
+               /* fall through */
+       case HERMES_INQ_HOSTSCAN:
+       case HERMES_INQ_HOSTSCAN_SYMBOL: {
+               /* Result of a scanning. Contains information about
+                * cells in the vicinity - Jean II */
+               union iwreq_data        wrqu;
+               unsigned char *buf;
+
+               /* Sanity check */
+               if (len > 4096) {
+                       printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+                              dev->name, len);
+                       break;
+               }
+
+               /* We are a strict producer. If the previous scan results
+                * have not been consumed, we just have to drop this
+                * frame. We can't remove the previous results ourselves,
+                * that would be *very* racy... Jean II */
+               if (priv->scan_result != NULL) {
+                       printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
+                       break;
+               }
+
+               /* Allocate buffer for results */
+               buf = kmalloc(len, GFP_ATOMIC);
+               if (buf == NULL)
+                       /* No memory, so can't printk()... */
+                       break;
 
-               priv->last_linkstatus = newstatus;
+               /* Read scan data */
+               err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+                                      infofid, sizeof(info));
+               if (err)
+                       break;
+
+#ifdef ORINOCO_DEBUG
+               {
+                       int     i;
+                       printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+                       for(i = 1; i < (len * 2); i++)
+                               printk(":%02X", buf[i]);
+                       printk("]\n");
+               }
+#endif /* ORINOCO_DEBUG */
+
+               /* Allow the clients to access the results */
+               priv->scan_len = len;
+               priv->scan_result = buf;
+
+               /* Send an empty event to user space.
+                * We don't send the received data on the event because
+                * it would require us to do complex transcoding, and
+                * we want to minimise the work done in the irq handler
+                * Use a request to extract the data - Jean II */
+               wrqu.data.length = 0;
+               wrqu.data.flags = 0;
+               wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
        }
        break;
+       case HERMES_INQ_SEC_STAT_AGERE:
+               /* Security status (Agere specific) */
+               /* Ignore this frame for now */
+               if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+                       break;
+               /* fall through */
        default:
                printk(KERN_DEBUG "%s: Unknown information frame received: "
                       "type 0x%04x, length %d\n", dev->name, type, len);
@@ -1470,6 +1452,36 @@ static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
        return err;
 }
 
+/* Set fixed AP address */
+static int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+       int roaming_flag;
+       int err = 0;
+       hermes_t *hw = &priv->hw;
+
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               /* not supported */
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+               if (priv->bssid_fixed)
+                       roaming_flag = 2;
+               else
+                       roaming_flag = 1;
+
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFROAMINGMODE,
+                                          roaming_flag);
+               break;
+       case FIRMWARE_TYPE_SYMBOL:
+               err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                         HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+                                         &priv->desired_bssid);
+               break;
+       }
+       return err;
+}
+
 /* Change the WEP keys and/or the current keys.  Can be called
  * either from __orinoco_hw_setup_wep() or directly from
  * orinoco_ioctl_setiwencode().  In the later case the association
@@ -1655,6 +1667,13 @@ static int __orinoco_program_rids(struct net_device *dev)
                }
        }
 
+       /* Set the desired BSSID */
+       err = __orinoco_hw_set_wap(priv);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting AP address\n",
+                      dev->name, err);
+               return err;
+       }
        /* Set the desired ESSID */
        idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
        memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
@@ -1793,7 +1812,21 @@ static int __orinoco_program_rids(struct net_device *dev)
                }
        }
 
-       /* Set promiscuity / multicast*/
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               /* Enable monitor mode */
+               dev->type = ARPHRD_IEEE80211;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST | 
+                                           HERMES_TEST_MONITOR, 0, NULL);
+       } else {
+               /* Disable monitor mode */
+               dev->type = ARPHRD_ETHER;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_STOP, 0, NULL);
+       }
+       if (err)
+               return err;
+
+       /* Set promiscuity / multicast*/
        priv->promiscuous = 0;
        priv->mc_count = 0;
        __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
@@ -1869,55 +1902,6 @@ __orinoco_set_multicast_list(struct net_device *dev)
                dev->flags &= ~IFF_PROMISC;
 }
 
-static int orinoco_reconfigure(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       unsigned long flags;
-       int err = 0;
-
-       if (priv->broken_disableport) {
-               schedule_work(&priv->reset_work);
-               return 0;
-       }
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-               
-       err = hermes_disable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
-                      dev->name);
-               priv->broken_disableport = 1;
-               goto out;
-       }
-
-       err = __orinoco_program_rids(dev);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-                      dev->name);
-               goto out;
-       }
-
-       err = hermes_enable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-                      dev->name);
-               goto out;
-       }
-
- out:
-       if (err) {
-               printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-               schedule_work(&priv->reset_work);
-               err = 0;
-       }
-
-       orinoco_unlock(priv, &flags);
-       return err;
-
-}
-
 /* This must be called from user context, without locks held - use
  * schedule_work() */
 static void orinoco_reset(struct net_device *dev)
@@ -1946,6 +1930,11 @@ static void orinoco_reset(struct net_device *dev)
 
        orinoco_unlock(priv, &flags);
 
+       /* Scanning support: Cleanup of driver struct */
+       kfree(priv->scan_result);
+       priv->scan_result = NULL;
+       priv->scan_inprogress = 0;
+
        if (priv->hard_reset) {
                err = (*priv->hard_reset)(priv);
                if (err) {
@@ -2184,6 +2173,8 @@ static int determine_firmware(struct net_device *dev)
                priv->has_mwo = (firmver >= 0x60000);
                priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
                priv->ibss_port = 1;
+               priv->has_hostscan = (firmver >= 0x8000a);
+               priv->broken_monitor = (firmver >= 0x80000);
 
                /* Tested with Agere firmware :
                 *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2229,6 +2220,8 @@ static int determine_firmware(struct net_device *dev)
                priv->ibss_port = 4;
                priv->broken_disableport = (firmver == 0x25013) ||
                                           (firmver >= 0x30000 && firmver <= 0x31000);
+               priv->has_hostscan = (firmver >= 0x31001) ||
+                                    (firmver >= 0x29057 && firmver < 0x30000);
                /* Tested with Intel firmware : 0x20015 => Jean II */
                /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
                break;
@@ -2248,6 +2241,7 @@ static int determine_firmware(struct net_device *dev)
                priv->has_ibss = (firmver >= 0x000700); /* FIXME */
                priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
                priv->has_pm = (firmver >= 0x000700);
+               priv->has_hostscan = (firmver >= 0x010301);
 
                if (firmver >= 0x000800)
                        priv->ibss_port = 0;
@@ -2456,8 +2450,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
        dev->tx_timeout = orinoco_tx_timeout;
        dev->watchdog_timeo = HZ; /* 1 second timeout */
        dev->get_stats = orinoco_get_stats;
+       dev->ethtool_ops = &orinoco_ethtool_ops;
        dev->get_wireless_stats = orinoco_get_wireless_stats;
-       dev->do_ioctl = orinoco_ioctl;
+       dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
        dev->change_mtu = orinoco_change_mtu;
        dev->set_multicast_list = orinoco_set_multicast_list;
        /* we use the default eth_mac_addr for setting the MAC addr */
@@ -2473,6 +2468,8 @@ struct net_device *alloc_orinocodev(int sizeof_card,
                                   * before anything else touches the
                                   * hardware */
        INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+       INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
+       INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
 
        netif_carrier_off(dev);
        priv->last_linkstatus = 0xffff;
@@ -2483,6 +2480,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
 
 void free_orinocodev(struct net_device *dev)
 {
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       kfree(priv->scan_result);
        free_netdev(dev);
 }
 
@@ -2490,24 +2490,6 @@ void free_orinocodev(struct net_device *dev)
 /* Wireless extensions                                              */
 /********************************************************************/
 
-static int orinoco_hw_get_bssid(struct orinoco_private *priv,
-                               char buf[ETH_ALEN])
-{
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, buf);
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
 static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
                                char buf[IW_ESSID_MAX_SIZE+1])
 {
@@ -2633,140 +2615,271 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
        return 0;
 }
 
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int orinoco_ioctl_getname(struct net_device *dev,
+                                struct iw_request_info *info,
+                                char *name,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
-       int mode;
-       struct iw_range range;
        int numrates;
-       int i, k;
+       int err;
+
+       err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
+
+       if (!err && (numrates > 2))
+               strcpy(name, "IEEE 802.11b");
+       else
+               strcpy(name, "IEEE 802.11-DS");
+
+       return 0;
+}
+
+static int orinoco_ioctl_setwap(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct sockaddr *ap_addr,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
+       static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-       TRACE_ENTER(dev->name);
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* Enable automatic roaming - no sanity checks are needed */
+       if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+           memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+               priv->bssid_fixed = 0;
+               memset(priv->desired_bssid, 0, ETH_ALEN);
+
+               /* "off" means keep existing connection */
+               if (ap_addr->sa_data[0] == 0) {
+                       __orinoco_hw_set_wap(priv);
+                       err = 0;
+               }
+               goto out;
+       }
+
+       if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+               printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+                      "support manual roaming\n",
+                      dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (priv->iw_mode != IW_MODE_INFRA) {
+               printk(KERN_WARNING "%s: Manual roaming supported only in "
+                      "managed mode\n", dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* Intersil firmware hangs without Desired ESSID */
+       if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+           strlen(priv->desired_essid) == 0) {
+               printk(KERN_WARNING "%s: Desired ESSID must be set for "
+                      "manual roaming\n", dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* Finally, enable manual roaming */
+       priv->bssid_fixed = 1;
+       memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
+
+ out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct sockaddr *ap_addr,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       ap_addr->sa_family = ARPHRD_ETHER;
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                             ETH_ALEN, NULL, ap_addr->sa_data);
+
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
 
-       if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range)))
-               return -EFAULT;
+static int orinoco_ioctl_setmode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                u32 *mode,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
+       unsigned long flags;
 
-       rrq->length = sizeof(range);
+       if (priv->iw_mode == *mode)
+               return 0;
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       mode = priv->iw_mode;
+       switch (*mode) {
+       case IW_MODE_ADHOC:
+               if (!priv->has_ibss && !priv->has_port3)
+                       err = -EOPNOTSUPP;
+               break;
+
+       case IW_MODE_INFRA:
+               break;
+
+       case IW_MODE_MONITOR:
+               if (priv->broken_monitor && !force_monitor) {
+                       printk(KERN_WARNING "%s: Monitor mode support is "
+                              "buggy in this firmware, not enabling\n",
+                              dev->name);
+                       err = -EOPNOTSUPP;
+               }
+               break;
+
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       if (err == -EINPROGRESS) {
+               priv->iw_mode = *mode;
+               set_port_type(priv);
+       }
+
        orinoco_unlock(priv, &flags);
 
-       memset(&range, 0, sizeof(range));
+       return err;
+}
 
-       /* Much of this shamelessly taken from wvlan_cs.c. No idea
-        * what it all means -dgibson */
-       range.we_version_compiled = WIRELESS_EXT;
-       range.we_version_source = 11;
+static int orinoco_ioctl_getmode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                u32 *mode,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
 
-       range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+       *mode = priv->iw_mode;
+       return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_point *rrq,
+                                   char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = 0;
+       struct iw_range *range = (struct iw_range *) extra;
+       int numrates;
+       int i, k;
+
+       TRACE_ENTER(dev->name);
+
+       rrq->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 14;
 
        /* Set available channels/frequencies */
-       range.num_channels = NUM_CHANNELS;
+       range->num_channels = NUM_CHANNELS;
        k = 0;
        for (i = 0; i < NUM_CHANNELS; i++) {
                if (priv->channel_mask & (1 << i)) {
-                       range.freq[k].i = i + 1;
-                       range.freq[k].m = channel_frequency[i] * 100000;
-                       range.freq[k].e = 1;
+                       range->freq[k].i = i + 1;
+                       range->freq[k].m = channel_frequency[i] * 100000;
+                       range->freq[k].e = 1;
                        k++;
                }
                
                if (k >= IW_MAX_FREQUENCIES)
                        break;
        }
-       range.num_frequency = k;
+       range->num_frequency = k;
+       range->sensitivity = 3;
+
+       if (priv->has_wep) {
+               range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+               range->encoding_size[0] = SMALL_KEY_SIZE;
+               range->num_encoding_sizes = 1;
 
-       range.sensitivity = 3;
+               if (priv->has_big_wep) {
+                       range->encoding_size[1] = LARGE_KEY_SIZE;
+                       range->num_encoding_sizes = 2;
+               }
+       }
 
-       if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
+       if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
                /* Quality stats meaningless in ad-hoc mode */
-               range.max_qual.qual = 0;
-               range.max_qual.level = 0;
-               range.max_qual.noise = 0;
-               range.avg_qual.qual = 0;
-               range.avg_qual.level = 0;
-               range.avg_qual.noise = 0;
        } else {
-               range.max_qual.qual = 0x8b - 0x2f;
-               range.max_qual.level = 0x2f - 0x95 - 1;
-               range.max_qual.noise = 0x2f - 0x95 - 1;
+               range->max_qual.qual = 0x8b - 0x2f;
+               range->max_qual.level = 0x2f - 0x95 - 1;
+               range->max_qual.noise = 0x2f - 0x95 - 1;
                /* Need to get better values */
-               range.avg_qual.qual = 0x24;
-               range.avg_qual.level = 0xC2;
-               range.avg_qual.noise = 0x9E;
+               range->avg_qual.qual = 0x24;
+               range->avg_qual.level = 0xC2;
+               range->avg_qual.noise = 0x9E;
        }
 
        err = orinoco_hw_get_bitratelist(priv, &numrates,
-                                        range.bitrate, IW_MAX_BITRATES);
+                                        range->bitrate, IW_MAX_BITRATES);
        if (err)
                return err;
-       range.num_bitrates = numrates;
-       
+       range->num_bitrates = numrates;
+
        /* Set an indication of the max TCP throughput in bit/s that we can
         * expect using this interface. May be use for QoS stuff...
         * Jean II */
-       if(numrates > 2)
-               range.throughput = 5 * 1000 * 1000;     /* ~5 Mb/s */
+       if (numrates > 2)
+               range->throughput = 5 * 1000 * 1000;    /* ~5 Mb/s */
        else
-               range.throughput = 1.5 * 1000 * 1000;   /* ~1.5 Mb/s */
-
-       range.min_rts = 0;
-       range.max_rts = 2347;
-       range.min_frag = 256;
-       range.max_frag = 2346;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       if (priv->has_wep) {
-               range.max_encoding_tokens = ORINOCO_MAX_KEYS;
-
-               range.encoding_size[0] = SMALL_KEY_SIZE;
-               range.num_encoding_sizes = 1;
-
-               if (priv->has_big_wep) {
-                       range.encoding_size[1] = LARGE_KEY_SIZE;
-                       range.num_encoding_sizes = 2;
-               }
-       } else {
-               range.num_encoding_sizes = 0;
-               range.max_encoding_tokens = 0;
-       }
-       orinoco_unlock(priv, &flags);
-               
-       range.min_pmp = 0;
-       range.max_pmp = 65535000;
-       range.min_pmt = 0;
-       range.max_pmt = 65535 * 1000;   /* ??? */
-       range.pmp_flags = IW_POWER_PERIOD;
-       range.pmt_flags = IW_POWER_TIMEOUT;
-       range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-       range.num_txpower = 1;
-       range.txpower[0] = 15; /* 15dBm */
-       range.txpower_capa = IW_TXPOW_DBM;
-
-       range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-       range.retry_flags = IW_RETRY_LIMIT;
-       range.r_time_flags = IW_RETRY_LIFETIME;
-       range.min_retry = 0;
-       range.max_retry = 65535;        /* ??? */
-       range.min_r_time = 0;
-       range.max_r_time = 65535 * 1000;        /* ??? */
-
-       if (copy_to_user(rrq->pointer, &range, sizeof(range)))
-               return -EFAULT;
+               range->throughput = 1.5 * 1000 * 1000;  /* ~1.5 Mb/s */
+
+       range->min_rts = 0;
+       range->max_rts = 2347;
+       range->min_frag = 256;
+       range->max_frag = 2346;
+
+       range->min_pmp = 0;
+       range->max_pmp = 65535000;
+       range->min_pmt = 0;
+       range->max_pmt = 65535 * 1000;  /* ??? */
+       range->pmp_flags = IW_POWER_PERIOD;
+       range->pmt_flags = IW_POWER_TIMEOUT;
+       range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+       range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+       range->retry_flags = IW_RETRY_LIMIT;
+       range->r_time_flags = IW_RETRY_LIFETIME;
+       range->min_retry = 0;
+       range->max_retry = 65535;       /* ??? */
+       range->min_r_time = 0;
+       range->max_r_time = 65535 * 1000;       /* ??? */
 
        TRACE_EXIT(dev->name);
 
        return 0;
 }
 
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq,
+                                    char *keybuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int index = (erq->flags & IW_ENCODE_INDEX) - 1;
@@ -2774,8 +2887,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
        int enable = priv->wep_on;
        int restricted = priv->wep_restrict;
        u16 xlen = 0;
-       int err = 0;
-       char keybuf[ORINOCO_MAX_KEY_SIZE];
+       int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
 
        if (! priv->has_wep)
@@ -2788,9 +2900,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
 
                if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
                        return -E2BIG;
-               
-               if (copy_from_user(keybuf, erq->pointer, erq->length))
-                       return -EFAULT;
        }
 
        if (orinoco_lock(priv, &flags) != 0)
@@ -2864,12 +2973,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
        return err;
 }
 
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq,
+                                    char *keybuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int index = (erq->flags & IW_ENCODE_INDEX) - 1;
        u16 xlen = 0;
-       char keybuf[ORINOCO_MAX_KEY_SIZE];
        unsigned long flags;
 
        if (! priv->has_wep)
@@ -2898,51 +3009,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er
        memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
 
        orinoco_unlock(priv, &flags);
-
-       if (erq->pointer) {
-               if (copy_to_user(erq->pointer, keybuf, xlen))
-                       return -EFAULT;
-       }
-
        return 0;
 }
 
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq,
+                                 char *essidbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char essidbuf[IW_ESSID_MAX_SIZE+1];
        unsigned long flags;
 
        /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
         * anyway... - Jean II */
 
-       memset(&essidbuf, 0, sizeof(essidbuf));
-
-       if (erq->flags) {
-               /* iwconfig includes the NUL in the specified length */
-               if (erq->length > IW_ESSID_MAX_SIZE+1)
-                       return -E2BIG;
-               
-               if (copy_from_user(&essidbuf, erq->pointer, erq->length))
-                       return -EFAULT;
-
-               essidbuf[IW_ESSID_MAX_SIZE] = '\0';
-       }
+       /* Hum... Should not use Wireless Extension constant (may change),
+        * should use our own... - Jean II */
+       if (erq->length > IW_ESSID_MAX_SIZE)
+               return -E2BIG;
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
+       /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+       memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+       /* If not ANY, get the new ESSID */
+       if (erq->flags) {
+               memcpy(priv->desired_essid, essidbuf, erq->length);
+       }
 
        orinoco_unlock(priv, &flags);
 
-       return 0;
+       return -EINPROGRESS;            /* Call commit handler */
 }
 
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq,
+                                 char *essidbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char essidbuf[IW_ESSID_MAX_SIZE+1];
        int active;
        int err = 0;
        unsigned long flags;
@@ -2956,51 +3063,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
        } else {
                if (orinoco_lock(priv, &flags) != 0)
                        return -EBUSY;
-               memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
+               memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
                orinoco_unlock(priv, &flags);
        }
 
        erq->flags = 1;
        erq->length = strlen(essidbuf) + 1;
-       if (erq->pointer)
-               if (copy_to_user(erq->pointer, essidbuf, erq->length))
-                       return -EFAULT;
 
        TRACE_EXIT(dev->name);
        
        return 0;
 }
 
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *nrq,
+                                char *nickbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char nickbuf[IW_ESSID_MAX_SIZE+1];
        unsigned long flags;
 
        if (nrq->length > IW_ESSID_MAX_SIZE)
                return -E2BIG;
 
-       memset(nickbuf, 0, sizeof(nickbuf));
-
-       if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
-               return -EFAULT;
-
-       nickbuf[nrq->length] = '\0';
-       
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+       memset(priv->nick, 0, sizeof(priv->nick));
+       memcpy(priv->nick, nickbuf, nrq->length);
 
        orinoco_unlock(priv, &flags);
 
-       return 0;
+       return -EINPROGRESS;            /* Call commit handler */
 }
 
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *nrq,
+                                char *nickbuf)
 {
        struct orinoco_private *priv = netdev_priv(dev);
-       char nickbuf[IW_ESSID_MAX_SIZE+1];
        unsigned long flags;
 
        if (orinoco_lock(priv, &flags) != 0)
@@ -3011,23 +3113,22 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
 
        nrq->length = strlen(nickbuf)+1;
 
-       if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
-               return -EFAULT;
-
        return 0;
 }
 
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_freq *frq,
+                                char *extra)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        int chan = -1;
        unsigned long flags;
+       int err = -EINPROGRESS;         /* Call commit handler */
 
-       /* We can only use this in Ad-Hoc demo mode to set the operating
-        * frequency, or in IBSS mode to set the frequency where the IBSS
-        * will be created - Jean II */
-       if (priv->iw_mode != IW_MODE_ADHOC)
-               return -EOPNOTSUPP;
+       /* In infrastructure mode the AP sets the channel */
+       if (priv->iw_mode == IW_MODE_INFRA)
+               return -EBUSY;
 
        if ( (frq->e == 0) && (frq->m <= 1000) ) {
                /* Setting by channel number */
@@ -3051,13 +3152,44 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
+
        priv->channel = chan;
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               /* Fast channel change - no commit if successful */
+               hermes_t *hw = &priv->hw;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_SET_CHANNEL,
+                                       chan, NULL);
+       }
        orinoco_unlock(priv, &flags);
 
+       return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_freq *frq,
+             &