toshiba: Move the Toshiba drivers
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 30 Jul 2011 07:36:02 +0000 (00:36 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 12 Aug 2011 07:27:04 +0000 (00:27 -0700)
Move the Toshiba ethernet drivers into drivers/net/ethernet/toshiba
and make the necessary Kconfig and Makefile changes.

CC: Geoff Levand <geoff@infradead.org>
CC: Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
CC: Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
23 files changed:
MAINTAINERS
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/toshiba/Kconfig [new file with mode: 0644]
drivers/net/ethernet/toshiba/Makefile [new file with mode: 0644]
drivers/net/ethernet/toshiba/ps3_gelic_net.c [new file with mode: 0644]
drivers/net/ethernet/toshiba/ps3_gelic_net.h [new file with mode: 0644]
drivers/net/ethernet/toshiba/ps3_gelic_wireless.c [new file with mode: 0644]
drivers/net/ethernet/toshiba/ps3_gelic_wireless.h [new file with mode: 0644]
drivers/net/ethernet/toshiba/spider_net.c [new file with mode: 0644]
drivers/net/ethernet/toshiba/spider_net.h [new file with mode: 0644]
drivers/net/ethernet/toshiba/spider_net_ethtool.c [new file with mode: 0644]
drivers/net/ethernet/toshiba/tc35815.c [new file with mode: 0644]
drivers/net/ps3_gelic_net.c [deleted file]
drivers/net/ps3_gelic_net.h [deleted file]
drivers/net/ps3_gelic_wireless.c [deleted file]
drivers/net/ps3_gelic_wireless.h [deleted file]
drivers/net/spider_net.c [deleted file]
drivers/net/spider_net.h [deleted file]
drivers/net/spider_net_ethtool.c [deleted file]
drivers/net/tc35815.c [deleted file]

index 77ca43046b7e1c67e9b03c3b08f26576defc34c6..84948bd44b841af89099837cf76d27c9c83e5c21 100644 (file)
@@ -5127,7 +5127,7 @@ M:        Geoff Levand <geoff@infradead.org>
 L:     netdev@vger.kernel.org
 L:     cbe-oss-dev@lists.ozlabs.org
 S:     Maintained
-F:     drivers/net/ps3_gelic_net.*
+F:     drivers/net/ethernet/toshiba/ps3_gelic_net.*
 
 PS3 PLATFORM SUPPORT
 M:     Geoff Levand <geoff@infradead.org>
@@ -6084,7 +6084,7 @@ M:        Jens Osterkamp <jens@de.ibm.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     Documentation/networking/spider_net.txt
-F:     drivers/net/spider_net*
+F:     drivers/net/ethernet/toshiba/spider_net*
 
 SPU FILE SYSTEM
 M:     Jeremy Kerr <jk@ozlabs.org>
index a6edd3546fe92839ed7cd6d4499e420220510cee..1e1df3d79850fdc32c7e941b552de759deb8a8d6 100644 (file)
@@ -478,11 +478,6 @@ config FORCEDETH
          To compile this driver as a module, choose M here. The module
          will be called forcedeth.
 
-config TC35815
-       tristate "TOSHIBA TC35815 Ethernet support"
-       depends on NET_PCI && PCI && MIPS
-       select PHYLIB
-
 config FEALNX
        tristate "Myson MTD-8xx PCI Ethernet support"
        depends on NET_PCI && PCI
@@ -658,15 +653,6 @@ config SIS190
          To compile this driver as a module, choose M here: the module
          will be called sis190.  This is recommended.
 
-config SPIDER_NET
-       tristate "Spider Gigabit Ethernet driver"
-       depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
-       select FW_LOADER
-       select SUNGEM_PHY
-       help
-         This driver supports the Gigabit Ethernet chips present on the
-         Cell Processor-Based Blades from IBM.
-
 config TSI108_ETH
        tristate "Tundra TSI108 gigabit Ethernet support"
        depends on TSI108_BRIDGE
@@ -675,29 +661,6 @@ config TSI108_ETH
          To compile this driver as a module, choose M here: the module
          will be called tsi108_eth.
 
-config GELIC_NET
-       tristate "PS3 Gigabit Ethernet driver"
-       depends on PPC_PS3
-       select PS3_SYS_MANAGER
-       help
-         This driver supports the network device on the PS3 game
-         console.  This driver has built-in support for Ethernet.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ps3_gelic.
-
-config GELIC_WIRELESS
-       bool "PS3 Wireless support"
-       depends on WLAN
-       depends on GELIC_NET
-       select WIRELESS_EXT
-       help
-         This option adds the support for the wireless feature of PS3.
-         If you have the wireless-less model of PS3 or have no plan to
-         use wireless feature, disabling this option saves memory.  As
-         the driver automatically distinguishes the models, you can
-         safely enable this option even if you have a wireless-less model.
-
 config XILINX_LL_TEMAC
        tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
        depends on PPC || MICROBLAZE
index e448e6ed5918f5ce22b820ef421e151c525b6822..275ed4a548ae0c422f467334a462e66c776901e0 100644 (file)
@@ -29,12 +29,6 @@ obj-$(CONFIG_SIS900) += sis900.o
 obj-$(CONFIG_R6040) += r6040.o
 obj-$(CONFIG_YELLOWFIN) += yellowfin.o
 obj-$(CONFIG_FEALNX) += fealnx.o
-spidernet-y += spider_net.o spider_net_ethtool.o
-obj-$(CONFIG_SPIDER_NET) += spidernet.o
-obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
-gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o
-ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y)
-obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_SKFP) += skfp/
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
 obj-$(CONFIG_RIONET) += rionet.o
index d90f47f3b78287dab12c15c2be780ee12c68b701..97542479c01fb2f2412762cd8659456fcdf10e61 100644 (file)
@@ -48,6 +48,7 @@ source "drivers/net/ethernet/smsc/Kconfig"
 source "drivers/net/ethernet/stmicro/Kconfig"
 source "drivers/net/ethernet/sun/Kconfig"
 source "drivers/net/ethernet/tehuti/Kconfig"
+source "drivers/net/ethernet/toshiba/Kconfig"
 source "drivers/net/ethernet/via/Kconfig"
 
 endif # ETHERNET
index cf27ae0eb3ecea9b80cb59ccb10ecba7cb0513c3..7e7a319e7187b0d945ccbab30aa9fa741c9e8e7c 100644 (file)
@@ -39,4 +39,5 @@ obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
 obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
 obj-$(CONFIG_NET_VENDOR_SUN) += sun/
 obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
+obj-$(CONFIG_NET_VENDOR_TOSHIBA) += toshiba/
 obj-$(CONFIG_NET_VENDOR_VIA) += via/
diff --git a/drivers/net/ethernet/toshiba/Kconfig b/drivers/net/ethernet/toshiba/Kconfig
new file mode 100644 (file)
index 0000000..6ef2ce2
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# Toshiba network device configuration
+#
+
+config NET_VENDOR_TOSHIBA
+       bool "Toshiba devices"
+       depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) || PPC_PS3
+       ---help---
+         If you have a network (Ethernet) card belonging to this class, say Y
+         and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about Toshiba cards. If you say Y, you will be asked
+         for your specific card in the following questions.
+
+if NET_VENDOR_TOSHIBA
+
+config GELIC_NET
+       tristate "PS3 Gigabit Ethernet driver"
+       depends on PPC_PS3
+       select PS3_SYS_MANAGER
+       ---help---
+         This driver supports the network device on the PS3 game
+         console.  This driver has built-in support for Ethernet.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ps3_gelic.
+
+config GELIC_WIRELESS
+       bool "PS3 Wireless support"
+       depends on GELIC_NET && WLAN
+       select WIRELESS_EXT
+       ---help---
+         This option adds the support for the wireless feature of PS3.
+         If you have the wireless-less model of PS3 or have no plan to
+         use wireless feature, disabling this option saves memory.  As
+         the driver automatically distinguishes the models, you can
+         safely enable this option even if you have a wireless-less model.
+
+config SPIDER_NET
+       tristate "Spider Gigabit Ethernet driver"
+       depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
+       select FW_LOADER
+       select SUNGEM_PHY
+       ---help---
+         This driver supports the Gigabit Ethernet chips present on the
+         Cell Processor-Based Blades from IBM.
+
+config TC35815
+       tristate "TOSHIBA TC35815 Ethernet support"
+       depends on PCI && MIPS
+       select PHYLIB
+
+endif # NET_VENDOR_TOSHIBA
diff --git a/drivers/net/ethernet/toshiba/Makefile b/drivers/net/ethernet/toshiba/Makefile
new file mode 100644 (file)
index 0000000..71d861f
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the Toshiba network device drivers.
+#
+
+obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
+gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o
+ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y)
+spidernet-y += spider_net.o spider_net_ethtool.o
+obj-$(CONFIG_SPIDER_NET) += spidernet.o ethernet/sun/sungem_phy.o
+obj-$(CONFIG_TC35815) += tc35815.o
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
new file mode 100644 (file)
index 0000000..d82a82d
--- /dev/null
@@ -0,0 +1,1896 @@
+/*
+ *  PS3 gelic network driver.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This file is based on: spider_net.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+#include <linux/dma-mapping.h>
+#include <net/checksum.h>
+#include <asm/firmware.h>
+#include <asm/ps3.h>
+#include <asm/lv1call.h>
+
+#include "ps3_gelic_net.h"
+#include "ps3_gelic_wireless.h"
+
+#define DRV_NAME "Gelic Network Driver"
+#define DRV_VERSION "2.0"
+
+MODULE_AUTHOR("SCE Inc.");
+MODULE_DESCRIPTION("Gelic Network driver");
+MODULE_LICENSE("GPL");
+
+
+static inline void gelic_card_enable_rxdmac(struct gelic_card *card);
+static inline void gelic_card_disable_rxdmac(struct gelic_card *card);
+static inline void gelic_card_disable_txdmac(struct gelic_card *card);
+static inline void gelic_card_reset_chain(struct gelic_card *card,
+                                         struct gelic_descr_chain *chain,
+                                         struct gelic_descr *start_descr);
+
+/* set irq_mask */
+int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask)
+{
+       int status;
+
+       status = lv1_net_set_interrupt_mask(bus_id(card), dev_id(card),
+                                           mask, 0);
+       if (status)
+               dev_info(ctodev(card),
+                        "%s failed %d\n", __func__, status);
+       return status;
+}
+
+static inline void gelic_card_rx_irq_on(struct gelic_card *card)
+{
+       card->irq_mask |= GELIC_CARD_RXINT;
+       gelic_card_set_irq_mask(card, card->irq_mask);
+}
+static inline void gelic_card_rx_irq_off(struct gelic_card *card)
+{
+       card->irq_mask &= ~GELIC_CARD_RXINT;
+       gelic_card_set_irq_mask(card, card->irq_mask);
+}
+
+static void gelic_card_get_ether_port_status(struct gelic_card *card,
+                                            int inform)
+{
+       u64 v2;
+       struct net_device *ether_netdev;
+
+       lv1_net_control(bus_id(card), dev_id(card),
+                       GELIC_LV1_GET_ETH_PORT_STATUS,
+                       GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0,
+                       &card->ether_port_status, &v2);
+
+       if (inform) {
+               ether_netdev = card->netdev[GELIC_PORT_ETHERNET_0];
+               if (card->ether_port_status & GELIC_LV1_ETHER_LINK_UP)
+                       netif_carrier_on(ether_netdev);
+               else
+                       netif_carrier_off(ether_netdev);
+       }
+}
+
+static int gelic_card_set_link_mode(struct gelic_card *card, int mode)
+{
+       int status;
+       u64 v1, v2;
+
+       status = lv1_net_control(bus_id(card), dev_id(card),
+                                GELIC_LV1_SET_NEGOTIATION_MODE,
+                                GELIC_LV1_PHY_ETHERNET_0, mode, 0, &v1, &v2);
+       if (status) {
+               pr_info("%s: failed setting negotiation mode %d\n", __func__,
+                       status);
+               return -EBUSY;
+       }
+
+       card->link_mode = mode;
+       return 0;
+}
+
+void gelic_card_up(struct gelic_card *card)
+{
+       pr_debug("%s: called\n", __func__);
+       mutex_lock(&card->updown_lock);
+       if (atomic_inc_return(&card->users) == 1) {
+               pr_debug("%s: real do\n", __func__);
+               /* enable irq */
+               gelic_card_set_irq_mask(card, card->irq_mask);
+               /* start rx */
+               gelic_card_enable_rxdmac(card);
+
+               napi_enable(&card->napi);
+       }
+       mutex_unlock(&card->updown_lock);
+       pr_debug("%s: done\n", __func__);
+}
+
+void gelic_card_down(struct gelic_card *card)
+{
+       u64 mask;
+       pr_debug("%s: called\n", __func__);
+       mutex_lock(&card->updown_lock);
+       if (atomic_dec_if_positive(&card->users) == 0) {
+               pr_debug("%s: real do\n", __func__);
+               napi_disable(&card->napi);
+               /*
+                * Disable irq. Wireless interrupts will
+                * be disabled later if any
+                */
+               mask = card->irq_mask & (GELIC_CARD_WLAN_EVENT_RECEIVED |
+                                        GELIC_CARD_WLAN_COMMAND_COMPLETED);
+               gelic_card_set_irq_mask(card, mask);
+               /* stop rx */
+               gelic_card_disable_rxdmac(card);
+               gelic_card_reset_chain(card, &card->rx_chain,
+                                      card->descr + GELIC_NET_TX_DESCRIPTORS);
+               /* stop tx */
+               gelic_card_disable_txdmac(card);
+       }
+       mutex_unlock(&card->updown_lock);
+       pr_debug("%s: done\n", __func__);
+}
+
+/**
+ * gelic_descr_get_status -- returns the status of a descriptor
+ * @descr: descriptor to look at
+ *
+ * returns the status as in the dmac_cmd_status field of the descriptor
+ */
+static enum gelic_descr_dma_status
+gelic_descr_get_status(struct gelic_descr *descr)
+{
+       return be32_to_cpu(descr->dmac_cmd_status) & GELIC_DESCR_DMA_STAT_MASK;
+}
+
+/**
+ * gelic_descr_set_status -- sets the status of a descriptor
+ * @descr: descriptor to change
+ * @status: status to set in the descriptor
+ *
+ * changes the status to the specified value. Doesn't change other bits
+ * in the status
+ */
+static void gelic_descr_set_status(struct gelic_descr *descr,
+                                  enum gelic_descr_dma_status status)
+{
+       descr->dmac_cmd_status = cpu_to_be32(status |
+                       (be32_to_cpu(descr->dmac_cmd_status) &
+                        ~GELIC_DESCR_DMA_STAT_MASK));
+       /*
+        * dma_cmd_status field is used to indicate whether the descriptor
+        * is valid or not.
+        * Usually caller of this function wants to inform that to the
+        * hardware, so we assure here the hardware sees the change.
+        */
+       wmb();
+}
+
+/**
+ * gelic_card_free_chain - free descriptor chain
+ * @card: card structure
+ * @descr_in: address of desc
+ */
+static void gelic_card_free_chain(struct gelic_card *card,
+                                 struct gelic_descr *descr_in)
+{
+       struct gelic_descr *descr;
+
+       for (descr = descr_in; descr && descr->bus_addr; descr = descr->next) {
+               dma_unmap_single(ctodev(card), descr->bus_addr,
+                                GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL);
+               descr->bus_addr = 0;
+       }
+}
+
+/**
+ * gelic_card_init_chain - links descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ * @start_descr: address of descriptor array
+ * @no: number of descriptors
+ *
+ * we manage a circular list that mirrors the hardware structure,
+ * except that the hardware uses bus addresses.
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int __devinit gelic_card_init_chain(struct gelic_card *card,
+                                          struct gelic_descr_chain *chain,
+                                          struct gelic_descr *start_descr,
+                                          int no)
+{
+       int i;
+       struct gelic_descr *descr;
+
+       descr = start_descr;
+       memset(descr, 0, sizeof(*descr) * no);
+
+       /* set up the hardware pointers in each descriptor */
+       for (i = 0; i < no; i++, descr++) {
+               gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
+               descr->bus_addr =
+                       dma_map_single(ctodev(card), descr,
+                                      GELIC_DESCR_SIZE,
+                                      DMA_BIDIRECTIONAL);
+
+               if (!descr->bus_addr)
+                       goto iommu_error;
+
+               descr->next = descr + 1;
+               descr->prev = descr - 1;
+       }
+       /* make them as ring */
+       (descr - 1)->next = start_descr;
+       start_descr->prev = (descr - 1);
+
+       /* chain bus addr of hw descriptor */
+       descr = start_descr;
+       for (i = 0; i < no; i++, descr++) {
+               descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
+       }
+
+       chain->head = start_descr;
+       chain->tail = start_descr;
+
+       /* do not chain last hw descriptor */
+       (descr - 1)->next_descr_addr = 0;
+
+       return 0;
+
+iommu_error:
+       for (i--, descr--; 0 <= i; i--, descr--)
+               if (descr->bus_addr)
+                       dma_unmap_single(ctodev(card), descr->bus_addr,
+                                        GELIC_DESCR_SIZE,
+                                        DMA_BIDIRECTIONAL);
+       return -ENOMEM;
+}
+
+/**
+ * gelic_card_reset_chain - reset status of a descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ * @start_descr: address of descriptor array
+ *
+ * Reset the status of dma descriptors to ready state
+ * and re-initialize the hardware chain for later use
+ */
+static void gelic_card_reset_chain(struct gelic_card *card,
+                                  struct gelic_descr_chain *chain,
+                                  struct gelic_descr *start_descr)
+{
+       struct gelic_descr *descr;
+
+       for (descr = start_descr; start_descr != descr->next; descr++) {
+               gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
+               descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
+       }
+
+       chain->head = start_descr;
+       chain->tail = (descr - 1);
+
+       (descr - 1)->next_descr_addr = 0;
+}
+/**
+ * gelic_descr_prepare_rx - reinitializes a rx descriptor
+ * @card: card structure
+ * @descr: descriptor to re-init
+ *
+ * return 0 on success, <0 on failure
+ *
+ * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
+ * Activate the descriptor state-wise
+ */
+static int gelic_descr_prepare_rx(struct gelic_card *card,
+                                 struct gelic_descr *descr)
+{
+       int offset;
+       unsigned int bufsize;
+
+       if (gelic_descr_get_status(descr) !=  GELIC_DESCR_DMA_NOT_IN_USE)
+               dev_info(ctodev(card), "%s: ERROR status\n", __func__);
+       /* we need to round up the buffer size to a multiple of 128 */
+       bufsize = ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN);
+
+       /* and we need to have it 128 byte aligned, therefore we allocate a
+        * bit more */
+       descr->skb = dev_alloc_skb(bufsize + GELIC_NET_RXBUF_ALIGN - 1);
+       if (!descr->skb) {
+               descr->buf_addr = 0; /* tell DMAC don't touch memory */
+               dev_info(ctodev(card),
+                        "%s:allocate skb failed !!\n", __func__);
+               return -ENOMEM;
+       }
+       descr->buf_size = cpu_to_be32(bufsize);
+       descr->dmac_cmd_status = 0;
+       descr->result_size = 0;
+       descr->valid_size = 0;
+       descr->data_error = 0;
+
+       offset = ((unsigned long)descr->skb->data) &
+               (GELIC_NET_RXBUF_ALIGN - 1);
+       if (offset)
+               skb_reserve(descr->skb, GELIC_NET_RXBUF_ALIGN - offset);
+       /* io-mmu-map the skb */
+       descr->buf_addr = cpu_to_be32(dma_map_single(ctodev(card),
+                                                    descr->skb->data,
+                                                    GELIC_NET_MAX_MTU,
+                                                    DMA_FROM_DEVICE));
+       if (!descr->buf_addr) {
+               dev_kfree_skb_any(descr->skb);
+               descr->skb = NULL;
+               dev_info(ctodev(card),
+                        "%s:Could not iommu-map rx buffer\n", __func__);
+               gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
+               return -ENOMEM;
+       } else {
+               gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
+               return 0;
+       }
+}
+
+/**
+ * gelic_card_release_rx_chain - free all skb of rx descr
+ * @card: card structure
+ *
+ */
+static void gelic_card_release_rx_chain(struct gelic_card *card)
+{
+       struct gelic_descr *descr = card->rx_chain.head;
+
+       do {
+               if (descr->skb) {
+                       dma_unmap_single(ctodev(card),
+                                        be32_to_cpu(descr->buf_addr),
+                                        descr->skb->len,
+                                        DMA_FROM_DEVICE);
+                       descr->buf_addr = 0;
+                       dev_kfree_skb_any(descr->skb);
+                       descr->skb = NULL;
+                       gelic_descr_set_status(descr,
+                                              GELIC_DESCR_DMA_NOT_IN_USE);
+               }
+               descr = descr->next;
+       } while (descr != card->rx_chain.head);
+}
+
+/**
+ * gelic_card_fill_rx_chain - fills descriptors/skbs in the rx chains
+ * @card: card structure
+ *
+ * fills all descriptors in the rx chain: allocates skbs
+ * and iommu-maps them.
+ * returns 0 on success, < 0 on failure
+ */
+static int gelic_card_fill_rx_chain(struct gelic_card *card)
+{
+       struct gelic_descr *descr = card->rx_chain.head;
+       int ret;
+
+       do {
+               if (!descr->skb) {
+                       ret = gelic_descr_prepare_rx(card, descr);
+                       if (ret)
+                               goto rewind;
+               }
+               descr = descr->next;
+       } while (descr != card->rx_chain.head);
+
+       return 0;
+rewind:
+       gelic_card_release_rx_chain(card);
+       return ret;
+}
+
+/**
+ * gelic_card_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * @card: card structure
+ *
+ * returns 0 on success, < 0 on failure
+ */
+static int __devinit gelic_card_alloc_rx_skbs(struct gelic_card *card)
+{
+       struct gelic_descr_chain *chain;
+       int ret;
+       chain = &card->rx_chain;
+       ret = gelic_card_fill_rx_chain(card);
+       chain->tail = card->rx_top->prev; /* point to the last */
+       return ret;
+}
+
+/**
+ * gelic_descr_release_tx - processes a used tx descriptor
+ * @card: card structure
+ * @descr: descriptor to release
+ *
+ * releases a used tx descriptor (unmapping, freeing of skb)
+ */
+static void gelic_descr_release_tx(struct gelic_card *card,
+                                      struct gelic_descr *descr)
+{
+       struct sk_buff *skb = descr->skb;
+
+       BUG_ON(!(be32_to_cpu(descr->data_status) & GELIC_DESCR_TX_TAIL));
+
+       dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr), skb->len,
+                        DMA_TO_DEVICE);
+       dev_kfree_skb_any(skb);
+
+       descr->buf_addr = 0;
+       descr->buf_size = 0;
+       descr->next_descr_addr = 0;
+       descr->result_size = 0;
+       descr->valid_size = 0;
+       descr->data_status = 0;
+       descr->data_error = 0;
+       descr->skb = NULL;
+
+       /* set descr status */
+       gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
+}
+
+static void gelic_card_stop_queues(struct gelic_card *card)
+{
+       netif_stop_queue(card->netdev[GELIC_PORT_ETHERNET_0]);
+
+       if (card->netdev[GELIC_PORT_WIRELESS])
+               netif_stop_queue(card->netdev[GELIC_PORT_WIRELESS]);
+}
+static void gelic_card_wake_queues(struct gelic_card *card)
+{
+       netif_wake_queue(card->netdev[GELIC_PORT_ETHERNET_0]);
+
+       if (card->netdev[GELIC_PORT_WIRELESS])
+               netif_wake_queue(card->netdev[GELIC_PORT_WIRELESS]);
+}
+/**
+ * gelic_card_release_tx_chain - processes sent tx descriptors
+ * @card: adapter structure
+ * @stop: net_stop sequence
+ *
+ * releases the tx descriptors that gelic has finished with
+ */
+static void gelic_card_release_tx_chain(struct gelic_card *card, int stop)
+{
+       struct gelic_descr_chain *tx_chain;
+       enum gelic_descr_dma_status status;
+       struct net_device *netdev;
+       int release = 0;
+
+       for (tx_chain = &card->tx_chain;
+            tx_chain->head != tx_chain->tail && tx_chain->tail;
+            tx_chain->tail = tx_chain->tail->next) {
+               status = gelic_descr_get_status(tx_chain->tail);
+               netdev = tx_chain->tail->skb->dev;
+               switch (status) {
+               case GELIC_DESCR_DMA_RESPONSE_ERROR:
+               case GELIC_DESCR_DMA_PROTECTION_ERROR:
+               case GELIC_DESCR_DMA_FORCE_END:
+                       if (printk_ratelimit())
+                               dev_info(ctodev(card),
+                                        "%s: forcing end of tx descriptor " \
+                                        "with status %x\n",
+                                        __func__, status);
+                       netdev->stats.tx_dropped++;
+                       break;
+
+               case GELIC_DESCR_DMA_COMPLETE:
+                       if (tx_chain->tail->skb) {
+                               netdev->stats.tx_packets++;
+                               netdev->stats.tx_bytes +=
+                                       tx_chain->tail->skb->len;
+                       }
+                       break;
+
+               case GELIC_DESCR_DMA_CARDOWNED:
+                       /* pending tx request */
+               default:
+                       /* any other value (== GELIC_DESCR_DMA_NOT_IN_USE) */
+                       if (!stop)
+                               goto out;
+               }
+               gelic_descr_release_tx(card, tx_chain->tail);
+               release ++;
+       }
+out:
+       if (!stop && release)
+               gelic_card_wake_queues(card);
+}
+
+/**
+ * gelic_net_set_multi - sets multicast addresses and promisc flags
+ * @netdev: interface device structure
+ *
+ * gelic_net_set_multi configures multicast addresses as needed for the
+ * netdev interface. It also sets up multicast, allmulti and promisc
+ * flags appropriately
+ */
+void gelic_net_set_multi(struct net_device *netdev)
+{
+       struct gelic_card *card = netdev_card(netdev);
+       struct netdev_hw_addr *ha;
+       unsigned int i;
+       uint8_t *p;
+       u64 addr;
+       int status;
+
+       /* clear all multicast address */
+       status = lv1_net_remove_multicast_address(bus_id(card), dev_id(card),
+                                                 0, 1);
+       if (status)
+               dev_err(ctodev(card),
+                       "lv1_net_remove_multicast_address failed %d\n",
+                       status);
+       /* set broadcast address */
+       status = lv1_net_add_multicast_address(bus_id(card), dev_id(card),
+                                              GELIC_NET_BROADCAST_ADDR, 0);
+       if (status)
+               dev_err(ctodev(card),
+                       "lv1_net_add_multicast_address failed, %d\n",
+                       status);
+
+       if ((netdev->flags & IFF_ALLMULTI) ||
+           (netdev_mc_count(netdev) > GELIC_NET_MC_COUNT_MAX)) {
+               status = lv1_net_add_multicast_address(bus_id(card),
+                                                      dev_id(card),
+                                                      0, 1);
+               if (status)
+                       dev_err(ctodev(card),
+                               "lv1_net_add_multicast_address failed, %d\n",
+                               status);
+               return;
+       }
+
+       /* set multicast addresses */
+       netdev_for_each_mc_addr(ha, netdev) {
+               addr = 0;
+               p = ha->addr;
+               for (i = 0; i < ETH_ALEN; i++) {
+                       addr <<= 8;
+                       addr |= *p++;
+               }
+               status = lv1_net_add_multicast_address(bus_id(card),
+                                                      dev_id(card),
+                                                      addr, 0);
+               if (status)
+                       dev_err(ctodev(card),
+                               "lv1_net_add_multicast_address failed, %d\n",
+                               status);
+       }
+}
+
+/**
+ * gelic_card_enable_rxdmac - enables the receive DMA controller
+ * @card: card structure
+ *
+ * gelic_card_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
+ * in the GDADMACCNTR register
+ */
+static inline void gelic_card_enable_rxdmac(struct gelic_card *card)
+{
+       int status;
+
+#ifdef DEBUG
+       if (gelic_descr_get_status(card->rx_chain.head) !=
+           GELIC_DESCR_DMA_CARDOWNED) {
+               printk(KERN_ERR "%s: status=%x\n", __func__,
+                      be32_to_cpu(card->rx_chain.head->dmac_cmd_status));
+               printk(KERN_ERR "%s: nextphy=%x\n", __func__,
+                      be32_to_cpu(card->rx_chain.head->next_descr_addr));
+               printk(KERN_ERR "%s: head=%p\n", __func__,
+                      card->rx_chain.head);
+       }
+#endif
+       status = lv1_net_start_rx_dma(bus_id(card), dev_id(card),
+                               card->rx_chain.head->bus_addr, 0);
+       if (status)
+               dev_info(ctodev(card),
+                        "lv1_net_start_rx_dma failed, status=%d\n", status);
+}
+
+/**
+ * gelic_card_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * gelic_card_disable_rxdmac terminates processing on the DMA controller by
+ * turing off DMA and issuing a force end
+ */
+static inline void gelic_card_disable_rxdmac(struct gelic_card *card)
+{
+       int status;
+
+       /* this hvc blocks until the DMA in progress really stopped */
+       status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card), 0);
+       if (status)
+               dev_err(ctodev(card),
+                       "lv1_net_stop_rx_dma failed, %d\n", status);
+}
+
+/**
+ * gelic_card_disable_txdmac - disables the transmit DMA controller
+ * @card: card structure
+ *
+ * gelic_card_disable_txdmac terminates processing on the DMA controller by
+ * turing off DMA and issuing a force end
+ */
+static inline void gelic_card_disable_txdmac(struct gelic_card *card)
+{
+       int status;
+
+       /* this hvc blocks until the DMA in progress really stopped */
+       status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card), 0);
+       if (status)
+               dev_err(ctodev(card),
+                       "lv1_net_stop_tx_dma failed, status=%d\n", status);
+}
+
+/**
+ * gelic_net_stop - called upon ifconfig down
+ * @netdev: interface device structure
+ *
+ * always returns 0
+ */
+int gelic_net_stop(struct net_device *netdev)
+{
+       struct gelic_card *card;
+
+       pr_debug("%s: start\n", __func__);
+
+       netif_stop_queue(netdev);
+       netif_carrier_off(netdev);
+
+       card = netdev_card(netdev);
+       gelic_card_down(card);
+
+       pr_debug("%s: done\n", __func__);
+       return 0;
+}
+
+/**
+ * gelic_card_get_next_tx_descr - returns the next available tx descriptor
+ * @card: device structure to get descriptor from
+ *
+ * returns the address of the next descriptor, or NULL if not available.
+ */
+static struct gelic_descr *
+gelic_card_get_next_tx_descr(struct gelic_card *card)
+{
+       if (!card->tx_chain.head)
+               return NULL;
+       /*  see if the next descriptor is free */
+       if (card->tx_chain.tail != card->tx_chain.head->next &&
+           gelic_descr_get_status(card->tx_chain.head) ==
+           GELIC_DESCR_DMA_NOT_IN_USE)
+               return card->tx_chain.head;
+       else
+               return NULL;
+
+}
+
+/**
+ * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
+ * @descr: descriptor structure to fill out
+ * @skb: packet to consider
+ *
+ * fills out the command and status field of the descriptor structure,
+ * depending on hardware checksum settings. This function assumes a wmb()
+ * has executed before.
+ */
+static void gelic_descr_set_tx_cmdstat(struct gelic_descr *descr,
+                                      struct sk_buff *skb)
+{
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               descr->dmac_cmd_status =
+                       cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM |
+                                   GELIC_DESCR_TX_DMA_FRAME_TAIL);
+       else {
+               /* is packet ip?
+                * if yes: tcp? udp? */
+               if (skb->protocol == htons(ETH_P_IP)) {
+                       if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+                               descr->dmac_cmd_status =
+                               cpu_to_be32(GELIC_DESCR_DMA_CMD_TCP_CHKSUM |
+                                           GELIC_DESCR_TX_DMA_FRAME_TAIL);
+
+                       else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
+                               descr->dmac_cmd_status =
+                               cpu_to_be32(GELIC_DESCR_DMA_CMD_UDP_CHKSUM |
+                                           GELIC_DESCR_TX_DMA_FRAME_TAIL);
+                       else    /*
+                                * the stack should checksum non-tcp and non-udp
+                                * packets on his own: NETIF_F_IP_CSUM
+                                */
+                               descr->dmac_cmd_status =
+                               cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM |
+                                           GELIC_DESCR_TX_DMA_FRAME_TAIL);
+               }
+       }
+}
+
+static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
+                                                unsigned short tag)
+{
+       struct vlan_ethhdr *veth;
+       static unsigned int c;
+
+       if (skb_headroom(skb) < VLAN_HLEN) {
+               struct sk_buff *sk_tmp = skb;
+               pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c);
+               skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
+               if (!skb)
+                       return NULL;
+               dev_kfree_skb_any(sk_tmp);
+       }
+       veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
+
+       /* Move the mac addresses to the top of buffer */
+       memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+
+       veth->h_vlan_proto = cpu_to_be16(ETH_P_8021Q);
+       veth->h_vlan_TCI = htons(tag);
+
+       return skb;
+}
+
+/**
+ * gelic_descr_prepare_tx - setup a descriptor for sending packets
+ * @card: card structure
+ * @descr: descriptor structure
+ * @skb: packet to use
+ *
+ * returns 0 on success, <0 on failure.
+ *
+ */
+static int gelic_descr_prepare_tx(struct gelic_card *card,
+                                 struct gelic_descr *descr,
+                                 struct sk_buff *skb)
+{
+       dma_addr_t buf;
+
+       if (card->vlan_required) {
+               struct sk_buff *skb_tmp;
+               enum gelic_port_type type;
+
+               type = netdev_port(skb->dev)->type;
+               skb_tmp = gelic_put_vlan_tag(skb,
+                                            card->vlan[type].tx);
+               if (!skb_tmp)
+                       return -ENOMEM;
+               skb = skb_tmp;
+       }
+
+       buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE);
+
+       if (!buf) {
+               dev_err(ctodev(card),
+                       "dma map 2 failed (%p, %i). Dropping packet\n",
+                       skb->data, skb->len);
+               return -ENOMEM;
+       }
+
+       descr->buf_addr = cpu_to_be32(buf);
+       descr->buf_size = cpu_to_be32(skb->len);
+       descr->skb = skb;
+       descr->data_status = 0;
+       descr->next_descr_addr = 0; /* terminate hw descr */
+       gelic_descr_set_tx_cmdstat(descr, skb);
+
+       /* bump free descriptor pointer */
+       card->tx_chain.head = descr->next;
+       return 0;
+}
+
+/**
+ * gelic_card_kick_txdma - enables TX DMA processing
+ * @card: card structure
+ * @descr: descriptor address to enable TX processing at
+ *
+ */
+static int gelic_card_kick_txdma(struct gelic_card *card,
+                                struct gelic_descr *descr)
+{
+       int status = 0;
+
+       if (card->tx_dma_progress)
+               return 0;
+
+       if (gelic_descr_get_status(descr) == GELIC_DESCR_DMA_CARDOWNED) {
+               card->tx_dma_progress = 1;
+               status = lv1_net_start_tx_dma(bus_id(card), dev_id(card),
+                                             descr->bus_addr, 0);
+               if (status) {
+                       card->tx_dma_progress = 0;
+                       dev_info(ctodev(card), "lv1_net_start_txdma failed," \
+                                "status=%d\n", status);
+               }
+       }
+       return status;
+}
+
+/**
+ * gelic_net_xmit - transmits a frame over the device
+ * @skb: packet to send out
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct gelic_card *card = netdev_card(netdev);
+       struct gelic_descr *descr;
+       int result;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->tx_lock, flags);
+
+       gelic_card_release_tx_chain(card, 0);
+
+       descr = gelic_card_get_next_tx_descr(card);
+       if (!descr) {
+               /*
+                * no more descriptors free
+                */
+               gelic_card_stop_queues(card);
+               spin_unlock_irqrestore(&card->tx_lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+
+       result = gelic_descr_prepare_tx(card, descr, skb);
+       if (result) {
+               /*
+                * DMA map failed.  As chances are that failure
+                * would continue, just release skb and return
+                */
+               netdev->stats.tx_dropped++;
+               dev_kfree_skb_any(skb);
+               spin_unlock_irqrestore(&card->tx_lock, flags);
+               return NETDEV_TX_OK;
+       }
+       /*
+        * link this prepared descriptor to previous one
+        * to achieve high performance
+        */
+       descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
+       /*
+        * as hardware descriptor is modified in the above lines,
+        * ensure that the hardware sees it
+        */
+       wmb();
+       if (gelic_card_kick_txdma(card, descr)) {
+               /*
+                * kick failed.
+                * release descriptor which was just prepared
+                */
+               netdev->stats.tx_dropped++;
+               /* don't trigger BUG_ON() in gelic_descr_release_tx */
+               descr->data_status = cpu_to_be32(GELIC_DESCR_TX_TAIL);
+               gelic_descr_release_tx(card, descr);
+               /* reset head */
+               card->tx_chain.head = descr;
+               /* reset hw termination */
+               descr->prev->next_descr_addr = 0;
+               dev_info(ctodev(card), "%s: kick failure\n", __func__);
+       }
+
+       spin_unlock_irqrestore(&card->tx_lock, flags);
+       return NETDEV_TX_OK;
+}
+
+/**
+ * gelic_net_pass_skb_up - takes an skb from a descriptor and passes it on
+ * @descr: descriptor to process
+ * @card: card structure
+ * @netdev: net_device structure to be passed packet
+ *
+ * iommu-unmaps the skb, fills out skb structure and passes the data to the
+ * stack. The descriptor state is not changed.
+ */
+static void gelic_net_pass_skb_up(struct gelic_descr *descr,
+                                 struct gelic_card *card,
+                                 struct net_device *netdev)
+
+{
+       struct sk_buff *skb = descr->skb;
+       u32 data_status, data_error;
+
+       data_status = be32_to_cpu(descr->data_status);
+       data_error = be32_to_cpu(descr->data_error);
+       /* unmap skb buffer */
+       dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr),
+                        GELIC_NET_MAX_MTU,
+                        DMA_FROM_DEVICE);
+
+       skb_put(skb, be32_to_cpu(descr->valid_size)?
+               be32_to_cpu(descr->valid_size) :
+               be32_to_cpu(descr->result_size));
+       if (!descr->valid_size)
+               dev_info(ctodev(card), "buffer full %x %x %x\n",
+                        be32_to_cpu(descr->result_size),
+                        be32_to_cpu(descr->buf_size),
+                        be32_to_cpu(descr->dmac_cmd_status));
+
+       descr->skb = NULL;
+       /*
+        * the card put 2 bytes vlan tag in front
+        * of the ethernet frame
+        */
+       skb_pull(skb, 2);
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       /* checksum offload */
+       if (netdev->features & NETIF_F_RXCSUM) {
+               if ((data_status & GELIC_DESCR_DATA_STATUS_CHK_MASK) &&
+                   (!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK)))
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb_checksum_none_assert(skb);
+       } else
+               skb_checksum_none_assert(skb);
+
+       /* update netdevice statistics */
+       netdev->stats.rx_packets++;
+       netdev->stats.rx_bytes += skb->len;
+
+       /* pass skb up to stack */
+       netif_receive_skb(skb);
+}
+
+/**
+ * gelic_card_decode_one_descr - processes an rx descriptor
+ * @card: card structure
+ *
+ * returns 1 if a packet has been sent to the stack, otherwise 0
+ *
+ * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * the packet up to the stack
+ */
+static int gelic_card_decode_one_descr(struct gelic_card *card)
+{
+       enum gelic_descr_dma_status status;
+       struct gelic_descr_chain *chain = &card->rx_chain;
+       struct gelic_descr *descr = chain->head;
+       struct net_device *netdev = NULL;
+       int dmac_chain_ended;
+
+       status = gelic_descr_get_status(descr);
+
+       if (status == GELIC_DESCR_DMA_CARDOWNED)
+               return 0;
+
+       if (status == GELIC_DESCR_DMA_NOT_IN_USE) {
+               dev_dbg(ctodev(card), "dormant descr? %p\n", descr);
+               return 0;
+       }
+
+       /* netdevice select */
+       if (card->vlan_required) {
+               unsigned int i;
+               u16 vid;
+               vid = *(u16 *)(descr->skb->data) & VLAN_VID_MASK;
+               for (i = 0; i < GELIC_PORT_MAX; i++) {
+                       if (card->vlan[i].rx == vid) {
+                               netdev = card->netdev[i];
+                               break;
+                       }
+               }
+               if (GELIC_PORT_MAX <= i) {
+                       pr_info("%s: unknown packet vid=%x\n", __func__, vid);
+                       goto refill;
+               }
+       } else
+               netdev = card->netdev[GELIC_PORT_ETHERNET_0];
+
+       if ((status == GELIC_DESCR_DMA_RESPONSE_ERROR) ||
+           (status == GELIC_DESCR_DMA_PROTECTION_ERROR) ||
+           (status == GELIC_DESCR_DMA_FORCE_END)) {
+               dev_info(ctodev(card), "dropping RX descriptor with state %x\n",
+                        status);
+               netdev->stats.rx_dropped++;
+               goto refill;
+       }
+
+       if (status == GELIC_DESCR_DMA_BUFFER_FULL) {
+               /*
+                * Buffer full would occur if and only if
+                * the frame length was longer than the size of this
+                * descriptor's buffer.  If the frame length was equal
+                * to or shorter than buffer'size, FRAME_END condition
+                * would occur.
+                * Anyway this frame was longer than the MTU,
+                * just drop it.
+                */
+               dev_info(ctodev(card), "overlength frame\n");
+               goto refill;
+       }
+       /*
+        * descriptors any other than FRAME_END here should
+        * be treated as error.
+        */
+       if (status != GELIC_DESCR_DMA_FRAME_END) {
+               dev_dbg(ctodev(card), "RX descriptor with state %x\n",
+                       status);
+               goto refill;
+       }
+
+       /* ok, we've got a packet in descr */
+       gelic_net_pass_skb_up(descr, card, netdev);
+refill:
+
+       /* is the current descriptor terminated with next_descr == NULL? */
+       dmac_chain_ended =
+               be32_to_cpu(descr->dmac_cmd_status) &
+               GELIC_DESCR_RX_DMA_CHAIN_END;
+       /*
+        * So that always DMAC can see the end
+        * of the descriptor chain to avoid
+        * from unwanted DMAC overrun.
+        */
+       descr->next_descr_addr = 0;
+
+       /* change the descriptor state: */
+       gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
+
+       /*
+        * this call can fail, but for now, just leave this
+        * decriptor without skb
+        */
+       gelic_descr_prepare_rx(card, descr);
+
+       chain->tail = descr;
+       chain->head = descr->next;
+
+       /*
+        * Set this descriptor the end of the chain.
+        */
+       descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
+
+       /*
+        * If dmac chain was met, DMAC stopped.
+        * thus re-enable it
+        */
+
+       if (dmac_chain_ended)
+               gelic_card_enable_rxdmac(card);
+
+       return 1;
+}
+
+/**
+ * gelic_net_poll - NAPI poll function called by the stack to return packets
+ * @napi: napi structure
+ * @budget: number of packets we can pass to the stack at most
+ *
+ * returns the number of the processed packets
+ *
+ */
+static int gelic_net_poll(struct napi_struct *napi, int budget)
+{
+       struct gelic_card *card = container_of(napi, struct gelic_card, napi);
+       int packets_done = 0;
+
+       while (packets_done < budget) {
+               if (!gelic_card_decode_one_descr(card))
+                       break;
+
+               packets_done++;
+       }
+
+       if (packets_done < budget) {
+               napi_complete(napi);
+               gelic_card_rx_irq_on(card);
+       }
+       return packets_done;
+}
+/**
+ * gelic_net_change_mtu - changes the MTU of an interface
+ * @netdev: interface device structure
+ * @new_mtu: new MTU value
+ *
+ * returns 0 on success, <0 on failure
+ */
+int gelic_net_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       /* no need to re-alloc skbs or so -- the max mtu is about 2.3k
+        * and mtu is outbound only anyway */
+       if ((new_mtu < GELIC_NET_MIN_MTU) ||
+           (new_mtu > GELIC_NET_MAX_MTU)) {
+               return -EINVAL;
+       }
+       netdev->mtu = new_mtu;
+       return 0;
+}
+
+/**
+ * gelic_card_interrupt - event handler for gelic_net
+ */
+static irqreturn_t gelic_card_interrupt(int irq, void *ptr)
+{
+       unsigned long flags;
+       struct gelic_card *card = ptr;
+       u64 status;
+
+       status = card->irq_status;
+
+       if (!status)
+               return IRQ_NONE;
+
+       status &= card->irq_mask;
+
+       if (status & GELIC_CARD_RXINT) {
+               gelic_card_rx_irq_off(card);
+               napi_schedule(&card->napi);
+       }
+
+       if (status & GELIC_CARD_TXINT) {
+               spin_lock_irqsave(&card->tx_lock, flags);
+               card->tx_dma_progress = 0;
+               gelic_card_release_tx_chain(card, 0);
+               /* kick outstanding tx descriptor if any */
+               gelic_card_kick_txdma(card, card->tx_chain.tail);
+               spin_unlock_irqrestore(&card->tx_lock, flags);
+       }
+
+       /* ether port status changed */
+       if (status & GELIC_CARD_PORT_STATUS_CHANGED)
+               gelic_card_get_ether_port_status(card, 1);
+
+#ifdef CONFIG_GELIC_WIRELESS
+       if (status & (GELIC_CARD_WLAN_EVENT_RECEIVED |
+                     GELIC_CARD_WLAN_COMMAND_COMPLETED))
+               gelic_wl_interrupt(card->netdev[GELIC_PORT_WIRELESS], status);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * gelic_net_poll_controller - artificial interrupt for netconsole etc.
+ * @netdev: interface device structure
+ *
+ * see Documentation/networking/netconsole.txt
+ */
+void gelic_net_poll_controller(struct net_device *netdev)
+{
+       struct gelic_card *card = netdev_card(netdev);
+
+       gelic_card_set_irq_mask(card, 0);
+       gelic_card_interrupt(netdev->irq, netdev);
+       gelic_card_set_irq_mask(card, card->irq_mask);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+/**
+ * gelic_net_open - called upon ifconfig up
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * gelic_net_open allocates all the descriptors and memory needed for
+ * operation, sets up multicast list and enables interrupts
+ */
+int gelic_net_open(struct net_device *netdev)
+{
+       struct gelic_card *card = netdev_card(netdev);
+
+       dev_dbg(ctodev(card), " -> %s %p\n", __func__, netdev);
+
+       gelic_card_up(card);
+
+       netif_start_queue(netdev);
+       gelic_card_get_ether_port_status(card, 1);
+
+       dev_dbg(ctodev(card), " <- %s\n", __func__);
+       return 0;
+}
+
+void gelic_net_get_drvinfo(struct net_device *netdev,
+                          struct ethtool_drvinfo *info)
+{
+       strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
+       strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+}
+
+static int gelic_ether_get_settings(struct net_device *netdev,
+                                   struct ethtool_cmd *cmd)
+{
+       struct gelic_card *card = netdev_card(netdev);
+
+       gelic_card_get_ether_port_status(card, 0);
+
+       if (card->ether_port_status & GELIC_LV1_ETHER_FULL_DUPLEX)
+               cmd->duplex = DUPLEX_FULL;
+       else
+               cmd->duplex = DUPLEX_HALF;
+
+       switch (card->ether_port_status & GELIC_LV1_ETHER_SPEED_MASK) {
+       case GELIC_LV1_ETHER_SPEED_10:
+               ethtool_cmd_speed_set(cmd, SPEED_10);
+               break;
+       case GELIC_LV1_ETHER_SPEED_100:
+               ethtool_cmd_speed_set(cmd, SPEED_100);
+               break;
+       case GELIC_LV1_ETHER_SPEED_1000:
+               ethtool_cmd_speed_set(cmd, SPEED_1000);
+               break;
+       default:
+               pr_info("%s: speed unknown\n", __func__);
+               ethtool_cmd_speed_set(cmd, SPEED_10);
+               break;
+       }
+
+       cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg |
+                       SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+                       SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+                       SUPPORTED_1000baseT_Full;
+       cmd->advertising = cmd->supported;
+       if (card->link_mode & GELIC_LV1_ETHER_AUTO_NEG) {
+               cmd->autoneg = AUTONEG_ENABLE;
+       } else {
+               cmd->autoneg = AUTONEG_DISABLE;
+               cmd->advertising &= ~ADVERTISED_Autoneg;
+       }
+       cmd->port = PORT_TP;
+
+       return 0;
+}
+
+static int gelic_ether_set_settings(struct net_device *netdev,
+                                   struct ethtool_cmd *cmd)
+{
+       struct gelic_card *card = netdev_card(netdev);
+       u64 mode;
+       int ret;
+
+       if (cmd->autoneg == AUTONEG_ENABLE) {
+               mode = GELIC_LV1_ETHER_AUTO_NEG;
+       } else {
+               switch (cmd->speed) {
+               case SPEED_10:
+                       mode = GELIC_LV1_ETHER_SPEED_10;
+                       break;
+               case SPEED_100:
+                       mode = GELIC_LV1_ETHER_SPEED_100;
+                       break;
+               case SPEED_1000:
+                       mode = GELIC_LV1_ETHER_SPEED_1000;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               if (cmd->duplex == DUPLEX_FULL)
+                       mode |= GELIC_LV1_ETHER_FULL_DUPLEX;
+               else if (cmd->speed == SPEED_1000) {
+                       pr_info("1000 half duplex is not supported.\n");
+                       return -EINVAL;
+               }
+       }
+
+       ret = gelic_card_set_link_mode(card, mode);
+
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void gelic_net_get_wol(struct net_device *netdev,
+                             struct ethtool_wolinfo *wol)
+{
+       if (0 <= ps3_compare_firmware_version(2, 2, 0))
+               wol->supported = WAKE_MAGIC;
+       else
+               wol->supported = 0;
+
+       wol->wolopts = ps3_sys_manager_get_wol() ? wol->supported : 0;
+       memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+static int gelic_net_set_wol(struct net_device *netdev,
+                            struct ethtool_wolinfo *wol)
+{
+       int status;
+       struct gelic_card *card;
+       u64 v1, v2;
+
+       if (ps3_compare_firmware_version(2, 2, 0) < 0 ||
+           !capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (wol->wolopts & ~WAKE_MAGIC)
+               return -EINVAL;
+
+       card = netdev_card(netdev);
+       if (wol->wolopts & WAKE_MAGIC) {
+               status = lv1_net_control(bus_id(card), dev_id(card),
+                                        GELIC_LV1_SET_WOL,
+                                        GELIC_LV1_WOL_MAGIC_PACKET,
+                                        0, GELIC_LV1_WOL_MP_ENABLE,
+                                        &v1, &v2);
+               if (status) {
+                       pr_info("%s: enabling WOL failed %d\n", __func__,
+                               status);
+                       status = -EIO;
+                       goto done;
+               }
+               status = lv1_net_control(bus_id(card), dev_id(card),
+                                        GELIC_LV1_SET_WOL,
+                                        GELIC_LV1_WOL_ADD_MATCH_ADDR,
+                                        0, GELIC_LV1_WOL_MATCH_ALL,
+                                        &v1, &v2);
+               if (!status)
+                       ps3_sys_manager_set_wol(1);
+               else {
+                       pr_info("%s: enabling WOL filter failed %d\n",
+                               __func__, status);
+                       status = -EIO;
+               }
+       } else {
+               status = lv1_net_control(bus_id(card), dev_id(card),
+                                        GELIC_LV1_SET_WOL,
+                                        GELIC_LV1_WOL_MAGIC_PACKET,
+                                        0, GELIC_LV1_WOL_MP_DISABLE,
+                                        &v1, &v2);
+               if (status) {
+                       pr_info("%s: disabling WOL failed %d\n", __func__,
+                               status);
+                       status = -EIO;
+                       goto done;
+               }
+               status = lv1_net_control(bus_id(card), dev_id(card),
+                                        GELIC_LV1_SET_WOL,
+                                        GELIC_LV1_WOL_DELETE_MATCH_ADDR,
+                                        0, GELIC_LV1_WOL_MATCH_ALL,
+                                        &v1, &v2);
+               if (!status)
+                       ps3_sys_manager_set_wol(0);
+               else {
+                       pr_info("%s: removing WOL filter failed %d\n",
+                               __func__, status);
+                       status = -EIO;
+               }
+       }
+done:
+       return status;
+}
+
+static const struct ethtool_ops gelic_ether_ethtool_ops = {
+       .get_drvinfo    = gelic_net_get_drvinfo,
+       .get_settings   = gelic_ether_get_settings,
+       .set_settings   = gelic_ether_set_settings,
+       .get_link       = ethtool_op_get_link,
+       .get_wol        = gelic_net_get_wol,
+       .set_wol        = gelic_net_set_wol,
+};
+
+/**
+ * gelic_net_tx_timeout_task - task scheduled by the watchdog timeout
+ * function (to be called not under interrupt status)
+ * @work: work is context of tx timout task
+ *
+ * called as task when tx hangs, resets interface (if interface is up)
+ */
+static void gelic_net_tx_timeout_task(struct work_struct *work)
+{
+       struct gelic_card *card =
+               container_of(work, struct gelic_card, tx_timeout_task);
+       struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET_0];
+
+       dev_info(ctodev(card), "%s:Timed out. Restarting...\n", __func__);
+
+       if (!(netdev->flags & IFF_UP))
+               goto out;
+
+       netif_device_detach(netdev);
+       gelic_net_stop(netdev);
+
+       gelic_net_open(netdev);
+       netif_device_attach(netdev);
+
+out:
+       atomic_dec(&card->tx_timeout_task_counter);
+}
+
+/**
+ * gelic_net_tx_timeout - called when the tx timeout watchdog kicks in.
+ * @netdev: interface device structure
+ *
+ * called, if tx hangs. Schedules a task that resets the interface
+ */
+void gelic_net_tx_timeout(struct net_device *netdev)
+{
+       struct gelic_card *card;
+
+       card = netdev_card(netdev);
+       atomic_inc(&card->tx_timeout_task_counter);
+       if (netdev->flags & IFF_UP)
+               schedule_work(&card->tx_timeout_task);
+       else
+               atomic_dec(&card->tx_timeout_task_counter);
+}
+
+static const struct net_device_ops gelic_netdevice_ops = {
+       .ndo_open = gelic_net_open,
+       .ndo_stop = gelic_net_stop,
+       .ndo_start_xmit = gelic_net_xmit,
+       .ndo_set_multicast_list = gelic_net_set_multi,
+       .ndo_change_mtu = gelic_net_change_mtu,
+       .ndo_tx_timeout = gelic_net_tx_timeout,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = gelic_net_poll_controller,
+#endif
+};
+
+/**
+ * gelic_ether_setup_netdev_ops - initialization of net_device operations
+ * @netdev: net_device structure
+ *
+ * fills out function pointers in the net_device structure
+ */
+static void __devinit gelic_ether_setup_netdev_ops(struct net_device *netdev,
+                                                  struct napi_struct *napi)
+{
+       netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
+       /* NAPI */
+       netif_napi_add(netdev, napi,
+                      gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
+       netdev->ethtool_ops = &gelic_ether_ethtool_ops;
+       netdev->netdev_ops = &gelic_netdevice_ops;
+}
+
+/**
+ * gelic_ether_setup_netdev - initialization of net_device
+ * @netdev: net_device structure
+ * @card: card structure
+ *
+ * Returns 0 on success or <0 on failure
+ *
+ * gelic_ether_setup_netdev initializes the net_device structure
+ * and register it.
+ **/
+int __devinit gelic_net_setup_netdev(struct net_device *netdev,
+                                    struct gelic_card *card)
+{
+       int status;
+       u64 v1, v2;
+
+       netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+
+       netdev->features = NETIF_F_IP_CSUM;
+       if (GELIC_CARD_RX_CSUM_DEFAULT)
+               netdev->features |= NETIF_F_RXCSUM;
+
+       status = lv1_net_control(bus_id(card), dev_id(card),
+                                GELIC_LV1_GET_MAC_ADDRESS,
+                                0, 0, 0, &v1, &v2);
+       v1 <<= 16;
+       if (status || !is_valid_ether_addr((u8 *)&v1)) {
+               dev_info(ctodev(card),
+                        "%s:lv1_net_control GET_MAC_ADDR failed %d\n",
+                        __func__, status);
+               return -EINVAL;
+       }
+       memcpy(netdev->dev_addr, &v1, ETH_ALEN);
+
+       if (card->vlan_required) {
+               netdev->hard_header_len += VLAN_HLEN;
+               /*
+                * As vlan is internally used,
+                * we can not receive vlan packets
+                */
+               netdev->features |= NETIF_F_VLAN_CHALLENGED;
+       }
+
+       status = register_netdev(netdev);
+       if (status) {
+               dev_err(ctodev(card), "%s:Couldn't register %s %d\n",
+                       __func__, netdev->name, status);
+               return status;
+       }
+       dev_info(ctodev(card), "%s: MAC addr %pM\n",
+                netdev->name, netdev->dev_addr);
+
+       return 0;
+}
+
+/**
+ * gelic_alloc_card_net - allocates net_device and card structure
+ *
+ * returns the card structure or NULL in case of errors
+ *
+ * the card and net_device structures are linked to each other
+ */
+#define GELIC_ALIGN (32)
+static struct gelic_card * __devinit gelic_alloc_card_net(struct net_device **netdev)
+{
+       struct gelic_card *card;
+       struct gelic_port *port;
+       void *p;
+       size_t alloc_size;
+       /*
+        * gelic requires dma descriptor is 32 bytes aligned and
+        * the hypervisor requires irq_status is 8 bytes aligned.
+        */
+       BUILD_BUG_ON(offsetof(struct gelic_card, irq_status) % 8);
+       BUILD_BUG_ON(offsetof(struct gelic_card, descr) % 32);
+       alloc_size =
+               sizeof(struct gelic_card) +
+               sizeof(struct gelic_descr) * GELIC_NET_RX_DESCRIPTORS +
+               sizeof(struct gelic_descr) * GELIC_NET_TX_DESCRIPTORS +
+               GELIC_ALIGN - 1;
+
+       p  = kzalloc(alloc_size, GFP_KERNEL);
+       if (!p)
+               return NULL;
+       card = PTR_ALIGN(p, GELIC_ALIGN);
+       card->unalign = p;
+
+       /*
+        * alloc netdev
+        */
+       *netdev = alloc_etherdev(sizeof(struct gelic_port));
+       if (!netdev) {
+               kfree(card->unalign);
+               return NULL;
+       }
+       port = netdev_priv(*netdev);
+
+       /* gelic_port */
+       port->netdev = *netdev;
+       port->card = card;
+       port->type = GELIC_PORT_ETHERNET_0;
+
+       /* gelic_card */
+       card->netdev[GELIC_PORT_ETHERNET_0] = *netdev;
+
+       INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
+       init_waitqueue_head(&card->waitq);
+       atomic_set(&card->tx_timeout_task_counter, 0);
+       mutex_init(&card->updown_lock);
+       atomic_set(&card->users, 0);
+
+       return card;
+}
+
+static void __devinit gelic_card_get_vlan_info(struct gelic_card *card)
+{
+       u64 v1, v2;
+       int status;
+       unsigned int i;
+       struct {
+               int tx;
+               int rx;
+       } vlan_id_ix[2] = {
+               [GELIC_PORT_ETHERNET_0] = {
+                       .tx = GELIC_LV1_VLAN_TX_ETHERNET_0,
+                       .rx = GELIC_LV1_VLAN_RX_ETHERNET_0
+               },
+               [GELIC_PORT_WIRELESS] = {
+                       .tx = GELIC_LV1_VLAN_TX_WIRELESS,
+                       .rx = GELIC_LV1_VLAN_RX_WIRELESS
+               }
+       };
+
+       for (i = 0; i < ARRAY_SIZE(vlan_id_ix); i++) {
+               /* tx tag */
+               status = lv1_net_control(bus_id(card), dev_id(card),
+                                        GELIC_LV1_GET_VLAN_ID,
+                                        vlan_id_ix[i].tx,
+                                        0, 0, &v1, &v2);
+               if (status || !v1) {
+                       if (status != LV1_NO_ENTRY)
+                               dev_dbg(ctodev(card),
+                                       "get vlan id for tx(%d) failed(%d)\n",
+                                       vlan_id_ix[i].tx, status);
+                       card->vlan[i].tx = 0;
+                       card->vlan[i].rx = 0;
+                       continue;
+               }
+               card->vlan[i].tx = (u16)v1;
+
+               /* rx tag */
+               status = lv1_net_control(bus_id(card), dev_id(card),
+                                        GELIC_LV1_GET_VLAN_ID,
+                                        vlan_id_ix[i].rx,
+                                        0, 0, &v1, &v2);
+               if (status || !v1) {
+                       if (status != LV1_NO_ENTRY)
+                               dev_info(ctodev(card),
+                                        "get vlan id for rx(%d) failed(%d)\n",
+                                        vlan_id_ix[i].rx, status);
+                       card->vlan[i].tx = 0;
+                       card->vlan[i].rx = 0;
+                       continue;
+               }
+               card->vlan[i].rx = (u16)v1;
+
+               dev_dbg(ctodev(card), "vlan_id[%d] tx=%02x rx=%02x\n",
+                       i, card->vlan[i].tx, card->vlan[i].rx);
+       }
+
+       if (card->vlan[GELIC_PORT_ETHERNET_0].tx) {
+               BUG_ON(!card->vlan[GELIC_PORT_WIRELESS].tx);
+               card->vlan_required = 1;
+       } else
+               card->vlan_required = 0;
+
+       /* check wirelss capable firmware */
+       if (ps3_compare_firmware_version(1, 6, 0) < 0) {
+               card->vlan[GELIC_PORT_WIRELESS].tx = 0;
+               card->vlan[GELIC_PORT_WIRELESS].rx = 0;
+       }
+
+       dev_info(ctodev(card), "internal vlan %s\n",
+                card->vlan_required? "enabled" : "disabled");
+}
+/**
+ * ps3_gelic_driver_probe - add a device to the control of this driver
+ */
+static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
+{
+       struct gelic_card *card;
+       struct net_device *netdev;
+       int result;
+
+       pr_debug("%s: called\n", __func__);
+       result = ps3_open_hv_device(dev);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:ps3_open_hv_device failed\n",
+                       __func__);
+               goto fail_open;
+       }
+
+       result = ps3_dma_region_create(dev->d_region);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:ps3_dma_region_create failed(%d)\n",
+                       __func__, result);
+               BUG_ON("check region type");
+               goto fail_dma_region;
+       }
+
+       /* alloc card/netdevice */
+       card = gelic_alloc_card_net(&netdev);
+       if (!card) {
+               dev_info(&dev->core, "%s:gelic_net_alloc_card failed\n",
+                        __func__);
+               result = -ENOMEM;
+               goto fail_alloc_card;
+       }
+       ps3_system_bus_set_drvdata(dev, card);
+       card->dev = dev;
+
+       /* get internal vlan info */
+       gelic_card_get_vlan_info(card);
+
+       card->link_mode = GELIC_LV1_ETHER_AUTO_NEG;
+
+       /* setup interrupt */
+       result = lv1_net_set_interrupt_status_indicator(bus_id(card),
+                                                       dev_id(card),
+               ps3_mm_phys_to_lpar(__pa(&card->irq_status)),
+               0);
+
+       if (result) {
+               dev_dbg(&dev->core,
+                       "%s:set_interrupt_status_indicator failed: %s\n",
+                       __func__, ps3_result(result));
+               result = -EIO;
+               goto fail_status_indicator;
+       }
+
+       result = ps3_sb_event_receive_port_setup(dev, PS3_BINDING_CPU_ANY,
+               &card->irq);
+
+       if (result) {
+               dev_info(ctodev(card),
+                        "%s:gelic_net_open_device failed (%d)\n",
+                        __func__, result);
+               result = -EPERM;
+               goto fail_alloc_irq;
+       }
+       result = request_irq(card->irq, gelic_card_interrupt,
+                            IRQF_DISABLED, netdev->name, card);
+
+       if (result) {
+               dev_info(ctodev(card), "%s:request_irq failed (%d)\n",
+                       __func__, result);
+               goto fail_request_irq;
+       }
+
+       /* setup card structure */
+       card->irq_mask = GELIC_CARD_RXINT | GELIC_CARD_TXINT |
+               GELIC_CARD_PORT_STATUS_CHANGED;
+
+
+       if (gelic_card_init_chain(card, &card->tx_chain,
+                       card->descr, GELIC_NET_TX_DESCRIPTORS))
+               goto fail_alloc_tx;
+       if (gelic_card_init_chain(card, &card->rx_chain,
+                                card->descr + GELIC_NET_TX_DESCRIPTORS,
+                                GELIC_NET_RX_DESCRIPTORS))
+               goto fail_alloc_rx;
+
+       /* head of chain */
+       card->tx_top = card->tx_chain.head;
+       card->rx_top = card->rx_chain.head;
+       dev_dbg(ctodev(card), "descr rx %p, tx %p, size %#lx, num %#x\n",
+               card->rx_top, card->tx_top, sizeof(struct gelic_descr),
+               GELIC_NET_RX_DESCRIPTORS);
+       /* allocate rx skbs */
+       if (gelic_card_alloc_rx_skbs(card))
+               goto fail_alloc_skbs;
+
+       spin_lock_init(&card->tx_lock);
+       card->tx_dma_progress = 0;
+
+       /* setup net_device structure */
+       netdev->irq = card->irq;
+       SET_NETDEV_DEV(netdev, &card->dev->core);
+       gelic_ether_setup_netdev_ops(netdev, &card->napi);
+       result = gelic_net_setup_netdev(netdev, card);
+       if (result) {
+               dev_dbg(&dev->core, "%s: setup_netdev failed %d",
+                       __func__, result);
+               goto fail_setup_netdev;
+       }
+
+#ifdef CONFIG_GELIC_WIRELESS
+       if (gelic_wl_driver_probe(card)) {
+               dev_dbg(&dev->core, "%s: WL init failed\n", __func__);
+               goto fail_setup_netdev;
+       }
+#endif
+       pr_debug("%s: done\n", __func__);
+       return 0;
+
+fail_setup_netdev:
+fail_alloc_skbs:
+       gelic_card_free_chain(card, card->rx_chain.head);
+fail_alloc_rx:
+       gelic_card_free_chain(card, card->tx_chain.head);
+fail_alloc_tx:
+       free_irq(card->irq, card);
+       netdev->irq = NO_IRQ;
+fail_request_irq:
+       ps3_sb_event_receive_port_destroy(dev, card->irq);
+fail_alloc_irq:
+       lv1_net_set_interrupt_status_indicator(bus_id(card),
+                                              bus_id(card),
+                                              0, 0);
+fail_status_indicator:
+       ps3_system_bus_set_drvdata(dev, NULL);
+       kfree(netdev_card(netdev)->unalign);
+       free_netdev(netdev);
+fail_alloc_card:
+       ps3_dma_region_free(dev->d_region);
+fail_dma_region:
+       ps3_close_hv_device(dev);
+fail_open:
+       return result;
+}
+
+/**
+ * ps3_gelic_driver_remove - remove a device from the control of this driver
+ */
+
+static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
+{
+       struct gelic_card *card = ps3_system_bus_get_drvdata(dev);
+       struct net_device *netdev0;
+       pr_debug("%s: called\n", __func__);
+
+       /* set auto-negotiation */
+       gelic_card_set_link_mode(card, GELIC_LV1_ETHER_AUTO_NEG);
+
+#ifdef CONFIG_GELIC_WIRELESS
+       gelic_wl_driver_remove(card);
+#endif
+       /* stop interrupt */
+       gelic_card_set_irq_mask(card, 0);
+
+       /* turn off DMA, force end */
+       gelic_card_disable_rxdmac(card);
+       gelic_card_disable_txdmac(card);
+
+       /* release chains */
+       gelic_card_release_tx_chain(card, 1);
+       gelic_card_release_rx_chain(card);
+
+       gelic_card_free_chain(card, card->tx_top);
+       gelic_card_free_chain(card, card->rx_top);
+
+       netdev0 = card->netdev[GELIC_PORT_ETHERNET_0];
+       /* disconnect event port */
+       free_irq(card->irq, card);
+       netdev0->irq = NO_IRQ;
+       ps3_sb_event_receive_port_destroy(card->dev, card->irq);
+
+       wait_event(card->waitq,
+                  atomic_read(&card->tx_timeout_task_counter) == 0);
+
+       lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card),
+                                              0 , 0);
+
+       unregister_netdev(netdev0);
+       kfree(netdev_card(netdev0)->unalign);
+       free_netdev(netdev0);
+
+       ps3_system_bus_set_drvdata(dev, NULL);
+
+       ps3_dma_region_free(dev->d_region);
+
+       ps3_close_hv_device(dev);
+
+       pr_debug("%s: done\n", __func__);
+       return 0;
+}
+
+static struct ps3_system_bus_driver ps3_gelic_driver = {
+       .match_id = PS3_MATCH_ID_GELIC,
+       .probe = ps3_gelic_driver_probe,
+       .remove = ps3_gelic_driver_remove,
+       .shutdown = ps3_gelic_driver_remove,
+       .core.name = "ps3_gelic_driver",
+       .core.owner = THIS_MODULE,
+};
+
+static int __init ps3_gelic_driver_init (void)
+{
+       return firmware_has_feature(FW_FEATURE_PS3_LV1)
+               ? ps3_system_bus_driver_register(&ps3_gelic_driver)
+               : -ENODEV;
+}
+
+static void __exit ps3_gelic_driver_exit (void)
+{
+       ps3_system_bus_driver_unregister(&ps3_gelic_driver);
+}
+
+module_init(ps3_gelic_driver_init);
+module_exit(ps3_gelic_driver_exit);
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_GELIC);
+
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
new file mode 100644 (file)
index 0000000..d3fadfb
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ *  PS3 Platfom gelic network driver.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation.
+ *
+ * This file is based on: spider_net.h
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _GELIC_NET_H
+#define _GELIC_NET_H
+
+/* descriptors */
+#define GELIC_NET_RX_DESCRIPTORS        128 /* num of descriptors */
+#define GELIC_NET_TX_DESCRIPTORS        128 /* num of descriptors */
+
+#define GELIC_NET_MAX_MTU               VLAN_ETH_FRAME_LEN
+#define GELIC_NET_MIN_MTU               VLAN_ETH_ZLEN
+#define GELIC_NET_RXBUF_ALIGN           128
+#define GELIC_CARD_RX_CSUM_DEFAULT      1 /* hw chksum */
+#define GELIC_NET_WATCHDOG_TIMEOUT      5*HZ
+#define GELIC_NET_NAPI_WEIGHT           (GELIC_NET_RX_DESCRIPTORS)
+#define GELIC_NET_BROADCAST_ADDR        0xffffffffffffL
+
+#define GELIC_NET_MC_COUNT_MAX          32 /* multicast address list */
+
+/* virtual interrupt status register bits */
+       /* INT1 */
+#define GELIC_CARD_TX_RAM_FULL_ERR           0x0000000000000001L
+#define GELIC_CARD_RX_RAM_FULL_ERR           0x0000000000000002L
+#define GELIC_CARD_TX_SHORT_FRAME_ERR        0x0000000000000004L
+#define GELIC_CARD_TX_INVALID_DESCR_ERR      0x0000000000000008L
+#define GELIC_CARD_RX_FIFO_FULL_ERR          0x0000000000002000L
+#define GELIC_CARD_RX_DESCR_CHAIN_END        0x0000000000004000L
+#define GELIC_CARD_RX_INVALID_DESCR_ERR      0x0000000000008000L
+#define GELIC_CARD_TX_RESPONCE_ERR           0x0000000000010000L
+#define GELIC_CARD_RX_RESPONCE_ERR           0x0000000000100000L
+#define GELIC_CARD_TX_PROTECTION_ERR         0x0000000000400000L
+#define GELIC_CARD_RX_PROTECTION_ERR         0x0000000004000000L
+#define GELIC_CARD_TX_TCP_UDP_CHECKSUM_ERR   0x0000000008000000L
+#define GELIC_CARD_PORT_STATUS_CHANGED       0x0000000020000000L
+#define GELIC_CARD_WLAN_EVENT_RECEIVED       0x0000000040000000L
+#define GELIC_CARD_WLAN_COMMAND_COMPLETED    0x0000000080000000L
+       /* INT 0 */
+#define GELIC_CARD_TX_FLAGGED_DESCR          0x0004000000000000L
+#define GELIC_CARD_RX_FLAGGED_DESCR          0x0040000000000000L
+#define GELIC_CARD_TX_TRANSFER_END           0x0080000000000000L
+#define GELIC_CARD_TX_DESCR_CHAIN_END        0x0100000000000000L
+#define GELIC_CARD_NUMBER_OF_RX_FRAME        0x1000000000000000L
+#define GELIC_CARD_ONE_TIME_COUNT_TIMER      0x4000000000000000L
+#define GELIC_CARD_FREE_RUN_COUNT_TIMER      0x8000000000000000L
+
+/* initial interrupt mask */
+#define GELIC_CARD_TXINT       GELIC_CARD_TX_DESCR_CHAIN_END
+
+#define GELIC_CARD_RXINT       (GELIC_CARD_RX_DESCR_CHAIN_END | \
+                                GELIC_CARD_NUMBER_OF_RX_FRAME)
+
+ /* RX descriptor data_status bits */
+enum gelic_descr_rx_status {
+       GELIC_DESCR_RXDMADU     = 0x80000000, /* destination MAC addr unknown */
+       GELIC_DESCR_RXLSTFBF    = 0x40000000, /* last frame buffer            */
+       GELIC_DESCR_RXIPCHK     = 0x20000000, /* IP checksum performed        */
+       GELIC_DESCR_RXTCPCHK    = 0x10000000, /* TCP/UDP checksup performed   */
+       GELIC_DESCR_RXWTPKT     = 0x00C00000, /*
+                                              * wakeup trigger packet
+                                              * 01: Magic Packet (TM)
+                                              * 10: ARP packet
+                                              * 11: Multicast MAC addr
+                                              */
+       GELIC_DESCR_RXVLNPKT    = 0x00200000, /* VLAN packet */
+       /* bit 20..16 reserved */
+       GELIC_DESCR_RXRRECNUM   = 0x0000ff00, /* reception receipt number */
+       /* bit 7..0 reserved */
+};
+
+#define GELIC_DESCR_DATA_STATUS_CHK_MASK       \
+       (GELIC_DESCR_RXIPCHK | GELIC_DESCR_RXTCPCHK)
+
+ /* TX descriptor data_status bits */
+enum gelic_descr_tx_status {
+       GELIC_DESCR_TX_TAIL     = 0x00000001, /* gelic treated this
+                                              * descriptor was end of
+                                              * a tx frame
+                                              */
+};
+
+/* RX descriptor data error bits */
+enum gelic_descr_rx_error {
+       /* bit 31 reserved */
+       GELIC_DESCR_RXALNERR    = 0x40000000, /* alignement error 10/100M */
+       GELIC_DESCR_RXOVERERR   = 0x20000000, /* oversize error */
+       GELIC_DESCR_RXRNTERR    = 0x10000000, /* Runt error */
+       GELIC_DESCR_RXIPCHKERR  = 0x08000000, /* IP checksum  error */
+       GELIC_DESCR_RXTCPCHKERR = 0x04000000, /* TCP/UDP checksum  error */
+       GELIC_DESCR_RXDRPPKT    = 0x00100000, /* drop packet */
+       GELIC_DESCR_RXIPFMTERR  = 0x00080000, /* IP packet format error */
+       /* bit 18 reserved */
+       GELIC_DESCR_RXDATAERR   = 0x00020000, /* IP packet format error */
+       GELIC_DESCR_RXCALERR    = 0x00010000, /* cariier extension length
+                                             * error */
+       GELIC_DESCR_RXCREXERR   = 0x00008000, /* carrier extension error */
+       GELIC_DESCR_RXMLTCST    = 0x00004000, /* multicast address frame */
+       /* bit 13..0 reserved */
+};
+#define GELIC_DESCR_DATA_ERROR_CHK_MASK                \
+       (GELIC_DESCR_RXIPCHKERR | GELIC_DESCR_RXTCPCHKERR)
+
+/* DMA command and status (RX and TX)*/
+enum gelic_descr_dma_status {
+       GELIC_DESCR_DMA_COMPLETE            = 0x00000000, /* used in tx */
+       GELIC_DESCR_DMA_BUFFER_FULL         = 0x00000000, /* used in rx */
+       GELIC_DESCR_DMA_RESPONSE_ERROR      = 0x10000000, /* used in rx, tx */
+       GELIC_DESCR_DMA_PROTECTION_ERROR    = 0x20000000, /* used in rx, tx */
+       GELIC_DESCR_DMA_FRAME_END           = 0x40000000, /* used in rx */
+       GELIC_DESCR_DMA_FORCE_END           = 0x50000000, /* used in rx, tx */
+       GELIC_DESCR_DMA_CARDOWNED           = 0xa0000000, /* used in rx, tx */
+       GELIC_DESCR_DMA_NOT_IN_USE          = 0xb0000000, /* any other value */
+};
+
+#define GELIC_DESCR_DMA_STAT_MASK      (0xf0000000)
+
+/* tx descriptor command and status */
+enum gelic_descr_tx_dma_status {
+       /* [19] */
+       GELIC_DESCR_TX_DMA_IKE          = 0x00080000, /* IPSEC off */
+       /* [18] */
+       GELIC_DESCR_TX_DMA_FRAME_TAIL   = 0x00040000, /* last descriptor of
+                                                      * the packet
+                                                      */
+       /* [17..16] */
+       GELIC_DESCR_TX_DMA_TCP_CHKSUM   = 0x00020000, /* TCP packet */
+       GELIC_DESCR_TX_DMA_UDP_CHKSUM   = 0x00030000, /* UDP packet */
+       GELIC_DESCR_TX_DMA_NO_CHKSUM    = 0x00000000, /* no checksum */
+
+       /* [1] */
+       GELIC_DESCR_TX_DMA_CHAIN_END    = 0x00000002, /* DMA terminated
+                                                      * due to chain end
+                                                      */
+};
+
+#define GELIC_DESCR_DMA_CMD_NO_CHKSUM  \
+       (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \
+       GELIC_DESCR_TX_DMA_NO_CHKSUM)
+
+#define GELIC_DESCR_DMA_CMD_TCP_CHKSUM \
+       (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \
+       GELIC_DESCR_TX_DMA_TCP_CHKSUM)
+
+#define GELIC_DESCR_DMA_CMD_UDP_CHKSUM \
+       (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \
+       GELIC_DESCR_TX_DMA_UDP_CHKSUM)
+
+enum gelic_descr_rx_dma_status {
+       /* [ 1 ] */
+       GELIC_DESCR_RX_DMA_CHAIN_END    = 0x00000002, /* DMA terminated
+                                                      * due to chain end
+                                                      */
+};
+
+/* for lv1_net_control */
+enum gelic_lv1_net_control_code {
+       GELIC_LV1_GET_MAC_ADDRESS       = 1,
+       GELIC_LV1_GET_ETH_PORT_STATUS   = 2,
+       GELIC_LV1_SET_NEGOTIATION_MODE  = 3,
+       GELIC_LV1_GET_VLAN_ID           = 4,
+       GELIC_LV1_SET_WOL               = 5,
+       GELIC_LV1_GET_CHANNEL           = 6,
+       GELIC_LV1_POST_WLAN_CMD         = 9,
+       GELIC_LV1_GET_WLAN_CMD_RESULT   = 10,
+       GELIC_LV1_GET_WLAN_EVENT        = 11,
+};
+
+/* for GELIC_LV1_SET_WOL */
+enum gelic_lv1_wol_command {
+       GELIC_LV1_WOL_MAGIC_PACKET      = 1,
+       GELIC_LV1_WOL_ADD_MATCH_ADDR    = 6,
+       GELIC_LV1_WOL_DELETE_MATCH_ADDR = 7,
+};
+
+/* for GELIC_LV1_WOL_MAGIC_PACKET */
+enum gelic_lv1_wol_mp_arg {
+       GELIC_LV1_WOL_MP_DISABLE        = 0,
+       GELIC_LV1_WOL_MP_ENABLE         = 1,
+};
+
+/* for GELIC_LV1_WOL_{ADD,DELETE}_MATCH_ADDR */
+enum gelic_lv1_wol_match_arg {
+       GELIC_LV1_WOL_MATCH_INDIVIDUAL  = 0,
+       GELIC_LV1_WOL_MATCH_ALL         = 1,
+};
+
+/* status returened from GET_ETH_PORT_STATUS */
+enum gelic_lv1_ether_port_status {
+       GELIC_LV1_ETHER_LINK_UP         = 0x0000000000000001L,
+       GELIC_LV1_ETHER_FULL_DUPLEX     = 0x0000000000000002L,
+       GELIC_LV1_ETHER_AUTO_NEG        = 0x0000000000000004L,
+
+       GELIC_LV1_ETHER_SPEED_10        = 0x0000000000000010L,
+       GELIC_LV1_ETHER_SPEED_100       = 0x0000000000000020L,
+       GELIC_LV1_ETHER_SPEED_1000      = 0x0000000000000040L,
+       GELIC_LV1_ETHER_SPEED_MASK      = 0x0000000000000070L,
+};
+
+enum gelic_lv1_vlan_index {
+       /* for outgoing packets */
+       GELIC_LV1_VLAN_TX_ETHERNET_0    = 0x0000000000000002L,
+       GELIC_LV1_VLAN_TX_WIRELESS      = 0x0000000000000003L,
+
+       /* for incoming packets */
+       GELIC_LV1_VLAN_RX_ETHERNET_0    = 0x0000000000000012L,
+       GELIC_LV1_VLAN_RX_WIRELESS      = 0x0000000000000013L,
+};
+
+enum gelic_lv1_phy {
+       GELIC_LV1_PHY_ETHERNET_0        = 0x0000000000000002L,
+};
+
+/* size of hardware part of gelic descriptor */
+#define GELIC_DESCR_SIZE       (32)
+
+enum gelic_port_type {
+       GELIC_PORT_ETHERNET_0   = 0,
+       GELIC_PORT_WIRELESS     = 1,
+       GELIC_PORT_MAX
+};
+
+struct gelic_descr {
+       /* as defined by the hardware */
+       __be32 buf_addr;
+       __be32 buf_size;
+       __be32 next_descr_addr;
+       __be32 dmac_cmd_status;
+       __be32 result_size;
+       __be32 valid_size;      /* all zeroes for tx */
+       __be32 data_status;
+       __be32 data_error;      /* all zeroes for tx */
+
+       /* used in the driver */
+       struct sk_buff *skb;
+       dma_addr_t bus_addr;
+       struct gelic_descr *next;
+       struct gelic_descr *prev;
+} __attribute__((aligned(32)));
+
+struct gelic_descr_chain {
+       /* we walk from tail to head */
+       struct gelic_descr *head;
+       struct gelic_descr *tail;
+};
+
+struct gelic_vlan_id {
+       u16 tx;
+       u16 rx;
+};
+
+struct gelic_card {
+       struct napi_struct napi;
+       struct net_device *netdev[GELIC_PORT_MAX];
+       /*
+        * hypervisor requires irq_status should be
+        * 8 bytes aligned, but u64 member is
+        * always disposed in that manner
+        */
+       u64 irq_status;
+       u64 irq_mask;
+
+       struct ps3_system_bus_device *dev;
+       struct gelic_vlan_id vlan[GELIC_PORT_MAX];
+       int vlan_required;
+
+       struct gelic_descr_chain tx_chain;
+       struct gelic_descr_chain rx_chain;
+       /*
+        * tx_lock guards tx descriptor list and
+        * tx_dma_progress.
+        */
+       spinlock_t tx_lock;
+       int tx_dma_progress;
+
+       struct work_struct tx_timeout_task;
+       atomic_t tx_timeout_task_counter;
+       wait_queue_head_t waitq;
+
+       /* only first user should up the card */
+       struct mutex updown_lock;
+       atomic_t users;
+
+       u64 ether_port_status;
+       int link_mode;
+
+       /* original address returned by kzalloc */
+       void *unalign;
+
+       /*
+        * each netdevice has copy of irq
+        */
+       unsigned int irq;
+       struct gelic_descr *tx_top, *rx_top;
+       struct gelic_descr descr[0]; /* must be the last */
+};
+
+struct gelic_port {
+       struct gelic_card *card;
+       struct net_device *netdev;
+       enum gelic_port_type type;
+       long priv[0]; /* long for alignment */
+};
+
+static inline struct gelic_card *port_to_card(struct gelic_port *p)
+{
+       return p->card;
+}
+static inline struct net_device *port_to_netdev(struct gelic_port *p)
+{
+       return p->netdev;
+}
+static inline struct gelic_card *netdev_card(struct net_device *d)
+{
+       return ((struct gelic_port *)netdev_priv(d))->card;
+}
+static inline struct gelic_port *netdev_port(struct net_device *d)
+{
+       return (struct gelic_port *)netdev_priv(d);
+}
+static inline struct device *ctodev(struct gelic_card *card)
+{
+       return &card->dev->core;
+}
+static inline u64 bus_id(struct gelic_card *card)
+{
+       return card->dev->bus_id;
+}
+static inline u64 dev_id(struct gelic_card *card)
+{
+       return card->dev->dev_id;
+}
+
+static inline void *port_priv(struct gelic_port *port)
+{
+       return port->priv;
+}
+
+extern int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask);
+/* shared netdev ops */
+extern void gelic_card_up(struct gelic_card *card);
+extern void gelic_card_down(struct gelic_card *card);
+extern int gelic_net_open(struct net_device *netdev);
+extern int gelic_net_stop(struct net_device *netdev);
+extern int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev);
+extern void gelic_net_set_multi(struct net_device *netdev);
+extern void gelic_net_tx_timeout(struct net_device *netdev);
+extern int gelic_net_change_mtu(struct net_device *netdev, int new_mtu);
+extern int gelic_net_setup_netdev(struct net_device *netdev,
+                                 struct gelic_card *card);
+
+/* shared ethtool ops */
+extern void gelic_net_get_drvinfo(struct net_device *netdev,
+                                 struct ethtool_drvinfo *info);
+extern void gelic_net_poll_controller(struct net_device *netdev);
+
+#endif /* _GELIC_NET_H */
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
new file mode 100644 (file)
index 0000000..2e62938
--- /dev/null
@@ -0,0 +1,2681 @@
+/*
+ *  PS3 gelic network driver.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <net/iw_handler.h>
+
+#include <linux/dma-mapping.h>
+#include <net/checksum.h>
+#include <asm/firmware.h>
+#include <asm/ps3.h>
+#include <asm/lv1call.h>
+
+#include "ps3_gelic_net.h"
+#include "ps3_gelic_wireless.h"
+
+
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+                              u8 *essid, size_t essid_len);
+static int gelic_wl_try_associate(struct net_device *netdev);
+
+/*
+ * tables
+ */
+
+/* 802.11b/g channel to freq in MHz */
+static const int channel_freq[] = {
+       2412, 2417, 2422, 2427, 2432,
+       2437, 2442, 2447, 2452, 2457,
+       2462, 2467, 2472, 2484
+};
+#define NUM_CHANNELS ARRAY_SIZE(channel_freq)
+
+/* in bps */
+static const int bitrate_list[] = {
+         1000000,
+         2000000,
+         5500000,
+        11000000,
+         6000000,
+         9000000,
+        12000000,
+        18000000,
+        24000000,
+        36000000,
+        48000000,
+        54000000
+};
+#define NUM_BITRATES ARRAY_SIZE(bitrate_list)
+
+/*
+ * wpa2 support requires the hypervisor version 2.0 or later
+ */
+static inline int wpa2_capable(void)
+{
+       return 0 <= ps3_compare_firmware_version(2, 0, 0);
+}
+
+static inline int precise_ie(void)
+{
+       return 0 <= ps3_compare_firmware_version(2, 2, 0);
+}
+/*
+ * post_eurus_cmd helpers
+ */
+struct eurus_cmd_arg_info {
+       int pre_arg; /* command requires arg1, arg2 at POST COMMAND */
+       int post_arg; /* command requires arg1, arg2 at GET_RESULT */
+};
+
+static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = {
+       [GELIC_EURUS_CMD_SET_COMMON_CFG] = { .pre_arg = 1},
+       [GELIC_EURUS_CMD_SET_WEP_CFG]    = { .pre_arg = 1},
+       [GELIC_EURUS_CMD_SET_WPA_CFG]    = { .pre_arg = 1},
+       [GELIC_EURUS_CMD_GET_COMMON_CFG] = { .post_arg = 1},
+       [GELIC_EURUS_CMD_GET_WEP_CFG]    = { .post_arg = 1},
+       [GELIC_EURUS_CMD_GET_WPA_CFG]    = { .post_arg = 1},
+       [GELIC_EURUS_CMD_GET_RSSI_CFG]   = { .post_arg = 1},
+       [GELIC_EURUS_CMD_START_SCAN]     = { .pre_arg = 1},
+       [GELIC_EURUS_CMD_GET_SCAN]       = { .post_arg = 1},
+};
+
+#ifdef DEBUG
+static const char *cmdstr(enum gelic_eurus_command ix)
+{
+       switch (ix) {
+       case GELIC_EURUS_CMD_ASSOC:
+               return "ASSOC";
+       case GELIC_EURUS_CMD_DISASSOC:
+               return "DISASSOC";
+       case GELIC_EURUS_CMD_START_SCAN:
+               return "SCAN";
+       case GELIC_EURUS_CMD_GET_SCAN:
+               return "GET SCAN";
+       case GELIC_EURUS_CMD_SET_COMMON_CFG:
+               return "SET_COMMON_CFG";
+       case GELIC_EURUS_CMD_GET_COMMON_CFG:
+               return "GET_COMMON_CFG";
+       case GELIC_EURUS_CMD_SET_WEP_CFG:
+               return "SET_WEP_CFG";
+       case GELIC_EURUS_CMD_GET_WEP_CFG:
+               return "GET_WEP_CFG";
+       case GELIC_EURUS_CMD_SET_WPA_CFG:
+               return "SET_WPA_CFG";
+       case GELIC_EURUS_CMD_GET_WPA_CFG:
+               return "GET_WPA_CFG";
+       case GELIC_EURUS_CMD_GET_RSSI_CFG:
+               return "GET_RSSI";
+       default:
+               break;
+       }
+       return "";
+};
+#else
+static inline const char *cmdstr(enum gelic_eurus_command ix)
+{
+       return "";
+}
+#endif
+
+/* synchronously do eurus commands */
+static void gelic_eurus_sync_cmd_worker(struct work_struct *work)
+{
+       struct gelic_eurus_cmd *cmd;
+       struct gelic_card *card;
+       struct gelic_wl_info *wl;
+
+       u64 arg1, arg2;
+
+       pr_debug("%s: <-\n", __func__);
+       cmd = container_of(work, struct gelic_eurus_cmd, work);
+       BUG_ON(cmd_info[cmd->cmd].pre_arg &&
+              cmd_info[cmd->cmd].post_arg);
+       wl = cmd->wl;
+       card = port_to_card(wl_port(wl));
+
+       if (cmd_info[cmd->cmd].pre_arg) {
+               arg1 = (cmd->buffer) ?
+                       ps3_mm_phys_to_lpar(__pa(cmd->buffer)) :
+                       0;
+               arg2 = cmd->buf_size;
+       } else {
+               arg1 = 0;
+               arg2 = 0;
+       }
+       init_completion(&wl->cmd_done_intr);
+       pr_debug("%s: cmd='%s' start\n", __func__, cmdstr(cmd->cmd));
+       cmd->status = lv1_net_control(bus_id(card), dev_id(card),
+                                     GELIC_LV1_POST_WLAN_CMD,
+                                     cmd->cmd, arg1, arg2,
+                                     &cmd->tag, &cmd->size);
+       if (cmd->status) {
+               complete(&cmd->done);
+               pr_info("%s: cmd issue failed\n", __func__);
+               return;
+       }
+
+       wait_for_completion(&wl->cmd_done_intr);
+
+       if (cmd_info[cmd->cmd].post_arg) {
+               arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
+               arg2 = cmd->buf_size;
+       } else {
+               arg1 = 0;
+               arg2 = 0;
+       }
+
+       cmd->status = lv1_net_control(bus_id(card), dev_id(card),
+                                     GELIC_LV1_GET_WLAN_CMD_RESULT,
+                                     cmd->tag, arg1, arg2,
+                                     &cmd->cmd_status, &cmd->size);
+#ifdef DEBUG
+       if (cmd->status || cmd->cmd_status) {
+       pr_debug("%s: cmd done tag=%#lx arg1=%#lx, arg2=%#lx\n", __func__,
+                cmd->tag, arg1, arg2);
+       pr_debug("%s: cmd done status=%#x cmd_status=%#lx size=%#lx\n",
+                __func__, cmd->status, cmd->cmd_status, cmd->size);
+       }
+#endif
+       complete(&cmd->done);
+       pr_debug("%s: cmd='%s' done\n", __func__, cmdstr(cmd->cmd));
+}
+
+static struct gelic_eurus_cmd *gelic_eurus_sync_cmd(struct gelic_wl_info *wl,
+                                                   unsigned int eurus_cmd,
+                                                   void *buffer,
+                                                   unsigned int buf_size)
+{
+       struct gelic_eurus_cmd *cmd;
+
+       /* allocate cmd */
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return NULL;
+
+       /* initialize members */
+       cmd->cmd = eurus_cmd;
+       cmd->buffer = buffer;
+       cmd->buf_size = buf_size;
+       cmd->wl = wl;
+       INIT_WORK(&cmd->work, gelic_eurus_sync_cmd_worker);
+       init_completion(&cmd->done);
+       queue_work(wl->eurus_cmd_queue, &cmd->work);
+
+       /* wait for command completion */
+       wait_for_completion(&cmd->done);
+
+       return cmd;
+}
+
+static u32 gelic_wl_get_link(struct net_device *netdev)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
+       u32 ret;
+
+       pr_debug("%s: <-\n", __func__);
+       mutex_lock(&wl->assoc_stat_lock);
+       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
+               ret = 1;
+       else
+               ret = 0;
+       mutex_unlock(&wl->assoc_stat_lock);
+       pr_debug("%s: ->\n", __func__);
+       return ret;
+}
+
+static void gelic_wl_send_iwap_event(struct gelic_wl_info *wl, u8 *bssid)
+{
+       union iwreq_data data;
+
+       memset(&data, 0, sizeof(data));
+       if (bssid)
+               memcpy(data.ap_addr.sa_data, bssid, ETH_ALEN);
+       data.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWAP,
+                           &data, NULL);
+}
+
+/*
+ * wireless extension handlers and helpers
+ */
+
+/* SIOGIWNAME */
+static int gelic_wl_get_name(struct net_device *dev,
+                            struct iw_request_info *info,
+                            union iwreq_data *iwreq, char *extra)
+{
+       strcpy(iwreq->name, "IEEE 802.11bg");
+       return 0;
+}
+
+static void gelic_wl_get_ch_info(struct gelic_wl_info *wl)
+{
+       struct gelic_card *card = port_to_card(wl_port(wl));
+       u64 ch_info_raw, tmp;
+       int status;
+
+       if (!test_and_set_bit(GELIC_WL_STAT_CH_INFO, &wl->stat)) {
+               status = lv1_net_control(bus_id(card), dev_id(card),
+                                        GELIC_LV1_GET_CHANNEL, 0, 0, 0,
+                                        &ch_info_raw,
+                                        &tmp);
+               /* some fw versions may return error */
+               if (status) {
+                       if (status != LV1_NO_ENTRY)
+                               pr_info("%s: available ch unknown\n", __func__);
+                       wl->ch_info = 0x07ff;/* 11 ch */
+               } else
+                       /* 16 bits of MSB has available channels */
+                       wl->ch_info = ch_info_raw >> 48;
+       }
+}
+
+/* SIOGIWRANGE */
+static int gelic_wl_get_range(struct net_device *netdev,
+                             struct iw_request_info *info,
+                             union iwreq_data *iwreq, char *extra)
+{
+       struct iw_point *point = &iwreq->data;
+       struct iw_range *range = (struct iw_range *)extra;
+       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
+       unsigned int i, chs;
+
+       pr_debug("%s: <-\n", __func__);
+       point->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 22;
+
+       /* available channels and frequencies */
+       gelic_wl_get_ch_info(wl);
+
+       for (i = 0, chs = 0;
+            i < NUM_CHANNELS && chs < IW_MAX_FREQUENCIES; i++)
+               if (wl->ch_info & (1 << i)) {
+                       range->freq[chs].i = i + 1;
+                       range->freq[chs].m = channel_freq[i];
+                       range->freq[chs].e = 6;
+                       chs++;
+               }
+       range->num_frequency = chs;
+       range->old_num_frequency = chs;
+       range->num_channels = chs;
+       range->old_num_channels = chs;
+
+       /* bitrates */
+       for (i = 0; i < NUM_BITRATES; i++)
+               range->bitrate[i] = bitrate_list[i];
+       range->num_bitrates = i;
+
+       /* signal levels */
+       range->max_qual.qual = 100; /* relative value */
+       range->max_qual.level = 100;
+       range->avg_qual.qual = 50;
+       range->avg_qual.level = 50;
+       range->sensitivity = 0;
+
+       /* Event capability */
+       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+
+       /* encryption capability */
+       range->enc_capa = IW_ENC_CAPA_WPA |
+               IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP |
+               IW_ENC_CAPA_4WAY_HANDSHAKE;
+       if (wpa2_capable())
+               range->enc_capa |= IW_ENC_CAPA_WPA2;
+       range->encoding_size[0] = 5;    /* 40bit WEP */
+       range->encoding_size[1] = 13;   /* 104bit WEP */
+       range->encoding_size[2] = 32;   /* WPA-PSK */
+       range->num_encoding_sizes = 3;
+       range->max_encoding_tokens = GELIC_WEP_KEYS;
+
+       /* scan capability */
+       range->scan_capa = IW_SCAN_CAPA_ESSID;
+
+       pr_debug("%s: ->\n", __func__);
+       return 0;
+
+}
+
+/* SIOC{G,S}IWSCAN */
+static int gelic_wl_set_scan(struct net_device *netdev,
+                          struct iw_request_info *info,
+                          union iwreq_data *wrqu, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       struct iw_scan_req *req;
+       u8 *essid = NULL;
+       size_t essid_len = 0;
+
+       if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+           wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+               req = (struct iw_scan_req*)extra;
+               essid = req->essid;
+               essid_len = req->essid_len;
+               pr_debug("%s: ESSID scan =%s\n", __func__, essid);
+       }
+       return gelic_wl_start_scan(wl, 1, essid, essid_len);
+}
+
+#define OUI_LEN 3
+static const u8 rsn_oui[OUI_LEN] = { 0x00, 0x0f, 0xac };
+static const u8 wpa_oui[OUI_LEN] = { 0x00, 0x50, 0xf2 };
+
+/*
+ * synthesize WPA/RSN IE data
+ * See WiFi WPA specification and IEEE 802.11-2007 7.3.2.25
+ * for the format
+ */
+static size_t gelic_wl_synthesize_ie(u8 *buf,
+                                    struct gelic_eurus_scan_info *scan)
+{
+
+       const u8 *oui_header;
+       u8 *start = buf;
+       int rsn;
+       int ccmp;
+
+       pr_debug("%s: <- sec=%16x\n", __func__, scan->security);
+       switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_MASK) {
+       case GELIC_EURUS_SCAN_SEC_WPA:
+               rsn = 0;
+               break;
+       case GELIC_EURUS_SCAN_SEC_WPA2:
+               rsn = 1;
+               break;
+       default:
+               /* WEP or none.  No IE returned */
+               return 0;
+       }
+
+       switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_WPA_MASK) {
+       case GELIC_EURUS_SCAN_SEC_WPA_TKIP:
+               ccmp = 0;
+               break;
+       case GELIC_EURUS_SCAN_SEC_WPA_AES:
+               ccmp = 1;
+               break;
+       default:
+               if (rsn) {
+                       ccmp = 1;
+                       pr_info("%s: no cipher info. defaulted to CCMP\n",
+                               __func__);
+               } else {
+                       ccmp = 0;
+                       pr_info("%s: no cipher info. defaulted to TKIP\n",
+                               __func__);
+               }
+       }
+
+       if (rsn)
+               oui_header = rsn_oui;
+       else
+               oui_header = wpa_oui;
+
+       /* element id */
+       if (rsn)
+               *buf++ = WLAN_EID_RSN;
+       else
+               *buf++ = WLAN_EID_GENERIC;
+
+       /* length filed; set later */
+       buf++;
+
+       /* wpa special header */
+       if (!rsn) {
+               memcpy(buf, wpa_oui, OUI_LEN);
+               buf += OUI_LEN;
+               *buf++ = 0x01;
+       }
+
+       /* version */
+       *buf++ = 0x01; /* version 1.0 */
+       *buf++ = 0x00;
+
+       /* group cipher */
+       memcpy(buf, oui_header, OUI_LEN);
+       buf += OUI_LEN;
+
+       if (ccmp)
+               *buf++ = 0x04; /* CCMP */
+       else
+               *buf++ = 0x02; /* TKIP */
+
+       /* pairwise key count always 1 */
+       *buf++ = 0x01;
+       *buf++ = 0x00;
+
+       /* pairwise key suit */
+       memcpy(buf, oui_header, OUI_LEN);
+       buf += OUI_LEN;
+       if (ccmp)
+               *buf++ = 0x04; /* CCMP */
+       else
+               *buf++ = 0x02; /* TKIP */
+
+       /* AKM count is 1 */
+       *buf++ = 0x01;
+       *buf++ = 0x00;
+
+       /* AKM suite is assumed as PSK*/
+       memcpy(buf, oui_header, OUI_LEN);
+       buf += OUI_LEN;
+       *buf++ = 0x02; /* PSK */
+
+       /* RSN capabilities is 0 */
+       *buf++ = 0x00;
+       *buf++ = 0x00;
+
+       /* set length field */
+       start[1] = (buf - start - 2);
+
+       pr_debug("%s: ->\n", __func__);
+       return buf - start;
+}
+
+struct ie_item {
+       u8 *data;
+       u8 len;
+};
+
+struct ie_info {
+       struct ie_item wpa;
+       struct ie_item rsn;
+};
+
+static void gelic_wl_parse_ie(u8 *data, size_t len,
+                             struct ie_info *ie_info)
+{
+       size_t data_left = len;
+       u8 *pos = data;
+       u8 item_len;
+       u8 item_id;
+
+       pr_debug("%s: data=%p len=%ld\n", __func__,
+                data, len);
+       memset(ie_info, 0, sizeof(struct ie_info));
+
+       while (2 <= data_left) {
+               item_id = *pos++;
+               item_len = *pos++;
+               data_left -= 2;
+
+               if (data_left < item_len)
+                       break;
+
+               switch (item_id) {
+               case WLAN_EID_GENERIC:
+                       if ((OUI_LEN + 1 <= item_len) &&
+                           !memcmp(pos, wpa_oui, OUI_LEN) &&
+                           pos[OUI_LEN] == 0x01) {
+                               ie_info->wpa.data = pos - 2;
+                               ie_info->wpa.len = item_len + 2;
+                       }
+                       break;
+               case WLAN_EID_RSN:
+                       ie_info->rsn.data = pos - 2;
+                       /* length includes the header */
+                       ie_info->rsn.len = item_len + 2;
+                       break;
+               default:
+                       pr_debug("%s: ignore %#x,%d\n", __func__,
+                                item_id, item_len);
+                       break;
+               }
+               pos += item_len;
+               data_left -= item_len;
+       }
+       pr_debug("%s: wpa=%p,%d wpa2=%p,%d\n", __func__,
+                ie_info->wpa.data, ie_info->wpa.len,
+                ie_info->rsn.data, ie_info->rsn.len);
+}
+
+
+/*
+ * translate the scan informations from hypervisor to a
+ * independent format
+ */
+static char *gelic_wl_translate_scan(struct net_device *netdev,
+                                    struct iw_request_info *info,
+                                    char *ev,
+                                    char *stop,
+                                    struct gelic_wl_scan_info *network)
+{
+       struct iw_event iwe;
+       struct gelic_eurus_scan_info *scan = network->hwinfo;
+       char *tmp;
+       u8 rate;
+       unsigned int i, j, len;
+       u8 buf[64]; /* arbitrary size large enough */
+
+       pr_debug("%s: <-\n", __func__);
+
+       /* first entry should be AP's mac address */
+       iwe.cmd = SIOCGIWAP;
+       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
+       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_ADDR_LEN);
+
+       /* ESSID */
+       iwe.cmd = SIOCGIWESSID;
+       iwe.u.data.flags = 1;
+       iwe.u.data.length = strnlen(scan->essid, 32);
+       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
+
+       /* FREQUENCY */
+       iwe.cmd = SIOCGIWFREQ;
+       iwe.u.freq.m = be16_to_cpu(scan->channel);
+       iwe.u.freq.e = 0; /* table value in MHz */
+       iwe.u.freq.i = 0;
+       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_FREQ_LEN);
+
+       /* RATES */
+       iwe.cmd = SIOCGIWRATE;
+       iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+       /* to stuff multiple values in one event */
+       tmp = ev + iwe_stream_lcp_len(info);
+       /* put them in ascendant order (older is first) */
+       i = 0;
+       j = 0;
+       pr_debug("%s: rates=%d rate=%d\n", __func__,
+                network->rate_len, network->rate_ext_len);
+       while (i < network->rate_len) {
+               if (j < network->rate_ext_len &&
+                   ((scan->ext_rate[j] & 0x7f) < (scan->rate[i] & 0x7f)))
+                   rate = scan->ext_rate[j++] & 0x7f;
+               else
+                   rate = scan->rate[i++] & 0x7f;
+               iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
+               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
+                                          IW_EV_PARAM_LEN);
+       }
+       while (j < network->rate_ext_len) {
+               iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
+               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
+                                          IW_EV_PARAM_LEN);
+       }
+       /* Check if we added any rate */
+       if (iwe_stream_lcp_len(info) < (tmp - ev))
+               ev = tmp;
+
+       /* ENCODE */
+       iwe.cmd = SIOCGIWENCODE;
+       if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_PRIVACY)
+               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+       else
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       iwe.u.data.length = 0;
+       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
+
+       /* MODE */
+       iwe.cmd = SIOCGIWMODE;
+       if (be16_to_cpu(scan->capability) &
+           (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+               if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_ESS)
+                       iwe.u.mode = IW_MODE_MASTER;
+               else
+                       iwe.u.mode = IW_MODE_ADHOC;
+               ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_UINT_LEN);
+       }
+
+       /* QUAL */
+       iwe.cmd = IWEVQUAL;
+       iwe.u.qual.updated  = IW_QUAL_ALL_UPDATED |
+                       IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
+       iwe.u.qual.level = be16_to_cpu(scan->rssi);
+       iwe.u.qual.qual = be16_to_cpu(scan->rssi);
+       iwe.u.qual.noise = 0;
+       ev  = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_QUAL_LEN);
+
+       /* RSN */
+       memset(&iwe, 0, sizeof(iwe));
+       if (be16_to_cpu(scan->size) <= sizeof(*scan)) {
+               /* If wpa[2] capable station, synthesize IE and put it */
+               len = gelic_wl_synthesize_ie(buf, scan);
+               if (len) {
+                       iwe.cmd = IWEVGENIE;
+                       iwe.u.data.length = len;
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
+               }
+       } else {
+               /* this scan info has IE data */
+               struct ie_info ie_info;
+               size_t data_len;
+
+               data_len = be16_to_cpu(scan->size) - sizeof(*scan);
+
+               gelic_wl_parse_ie(scan->elements, data_len, &ie_info);
+
+               if (ie_info.wpa.len && (ie_info.wpa.len <= sizeof(buf))) {
+                       memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
+                       iwe.cmd = IWEVGENIE;
+                       iwe.u.data.length = ie_info.wpa.len;
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
+               }
+
+               if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
+                       memset(&iwe, 0, sizeof(iwe));
+                       memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
+                       iwe.cmd = IWEVGENIE;
+                       iwe.u.data.length = ie_info.rsn.len;
+                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
+               }
+       }
+
+       pr_debug("%s: ->\n", __func__);
+       return ev;
+}
+
+
+static int gelic_wl_get_scan(struct net_device *netdev,
+                            struct iw_request_info *info,
+                            union iwreq_data *wrqu, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       struct gelic_wl_scan_info *scan_info;
+       char *ev = extra;
+       char *stop = ev + wrqu->data.length;
+       int ret = 0;
+       unsigned long this_time = jiffies;
+
+       pr_debug("%s: <-\n", __func__);
+       if (mutex_lock_interruptible(&wl->scan_lock))
+               return -EAGAIN;
+
+       switch (wl->scan_stat) {
+       case GELIC_WL_SCAN_STAT_SCANNING:
+               /* If a scan in progress, caller should call me again */
+               ret = -EAGAIN;
+               goto out;
+               break;
+
+       case GELIC_WL_SCAN_STAT_INIT:
+               /* last scan request failed or never issued */
+               ret = -ENODEV;
+               goto out;
+               break;
+       case GELIC_WL_SCAN_STAT_GOT_LIST:
+               /* ok, use current list */
+               break;
+       }
+
+       list_for_each_entry(scan_info, &wl->network_list, list) {
+               if (wl->scan_age == 0 ||
+                   time_after(scan_info->last_scanned + wl->scan_age,
+                              this_time))
+                       ev = gelic_wl_translate_scan(netdev, info,
+                                                    ev, stop,
+                                                    scan_info);
+               else
+                       pr_debug("%s:entry too old\n", __func__);
+
+               if (stop - ev <= IW_EV_ADDR_LEN) {
+                       ret = -E2BIG;
+                       goto out;
+               }
+       }
+
+       wrqu->data.length = ev - extra;
+       wrqu->data.flags = 0;
+out:
+       mutex_unlock(&wl->scan_lock);
+       pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length);
+       return ret;
+}
+
+#ifdef DEBUG
+static void scan_list_dump(struct gelic_wl_info *wl)
+{
+       struct gelic_wl_scan_info *scan_info;
+       int i;
+
+       i = 0;
+       list_for_each_entry(scan_info, &wl->network_list, list) {
+               pr_debug("%s: item %d\n", __func__, i++);
+               pr_debug("valid=%d eurusindex=%d last=%lx\n",
+                        scan_info->valid, scan_info->eurus_index,
+                        scan_info->last_scanned);
+               pr_debug("r_len=%d r_ext_len=%d essid_len=%d\n",
+                        scan_info->rate_len, scan_info->rate_ext_len,
+                        scan_info->essid_len);
+               /* -- */
+               pr_debug("bssid=%pM\n", &scan_info->hwinfo->bssid[2]);
+               pr_debug("essid=%s\n", scan_info->hwinfo->essid);
+       }
+}
+#endif
+
+static int gelic_wl_set_auth(struct net_device *netdev,
+                            struct iw_request_info *info,
+                            union iwreq_data *data, char *extra)
+{
+       struct iw_param *param = &data->param;
+       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
+       unsigned long irqflag;
+       int ret = 0;
+
+       pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
+       spin_lock_irqsave(&wl->lock, irqflag);
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+               if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
+                       pr_debug("%s: NO WPA selected\n", __func__);
+                       wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
+                       wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
+                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
+               }
+               if (param->value & IW_AUTH_WPA_VERSION_WPA) {
+                       pr_debug("%s: WPA version 1 selected\n", __func__);
+                       wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
+                       wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
+                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
+                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
+               }
+               if (param->value & IW_AUTH_WPA_VERSION_WPA2) {
+                       /*
+                        * As the hypervisor may not tell the cipher
+                        * information of the AP if it is WPA2,
+                        * you will not decide suitable cipher from
+                        * its beacon.
+                        * You should have knowledge about the AP's
+                        * cipher information in other method prior to
+                        * the association.
+                        */
+                       if (!precise_ie())
+                               pr_info("%s: WPA2 may not work\n", __func__);
+                       if (wpa2_capable()) {
+                               wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
+                               wl->group_cipher_method = GELIC_WL_CIPHER_AES;
+                               wl->pairwise_cipher_method =
+                                       GELIC_WL_CIPHER_AES;
+                               wl->auth_method = GELIC_EURUS_AUTH_OPEN;
+                       } else
+                               ret = -EINVAL;
+               }
+               break;
+
+       case IW_AUTH_CIPHER_PAIRWISE:
+               if (param->value &
+                   (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
+                       pr_debug("%s: WEP selected\n", __func__);
+                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
+               }
+               if (param->value & IW_AUTH_CIPHER_TKIP) {
+                       pr_debug("%s: TKIP selected\n", __func__);
+                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
+               }
+               if (param->value & IW_AUTH_CIPHER_CCMP) {
+                       pr_debug("%s: CCMP selected\n", __func__);
+                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
+               }
+               if (param->value & IW_AUTH_CIPHER_NONE) {
+                       pr_debug("%s: no auth selected\n", __func__);
+                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
+               }
+               break;
+       case IW_AUTH_CIPHER_GROUP:
+               if (param->value &
+                   (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
+                       pr_debug("%s: WEP selected\n", __func__);
+                       wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
+               }
+               if (param->value & IW_AUTH_CIPHER_TKIP) {
+                       pr_debug("%s: TKIP selected\n", __func__);
+                       wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
+               }
+               if (param->value & IW_AUTH_CIPHER_CCMP) {
+                       pr_debug("%s: CCMP selected\n", __func__);
+                       wl->group_cipher_method = GELIC_WL_CIPHER_AES;
+               }
+               if (param->value & IW_AUTH_CIPHER_NONE) {
+                       pr_debug("%s: no auth selected\n", __func__);
+                       wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
+               }
+               break;
+       case IW_AUTH_80211_AUTH_ALG:
+               if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+                       pr_debug("%s: shared key specified\n", __func__);
+                       wl->auth_method = GELIC_EURUS_AUTH_SHARED;
+               } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+                       pr_debug("%s: open system specified\n", __func__);
+                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
+               } else
+                       ret = -EINVAL;
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               if (param->value) {
+                       pr_debug("%s: WPA enabled\n", __func__);
+                       wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
+               } else {
+                       pr_debug("%s: WPA disabled\n", __func__);
+                       wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
+               }
+               break;
+
+       case IW_AUTH_KEY_MGMT:
+               if (param->value & IW_AUTH_KEY_MGMT_PSK)
+                       break;
+               /* intentionally fall through */
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       if (!ret)
+               set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
+
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       pr_debug("%s: -> %d\n", __func__, ret);
+       return ret;
+}
+
+static int gelic_wl_get_auth(struct net_device *netdev,
+                            struct iw_request_info *info,
+                            union iwreq_data *iwreq, char *extra)
+{
+       struct iw_param *param = &iwreq->param;
+       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
+       unsigned long irqflag;
+       int ret = 0;
+
+       pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
+       spin_lock_irqsave(&wl->lock, irqflag);
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+               switch (wl->wpa_level) {
+               case GELIC_WL_WPA_LEVEL_WPA:
+                       param->value |= IW_AUTH_WPA_VERSION_WPA;
+                       break;
+               case GELIC_WL_WPA_LEVEL_WPA2:
+                       param->value |= IW_AUTH_WPA_VERSION_WPA2;
+                       break;
+               default:
+                       param->value |= IW_AUTH_WPA_VERSION_DISABLED;
+               }
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               if (wl->auth_method == GELIC_EURUS_AUTH_SHARED)
+                       param->value = IW_AUTH_ALG_SHARED_KEY;
+               else if (wl->auth_method == GELIC_EURUS_AUTH_OPEN)
+                       param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               switch (wl->wpa_level) {
+               case GELIC_WL_WPA_LEVEL_WPA:
+               case GELIC_WL_WPA_LEVEL_WPA2:
+                       param->value = 1;
+                       break;
+               default:
+                       param->value = 0;
+                       break;
+               }
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+       }
+
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       pr_debug("%s: -> %d\n", __func__, ret);
+       return ret;
+}
+
+/* SIOC{S,G}IWESSID */
+static int gelic_wl_set_essid(struct net_device *netdev,
+                             struct iw_request_info *info,
+                             union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       unsigned long irqflag;
+
+       pr_debug("%s: <- l=%d f=%d\n", __func__,
+                data->essid.length, data->essid.flags);
+       if (IW_ESSID_MAX_SIZE < data->essid.length)
+               return -EINVAL;
+
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (data->essid.flags) {
+               wl->essid_len = data->essid.length;
+               memcpy(wl->essid, extra, wl->essid_len);
+               pr_debug("%s: essid = '%s'\n", __func__, extra);
+               set_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
+       } else {
+               pr_debug("%s: ESSID any\n", __func__);
+               clear_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
+       }
+       set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+
+
+       gelic_wl_try_associate(netdev); /* FIXME */
+       pr_debug("%s: ->\n", __func__);
+       return 0;
+}
+
+static int gelic_wl_get_essid(struct net_device *netdev,
+                             struct iw_request_info *info,
+                             union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       unsigned long irqflag;
+
+       pr_debug("%s: <-\n", __func__);
+       mutex_lock(&wl->assoc_stat_lock);
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) ||
+           wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
+               memcpy(extra, wl->essid, wl->essid_len);
+               data->essid.length = wl->essid_len;
+               data->essid.flags = 1;
+       } else
+               data->essid.flags = 0;
+
+       mutex_unlock(&wl->assoc_stat_lock);
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       pr_debug("%s: -> len=%d\n", __func__, data->essid.length);
+
+       return 0;
+}
+
+/* SIO{S,G}IWENCODE */
+static int gelic_wl_set_encode(struct net_device *netdev,
+                              struct iw_request_info *info,
+                              union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       struct iw_point *enc = &data->encoding;
+       __u16 flags;
+       unsigned long irqflag;
+       int key_index, index_specified;
+       int ret = 0;
+
+       pr_debug("%s: <-\n", __func__);
+       flags = enc->flags & IW_ENCODE_FLAGS;
+       key_index = enc->flags & IW_ENCODE_INDEX;
+
+       pr_debug("%s: key_index = %d\n", __func__, key_index);
+       pr_debug("%s: key_len = %d\n", __func__, enc->length);
+       pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
+
+       if (GELIC_WEP_KEYS < key_index)
+               return -EINVAL;
+
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (key_index) {
+               index_specified = 1;
+               key_index--;
+       } else {
+               index_specified = 0;
+               key_index = wl->current_key;
+       }
+
+       if (flags & IW_ENCODE_NOKEY) {
+               /* if just IW_ENCODE_NOKEY, change current key index */
+               if (!flags && index_specified) {
+                       wl->current_key = key_index;
+                       goto done;
+               }
+
+               if (flags & IW_ENCODE_DISABLED) {
+                       if (!index_specified) {
+                               /* disable encryption */
+                               wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
+                               wl->pairwise_cipher_method =
+                                       GELIC_WL_CIPHER_NONE;
+                               /* invalidate all key */
+                               wl->key_enabled = 0;
+                       } else
+                               clear_bit(key_index, &wl->key_enabled);
+               }
+
+               if (flags & IW_ENCODE_OPEN)
+                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
+               if (flags & IW_ENCODE_RESTRICTED) {
+                       pr_info("%s: shared key mode enabled\n", __func__);
+                       wl->auth_method = GELIC_EURUS_AUTH_SHARED;
+               }
+       } else {
+               if (IW_ENCODING_TOKEN_MAX < enc->length) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+               wl->key_len[key_index] = enc->length;
+               memcpy(wl->key[key_index], extra, enc->length);
+               set_bit(key_index, &wl->key_enabled);
+               wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
+               wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
+       }
+       set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
+done:
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       pr_debug("%s: ->\n", __func__);
+       return ret;
+}
+
+static int gelic_wl_get_encode(struct net_device *netdev,
+                              struct iw_request_info *info,
+                              union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       struct iw_point *enc = &data->encoding;
+       unsigned long irqflag;
+       unsigned int key_index, index_specified;
+       int ret = 0;
+
+       pr_debug("%s: <-\n", __func__);
+       key_index = enc->flags & IW_ENCODE_INDEX;
+       pr_debug("%s: flag=%#x point=%p len=%d extra=%p\n", __func__,
+                enc->flags, enc->pointer, enc->length, extra);
+       if (GELIC_WEP_KEYS < key_index)
+               return -EINVAL;
+
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (key_index) {
+               index_specified = 1;
+               key_index--;
+       } else {
+               index_specified = 0;
+               key_index = wl->current_key;
+       }
+
+       if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
+               switch (wl->auth_method) {
+               case GELIC_EURUS_AUTH_OPEN:
+                       enc->flags = IW_ENCODE_OPEN;
+                       break;
+               case GELIC_EURUS_AUTH_SHARED:
+                       enc->flags = IW_ENCODE_RESTRICTED;
+                       break;
+               }
+       } else
+               enc->flags = IW_ENCODE_DISABLED;
+
+       if (test_bit(key_index, &wl->key_enabled)) {
+               if (enc->length < wl->key_len[key_index]) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+               enc->length = wl->key_len[key_index];
+               memcpy(extra, wl->key[key_index], wl->key_len[key_index]);
+       } else {
+               enc->length = 0;
+               enc->flags |= IW_ENCODE_NOKEY;
+       }
+       enc->flags |= key_index + 1;
+       pr_debug("%s: -> flag=%x len=%d\n", __func__,
+                enc->flags, enc->length);
+
+done:
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       return ret;
+}
+
+/* SIOC{S,G}IWAP */
+static int gelic_wl_set_ap(struct net_device *netdev,
+                          struct iw_request_info *info,
+                          union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       unsigned long irqflag;
+
+       pr_debug("%s: <-\n", __func__);
+       if (data->ap_addr.sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (is_valid_ether_addr(data->ap_addr.sa_data)) {
+               memcpy(wl->bssid, data->ap_addr.sa_data,
+                      ETH_ALEN);
+               set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
+               set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
+               pr_debug("%s: bss=%pM\n", __func__, wl->bssid);
+       } else {
+               pr_debug("%s: clear bssid\n", __func__);
+               clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
+               memset(wl->bssid, 0, ETH_ALEN);
+       }
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       pr_debug("%s: ->\n", __func__);
+       return 0;
+}
+
+static int gelic_wl_get_ap(struct net_device *netdev,
+                          struct iw_request_info *info,
+                          union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       unsigned long irqflag;
+
+       pr_debug("%s: <-\n", __func__);
+       mutex_lock(&wl->assoc_stat_lock);
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
+               data->ap_addr.sa_family = ARPHRD_ETHER;
+               memcpy(data->ap_addr.sa_data, wl->active_bssid,
+                      ETH_ALEN);
+       } else
+               memset(data->ap_addr.sa_data, 0, ETH_ALEN);
+
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       mutex_unlock(&wl->assoc_stat_lock);
+       pr_debug("%s: ->\n", __func__);
+       return 0;
+}
+
+/* SIOC{S,G}IWENCODEEXT */
+static int gelic_wl_set_encodeext(struct net_device *netdev,
+                                 struct iw_request_info *info,
+                                 union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       struct iw_point *enc = &data->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       __u16 alg;
+       __u16 flags;
+       unsigned long irqflag;
+       int key_index;
+       int ret = 0;
+
+       pr_debug("%s: <-\n", __func__);
+       flags = enc->flags & IW_ENCODE_FLAGS;
+       alg = ext->alg;
+       key_index = enc->flags & IW_ENCODE_INDEX;
+
+       pr_debug("%s: key_index = %d\n", __func__, key_index);
+       pr_debug("%s: key_len = %d\n", __func__, enc->length);
+       pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
+       pr_debug("%s: ext_flag=%x\n", __func__, ext->ext_flags);
+       pr_debug("%s: ext_key_len=%x\n", __func__, ext->key_len);
+
+       if (GELIC_WEP_KEYS < key_index)
+               return -EINVAL;
+
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (key_index)
+               key_index--;
+       else
+               key_index = wl->current_key;
+
+       if (!enc->length && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
+               /* reques to change default key index */
+               pr_debug("%s: request to change default key to %d\n",
+                        __func__, key_index);
+               wl->current_key = key_index;
+               goto done;
+       }
+
+       if (alg == IW_ENCODE_ALG_NONE || (flags & IW_ENCODE_DISABLED)) {
+               pr_debug("%s: alg disabled\n", __func__);
+               wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
+               wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
+               wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
+               wl->auth_method = GELIC_EURUS_AUTH_OPEN; /* should be open */
+       } else if (alg == IW_ENCODE_ALG_WEP) {
+               pr_debug("%s: WEP requested\n", __func__);
+               if (flags & IW_ENCODE_OPEN) {
+                       pr_debug("%s: open key mode\n", __func__);
+                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
+               }
+               if (flags & IW_ENCODE_RESTRICTED) {
+                       pr_debug("%s: shared key mode\n", __func__);
+                       wl->auth_method = GELIC_EURUS_AUTH_SHARED;
+               }
+               if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
+                       pr_info("%s: key is too long %d\n", __func__,
+                               ext->key_len);
+                       ret = -EINVAL;
+                       goto done;
+               }
+               /* OK, update the key */
+               wl->key_len[key_index] = ext->key_len;
+               memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
+               memcpy(wl->key[key_index], ext->key, ext->key_len);
+               set_bit(key_index, &wl->key_enabled);
+               /* remember wep info changed */
+               set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
+       } else if (alg == IW_ENCODE_ALG_PMK) {
+               if (ext->key_len != WPA_PSK_LEN) {
+                       pr_err("%s: PSK length wrong %d\n", __func__,
+                              ext->key_len);
+                       ret = -EINVAL;
+                       goto done;
+               }
+               memset(wl->psk, 0, sizeof(wl->psk));
+               memcpy(wl->psk, ext->key, ext->key_len);
+               wl->psk_len = ext->key_len;
+               wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
+               /* remember PSK configured */
+               set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
+       }
+done:
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       pr_debug("%s: ->\n", __func__);
+       return ret;
+}
+
+static int gelic_wl_get_encodeext(struct net_device *netdev,
+                                 struct iw_request_info *info,
+                                 union iwreq_data *data, char *extra)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       struct iw_point *enc = &data->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       unsigned long irqflag;
+       int key_index;
+       int ret = 0;
+       int max_key_len;
+
+       pr_debug("%s: <-\n", __func__);
+
+       max_key_len = enc->length - sizeof(struct iw_encode_ext);
+       if (max_key_len < 0)
+               return -EINVAL;
+       key_index = enc->flags & IW_ENCODE_INDEX;
+
+       pr_debug("%s: key_index = %d\n", __func__, key_index);
+       pr_debug("%s: key_len = %d\n", __func__, enc->length);
+       pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
+
+       if (GELIC_WEP_KEYS < key_index)
+               return -EINVAL;
+
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (key_index)
+               key_index--;
+       else
+               key_index = wl->current_key;
+
+       memset(ext, 0, sizeof(struct iw_encode_ext));
+       switch (wl->group_cipher_method) {
+       case GELIC_WL_CIPHER_WEP:
+               ext->alg = IW_ENCODE_ALG_WEP;
+               enc->flags |= IW_ENCODE_ENABLED;
+               break;
+       case GELIC_WL_CIPHER_TKIP:
+               ext->alg = IW_ENCODE_ALG_TKIP;
+               enc->flags |= IW_ENCODE_ENABLED;
+               break;
+       case GELIC_WL_CIPHER_AES:
+               ext->alg = IW_ENCODE_ALG_CCMP;
+               enc->flags |= IW_ENCODE_ENABLED;
+               break;
+       case GELIC_WL_CIPHER_NONE:
+       default:
+               ext->alg = IW_ENCODE_ALG_NONE;
+               enc->flags |= IW_ENCODE_NOKEY;
+               break;
+       }
+
+       if (!(enc->flags & IW_ENCODE_NOKEY)) {
+               if (max_key_len < wl->key_len[key_index]) {
+                       ret = -E2BIG;
+                       goto out;
+               }
+               if (test_bit(key_index, &wl->key_enabled))
+                       memcpy(ext->key, wl->key[key_index],
+                              wl->key_len[key_index]);
+               else
+                       pr_debug("%s: disabled key requested ix=%d\n",
+                                __func__, key_index);
+       }
+out:
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+       pr_debug("%s: ->\n", __func__);
+       return ret;
+}
+/* SIOC{S,G}IWMODE */
+static int gelic_wl_set_mode(struct net_device *netdev,
+                            struct iw_request_info *info,
+                            union iwreq_data *data, char *extra)
+{
+       __u32 mode = data->mode;
+       int ret;
+
+       pr_debug("%s: <-\n", __func__);
+       if (mode == IW_MODE_INFRA)
+               ret = 0;
+       else
+               ret = -EOPNOTSUPP;
+       pr_debug("%s: -> %d\n", __func__, ret);
+       return ret;
+}
+
+static int gelic_wl_get_mode(struct net_device *netdev,
+                            struct iw_request_info *info,
+                            union iwreq_data *data, char *extra)
+{
+       __u32 *mode = &data->mode;
+       pr_debug("%s: <-\n", __func__);
+       *mode = IW_MODE_INFRA;
+       pr_debug("%s: ->\n", __func__);
+       return 0;
+}
+
+/* SIOCGIWNICKN */
+static int gelic_wl_get_nick(struct net_device *net_dev,
+                                 struct iw_request_info *info,
+                                 union iwreq_data *data, char *extra)
+{
+       strcpy(extra, "gelic_wl");
+       data->data.length = strlen(extra);
+       data->data.flags = 1;
+       return 0;
+}
+
+
+/* --- */
+
+static struct iw_statistics *gelic_wl_get_wireless_stats(
+       struct net_device *netdev)
+{
+
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       struct gelic_eurus_cmd *cmd;
+       struct iw_statistics *is;
+       struct gelic_eurus_rssi_info *rssi;
+       void *buf;
+
+       pr_debug("%s: <-\n", __func__);
+
+       buf = (void *)__get_free_page(GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       is = &wl->iwstat;
+       memset(is, 0, sizeof(*is));
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG,
+                                  buf, sizeof(*rssi));
+       if (cmd && !cmd->status && !cmd->cmd_status) {
+               rssi = buf;
+               is->qual.level = be16_to_cpu(rssi->rssi);
+               is->qual.updated = IW_QUAL_LEVEL_UPDATED |
+                       IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
+       } else
+               /* not associated */
+               is->qual.updated = IW_QUAL_ALL_INVALID;
+
+       kfree(cmd);
+       free_page((unsigned long)buf);
+       pr_debug("%s: ->\n", __func__);
+       return is;
+}
+
+/*
+ *  scanning helpers
+ */
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+                              u8 *essid, size_t essid_len)
+{
+       struct gelic_eurus_cmd *cmd;
+       int ret = 0;
+       void *buf = NULL;
+       size_t len;
+
+       pr_debug("%s: <- always=%d\n", __func__, always_scan);
+       if (mutex_lock_interruptible(&wl->scan_lock))
+               return -ERESTARTSYS;
+
+       /*
+        * If already a scan in progress, do not trigger more
+        */
+       if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING) {
+               pr_debug("%s: scanning now\n", __func__);
+               goto out;
+       }
+
+       init_completion(&wl->scan_done);
+       /*
+        * If we have already a bss list, don't try to get new
+        * unless we are doing an ESSID scan
+        */
+       if ((!essid_len && !always_scan)
+           && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
+               pr_debug("%s: already has the list\n", __func__);
+               complete(&wl->scan_done);
+               goto out;
+       }
+
+       /* ESSID scan ? */
+       if (essid_len && essid) {
+               buf = (void *)__get_free_page(GFP_KERNEL);
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */
+               memset(buf, 0, len);
+               memcpy(buf, essid, essid_len);
+               pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf);
+       } else
+               len = 0;
+
+       /*
+        * issue start scan request
+        */
+       wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
+                                  buf, len);
+       if (!cmd || cmd->status || cmd->cmd_status) {
+               wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
+               complete(&wl->scan_done);
+               ret = -ENOMEM;
+               goto out;
+       }
+       kfree(cmd);
+out:
+       free_page((unsigned long)buf);
+       mutex_unlock(&wl->scan_lock);
+       pr_debug("%s: ->\n", __func__);
+       return ret;
+}
+
+/*
+ * retrieve scan result from the chip (hypervisor)
+ * this function is invoked by schedule work.
+ */
+static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
+{
+       struct gelic_eurus_cmd *cmd = NULL;
+       struct gelic_wl_scan_info *target, *tmp;
+       struct gelic_wl_scan_info *oldest = NULL;
+       struct gelic_eurus_scan_info *scan_info;
+       unsigned int scan_info_size;
+       union iwreq_data data;
+       unsigned long this_time = jiffies;
+       unsigned int data_len, i, found, r;
+       void *buf;
+
+       pr_debug("%s:start\n", __func__);
+       mutex_lock(&wl->scan_lock);
+
+       buf = (void *)__get_free_page(GFP_KERNEL);
+       if (!buf) {
+               pr_info("%s: scan buffer alloc failed\n", __func__);
+               goto out;
+       }
+
+       if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) {
+               /*
+                * stop() may be called while scanning, ignore result
+                */
+               pr_debug("%s: scan complete when stat != scanning(%d)\n",
+                        __func__, wl->scan_stat);
+               goto out;
+       }
+
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN,
+                                  buf, PAGE_SIZE);
+       if (!cmd || cmd->status || cmd->cmd_status) {
+               wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
+               pr_info("%s:cmd failed\n", __func__);
+               kfree(cmd);
+               goto out;
+       }
+       data_len = cmd->size;
+       pr_debug("%s: data_len = %d\n", __func__, data_len);
+       kfree(cmd);
+
+       /* OK, bss list retrieved */
+       wl->scan_stat = GELIC_WL_SCAN_STAT_GOT_LIST;
+
+       /* mark all entries are old */
+       list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
+               target->valid = 0;
+               /* expire too old entries */
+               if (time_before(target->last_scanned + wl->scan_age,
+                               this_time)) {
+                       kfree(target->hwinfo);
+                       target->hwinfo = NULL;
+                       list_move_tail(&target->list, &wl->network_free_list);
+               }
+       }
+
+       /* put them in the network_list */
+       for (i = 0, scan_info_size = 0, scan_info = buf;
+            scan_info_size < data_len;
+            i++, scan_info_size += be16_to_cpu(scan_info->size),
+            scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
+               pr_debug("%s:size=%d bssid=%pM scan_info=%p\n", __func__,
+                        be16_to_cpu(scan_info->size),
+                        &scan_info->bssid[2], scan_info);
+
+               /*
+                * The wireless firmware may return invalid channel 0 and/or
+                * invalid rate if the AP emits zero length SSID ie. As this
+                * scan information is useless, ignore it
+                */
+               if (!be16_to_cpu(scan_info->channel) || !scan_info->rate[0]) {
+                       pr_debug("%s: invalid scan info\n", __func__);
+                       continue;
+               }
+
+               found = 0;
+               oldest = NULL;
+               list_for_each_entry(target, &wl->network_list, list) {
+                       if (!compare_ether_addr(&target->hwinfo->bssid[2],
+                                               &scan_info->bssid[2])) {
+                               found = 1;
+                               pr_debug("%s: same BBS found scanned list\n",
+                                        __func__);
+                               break;
+                       }
+                       if (!oldest ||
+                           (target->last_scanned < oldest->last_scanned))
+                               oldest = target;
+               }
+
+               if (!found) {
+                       /* not found in the list */
+                       if (list_empty(&wl->network_free_list)) {
+                               /* expire oldest */
+                               target = oldest;
+                       } else {
+                               target = list_entry(wl->network_free_list.next,
+                                                   struct gelic_wl_scan_info,
+                                                   list);
+                       }
+               }
+
+               /* update the item */
+               target->last_scanned = this_time;
+               target->valid = 1;
+               target->eurus_index = i;
+               kfree(target->hwinfo);
+               target->hwinfo = kzalloc(be16_to_cpu(scan_info->size),
+                                        GFP_KERNEL);
+               if (!target->hwinfo) {
+                       pr_info("%s: kzalloc failed\n", __func__);
+                       continue;
+               }
+               /* copy hw scan info */
+               memcpy(target->hwinfo, scan_info, scan_info->size);
+               target->essid_len = strnlen(scan_info->essid,
+                                           sizeof(scan_info->essid));
+               target->rate_len = 0;
+               for (r = 0; r < 12; r++)
+                       if (scan_info->rate[r])
+                               target->rate_len++;
+               if (8 < target->rate_len)
+                       pr_info("%s: AP returns %d rates\n", __func__,
+                               target->rate_len);
+               target->rate_ext_len = 0;
+               for (r = 0; r < 16; r++)
+                       if (scan_info->ext_rate[r])
+                               target->rate_ext_len++;
+               list_move_tail(&target->list, &wl->network_list);
+       }
+       memset(&data, 0, sizeof(data));
+       wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data,
+                           NULL);
+out:
+       free_page((unsigned long)buf);
+       complete(&wl->scan_done);
+       mutex_unlock(&wl->scan_lock);
+       pr_debug("%s:end\n", __func__);
+}
+
+/*
+ * Select an appropriate bss from current scan list regarding
+ * current settings from userspace.
+ * The caller must hold wl->scan_lock,
+ * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
+ */
+static void update_best(struct gelic_wl_scan_info **best,
+                       struct gelic_wl_scan_info *candid,
+                       int *best_weight,
+                       int *weight)
+{
+       if (*best_weight < ++(*weight)) {
+               *best_weight = *weight;
+               *best = candid;
+       }
+}
+
+static
+struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl)
+{
+       struct gelic_wl_scan_info *scan_info;
+       struct gelic_wl_scan_info *best_bss;
+       int weight, best_weight;
+       u16 security;
+
+       pr_debug("%s: <-\n", __func__);
+
+       best_bss = NULL;
+       best_weight = 0;
+
+       list_for_each_entry(scan_info, &wl->network_list, list) {
+               pr_debug("%s: station %p\n", __func__, scan_info);
+
+               if (!scan_info->valid) {
+                       pr_debug("%s: station invalid\n", __func__);
+                       continue;
+               }
+
+               /* If bss specified, check it only */
+               if (test_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat)) {
+                       if (!compare_ether_addr(&scan_info->hwinfo->bssid[2],
+                                               wl->bssid)) {
+                               best_bss = scan_info;
+                               pr_debug("%s: bssid matched\n", __func__);
+                               break;
+                       } else {
+                               pr_debug("%s: bssid unmached\n", __func__);
+                               continue;
+                       }
+               }
+
+               weight = 0;
+
+               /* security */
+               security = be16_to_cpu(scan_info->hwinfo->security) &
+                       GELIC_EURUS_SCAN_SEC_MASK;
+               if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
+                       if (security == GELIC_EURUS_SCAN_SEC_WPA2)
+                               update_best(&best_bss, scan_info,
+                                           &best_weight, &weight);
+                       else
+                               continue;
+               } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA) {
+                       if (security == GELIC_EURUS_SCAN_SEC_WPA)
+                               update_best(&best_bss, scan_info,
+                                           &best_weight, &weight);
+                       else
+                               continue;
+               } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_NONE &&
+                          wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
+                       if (security == GELIC_EURUS_SCAN_SEC_WEP)
+                               update_best(&best_bss, scan_info,
+                                           &best_weight, &weight);
+                       else
+                               continue;
+               }
+
+               /* If ESSID is set, check it */
+               if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
+                       if ((scan_info->essid_len == wl->essid_len) &&
+                           !strncmp(wl->essid,
+                                    scan_info->hwinfo->essid,
+                                    scan_info->essid_len))
+                               update_best(&best_bss, scan_info,
+                                           &best_weight, &weight);
+                       else
+                               continue;
+               }
+       }
+
+#ifdef DEBUG
+       pr_debug("%s: -> bss=%p\n", __func__, best_bss);
+       if (best_bss) {
+               pr_debug("%s:addr=%pM\n", __func__,
+                        &best_bss->hwinfo->bssid[2]);
+       }
+#endif
+       return best_bss;
+}
+
+/*
+ * Setup WEP configuration to the chip
+ * The caller must hold wl->scan_lock,
+ * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
+ */
+static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
+{
+       unsigned int i;
+       struct gelic_eurus_wep_cfg *wep;
+       struct gelic_eurus_cmd *cmd;
+       int wep104 = 0;
+       int have_key = 0;
+       int ret = 0;
+
+       pr_debug("%s: <-\n", __func__);
+       /* we can assume no one should uses the buffer */
+       wep = (struct gelic_eurus_wep_cfg *)__get_free_page(GFP_KERNEL);
+       if (!wep)
+               return -ENOMEM;
+
+       memset(wep, 0, sizeof(*wep));
+
+       if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
+               pr_debug("%s: WEP mode\n", __func__);
+               for (i = 0; i < GELIC_WEP_KEYS; i++) {
+                       if (!test_bit(i, &wl->key_enabled))
+                               continue;
+
+                       pr_debug("%s: key#%d enabled\n", __func__, i);
+                       have_key = 1;
+                       if (wl->key_len[i] == 13)
+                               wep104 = 1;
+                       else if (wl->key_len[i] != 5) {
+                               pr_info("%s: wrong wep key[%d]=%d\n",
+                                       __func__, i, wl->key_len[i]);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       memcpy(wep->key[i], wl->key[i], wl->key_len[i]);
+               }
+
+               if (!have_key) {
+                       pr_info("%s: all wep key disabled\n", __func__);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (wep104) {
+                       pr_debug("%s: 104bit key\n", __func__);
+                       wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_104BIT);
+               } else {
+                       pr_debug("%s: 40bit key\n", __func__);
+                       wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_40BIT);
+               }
+       } else {
+               pr_debug("%s: NO encryption\n", __func__);
+               wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_NONE);
+       }
+
+       /* issue wep setup */
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WEP_CFG,
+                                  wep, sizeof(*wep));
+       if (!cmd)
+               ret = -ENOMEM;
+       else if (cmd->status || cmd->cmd_status)
+               ret = -ENXIO;
+
+       kfree(cmd);
+out:
+       free_page((unsigned long)wep);
+       pr_debug("%s: ->\n", __func__);
+       return ret;
+}
+
+#ifdef DEBUG
+static const char *wpasecstr(enum gelic_eurus_wpa_security sec)
+{
+       switch (sec) {
+       case GELIC_EURUS_WPA_SEC_NONE:
+               return "NONE";
+               break;
+       case GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP:
+               return "WPA_TKIP_TKIP";
+               break;
+       case GELIC_EURUS_WPA_SEC_WPA_TKIP_AES:
+               return "WPA_TKIP_AES";
+               break;
+       case GELIC_EURUS_WPA_SEC_WPA_AES_AES:
+               return "WPA_AES_AES";
+               break;
+       case GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP:
+               return "WPA2_TKIP_TKIP";
+               break;
+       case GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES:
+               return "WPA2_TKIP_AES";
+               break;
+       case GELIC_EURUS_WPA_SEC_WPA2_AES_AES:
+               return "WPA2_AES_AES";
+               break;
+       }
+       return "";
+};
+#endif
+
+static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
+{
+       struct gelic_eurus_wpa_cfg *wpa;
+       struct gelic_eurus_cmd *cmd;
+       u16 security;
+       int ret = 0;
+
+       pr_debug("%s: <-\n", __func__);
+       /* we can assume no one should uses the buffer */
+       wpa = (struct gelic_eurus_wpa_cfg *)__get_free_page(GFP_KERNEL);
+       if (!wpa)
+               return -ENOMEM;
+
+       memset(wpa, 0, sizeof(*wpa));
+
+       if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat))
+               pr_info("%s: PSK not configured yet\n", __func__);
+
+       /* copy key */
+       memcpy(wpa->psk, wl->psk, wl->psk_len);
+
+       /* set security level */
+       if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
+               if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
+                       security = GELIC_EURUS_WPA_SEC_WPA2_AES_AES;
+               } else {
+                       if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
+                           precise_ie())
+                               security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES;
+                       else
+                               security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP;
+               }
+       } else {
+               if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
+                       security = GELIC_EURUS_WPA_SEC_WPA_AES_AES;
+               } else {
+                       if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
+                           precise_ie())
+                               security = GELIC_EURUS_WPA_SEC_WPA_TKIP_AES;
+                       else
+                               security = GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP;
+               }
+       }
+       wpa->security = cpu_to_be16(security);
+
+       /* PSK type */
+       wpa->psk_type = cpu_to_be16(wl->psk_type);
+#ifdef DEBUG
+       pr_debug("%s: sec=%s psktype=%s\n", __func__,
+                wpasecstr(wpa->security),
+                (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
+                "BIN" : "passphrase");
+#if 0
+       /*
+        * don't enable here if you plan to submit
+        * the debug log because this dumps your precious
+        * passphrase/key.
+        */
+       pr_debug("%s: psk=%s\n", __func__,
+                (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
+                "N/A" : wpa->psk);
+#endif
+#endif
+       /* issue wpa setup */
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WPA_CFG,
+                                  wpa, sizeof(*wpa));
+       if (!cmd)
+               ret = -ENOMEM;
+       else if (cmd->status || cmd->cmd_status)
+               ret = -ENXIO;
+       kfree(cmd);
+       free_page((unsigned long)wpa);
+       pr_debug("%s: --> %d\n", __func__, ret);
+       return ret;
+}
+
+/*
+ * Start association. caller must hold assoc_stat_lock
+ */
+static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
+                                 struct gelic_wl_scan_info *bss)
+{
+       struct gelic_eurus_cmd *cmd;
+       struct gelic_eurus_common_cfg *common;
+       int ret = 0;
+       unsigned long rc;
+
+       pr_debug("%s: <-\n", __func__);
+
+       /* do common config */
+       common = (struct gelic_eurus_common_cfg *)__get_free_page(GFP_KERNEL);
+       if (!common)
+               return -ENOMEM;
+
+       memset(common, 0, sizeof(*common));
+       common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA);
+       common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG);
+
+       common->scan_index = cpu_to_be16(bss->eurus_index);
+       switch (wl->auth_method) {
+       case GELIC_EURUS_AUTH_OPEN:
+               common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_OPEN);
+               break;
+       case GELIC_EURUS_AUTH_SHARED:
+               common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_SHARED);
+               break;
+       }
+
+#ifdef DEBUG
+       scan_list_dump(wl);
+#endif
+       pr_debug("%s: common cfg index=%d bsstype=%d auth=%d\n", __func__,
+                be16_to_cpu(common->scan_index),
+                be16_to_cpu(common->bss_type),
+                be16_to_cpu(common->auth_method));
+
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_COMMON_CFG,
+                                  common, sizeof(*common));
+       if (!cmd || cmd->status || cmd->cmd_status) {
+               ret = -ENOMEM;
+               kfree(cmd);
+               goto out;
+       }
+       kfree(cmd);
+
+       /* WEP/WPA */
+       switch (wl->wpa_level) {
+       case GELIC_WL_WPA_LEVEL_NONE:
+               /* If WEP or no security, setup WEP config */
+               ret = gelic_wl_do_wep_setup(wl);
+               break;
+       case GELIC_WL_WPA_LEVEL_WPA:
+       case GELIC_WL_WPA_LEVEL_WPA2:
+               ret = gelic_wl_do_wpa_setup(wl);
+               break;
+       }
+
+       if (ret) {
+               pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
+                        ret);
+               ret = -EPERM;
+               gelic_wl_send_iwap_event(wl, NULL);
+               goto out;
+       }
+
+       /* start association */
+       init_completion(&wl->assoc_done);
+       wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATING;
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_ASSOC,
+                                  NULL, 0);
+       if (!cmd || cmd->status || cmd->cmd_status) {
+               pr_debug("%s: assoc request failed\n", __func__);
+               wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
+               kfree(cmd);
+               ret = -ENOMEM;
+               gelic_wl_send_iwap_event(wl, NULL);
+               goto out;
+       }
+       kfree(cmd);
+
+       /* wait for connected event */
+       rc = wait_for_completion_timeout(&wl->assoc_done, HZ * 4);/*FIXME*/
+
+       if (!rc) {
+               /* timeouted.  Maybe key or cyrpt mode is wrong */
+               pr_info("%s: connect timeout\n", __func__);
+               cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC,
+                                          NULL, 0);
+               kfree(cmd);
+               wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
+               gelic_wl_send_iwap_event(wl, NULL);
+               ret = -ENXIO;
+       } else {
+               wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATED;
+               /* copy bssid */
+               memcpy(wl->active_bssid, &bss->hwinfo->bssid[2], ETH_ALEN);
+
+               /* send connect event */
+               gelic_wl_send_iwap_event(wl, wl->active_bssid);
+               pr_info("%s: connected\n", __func__);
+       }
+out:
+       free_page((unsigned long)common);
+       pr_debug("%s: ->\n", __func__);
+       return ret;
+}
+
+/*
+ * connected event
+ */
+static void gelic_wl_connected_event(struct gelic_wl_info *wl,
+                                    u64 event)
+{
+       u64 desired_event = 0;
+
+       switch (wl->wpa_level) {
+       case GELIC_WL_WPA_LEVEL_NONE:
+               desired_event = GELIC_LV1_WL_EVENT_CONNECTED;
+               break;
+       case GELIC_WL_WPA_LEVEL_WPA:
+       case GELIC_WL_WPA_LEVEL_WPA2:
+               desired_event = GELIC_LV1_WL_EVENT_WPA_CONNECTED;
+               break;
+       }
+
+       if (desired_event == event) {
+               pr_debug("%s: completed\n", __func__);
+               complete(&wl->assoc_done);
+               netif_carrier_on(port_to_netdev(wl_port(wl)));
+       } else
+               pr_debug("%s: event %#llx under wpa\n",
+                                __func__, event);
+}
+
+/*
+ * disconnect event
+ */
+static void gelic_wl_disconnect_event(struct gelic_wl_info *wl,
+                                     u64 event)
+{
+       struct gelic_eurus_cmd *cmd;
+       int lock;
+
+       /*
+        * If we fall here in the middle of association,
+        * associate_bss() should be waiting for complation of
+        * wl->assoc_done.
+        * As it waits with timeout, just leave assoc_done
+        * uncompleted, then it terminates with timeout
+        */
+       if (!mutex_trylock(&wl->assoc_stat_lock)) {
+               pr_debug("%s: already locked\n", __func__);
+               lock = 0;
+       } else {
+               pr_debug("%s: obtain lock\n", __func__);
+               lock = 1;
+       }
+
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
+       kfree(cmd);
+
+       /* send disconnected event to the supplicant */
+       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
+               gelic_wl_send_iwap_event(wl, NULL);
+
+       wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
+       netif_carrier_off(port_to_netdev(wl_port(wl)));
+
+       if (lock)
+               mutex_unlock(&wl->assoc_stat_lock);
+}
+/*
+ * event worker
+ */
+#ifdef DEBUG
+static const char *eventstr(enum gelic_lv1_wl_event event)
+{
+       static char buf[32];
+       char *ret;
+       if (event & GELIC_LV1_WL_EVENT_DEVICE_READY)
+               ret = "EURUS_READY";
+       else if (event & GELIC_LV1_WL_EVENT_SCAN_COMPLETED)
+               ret = "SCAN_COMPLETED";
+       else if (event & GELIC_LV1_WL_EVENT_DEAUTH)
+               ret = "DEAUTH";
+       else if (event & GELIC_LV1_WL_EVENT_BEACON_LOST)
+               ret = "BEACON_LOST";
+       else if (event & GELIC_LV1_WL_EVENT_CONNECTED)
+               ret = "CONNECTED";
+       else if (event & GELIC_LV1_WL_EVENT_WPA_CONNECTED)
+               ret = "WPA_CONNECTED";
+       else if (event & GELIC_LV1_WL_EVENT_WPA_ERROR)
+               ret = "WPA_ERROR";
+       else {
+               sprintf(buf, "Unknown(%#x)", event);
+               ret = buf;
+       }
+       return ret;
+}
+#else
+static const char *eventstr(enum gelic_lv1_wl_event event)
+{
+       return NULL;
+}
+#endif
+static void gelic_wl_event_worker(struct work_struct *work)
+{
+       struct gelic_wl_info *wl;
+       struct gelic_port *port;
+       u64 event, tmp;
+       int status;
+
+       pr_debug("%s:start\n", __func__);
+       wl = container_of(work, struct gelic_wl_info, event_work.work);
+       port = wl_port(wl);
+       while (1) {
+               status = lv1_net_control(bus_id(port->card), dev_id(port->card),
+                                        GELIC_LV1_GET_WLAN_EVENT, 0, 0, 0,
+                                        &event, &tmp);
+               if (status) {
+                       if (status != LV1_NO_ENTRY)
+                               pr_debug("%s:wlan event failed %d\n",
+                                        __func__, status);
+                       /* got all events */
+                       pr_debug("%s:end\n", __func__);
+                       return;
+               }
+               pr_debug("%s: event=%s\n", __func__, eventstr(event));
+               switch (event) {
+               case GELIC_LV1_WL_EVENT_SCAN_COMPLETED:
+                       gelic_wl_scan_complete_event(wl);
+                       break;
+               case GELIC_LV1_WL_EVENT_BEACON_LOST:
+               case GELIC_LV1_WL_EVENT_DEAUTH:
+                       gelic_wl_disconnect_event(wl, event);
+                       break;
+               case GELIC_LV1_WL_EVENT_CONNECTED:
+               case GELIC_LV1_WL_EVENT_WPA_CONNECTED:
+                       gelic_wl_connected_event(wl, event);
+                       break;
+               default:
+                       break;
+               }
+       } /* while */
+}
+/*
+ * association worker
+ */
+static void gelic_wl_assoc_worker(struct work_struct *work)
+{
+       struct gelic_wl_info *wl;
+
+       struct gelic_wl_scan_info *best_bss;
+       int ret;
+       unsigned long irqflag;
+       u8 *essid;
+       size_t essid_len;
+
+       wl = container_of(work, struct gelic_wl_info, assoc_work.work);
+
+       mutex_lock(&wl->assoc_stat_lock);
+
+       if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
+               goto out;
+
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
+               pr_debug("%s: assoc ESSID configured %s\n", __func__,
+                        wl->essid);
+               essid = wl->essid;
+               essid_len = wl->essid_len;
+       } else {
+               essid = NULL;
+               essid_len = 0;
+       }
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+
+       ret = gelic_wl_start_scan(wl, 0, essid, essid_len);
+       if (ret == -ERESTARTSYS) {
+               pr_debug("%s: scan start failed association\n", __func__);
+               schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
+               goto out;
+       } else if (ret) {
+               pr_info("%s: scan prerequisite failed\n", __func__);
+               goto out;
+       }
+
+       /*
+        * Wait for bss scan completion
+        * If we have scan list already, gelic_wl_start_scan()
+        * returns OK and raises the complete.  Thus,
+        * it's ok to wait unconditionally here
+        */
+       wait_for_completion(&wl->scan_done);
+
+       pr_debug("%s: scan done\n", __func__);
+       mutex_lock(&wl->scan_lock);
+       if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) {
+               gelic_wl_send_iwap_event(wl, NULL);
+               pr_info("%s: no scan list. association failed\n", __func__);
+               goto scan_lock_out;
+       }
+
+       /* find best matching bss */
+       best_bss = gelic_wl_find_best_bss(wl);
+       if (!best_bss) {
+               gelic_wl_send_iwap_event(wl, NULL);
+               pr_info("%s: no bss matched. association failed\n", __func__);
+               goto scan_lock_out;
+       }
+
+       /* ok, do association */
+       ret = gelic_wl_associate_bss(wl, best_bss);
+       if (ret)
+               pr_info("%s: association failed %d\n", __func__, ret);
+scan_lock_out:
+       mutex_unlock(&wl->scan_lock);
+out:
+       mutex_unlock(&wl->assoc_stat_lock);
+}
+/*
+ * Interrupt handler
+ * Called from the ethernet interrupt handler
+ * Processes wireless specific virtual interrupts only
+ */
+void gelic_wl_interrupt(struct net_device *netdev, u64 status)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+
+       if (status & GELIC_CARD_WLAN_COMMAND_COMPLETED) {
+               pr_debug("%s:cmd complete\n", __func__);
+               complete(&wl->cmd_done_intr);
+       }
+
+       if (status & GELIC_CARD_WLAN_EVENT_RECEIVED) {
+               pr_debug("%s:event received\n", __func__);
+               queue_delayed_work(wl->event_queue, &wl->event_work, 0);
+       }
+}
+
+/*
+ * driver helpers
+ */
+static const iw_handler gelic_wl_wext_handler[] =
+{
+       IW_HANDLER(SIOCGIWNAME, gelic_wl_get_name),
+       IW_HANDLER(SIOCGIWRANGE, gelic_wl_get_range),
+       IW_HANDLER(SIOCSIWSCAN, gelic_wl_set_scan),
+       IW_HANDLER(SIOCGIWSCAN, gelic_wl_get_scan),
+       IW_HANDLER(SIOCSIWAUTH, gelic_wl_set_auth),
+       IW_HANDLER(SIOCGIWAUTH, gelic_wl_get_auth),
+       IW_HANDLER(SIOCSIWESSID, gelic_wl_set_essid),
+       IW_HANDLER(SIOCGIWESSID, gelic_wl_get_essid),
+       IW_HANDLER(SIOCSIWENCODE, gelic_wl_set_encode),
+       IW_HANDLER(SIOCGIWENCODE, gelic_wl_get_encode),
+       IW_HANDLER(SIOCSIWAP, gelic_wl_set_ap),
+       IW_HANDLER(SIOCGIWAP, gelic_wl_get_ap),
+       IW_HANDLER(SIOCSIWENCODEEXT, gelic_wl_set_encodeext),
+       IW_HANDLER(SIOCGIWENCODEEXT, gelic_wl_get_encodeext),
+       IW_HANDLER(SIOCSIWMODE, gelic_wl_set_mode),
+       IW_HANDLER(SIOCGIWMODE, gelic_wl_get_mode),
+       IW_HANDLER(SIOCGIWNICKN, gelic_wl_get_nick),
+};
+
+static const struct iw_handler_def gelic_wl_wext_handler_def = {
+       .num_standard           = ARRAY_SIZE(gelic_wl_wext_handler),
+       .standard               = gelic_wl_wext_handler,
+       .get_wireless_stats     = gelic_wl_get_wireless_stats,
+};
+
+static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card)
+{
+       struct net_device *netdev;
+       struct gelic_port *port;
+       struct gelic_wl_info *wl;
+       unsigned int i;
+
+       pr_debug("%s:start\n", __func__);
+       netdev = alloc_etherdev(sizeof(struct gelic_port) +
+                               sizeof(struct gelic_wl_info));
+       pr_debug("%s: netdev =%p card=%p\n", __func__, netdev, card);
+       if (!netdev)
+               return NULL;
+
+       strcpy(netdev->name, "wlan%d");
+
+       port = netdev_priv(netdev);
+       port->netdev = netdev;
+       port->card = card;
+       port->type = GELIC_PORT_WIRELESS;
+
+       wl = port_wl(port);
+       pr_debug("%s: wl=%p port=%p\n", __func__, wl, port);
+
+       /* allocate scan list */
+       wl->networks = kzalloc(sizeof(struct gelic_wl_scan_info) *
+                              GELIC_WL_BSS_MAX_ENT, GFP_KERNEL);
+
+       if (!wl->networks)
+               goto fail_bss;
+
+       wl->eurus_cmd_queue = create_singlethread_workqueue("gelic_cmd");
+       if (!wl->eurus_cmd_queue)
+               goto fail_cmd_workqueue;
+
+       wl->event_queue = create_singlethread_workqueue("gelic_event");
+       if (!wl->event_queue)
+               goto fail_event_workqueue;
+
+       INIT_LIST_HEAD(&wl->network_free_list);
+       INIT_LIST_HEAD(&wl->network_list);
+       for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++)
+               list_add_tail(&wl->networks[i].list,
+                             &wl->network_free_list);
+       init_completion(&wl->cmd_done_intr);
+
+       INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker);
+       INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker);
+       mutex_init(&wl->scan_lock);
+       mutex_init(&wl->assoc_stat_lock);
+
+       init_completion(&wl->scan_done);
+       /* for the case that no scan request is issued and stop() is called */
+       complete(&wl->scan_done);
+
+       spin_lock_init(&wl->lock);
+
+       wl->scan_age = 5*HZ; /* FIXME */
+
+       /* buffer for receiving scanned list etc */
+       BUILD_BUG_ON(PAGE_SIZE <
+                    sizeof(struct gelic_eurus_scan_info) *
+                    GELIC_EURUS_MAX_SCAN);
+       pr_debug("%s:end\n", __func__);
+       return netdev;
+
+fail_event_workqueue:
+       destroy_workqueue(wl->eurus_cmd_queue);
+fail_cmd_workqueue:
+       kfree(wl->networks);
+fail_bss:
+       free_netdev(netdev);
+       pr_debug("%s:end error\n", __func__);
+       return NULL;
+
+}
+
+static void gelic_wl_free(struct gelic_wl_info *wl)
+{
+       struct gelic_wl_scan_info *scan_info;
+       unsigned int i;
+
+       pr_debug("%s: <-\n", __func__);
+
+       pr_debug("%s: destroy queues\n", __func__);
+       destroy_workqueue(wl->eurus_cmd_queue);
+       destroy_workqueue(wl->event_queue);
+
+       scan_info = wl->networks;
+       for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++, scan_info++)
+               kfree(scan_info->hwinfo);
+       kfree(wl->networks);
+
+       free_netdev(port_to_netdev(wl_port(wl)));
+
+       pr_debug("%s: ->\n", __func__);
+}
+
+static int gelic_wl_try_associate(struct net_device *netdev)
+{
+       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+       int ret = -1;
+       unsigned int i;
+
+       pr_debug("%s: <-\n", __func__);
+
+       /* check constraits for start association */
+       /* for no access restriction AP */
+       if (wl->group_cipher_method == GELIC_WL_CIPHER_NONE) {
+               if (test_bit(GELIC_WL_STAT_CONFIGURED,
+                            &wl->stat))
+                       goto do_associate;
+               else {
+                       pr_debug("%s: no wep, not configured\n", __func__);
+                       return ret;
+               }
+       }
+
+       /* for WEP, one of four keys should be set */
+       if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
+               /* one of keys set */
+               for (i = 0; i < GELIC_WEP_KEYS; i++) {
+                       if (test_bit(i, &wl->key_enabled))
+                           goto do_associate;
+               }
+               pr_debug("%s: WEP, but no key specified\n", __func__);
+               return ret;
+       }
+
+       /* for WPA[2], psk should be set */
+       if ((wl->group_cipher_method == GELIC_WL_CIPHER_TKIP) ||
+           (wl->group_cipher_method == GELIC_WL_CIPHER_AES)) {
+               if (test_bit(GELIC_WL_STAT_WPA_PSK_SET,
+                            &wl->stat))
+                       goto do_associate;
+               else {
+                       pr_debug("%s: AES/TKIP, but PSK not configured\n",
+                                __func__);
+                       return ret;
+               }
+       }
+
+do_associate:
+       ret = schedule_delayed_work(&wl->assoc_work, 0);
+       pr_debug("%s: start association work %d\n", __func__, ret);
+       return ret;
+}
+
+/*
+ * netdev handlers
+ */
+static int gelic_wl_open(struct net_device *netdev)
+{
+       struct gelic_card *card = netdev_card(netdev);
+
+       pr_debug("%s:->%p\n", __func__, netdev);
+
+       gelic_card_up(card);
+
+       /* try to associate */
+       gelic_wl_try_associate(netdev);
+
+       netif_start_queue(netdev);
+
+       pr_debug("%s:<-\n", __func__);
+       return 0;
+}
+
+/*
+ * reset state machine
+ */
+static int gelic_wl_reset_state(struct gelic_wl_info *wl)
+{
+       struct gelic_wl_scan_info *target;
+       struct gelic_wl_scan_info *tmp;
+
+       /* empty scan list */
+       list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
+               list_move_tail(&target->list, &wl->network_free_list);
+       }
+       wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
+
+       /* clear configuration */
+       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
+       wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
+       wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
+       wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
+
+       wl->key_enabled = 0;
+       wl->current_key = 0;
+
+       wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
+       wl->psk_len = 0;
+
+       wl->essid_len = 0;
+       memset(wl->essid, 0, sizeof(wl->essid));
+       memset(wl->bssid, 0, sizeof(wl->bssid));
+       memset(wl->active_bssid, 0, sizeof(wl->active_bssid));
+
+       wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
+
+       memset(&wl->iwstat, 0, sizeof(wl->iwstat));
+       /* all status bit clear */
+       wl->stat = 0;
+       return 0;
+}
+
+/*
+ * Tell eurus to terminate association
+ */
+static void gelic_wl_disconnect(struct net_device *netdev)
+{
+       struct gelic_port *port = netdev_priv(netdev);
+       struct gelic_wl_info *wl = port_wl(port);
+       struct gelic_eurus_cmd *cmd;
+
+       /*
+        * If scann process is running on chip,
+        * further requests will be rejected
+        */
+       if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING)
+               wait_for_completion_timeout(&wl->scan_done, HZ);
+
+       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
+       kfree(cmd);
+       gelic_wl_send_iwap_event(wl, NULL);
+};
+
+static int gelic_wl_stop(struct net_device *netdev)
+{
+       struct gelic_port *port = netdev_priv(netdev);
+       struct gelic_wl_info *wl = port_wl(port);
+       struct gelic_card *card = netdev_card(netdev);
+
+       pr_debug("%s:<-\n", __func__);
+
+       /*
+        * Cancel pending association work.
+        * event work can run after netdev down
+        */
+       cancel_delayed_work(&wl->assoc_work);
+
+       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
+               gelic_wl_disconnect(netdev);
+
+       /* reset our state machine */
+       gelic_wl_reset_state(wl);
+
+       netif_stop_queue(netdev);
+
+       gelic_card_down(card);
+
+       pr_debug("%s:->\n", __func__);
+       return 0;
+}
+
+/* -- */
+
+static const struct net_device_ops gelic_wl_netdevice_ops = {
+       .ndo_open = gelic_wl_open,
+       .ndo_stop = gelic_wl_stop,
+       .ndo_start_xmit = gelic_net_xmit,
+       .ndo_set_multicast_list = gelic_net_set_multi,
+       .ndo_change_mtu = gelic_net_change_mtu,
+       .ndo_tx_timeout = gelic_net_tx_timeout,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = gelic_net_poll_controller,
+#endif
+};
+
+static const struct ethtool_ops gelic_wl_ethtool_ops = {
+       .get_drvinfo    = gelic_net_get_drvinfo,
+       .get_link       = gelic_wl_get_link,
+};
+
+static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev)
+{
+       struct gelic_wl_info *wl;
+       wl = port_wl(netdev_priv(netdev));
+       BUG_ON(!wl);
+       netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
+
+       netdev->ethtool_ops = &gelic_wl_ethtool_ops;
+       netdev->netdev_ops = &gelic_wl_netdevice_ops;
+       netdev->wireless_data = &wl->wireless_data;
+       netdev->wireless_handlers = &gelic_wl_wext_handler_def;
+}
+
+/*
+ * driver probe/remove
+ */
+int __devinit gelic_wl_driver_probe(struct gelic_card *card)
+{
+       int ret;
+       struct net_device *netdev;
+
+       pr_debug("%s:start\n", __func__);
+
+       if (ps3_compare_firmware_version(1, 6, 0) < 0)
+               return 0;
+       if (!card->vlan[GELIC_PORT_WIRELESS].tx)
+               return 0;
+
+       /* alloc netdevice for wireless */
+       netdev = gelic_wl_alloc(card);
+       if (!netdev)
+               return -ENOMEM;
+
+       /* setup net_device structure */
+       SET_NETDEV_DEV(netdev, &card->dev->core);
+       gelic_wl_setup_netdev_ops(netdev);
+
+       /* setup some of net_device and register it */
+       ret = gelic_net_setup_netdev(netdev, card);
+       if (ret)
+               goto fail_setup;
+       card->netdev[GELIC_PORT_WIRELESS] = netdev;
+
+       /* add enable wireless interrupt */
+       card->irq_mask |= GELIC_CARD_WLAN_EVENT_RECEIVED |
+               GELIC_CARD_WLAN_COMMAND_COMPLETED;
+       /* to allow wireless commands while both interfaces are down */
+       gelic_card_set_irq_mask(card, GELIC_CARD_WLAN_EVENT_RECEIVED |
+                               GELIC_CARD_WLAN_COMMAND_COMPLETED);
+       pr_debug("%s:end\n", __func__);
+       return 0;
+
+fail_setup:
+       gelic_wl_free(port_wl(netdev_port(netdev)));
+
+       return ret;
+}
+
+int gelic_wl_driver_remove(struct gelic_card *card)
+{
+       struct gelic_wl_info *wl;
+       struct net_device *netdev;
+
+       pr_debug("%s:start\n", __func__);
+
+       if (ps3_compare_firmware_version(1, 6, 0) < 0)
+               return 0;
+       if (!card->vlan[GELIC_PORT_WIRELESS].tx)
+               return 0;
+
+       netdev = card->netdev[GELIC_PORT_WIRELESS];
+       wl = port_wl(netdev_priv(netdev));
+
+       /* if the interface was not up, but associated */
+       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
+               gelic_wl_disconnect(netdev);
+
+       complete(&wl->cmd_done_intr);
+
+       /* cancel all work queue */
+       cancel_delayed_work(&wl->assoc_work);
+       cancel_delayed_work(&wl->event_work);
+       flush_workqueue(wl->eurus_cmd_queue);
+       flush_workqueue(wl->event_queue);
+
+       unregister_netdev(netdev);
+
+       /* disable wireless interrupt */
+       pr_debug("%s: disable intr\n", __func__);
+       card->irq_mask &= ~(GELIC_CARD_WLAN_EVENT_RECEIVED |
+                           GELIC_CARD_WLAN_COMMAND_COMPLETED);
+       /* free bss list, netdev*/
+       gelic_wl_free(wl);
+       pr_debug("%s:end\n", __func__);
+       return 0;
+}
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h
new file mode 100644 (file)
index 0000000..f7e51b7
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ *  PS3 gelic network driver.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corporation
+ *
+ * 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _GELIC_WIRELESS_H
+#define _GELIC_WIRELESS_H
+
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+
+/* return value from  GELIC_LV1_GET_WLAN_EVENT netcontrol */
+enum gelic_lv1_wl_event {
+       GELIC_LV1_WL_EVENT_DEVICE_READY   = 0x01, /* Eurus ready */
+       GELIC_LV1_WL_EVENT_SCAN_COMPLETED = 0x02, /* Scan has completed */
+       GELIC_LV1_WL_EVENT_DEAUTH         = 0x04, /* Deauthed by the AP */
+       GELIC_LV1_WL_EVENT_BEACON_LOST    = 0x08, /* Beacon lost detected */
+       GELIC_LV1_WL_EVENT_CONNECTED      = 0x10, /* Connected to AP */
+       GELIC_LV1_WL_EVENT_WPA_CONNECTED  = 0x20, /* WPA connection */
+       GELIC_LV1_WL_EVENT_WPA_ERROR      = 0x40, /* MIC error */
+};
+
+/* arguments for GELIC_LV1_POST_WLAN_COMMAND netcontrol */
+enum gelic_eurus_command {
+       GELIC_EURUS_CMD_ASSOC           =  1, /* association start */
+       GELIC_EURUS_CMD_DISASSOC        =  2, /* disassociate      */
+       GELIC_EURUS_CMD_START_SCAN      =  3, /* scan start        */
+       GELIC_EURUS_CMD_GET_SCAN        =  4, /* get scan result   */
+       GELIC_EURUS_CMD_SET_COMMON_CFG  =  5, /* set common config */
+       GELIC_EURUS_CMD_GET_COMMON_CFG  =  6, /* set common config */
+       GELIC_EURUS_CMD_SET_WEP_CFG     =  7, /* set WEP config    */
+       GELIC_EURUS_CMD_GET_WEP_CFG     =  8, /* get WEP config    */
+       GELIC_EURUS_CMD_SET_WPA_CFG     =  9, /* set WPA config    */
+       GELIC_EURUS_CMD_GET_WPA_CFG     = 10, /* get WPA config    */
+       GELIC_EURUS_CMD_GET_RSSI_CFG    = 11, /* get RSSI info.    */
+       GELIC_EURUS_CMD_MAX_INDEX
+};
+
+/* for GELIC_EURUS_CMD_COMMON_CFG */
+enum gelic_eurus_bss_type {
+       GELIC_EURUS_BSS_INFRA = 0,
+       GELIC_EURUS_BSS_ADHOC = 1, /* not supported */
+};
+
+enum gelic_eurus_auth_method {
+       GELIC_EURUS_AUTH_OPEN = 0, /* FIXME: WLAN_AUTH_OPEN */
+       GELIC_EURUS_AUTH_SHARED = 1, /* not supported */
+};
+
+enum gelic_eurus_opmode {
+       GELIC_EURUS_OPMODE_11BG = 0, /* 802.11b/g */
+       GELIC_EURUS_OPMODE_11B = 1, /* 802.11b only */
+       GELIC_EURUS_OPMODE_11G = 2, /* 802.11g only */
+};
+
+struct gelic_eurus_common_cfg {
+       /* all fields are big endian */
+       u16 scan_index;
+       u16 bss_type;    /* infra or adhoc */
+       u16 auth_method; /* shared key or open */
+       u16 op_mode; /* B/G */
+} __packed;
+
+
+/* for GELIC_EURUS_CMD_WEP_CFG */
+enum gelic_eurus_wep_security {
+       GELIC_EURUS_WEP_SEC_NONE        = 0,
+       GELIC_EURUS_WEP_SEC_40BIT       = 1,
+       GELIC_EURUS_WEP_SEC_104BIT      = 2,
+};
+
+struct gelic_eurus_wep_cfg {
+       /* all fields are big endian */
+       u16 security;
+       u8 key[4][16];
+} __packed;
+
+/* for GELIC_EURUS_CMD_WPA_CFG */
+enum gelic_eurus_wpa_security {
+       GELIC_EURUS_WPA_SEC_NONE                = 0x0000,
+       /* group=TKIP, pairwise=TKIP */
+       GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP       = 0x0001,
+       /* group=AES, pairwise=AES */
+       GELIC_EURUS_WPA_SEC_WPA_AES_AES         = 0x0002,
+       /* group=TKIP, pairwise=TKIP */
+       GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP      = 0x0004,
+       /* group=AES, pairwise=AES */
+       GELIC_EURUS_WPA_SEC_WPA2_AES_AES        = 0x0008,
+       /* group=TKIP, pairwise=AES */
+       GELIC_EURUS_WPA_SEC_WPA_TKIP_AES        = 0x0010,
+       /* group=TKIP, pairwise=AES */
+       GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES       = 0x0020,
+};
+
+enum gelic_eurus_wpa_psk_type {
+       GELIC_EURUS_WPA_PSK_PASSPHRASE  = 0, /* passphrase string   */
+       GELIC_EURUS_WPA_PSK_BIN         = 1, /* 32 bytes binary key */
+};
+
+#define GELIC_WL_EURUS_PSK_MAX_LEN     64
+#define WPA_PSK_LEN                    32 /* WPA spec says 256bit */
+
+struct gelic_eurus_wpa_cfg {
+       /* all fields are big endian */
+       u16 security;
+       u16 psk_type; /* psk key encoding type */
+       u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */
+} __packed;
+
+/* for GELIC_EURUS_CMD_{START,GET}_SCAN */
+enum gelic_eurus_scan_capability {
+       GELIC_EURUS_SCAN_CAP_ADHOC      = 0x0000,
+       GELIC_EURUS_SCAN_CAP_INFRA      = 0x0001,
+       GELIC_EURUS_SCAN_CAP_MASK       = 0x0001,
+};
+
+enum gelic_eurus_scan_sec_type {
+       GELIC_EURUS_SCAN_SEC_NONE       = 0x0000,
+       GELIC_EURUS_SCAN_SEC_WEP        = 0x0100,
+       GELIC_EURUS_SCAN_SEC_WPA        = 0x0200,
+       GELIC_EURUS_SCAN_SEC_WPA2       = 0x0400,
+       GELIC_EURUS_SCAN_SEC_MASK       = 0x0f00,
+};
+
+enum gelic_eurus_scan_sec_wep_type {
+       GELIC_EURUS_SCAN_SEC_WEP_UNKNOWN        = 0x0000,
+       GELIC_EURUS_SCAN_SEC_WEP_40             = 0x0001,
+       GELIC_EURUS_SCAN_SEC_WEP_104            = 0x0002,
+       GELIC_EURUS_SCAN_SEC_WEP_MASK           = 0x0003,
+};
+
+enum gelic_eurus_scan_sec_wpa_type {
+       GELIC_EURUS_SCAN_SEC_WPA_UNKNOWN        = 0x0000,
+       GELIC_EURUS_SCAN_SEC_WPA_TKIP           = 0x0001,
+       GELIC_EURUS_SCAN_SEC_WPA_AES            = 0x0002,
+       GELIC_EURUS_SCAN_SEC_WPA_MASK           = 0x0003,
+};
+
+/*
+ * hw BSS information structure returned from GELIC_EURUS_CMD_GET_SCAN
+ */
+struct gelic_eurus_scan_info {
+       /* all fields are big endian */
+       __be16 size;
+       __be16 rssi; /* percentage */
+       __be16 channel; /* channel number */
+       __be16 beacon_period; /* FIXME: in msec unit */
+       __be16 capability;
+       __be16 security;
+       u8  bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */
+       u8  essid[32]; /* IW_ESSID_MAX_SIZE */
+       u8  rate[16]; /* first 12 are valid */
+       u8  ext_rate[16]; /* first 16 are valid */
+       __be32 reserved1;
+       __be32 reserved2;
+       __be32 reserved3;
+       __be32 reserved4;
+       u8 elements[0]; /* ie */
+} __packed;
+
+/* the hypervisor returns bbs up to 16 */
+#define GELIC_EURUS_MAX_SCAN  (16)
+struct gelic_wl_scan_info {
+       struct list_head list;
+       struct gelic_eurus_scan_info *hwinfo;
+
+       int valid; /* set 1 if this entry was in latest scanned list
+                    * from Eurus */
+       unsigned int eurus_index; /* index in the Eurus list */
+       unsigned long last_scanned; /* acquired time */
+
+       unsigned int rate_len;
+       unsigned int rate_ext_len;
+       unsigned int essid_len;
+};
+
+/* for GELIC_EURUS_CMD_GET_RSSI */
+struct gelic_eurus_rssi_info {
+       /* big endian */
+       __be16 rssi;
+} __packed;
+
+
+/* for 'stat' member of gelic_wl_info */
+enum gelic_wl_info_status_bit {
+       GELIC_WL_STAT_CONFIGURED,
+       GELIC_WL_STAT_CH_INFO,   /* ch info acquired */
+       GELIC_WL_STAT_ESSID_SET, /* ESSID specified by userspace */
+       GELIC_WL_STAT_BSSID_SET, /* BSSID specified by userspace */
+       GELIC_WL_STAT_WPA_PSK_SET, /* PMK specified by userspace */
+       GELIC_WL_STAT_WPA_LEVEL_SET, /* WEP or WPA[2] selected */
+};
+
+/* for 'scan_stat' member of gelic_wl_info */
+enum gelic_wl_scan_state {
+       /* just initialized or get last scan result failed */
+       GELIC_WL_SCAN_STAT_INIT,
+       /* scan request issued, accepted or chip is scanning */
+       GELIC_WL_SCAN_STAT_SCANNING,
+       /* scan results retrieved */
+       GELIC_WL_SCAN_STAT_GOT_LIST,
+};
+
+/* for 'cipher_method' */
+enum gelic_wl_cipher_method {
+       GELIC_WL_CIPHER_NONE,
+       GELIC_WL_CIPHER_WEP,
+       GELIC_WL_CIPHER_TKIP,
+       GELIC_WL_CIPHER_AES,
+};
+
+/* for 'wpa_level' */
+enum gelic_wl_wpa_level {
+       GELIC_WL_WPA_LEVEL_NONE,
+       GELIC_WL_WPA_LEVEL_WPA,
+       GELIC_WL_WPA_LEVEL_WPA2,
+};
+
+/* for 'assoc_stat' */
+enum gelic_wl_assoc_state {
+       GELIC_WL_ASSOC_STAT_DISCONN,
+       GELIC_WL_ASSOC_STAT_ASSOCIATING,
+       GELIC_WL_ASSOC_STAT_ASSOCIATED,
+};
+/* part of private data alloc_etherdev() allocated */
+#define GELIC_WEP_KEYS 4
+struct gelic_wl_info {
+       /* bss list */
+       struct mutex scan_lock;
+       struct list_head network_list;
+       struct list_head network_free_list;
+       struct gelic_wl_scan_info *networks;
+
+       unsigned long scan_age; /* last scanned time */
+       enum gelic_wl_scan_state scan_stat;
+       struct completion scan_done;
+
+       /* eurus command queue */
+       struct workqueue_struct *eurus_cmd_queue;
+       struct completion cmd_done_intr;
+
+       /* eurus event handling */
+       struct workqueue_struct *event_queue;
+       struct delayed_work event_work;
+
+       /* wl status bits */
+       unsigned long stat;
+       enum gelic_eurus_auth_method auth_method; /* open/shared */
+       enum gelic_wl_cipher_method group_cipher_method;
+       enum gelic_wl_cipher_method pairwise_cipher_method;
+       enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */
+
+       /* association handling */
+       struct mutex assoc_stat_lock;
+       struct delayed_work assoc_work;
+       enum gelic_wl_assoc_state assoc_stat;
+       struct completion assoc_done;
+
+       spinlock_t lock;
+       u16 ch_info; /* available channels. bit0 = ch1 */
+       /* WEP keys */
+       u8 key[GELIC_WEP_KEYS][IW_ENCODING_TOKEN_MAX];
+       unsigned long key_enabled;
+       unsigned int key_len[GELIC_WEP_KEYS];
+       unsigned int current_key;
+       /* WWPA PSK */
+       u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN];
+       enum gelic_eurus_wpa_psk_type psk_type;
+       unsigned int psk_len;
+
+       u8 essid[IW_ESSID_MAX_SIZE];
+       u8 bssid[ETH_ALEN]; /* userland requested */
+       u8 active_bssid[ETH_ALEN]; /* associated bssid */
+       unsigned int essid_len;
+
+       struct iw_public_data wireless_data;
+       struct iw_statistics iwstat;
+};
+
+#define GELIC_WL_BSS_MAX_ENT 32
+#define GELIC_WL_ASSOC_RETRY 50
+static inline struct gelic_port *wl_port(struct gelic_wl_info *wl)
+{
+       return container_of((void *)wl, struct gelic_port, priv);
+}
+static inline struct gelic_wl_info *port_wl(struct gelic_port *port)
+{
+       return port_priv(port);
+}
+
+struct gelic_eurus_cmd {
+       struct work_struct work;
+       struct gelic_wl_info *wl;
+       unsigned int cmd; /* command code */
+       u64 tag;
+       u64 size;
+       void *buffer;
+       unsigned int buf_size;
+       struct completion done;
+       int status;
+       u64 cmd_status;
+};
+
+/* private ioctls to pass PSK */
+#define GELIC_WL_PRIV_SET_PSK          (SIOCIWFIRSTPRIV + 0)
+#define GELIC_WL_PRIV_GET_PSK          (SIOCIWFIRSTPRIV + 1)
+
+extern int gelic_wl_driver_probe(struct gelic_card *card);
+extern int gelic_wl_driver_remove(struct gelic_card *card);
+extern void gelic_wl_interrupt(struct net_device *netdev, u64 status);
+#endif /* _GELIC_WIRELESS_H */
diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
new file mode 100644 (file)
index 0000000..1ff3491
--- /dev/null
@@ -0,0 +1,2603 @@
+/*
+ * Network device driver for Cell Processor-Based Blade and Celleb platform
+ *
+ * (C) Copyright IBM Corp. 2005
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/compiler.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/firmware.h>
+#include <linux/if_vlan.h>
+#include <linux/in.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gfp.h>
+#include <linux/ioport.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+#include <asm/pci-bridge.h>
+#include <net/checksum.h>
+
+#include "spider_net.h"
+
+MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \
+             "<Jens.Osterkamp@de.ibm.com>");
+MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
+MODULE_FIRMWARE(SPIDER_NET_FIRMWARE_NAME);
+
+static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;
+static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;
+
+module_param(rx_descriptors, int, 0444);
+module_param(tx_descriptors, int, 0444);
+
+MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \
+                "in rx chains");
+MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \
+                "in tx chain");
+
+char spider_net_driver_name[] = "spidernet";
+
+static DEFINE_PCI_DEVICE_TABLE(spider_net_pci_tbl) = {
+       { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
+
+/**
+ * spider_net_read_reg - reads an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to read from
+ *
+ * returns the content of the specified SMMIO register.
+ */
+static inline u32
+spider_net_read_reg(struct spider_net_card *card, u32 reg)
+{
+       /* We use the powerpc specific variants instead of readl_be() because
+        * we know spidernet is not a real PCI device and we can thus avoid the
+        * performance hit caused by the PCI workarounds.
+        */
+       return in_be32(card->regs + reg);
+}
+
+/**
+ * spider_net_write_reg - writes to an SMMIO register of a card
+ * @card: device structure
+ * @reg: register to write to
+ * @value: value to write into the specified SMMIO register
+ */
+static inline void
+spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
+{
+       /* We use the powerpc specific variants instead of writel_be() because
+        * we know spidernet is not a real PCI device and we can thus avoid the
+        * performance hit caused by the PCI workarounds.
+        */
+       out_be32(card->regs + reg, value);
+}
+
+/** spider_net_write_phy - write to phy register
+ * @netdev: adapter to be written to
+ * @mii_id: id of MII
+ * @reg: PHY register
+ * @val: value to be written to phy register
+ *
+ * spider_net_write_phy_register writes to an arbitrary PHY
+ * register via the spider GPCWOPCMD register. We assume the queue does
+ * not run full (not more than 15 commands outstanding).
+ **/
+static void
+spider_net_write_phy(struct net_device *netdev, int mii_id,
+                    int reg, int val)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 writevalue;
+
+       writevalue = ((u32)mii_id << 21) |
+               ((u32)reg << 16) | ((u32)val);
+
+       spider_net_write_reg(card, SPIDER_NET_GPCWOPCMD, writevalue);
+}
+
+/** spider_net_read_phy - read from phy register
+ * @netdev: network device to be read from
+ * @mii_id: id of MII
+ * @reg: PHY register
+ *
+ * Returns value read from PHY register
+ *
+ * spider_net_write_phy reads from an arbitrary PHY
+ * register via the spider GPCROPCMD register
+ **/
+static int
+spider_net_read_phy(struct net_device *netdev, int mii_id, int reg)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 readvalue;
+
+       readvalue = ((u32)mii_id << 21) | ((u32)reg << 16);
+       spider_net_write_reg(card, SPIDER_NET_GPCROPCMD, readvalue);
+
+       /* we don't use semaphores to wait for an SPIDER_NET_GPROPCMPINT
+        * interrupt, as we poll for the completion of the read operation
+        * in spider_net_read_phy. Should take about 50 us */
+       do {
+               readvalue = spider_net_read_reg(card, SPIDER_NET_GPCROPCMD);
+       } while (readvalue & SPIDER_NET_GPREXEC);
+
+       readvalue &= SPIDER_NET_GPRDAT_MASK;
+
+       return readvalue;
+}
+
+/**
+ * spider_net_setup_aneg - initial auto-negotiation setup
+ * @card: device structure
+ **/
+static void
+spider_net_setup_aneg(struct spider_net_card *card)
+{
+       struct mii_phy *phy = &card->phy;
+       u32 advertise = 0;
+       u16 bmsr, estat;
+
+       bmsr  = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+       estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS);
+
+       if (bmsr & BMSR_10HALF)
+               advertise |= ADVERTISED_10baseT_Half;
+       if (bmsr & BMSR_10FULL)
+               advertise |= ADVERTISED_10baseT_Full;
+       if (bmsr & BMSR_100HALF)
+               advertise |= ADVERTISED_100baseT_Half;
+       if (bmsr & BMSR_100FULL)
+               advertise |= ADVERTISED_100baseT_Full;
+
+       if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL))
+               advertise |= SUPPORTED_1000baseT_Full;
+       if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
+               advertise |= SUPPORTED_1000baseT_Half;
+
+       mii_phy_probe(phy, phy->mii_id);
+       phy->def->ops->setup_aneg(phy, advertise);
+
+}
+
+/**
+ * spider_net_rx_irq_off - switch off rx irq on this spider card
+ * @card: device structure
+ *
+ * switches off rx irq by masking them out in the GHIINTnMSK register
+ */
+static void
+spider_net_rx_irq_off(struct spider_net_card *card)
+{
+       u32 regvalue;
+
+       regvalue = SPIDER_NET_INT0_MASK_VALUE & (~SPIDER_NET_RXINT);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);
+}
+
+/**
+ * spider_net_rx_irq_on - switch on rx irq on this spider card
+ * @card: device structure
+ *
+ * switches on rx irq by enabling them in the GHIINTnMSK register
+ */
+static void
+spider_net_rx_irq_on(struct spider_net_card *card)
+{
+       u32 regvalue;
+
+       regvalue = SPIDER_NET_INT0_MASK_VALUE | SPIDER_NET_RXINT;
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);
+}
+
+/**
+ * spider_net_set_promisc - sets the unicast address or the promiscuous mode
+ * @card: card structure
+ *
+ * spider_net_set_promisc sets the unicast destination address filter and
+ * thus either allows for non-promisc mode or promisc mode
+ */
+static void
+spider_net_set_promisc(struct spider_net_card *card)
+{
+       u32 macu, macl;
+       struct net_device *netdev = card->netdev;
+
+       if (netdev->flags & IFF_PROMISC) {
+               /* clear destination entry 0 */
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, 0);
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, 0);
+               spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
+                                    SPIDER_NET_PROMISC_VALUE);
+       } else {
+               macu = netdev->dev_addr[0];
+               macu <<= 8;
+               macu |= netdev->dev_addr[1];
+               memcpy(&macl, &netdev->dev_addr[2], sizeof(macl));
+
+               macu |= SPIDER_NET_UA_DESCR_VALUE;
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, macu);
+               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, macl);
+               spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
+                                    SPIDER_NET_NONPROMISC_VALUE);
+       }
+}
+
+/**
+ * spider_net_get_mac_address - read mac address from spider card
+ * @card: device structure
+ *
+ * reads MAC address from GMACUNIMACU and GMACUNIMACL registers
+ */
+static int
+spider_net_get_mac_address(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 macl, macu;
+
+       macl = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACL);
+       macu = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACU);
+
+       netdev->dev_addr[0] = (macu >> 24) & 0xff;
+       netdev->dev_addr[1] = (macu >> 16) & 0xff;
+       netdev->dev_addr[2] = (macu >> 8) & 0xff;
+       netdev->dev_addr[3] = macu & 0xff;
+       netdev->dev_addr[4] = (macl >> 8) & 0xff;
+       netdev->dev_addr[5] = macl & 0xff;
+
+       if (!is_valid_ether_addr(&netdev->dev_addr[0]))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * spider_net_get_descr_status -- returns the status of a descriptor
+ * @descr: descriptor to look at
+ *
+ * returns the status as in the dmac_cmd_status field of the descriptor
+ */
+static inline int
+spider_net_get_descr_status(struct spider_net_hw_descr *hwdescr)
+{
+       return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
+}
+
+/**
+ * spider_net_free_chain - free descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ *
+ */
+static void
+spider_net_free_chain(struct spider_net_card *card,
+                     struct spider_net_descr_chain *chain)
+{
+       struct spider_net_descr *descr;
+
+       descr = chain->ring;
+       do {
+               descr->bus_addr = 0;
+               descr->hwdescr->next_descr_addr = 0;
+               descr = descr->next;
+       } while (descr != chain->ring);
+
+       dma_free_coherent(&card->pdev->dev, chain->num_desc,
+           chain->hwring, chain->dma_addr);
+}
+
+/**
+ * spider_net_init_chain - alloc and link descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ *
+ * We manage a circular list that mirrors the hardware structure,
+ * except that the hardware uses bus addresses.
+ *
+ * Returns 0 on success, <0 on failure
+ */
+static int
+spider_net_init_chain(struct spider_net_card *card,
+                      struct spider_net_descr_chain *chain)
+{
+       int i;
+       struct spider_net_descr *descr;
+       struct spider_net_hw_descr *hwdescr;
+       dma_addr_t buf;
+       size_t alloc_size;
+
+       alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);
+
+       chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+               &chain->dma_addr, GFP_KERNEL);
+
+       if (!chain->hwring)
+               return -ENOMEM;
+
+       memset(chain->ring, 0, chain->num_desc * sizeof(struct spider_net_descr));
+
+       /* Set up the hardware pointers in each descriptor */
+       descr = chain->ring;
+       hwdescr = chain->hwring;
+       buf = chain->dma_addr;
+       for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) {
+               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+               hwdescr->next_descr_addr = 0;
+
+               descr->hwdescr = hwdescr;
+               descr->bus_addr = buf;
+               descr->next = descr + 1;
+               descr->prev = descr - 1;
+
+               buf += sizeof(struct spider_net_hw_descr);
+       }
+       /* do actual circular list */
+       (descr-1)->next = chain->ring;
+       chain->ring->prev = descr-1;
+
+       spin_lock_init(&chain->lock);
+       chain->head = chain->ring;
+       chain->tail = chain->ring;
+       return 0;
+}
+
+/**
+ * spider_net_free_rx_chain_contents - frees descr contents in rx chain
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ */
+static void
+spider_net_free_rx_chain_contents(struct spider_net_card *card)
+{
+       struct spider_net_descr *descr;
+
+       descr = card->rx_chain.head;
+       do {
+               if (descr->skb) {
+                       pci_unmap_single(card->pdev, descr->hwdescr->buf_addr,
+                                        SPIDER_NET_MAX_FRAME,
+                                        PCI_DMA_BIDIRECTIONAL);
+                       dev_kfree_skb(descr->skb);
+                       descr->skb = NULL;
+               }
+               descr = descr->next;
+       } while (descr != card->rx_chain.head);
+}
+
+/**
+ * spider_net_prepare_rx_descr - Reinitialize RX descriptor
+ * @card: card structure
+ * @descr: descriptor to re-init
+ *
+ * Return 0 on success, <0 on failure.
+ *
+ * Allocates a new rx skb, iommu-maps it and attaches it to the
+ * descriptor. Mark the descriptor as activated, ready-to-use.
+ */
+static int
+spider_net_prepare_rx_descr(struct spider_net_card *card,
+                           struct spider_net_descr *descr)
+{
+       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+       dma_addr_t buf;
+       int offset;
+       int bufsize;
+
+       /* we need to round up the buffer size to a multiple of 128 */
+       bufsize = (SPIDER_NET_MAX_FRAME + SPIDER_NET_RXBUF_ALIGN - 1) &
+               (~(SPIDER_NET_RXBUF_ALIGN - 1));
+
+       /* and we need to have it 128 byte aligned, therefore we allocate a
+        * bit more */
+       /* allocate an skb */
+       descr->skb = netdev_alloc_skb(card->netdev,
+                                     bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
+       if (!descr->skb) {
+               if (netif_msg_rx_err(card) && net_ratelimit())
+                       dev_err(&card->netdev->dev,
+                               "Not enough memory to allocate rx buffer\n");
+               card->spider_stats.alloc_rx_skb_error++;
+               return -ENOMEM;
+       }
+       hwdescr->buf_size = bufsize;
+       hwdescr->result_size = 0;
+       hwdescr->valid_size = 0;
+       hwdescr->data_status = 0;
+       hwdescr->data_error = 0;
+
+       offset = ((unsigned long)descr->skb->data) &
+               (SPIDER_NET_RXBUF_ALIGN - 1);
+       if (offset)
+               skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
+       /* iommu-map the skb */
+       buf = pci_map_single(card->pdev, descr->skb->data,
+                       SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+       if (pci_dma_mapping_error(card->pdev, buf)) {
+               dev_kfree_skb_any(descr->skb);
+               descr->skb = NULL;
+               if (netif_msg_rx_err(card) && net_ratelimit())
+                       dev_err(&card->netdev->dev, "Could not iommu-map rx buffer\n");
+               card->spider_stats.rx_iommu_map_error++;
+               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       } else {
+               hwdescr->buf_addr = buf;
+               wmb();
+               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
+                                        SPIDER_NET_DMAC_NOINTR_COMPLETE;
+       }
+
+       return 0;
+}
+
+/**
+ * spider_net_enable_rxchtails - sets RX dmac chain tail addresses
+ * @card: card structure
+ *
+ * spider_net_enable_rxchtails sets the RX DMAC chain tail addresses in the
+ * chip by writing to the appropriate register. DMA is enabled in
+ * spider_net_enable_rxdmac.
+ */
+static inline void
+spider_net_enable_rxchtails(struct spider_net_card *card)
+{
+       /* assume chain is aligned correctly */
+       spider_net_write_reg(card, SPIDER_NET_GDADCHA ,
+                            card->rx_chain.tail->bus_addr);
+}
+
+/**
+ * spider_net_enable_rxdmac - enables a receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
+ * in the GDADMACCNTR register
+ */
+static inline void
+spider_net_enable_rxdmac(struct spider_net_card *card)
+{
+       wmb();
+       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+                            SPIDER_NET_DMA_RX_VALUE);
+}
+
+/**
+ * spider_net_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_disable_rxdmac terminates processing on the DMA controller
+ * by turing off the DMA controller, with the force-end flag set.
+ */
+static inline void
+spider_net_disable_rxdmac(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+                            SPIDER_NET_DMA_RX_FEND_VALUE);
+}
+
+/**
+ * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
+ * @card: card structure
+ *
+ * refills descriptors in the rx chain: allocates skbs and iommu-maps them.
+ */
+static void
+spider_net_refill_rx_chain(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       unsigned long flags;
+
+       /* one context doing the refill (and a second context seeing that
+        * and omitting it) is ok. If called by NAPI, we'll be called again
+        * as spider_net_decode_one_descr is called several times. If some
+        * interrupt calls us, the NAPI is about to clean up anyway. */
+       if (!spin_trylock_irqsave(&chain->lock, flags))
+               return;
+
+       while (spider_net_get_descr_status(chain->head->hwdescr) ==
+                       SPIDER_NET_DESCR_NOT_IN_USE) {
+               if (spider_net_prepare_rx_descr(card, chain->head))
+                       break;
+               chain->head = chain->head->next;
+       }
+
+       spin_unlock_irqrestore(&chain->lock, flags);
+}
+
+/**
+ * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
+ * @card: card structure
+ *
+ * Returns 0 on success, <0 on failure.
+ */
+static int
+spider_net_alloc_rx_skbs(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *start = chain->tail;
+       struct spider_net_descr *descr = start;
+
+       /* Link up the hardware chain pointers */
+       do {
+               descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
+               descr = descr->next;
+       } while (descr != start);
+
+       /* Put at least one buffer into the chain. if this fails,
+        * we've got a problem. If not, spider_net_refill_rx_chain
+        * will do the rest at the end of this function. */
+       if (spider_net_prepare_rx_descr(card, chain->head))
+               goto error;
+       else
+               chain->head = chain->head->next;
+
+       /* This will allocate the rest of the rx buffers;
+        * if not, it's business as usual later on. */
+       spider_net_refill_rx_chain(card);
+       spider_net_enable_rxdmac(card);
+       return 0;
+
+error:
+       spider_net_free_rx_chain_contents(card);
+       return -ENOMEM;
+}
+
+/**
+ * spider_net_get_multicast_hash - generates hash for multicast filter table
+ * @addr: multicast address
+ *
+ * returns the hash value.
+ *
+ * spider_net_get_multicast_hash calculates a hash value for a given multicast
+ * address, that is used to set the multicast filter tables
+ */
+static u8
+spider_net_get_multicast_hash(struct net_device *netdev, __u8 *addr)
+{
+       u32 crc;
+       u8 hash;
+       char addr_for_crc[ETH_ALEN] = { 0, };
+       int i, bit;
+
+       for (i = 0; i < ETH_ALEN * 8; i++) {
+               bit = (addr[i / 8] >> (i % 8)) & 1;
+               addr_for_crc[ETH_ALEN - 1 - i / 8] += bit << (7 - (i % 8));
+       }
+
+       crc = crc32_be(~0, addr_for_crc, netdev->addr_len);
+
+       hash = (crc >> 27);
+       hash <<= 3;
+       hash |= crc & 7;
+       hash &= 0xff;
+
+       return hash;
+}
+
+/**
+ * spider_net_set_multi - sets multicast addresses and promisc flags
+ * @netdev: interface device structure
+ *
+ * spider_net_set_multi configures multicast addresses as needed for the
+ * netdev interface. It also sets up multicast, allmulti and promisc
+ * flags appropriately
+ */
+static void
+spider_net_set_multi(struct net_device *netdev)
+{
+       struct netdev_hw_addr *ha;
+       u8 hash;
+       int i;
+       u32 reg;
+       struct spider_net_card *card = netdev_priv(netdev);
+       unsigned long bitmask[SPIDER_NET_MULTICAST_HASHES / BITS_PER_LONG] =
+               {0, };
+
+       spider_net_set_promisc(card);
+
+       if (netdev->flags & IFF_ALLMULTI) {
+               for (i = 0; i < SPIDER_NET_MULTICAST_HASHES; i++) {
+                       set_bit(i, bitmask);
+               }
+               goto write_hash;
+       }
+
+       /* well, we know, what the broadcast hash value is: it's xfd
+       hash = spider_net_get_multicast_hash(netdev, netdev->broadcast); */
+       set_bit(0xfd, bitmask);
+
+       netdev_for_each_mc_addr(ha, netdev) {
+               hash = spider_net_get_multicast_hash(netdev, ha->addr);
+               set_bit(hash, bitmask);
+       }
+
+write_hash:
+       for (i = 0; i < SPIDER_NET_MULTICAST_HASHES / 4; i++) {
+               reg = 0;
+               if (test_bit(i * 4, bitmask))
+                       reg += 0x08;
+               reg <<= 8;
+               if (test_bit(i * 4 + 1, bitmask))
+                       reg += 0x08;
+               reg <<= 8;
+               if (test_bit(i * 4 + 2, bitmask))
+                       reg += 0x08;
+               reg <<= 8;
+               if (test_bit(i * 4 + 3, bitmask))
+                       reg += 0x08;
+
+               spider_net_write_reg(card, SPIDER_NET_GMRMHFILnR + i * 4, reg);
+       }
+}
+
+/**
+ * spider_net_prepare_tx_descr - fill tx descriptor with skb data
+ * @card: card structure
+ * @skb: packet to use
+ *
+ * returns 0 on success, <0 on failure.
+ *
+ * fills out the descriptor structure with skb data and len. Copies data,
+ * if needed (32bit DMA!)
+ */
+static int
+spider_net_prepare_tx_descr(struct spider_net_card *card,
+                           struct sk_buff *skb)
+{
+       struct spider_net_descr_chain *chain = &card->tx_chain;
+       struct spider_net_descr *descr;
+       struct spider_net_hw_descr *hwdescr;
+       dma_addr_t buf;
+       unsigned long flags;
+
+       buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(card->pdev, buf)) {
+               if (netif_msg_tx_err(card) && net_ratelimit())
+                       dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). "
+                                 "Dropping packet\n", skb->data, skb->len);
+               card->spider_stats.tx_iommu_map_error++;
+               return -ENOMEM;
+       }
+
+       spin_lock_irqsave(&chain->lock, flags);
+       descr = card->tx_chain.head;
+       if (descr->next == chain->tail->prev) {
+               spin_unlock_irqrestore(&chain->lock, flags);
+               pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE);
+               return -ENOMEM;
+       }
+       hwdescr = descr->hwdescr;
+       chain->head = descr->next;
+
+       descr->skb = skb;
+       hwdescr->buf_addr = buf;
+       hwdescr->buf_size = skb->len;
+       hwdescr->next_descr_addr = 0;
+       hwdescr->data_status = 0;
+
+       hwdescr->dmac_cmd_status =
+                       SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_TXFRMTL;
+       spin_unlock_irqrestore(&chain->lock, flags);
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               switch (ip_hdr(skb)->protocol) {
+               case IPPROTO_TCP:
+                       hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
+                       break;
+               case IPPROTO_UDP:
+                       hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
+                       break;
+               }
+
+       /* Chain the bus address, so that the DMA engine finds this descr. */
+       wmb();
+       descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
+
+       card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
+       return 0;
+}
+
+static int
+spider_net_set_low_watermark(struct spider_net_card *card)
+{
+       struct spider_net_descr *descr = card->tx_chain.tail;
+       struct spider_net_hw_descr *hwdescr;
+       unsigned long flags;
+       int status;
+       int cnt=0;
+       int i;
+
+       /* Measure the length of the queue. Measurement does not
+        * need to be precise -- does not need a lock. */
+       while (descr != card->tx_chain.head) {
+               status = descr->hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
+               if (status == SPIDER_NET_DESCR_NOT_IN_USE)
+                       break;
+               descr = descr->next;
+               cnt++;
+       }
+
+       /* If TX queue is short, don't even bother with interrupts */
+       if (cnt < card->tx_chain.num_desc/4)
+               return cnt;
+
+       /* Set low-watermark 3/4th's of the way into the queue. */
+       descr = card->tx_chain.tail;
+       cnt = (cnt*3)/4;
+       for (i=0;i<cnt; i++)
+               descr = descr->next;
+
+       /* Set the new watermark, clear the old watermark */
+       spin_lock_irqsave(&card->tx_chain.lock, flags);
+       descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
+       if (card->low_watermark && card->low_watermark != descr) {
+               hwdescr = card->low_watermark->hwdescr;
+               hwdescr->dmac_cmd_status =
+                    hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+       }
+       card->low_watermark = descr;
+       spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+       return cnt;
+}
+
+/**
+ * spider_net_release_tx_chain - processes sent tx descriptors
+ * @card: adapter structure
+ * @brutal: if set, don't care about whether descriptor seems to be in use
+ *
+ * returns 0 if the tx ring is empty, otherwise 1.
+ *
+ * spider_net_release_tx_chain releases the tx descriptors that spider has
+ * finished with (if non-brutal) or simply release tx descriptors (if brutal).
+ * If some other context is calling this function, we return 1 so that we're
+ * scheduled again (if we were scheduled) and will not lose initiative.
+ */
+static int
+spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
+{
+       struct net_device *dev = card->netdev;
+       struct spider_net_descr_chain *chain = &card->tx_chain;
+       struct spider_net_descr *descr;
+       struct spider_net_hw_descr *hwdescr;
+       struct sk_buff *skb;
+       u32 buf_addr;
+       unsigned long flags;
+       int status;
+
+       while (1) {
+               spin_lock_irqsave(&chain->lock, flags);
+               if (chain->tail == chain->head) {
+                       spin_unlock_irqrestore(&chain->lock, flags);
+                       return 0;
+               }
+               descr = chain->tail;
+               hwdescr = descr->hwdescr;
+
+               status = spider_net_get_descr_status(hwdescr);
+               switch (status) {
+               case SPIDER_NET_DESCR_COMPLETE:
+                       dev->stats.tx_packets++;
+                       dev->stats.tx_bytes += descr->skb->len;
+                       break;
+
+               case SPIDER_NET_DESCR_CARDOWNED:
+                       if (!brutal) {
+                               spin_unlock_irqrestore(&chain->lock, flags);
+                               return 1;
+                       }
+
+                       /* fallthrough, if we release the descriptors
+                        * brutally (then we don't care about
+                        * SPIDER_NET_DESCR_CARDOWNED) */
+
+               case SPIDER_NET_DESCR_RESPONSE_ERROR:
+               case SPIDER_NET_DESCR_PROTECTION_ERROR:
+               case SPIDER_NET_DESCR_FORCE_END:
+                       if (netif_msg_tx_err(card))
+                               dev_err(&card->netdev->dev, "forcing end of tx descriptor "
+                                      "with status x%02x\n", status);
+                       dev->stats.tx_errors++;
+                       break;
+
+               default:
+                       dev->stats.tx_dropped++;
+                       if (!brutal) {
+                               spin_unlock_irqrestore(&chain->lock, flags);
+                               return 1;
+                       }
+               }
+
+               chain->tail = descr->next;
+               hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+               skb = descr->skb;
+               descr->skb = NULL;
+               buf_addr = hwdescr->buf_addr;
+               spin_unlock_irqrestore(&chain->lock, flags);
+
+               /* unmap the skb */
+               if (skb) {
+                       pci_unmap_single(card->pdev, buf_addr, skb->len,
+                                       PCI_DMA_TODEVICE);
+                       dev_kfree_skb(skb);
+               }
+       }
+       return 0;
+}
+
+/**
+ * spider_net_kick_tx_dma - enables TX DMA processing
+ * @card: card structure
+ *
+ * This routine will start the transmit DMA running if
+ * it is not already running. This routine ned only be
+ * called when queueing a new packet to an empty tx queue.
+ * Writes the current tx chain head as start address
+ * of the tx descriptor chain and enables the transmission
+ * DMA engine.
+ */
+static inline void
+spider_net_kick_tx_dma(struct spider_net_card *card)
+{
+       struct spider_net_descr *descr;
+
+       if (spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR) &
+                       SPIDER_NET_TX_DMA_EN)
+               goto out;
+
+       descr = card->tx_chain.tail;
+       for (;;) {
+               if (spider_net_get_descr_status(descr->hwdescr) ==
+                               SPIDER_NET_DESCR_CARDOWNED) {
+                       spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
+                                       descr->bus_addr);
+                       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+                                       SPIDER_NET_DMA_TX_VALUE);
+                       break;
+               }
+               if (descr == card->tx_chain.head)
+                       break;
+               descr = descr->next;
+       }
+
+out:
+       mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
+}
+
+/**
+ * spider_net_xmit - transmits a frame over the device
+ * @skb: packet to send out
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, !0 on failure
+ */
+static int
+spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       int cnt;
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       spider_net_release_tx_chain(card, 0);
+
+       if (spider_net_prepare_tx_descr(card, skb) != 0) {
+               netdev->stats.tx_dropped++;
+               netif_stop_queue(netdev);
+               return NETDEV_TX_BUSY;
+       }
+
+       cnt = spider_net_set_low_watermark(card);
+       if (cnt < 5)
+               spider_net_kick_tx_dma(card);
+       return NETDEV_TX_OK;
+}
+
+/**
+ * spider_net_cleanup_tx_ring - cleans up the TX ring
+ * @card: card structure
+ *
+ * spider_net_cleanup_tx_ring is called by either the tx_timer
+ * or from the NAPI polling routine.
+ * This routine releases resources associted with transmitted
+ * packets, including updating the queue tail pointer.
+ */
+static void
+spider_net_cleanup_tx_ring(struct spider_net_card *card)
+{
+       if ((spider_net_release_tx_chain(card, 0) != 0) &&
+           (card->netdev->flags & IFF_UP)) {
+               spider_net_kick_tx_dma(card);
+               netif_wake_queue(card->netdev);
+       }
+}
+
+/**
+ * spider_net_do_ioctl - called for device ioctls
+ * @netdev: interface device structure
+ * @ifr: request parameter structure for ioctl
+ * @cmd: command code for ioctl
+ *
+ * returns 0 on success, <0 on failure. Currently, we have no special ioctls.
+ * -EOPNOTSUPP is returned, if an unknown ioctl was requested
+ */
+static int
+spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+/**
+ * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
+ * @descr: descriptor to process
+ * @card: card structure
+ *
+ * Fills out skb structure and passes the data to the stack.
+ * The descriptor state is not changed.
+ */
+static void
+spider_net_pass_skb_up(struct spider_net_descr *descr,
+                      struct spider_net_card *card)
+{
+       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+       struct sk_buff *skb = descr->skb;
+       struct net_device *netdev = card->netdev;
+       u32 data_status = hwdescr->data_status;
+       u32 data_error = hwdescr->data_error;
+
+       skb_put(skb, hwdescr->valid_size);
+
+       /* the card seems to add 2 bytes of junk in front
+        * of the ethernet frame */
+#define SPIDER_MISALIGN                2
+       skb_pull(skb, SPIDER_MISALIGN);
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       /* checksum offload */
+       skb_checksum_none_assert(skb);
+       if (netdev->features & NETIF_F_RXCSUM) {
+               if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) ==
+                      SPIDER_NET_DATA_STATUS_CKSUM_MASK) &&
+                    !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK))
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       }
+
+       if (data_status & SPIDER_NET_VLAN_PACKET) {
+               /* further enhancements: HW-accel VLAN */
+       }
+
+       /* update netdevice statistics */
+       netdev->stats.rx_packets++;
+       netdev->stats.rx_bytes += skb->len;
+
+       /* pass skb up to stack */
+       netif_receive_skb(skb);
+}
+
+static void show_rx_chain(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *start= chain->tail;
+       struct spider_net_descr *descr= start;
+       struct spider_net_hw_descr *hwd = start->hwdescr;
+       struct device *dev = &card->netdev->dev;
+       u32 curr_desc, next_desc;
+       int status;
+
+       int tot = 0;
+       int cnt = 0;
+       int off = start - chain->ring;
+       int cstat = hwd->dmac_cmd_status;
+
+       dev_info(dev, "Total number of descrs=%d\n",
+               chain->num_desc);
+       dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n",
+               off, cstat);
+
+       curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA);
+       next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA);
+
+       status = cstat;
+       do
+       {
+               hwd = descr->hwdescr;
+               off = descr - chain->ring;
+               status = hwd->dmac_cmd_status;
+
+               if (descr == chain->head)
+                       dev_info(dev, "Chain head is at %d, head status=0x%x\n",
+                                off, status);
+
+               if (curr_desc == descr->bus_addr)
+                       dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n",
+                                off, status);
+
+               if (next_desc == descr->bus_addr)
+                       dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n",
+                                off, status);
+
+               if (hwd->next_descr_addr == 0)
+                       dev_info(dev, "chain is cut at %d\n", off);
+
+               if (cstat != status) {
+                       int from = (chain->num_desc + off - cnt) % chain->num_desc;
+                       int to = (chain->num_desc + off - 1) % chain->num_desc;
+                       dev_info(dev, "Have %d (from %d to %d) descrs "
+                                "with stat=0x%08x\n", cnt, from, to, cstat);
+                       cstat = status;
+                       cnt = 0;
+               }
+
+               cnt ++;
+               tot ++;
+               descr = descr->next;
+       } while (descr != start);
+
+       dev_info(dev, "Last %d descrs with stat=0x%08x "
+                "for a total of %d descrs\n", cnt, cstat, tot);
+
+#ifdef DEBUG
+       /* Now dump the whole ring */
+       descr = start;
+       do
+       {
+               struct spider_net_hw_descr *hwd = descr->hwdescr;
+               status = spider_net_get_descr_status(hwd);
+               cnt = descr - chain->ring;
+               dev_info(dev, "Descr %d stat=0x%08x skb=%p\n",
+                        cnt, status, descr->skb);
+               dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n",
+                        descr->bus_addr, hwd->buf_addr, hwd->buf_size);
+               dev_info(dev, "next=%08x result sz=%d valid sz=%d\n",
+                        hwd->next_descr_addr, hwd->result_size,
+                        hwd->valid_size);
+               dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n",
+                        hwd->dmac_cmd_status, hwd->data_status,
+                        hwd->data_error);
+               dev_info(dev, "\n");
+
+               descr = descr->next;
+       } while (descr != start);
+#endif
+
+}
+
+/**
+ * spider_net_resync_head_ptr - Advance head ptr past empty descrs
+ *
+ * If the driver fails to keep up and empty the queue, then the
+ * hardware wil run out of room to put incoming packets. This
+ * will cause the hardware to skip descrs that are full (instead
+ * of halting/retrying). Thus, once the driver runs, it wil need
+ * to "catch up" to where the hardware chain pointer is at.
+ */
+static void spider_net_resync_head_ptr(struct spider_net_card *card)
+{
+       unsigned long flags;
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *descr;
+       int i, status;
+
+       /* Advance head pointer past any empty descrs */
+       descr = chain->head;
+       status = spider_net_get_descr_status(descr->hwdescr);
+
+       if (status == SPIDER_NET_DESCR_NOT_IN_USE)
+               return;
+
+       spin_lock_irqsave(&chain->lock, flags);
+
+       descr = chain->head;
+       status = spider_net_get_descr_status(descr->hwdescr);
+       for (i=0; i<chain->num_desc; i++) {
+               if (status != SPIDER_NET_DESCR_CARDOWNED) break;
+               descr = descr->next;
+               status = spider_net_get_descr_status(descr->hwdescr);
+       }
+       chain->head = descr;
+
+       spin_unlock_irqrestore(&chain->lock, flags);
+}
+
+static int spider_net_resync_tail_ptr(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *descr;
+       int i, status;
+
+       /* Advance tail pointer past any empty and reaped descrs */
+       descr = chain->tail;
+       status = spider_net_get_descr_status(descr->hwdescr);
+
+       for (i=0; i<chain->num_desc; i++) {
+               if ((status != SPIDER_NET_DESCR_CARDOWNED) &&
+                   (status != SPIDER_NET_DESCR_NOT_IN_USE)) break;
+               descr = descr->next;
+               status = spider_net_get_descr_status(descr->hwdescr);
+       }
+       chain->tail = descr;
+
+       if ((i == chain->num_desc) || (i == 0))
+               return 1;
+       return 0;
+}
+
+/**
+ * spider_net_decode_one_descr - processes an RX descriptor
+ * @card: card structure
+ *
+ * Returns 1 if a packet has been sent to the stack, otherwise 0.
+ *
+ * Processes an RX descriptor by iommu-unmapping the data buffer
+ * and passing the packet up to the stack. This function is called
+ * in softirq context, e.g. either bottom half from interrupt or
+ * NAPI polling context.
+ */
+static int
+spider_net_decode_one_descr(struct spider_net_card *card)
+{
+       struct net_device *dev = card->netdev;
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *descr = chain->tail;
+       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+       u32 hw_buf_addr;
+       int status;
+
+       status = spider_net_get_descr_status(hwdescr);
+
+       /* Nothing in the descriptor, or ring must be empty */
+       if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
+           (status == SPIDER_NET_DESCR_NOT_IN_USE))
+               return 0;
+
+       /* descriptor definitively used -- move on tail */
+       chain->tail = descr->next;
+
+       /* unmap descriptor */
+       hw_buf_addr = hwdescr->buf_addr;
+       hwdescr->buf_addr = 0xffffffff;
+       pci_unmap_single(card->pdev, hw_buf_addr,
+                       SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+
+       if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
+            (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
+            (status == SPIDER_NET_DESCR_FORCE_END) ) {
+               if (netif_msg_rx_err(card))
+                       dev_err(&dev->dev,
+                              "dropping RX descriptor with state %d\n", status);
+               dev->stats.rx_dropped++;
+               goto bad_desc;
+       }
+
+       if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
+            (status != SPIDER_NET_DESCR_FRAME_END) ) {
+               if (netif_msg_rx_err(card))
+                       dev_err(&card->netdev->dev,
+                              "RX descriptor with unknown state %d\n", status);
+               card->spider_stats.rx_desc_unk_state++;
+               goto bad_desc;
+       }
+
+       /* The cases we'll throw away the packet immediately */
+       if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+               if (netif_msg_rx_err(card))
+                       dev_err(&card->netdev->dev,
+                              "error in received descriptor found, "
+                              "data_status=x%08x, data_error=x%08x\n",
+                              hwdescr->data_status, hwdescr->data_error);
+               goto bad_desc;
+       }
+
+       if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) {
+               dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n",
+                              hwdescr->dmac_cmd_status);
+               pr_err("buf_addr=x%08x\n", hw_buf_addr);
+               pr_err("buf_size=x%08x\n", hwdescr->buf_size);
+               pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
+               pr_err("result_size=x%08x\n", hwdescr->result_size);
+               pr_err("valid_size=x%08x\n", hwdescr->valid_size);
+               pr_err("data_status=x%08x\n", hwdescr->data_status);
+               pr_err("data_error=x%08x\n", hwdescr->data_error);
+               pr_err("which=%ld\n", descr - card->rx_chain.ring);
+
+               card->spider_stats.rx_desc_error++;
+               goto bad_desc;
+       }
+
+       /* Ok, we've got a packet in descr */
+       spider_net_pass_skb_up(descr, card);
+       descr->skb = NULL;
+       hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       return 1;
+
+bad_desc:
+       if (netif_msg_rx_err(card))
+               show_rx_chain(card);
+       dev_kfree_skb_irq(descr->skb);
+       descr->skb = NULL;
+       hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       return 0;
+}
+
+/**
+ * spider_net_poll - NAPI poll function called by the stack to return packets
+ * @netdev: interface device structure
+ * @budget: number of packets we can pass to the stack at most
+ *
+ * returns 0 if no more packets available to the driver/stack. Returns 1,
+ * if the quota is exceeded, but the driver has still packets.
+ *
+ * spider_net_poll returns all packets from the rx descriptors to the stack
+ * (using netif_receive_skb). If all/enough packets are up, the driver
+ * reenables interrupts and returns 0. If not, 1 is returned.
+ */
+static int spider_net_poll(struct napi_struct *napi, int budget)
+{
+       struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
+       int packets_done = 0;
+
+       while (packets_done < budget) {
+               if (!spider_net_decode_one_descr(card))
+                       break;
+
+               packets_done++;
+       }
+
+       if ((packets_done == 0) && (card->num_rx_ints != 0)) {
+               if (!spider_net_resync_tail_ptr(card))
+                       packets_done = budget;
+               spider_net_resync_head_ptr(card);
+       }
+       card->num_rx_ints = 0;
+
+       spider_net_refill_rx_chain(card);
+       spider_net_enable_rxdmac(card);
+
+       spider_net_cleanup_tx_ring(card);
+
+       /* if all packets are in the stack, enable interrupts and return 0 */
+       /* if not, return 1 */
+       if (packets_done < budget) {
+               napi_complete(napi);
+               spider_net_rx_irq_on(card);
+               card->ignore_rx_ramfull = 0;
+       }
+
+       return packets_done;
+}
+
+/**
+ * spider_net_change_mtu - changes the MTU of an interface
+ * @netdev: interface device structure
+ * @new_mtu: new MTU value
+ *
+ * returns 0 on success, <0 on failure
+ */
+static int
+spider_net_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       /* no need to re-alloc skbs or so -- the max mtu is about 2.3k
+        * and mtu is outbound only anyway */
+       if ( (new_mtu < SPIDER_NET_MIN_MTU ) ||
+               (new_mtu > SPIDER_NET_MAX_MTU) )
+               return -EINVAL;
+       netdev->mtu = new_mtu;
+       return 0;
+}
+
+/**
+ * spider_net_set_mac - sets the MAC of an interface
+ * @netdev: interface device structure
+ * @ptr: pointer to new MAC address
+ *
+ * Returns 0 on success, <0 on failure. Currently, we don't support this
+ * and will always return EOPNOTSUPP.
+ */
+static int
+spider_net_set_mac(struct net_device *netdev, void *p)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 macl, macu, regvalue;
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       /* switch off GMACTPE and GMACRPE */
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
+       regvalue &= ~((1 << 5) | (1 << 6));
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
+
+       /* write mac */
+       macu = (addr->sa_data[0]<<24) + (addr->sa_data[1]<<16) +
+               (addr->sa_data[2]<<8) + (addr->sa_data[3]);
+       macl = (addr->sa_data[4]<<8) + (addr->sa_data[5]);
+       spider_net_write_reg(card, SPIDER_NET_GMACUNIMACU, macu);
+       spider_net_write_reg(card, SPIDER_NET_GMACUNIMACL, macl);
+
+       /* switch GMACTPE and GMACRPE back on */
+       regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
+       regvalue |= ((1 << 5) | (1 << 6));
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
+
+       spider_net_set_promisc(card);
+
+       /* look up, whether we have been successful */
+       if (spider_net_get_mac_address(netdev))
+               return -EADDRNOTAVAIL;
+       if (memcmp(netdev->dev_addr,addr->sa_data,netdev->addr_len))
+               return -EADDRNOTAVAIL;
+
+       return 0;
+}
+
+/**
+ * spider_net_link_reset
+ * @netdev: net device structure
+ *
+ * This is called when the PHY_LINK signal is asserted. For the blade this is
+ * not connected so we should never get here.
+ *
+ */
+static void
+spider_net_link_reset(struct net_device *netdev)
+{
+
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       del_timer_sync(&card->aneg_timer);
+
+       /* clear interrupt, block further interrupts */
+       spider_net_write_reg(card, SPIDER_NET_GMACST,
+                            spider_net_read_reg(card, SPIDER_NET_GMACST));
+       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
+
+       /* reset phy and setup aneg */
+       card->aneg_count = 0;
+       card->medium = BCM54XX_COPPER;
+       spider_net_setup_aneg(card);
+       mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
+}
+
+/**
+ * spider_net_handle_error_irq - handles errors raised by an interrupt
+ * @card: card structure
+ * @status_reg: interrupt status register 0 (GHIINT0STS)
+ *
+ * spider_net_handle_error_irq treats or ignores all error conditions
+ * found when an interrupt is presented
+ */
+static void
+spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
+                           u32 error_reg1, u32 error_reg2)
+{
+       u32 i;
+       int show_error = 1;
+
+       /* check GHIINT0STS ************************************/
+       if (status_reg)
+               for (i = 0; i < 32; i++)
+                       if (status_reg & (1<<i))
+                               switch (i)
+       {
+       /* let error_reg1 and error_reg2 evaluation decide, what to do
+       case SPIDER_NET_PHYINT:
+       case SPIDER_NET_GMAC2INT:
+       case SPIDER_NET_GMAC1INT:
+       case SPIDER_NET_GFIFOINT:
+       case SPIDER_NET_DMACINT:
+       case SPIDER_NET_GSYSINT:
+               break; */
+
+       case SPIDER_NET_GIPSINT:
+               show_error = 0;
+               break;
+
+       case SPIDER_NET_GPWOPCMPINT:
+               /* PHY write operation completed */
+               show_error = 0;
+               break;
+       case SPIDER_NET_GPROPCMPINT:
+               /* PHY read operation completed */
+               /* we don't use semaphores, as we poll for the completion
+                * of the read operation in spider_net_read_phy. Should take
+                * about 50 us */
+               show_error = 0;
+               break;
+       case SPIDER_NET_GPWFFINT:
+               /* PHY command queue full */
+               if (netif_msg_intr(card))
+                       dev_err(&card->netdev->dev, "PHY write queue full\n");
+               show_error = 0;
+               break;
+
+       /* case SPIDER_NET_GRMDADRINT: not used. print a message */
+       /* case SPIDER_NET_GRMARPINT: not used. print a message */
+       /* case SPIDER_NET_GRMMPINT: not used. print a message */
+
+       case SPIDER_NET_GDTDEN0INT:
+               /* someone has set TX_DMA_EN to 0 */
+               show_error = 0;
+               break;
+
+       case SPIDER_NET_GDDDEN0INT: /* fallthrough */
+       case SPIDER_NET_GDCDEN0INT: /* fallthrough */
+       case SPIDER_NET_GDBDEN0INT: /* fallthrough */
+       case SPIDER_NET_GDADEN0INT:
+               /* someone has set RX_DMA_EN to 0 */
+               show_error = 0;
+               break;
+
+       /* RX interrupts */
+       case SPIDER_NET_GDDFDCINT:
+       case SPIDER_NET_GDCFDCINT:
+       case SPIDER_NET_GDBFDCINT:
+       case SPIDER_NET_GDAFDCINT:
+       /* case SPIDER_NET_GDNMINT: not used. print a message */
+       /* case SPIDER_NET_GCNMINT: not used. print a message */
+       /* case SPIDER_NET_GBNMINT: not used. print a message */
+       /* case SPIDER_NET_GANMINT: not used. print a message */
+       /* case SPIDER_NET_GRFNMINT: not used. print a message */
+               show_error = 0;
+               break;
+
+       /* TX interrupts */
+       case SPIDER_NET_GDTFDCINT:
+               show_error = 0;
+               break;
+       case SPIDER_NET_GTTEDINT:
+               show_error = 0;
+               break;
+       case SPIDER_NET_GDTDCEINT:
+               /* chain end. If a descriptor should be sent, kick off
+                * tx dma
+               if (card->tx_chain.tail != card->tx_chain.head)
+                       spider_net_kick_tx_dma(card);
+               */
+               show_error = 0;
+               break;
+
+       /* case SPIDER_NET_G1TMCNTINT: not used. print a message */
+       /* case SPIDER_NET_GFREECNTINT: not used. print a message */
+       }
+
+       /* check GHIINT1STS ************************************/
+       if (error_reg1)
+               for (i = 0; i < 32; i++)
+                       if (error_reg1 & (1<<i))
+                               switch (i)
+       {
+       case SPIDER_NET_GTMFLLINT:
+               /* TX RAM full may happen on a usual case.
+                * Logging is not needed. */
+               show_error = 0;
+               break;
+       case SPIDER_NET_GRFDFLLINT: /* fallthrough */
+       case SPIDER_NET_GRFCFLLINT: /* fallthrough */
+       case SPIDER_NET_GRFBFLLINT: /* fallthrough */
+       case SPIDER_NET_GRFAFLLINT: /* fallthrough */
+       case SPIDER_NET_GRMFLLINT:
+               /* Could happen when rx chain is full */
+               if (card->ignore_rx_ramfull == 0) {
+                       card->ignore_rx_ramfull = 1;
+                       spider_net_resync_head_ptr(card);
+                       spider_net_refill_rx_chain(card);
+                       spider_net_enable_rxdmac(card);
+                       card->num_rx_ints ++;
+                       napi_schedule(&card->napi);
+               }
+               show_error = 0;
+               break;
+
+       /* case SPIDER_NET_GTMSHTINT: problem, print a message */
+       case SPIDER_NET_GDTINVDINT:
+               /* allrighty. tx from previous descr ok */
+               show_error = 0;
+               break;
+
+       /* chain end */
+       case SPIDER_NET_GDDDCEINT: /* fallthrough */
+       case SPIDER_NET_GDCDCEINT: /* fallthrough */
+       case SPIDER_NET_GDBDCEINT: /* fallthrough */
+       case SPIDER_NET_GDADCEINT:
+               spider_net_resync_head_ptr(card);
+               spider_net_refill_rx_chain(card);
+               spider_net_enable_rxdmac(card);
+               card->num_rx_ints ++;
+               napi_schedule(&card->napi);
+               show_error = 0;
+               break;
+
+       /* invalid descriptor */
+       case SPIDER_NET_GDDINVDINT: /* fallthrough */
+       case SPIDER_NET_GDCINVDINT: /* fallthrough */
+       case SPIDER_NET_GDBINVDINT: /* fallthrough */
+       case SPIDER_NET_GDAINVDINT:
+               /* Could happen when rx chain is full */
+               spider_net_resync_head_ptr(card);
+               spider_net_refill_rx_chain(card);
+               spider_net_enable_rxdmac(card);
+               card->num_rx_ints ++;
+               napi_schedule(&card->napi);
+               show_error = 0;
+               break;
+
+       /* case SPIDER_NET_GDTRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDDRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDCRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDBRSERINT: problem, print a message */
+       /* case SPIDER_NET_GDARSERINT: problem, print a message */
+       /* case SPIDER_NET_GDSERINT: problem, print a message */
+       /* case SPIDER_NET_GDTPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDDPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDCPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDBPTERINT: problem, print a message */
+       /* case SPIDER_NET_GDAPTERINT: problem, print a message */
+       default:
+               show_error = 1;
+               break;
+       }
+
+       /* check GHIINT2STS ************************************/
+       if (error_reg2)
+               for (i = 0; i < 32; i++)
+                       if (error_reg2 & (1<<i))
+                               switch (i)
+       {
+       /* there is nothing we can (want  to) do at this time. Log a
+        * message, we can switch on and off the specific values later on
+       case SPIDER_NET_GPROPERINT:
+       case SPIDER_NET_GMCTCRSNGINT:
+       case SPIDER_NET_GMCTLCOLINT:
+       case SPIDER_NET_GMCTTMOTINT:
+       case SPIDER_NET_GMCRCAERINT:
+       case SPIDER_NET_GMCRCALERINT:
+       case SPIDER_NET_GMCRALNERINT:
+       case SPIDER_NET_GMCROVRINT:
+       case SPIDER_NET_GMCRRNTINT:
+       case SPIDER_NET_GMCRRXERINT:
+       case SPIDER_NET_GTITCSERINT:
+       case SPIDER_NET_GTIFMTERINT:
+       case SPIDER_NET_GTIPKTRVKINT:
+       case SPIDER_NET_GTISPINGINT:
+       case SPIDER_NET_GTISADNGINT:
+       case SPIDER_NET_GTISPDNGINT:
+       case SPIDER_NET_GRIFMTERINT:
+       case SPIDER_NET_GRIPKTRVKINT:
+       case SPIDER_NET_GRISPINGINT:
+       case SPIDER_NET_GRISADNGINT:
+       case SPIDER_NET_GRISPDNGINT:
+               break;
+       */
+               default:
+                       break;
+       }
+
+       if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
+               dev_err(&card->netdev->dev, "Error interrupt, GHIINT0STS = 0x%08x, "
+                      "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
+                      status_reg, error_reg1, error_reg2);
+
+       /* clear interrupt sources */
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1STS, error_reg1);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2STS, error_reg2);
+}
+
+/**
+ * spider_net_interrupt - interrupt handler for spider_net
+ * @irq: interrupt number
+ * @ptr: pointer to net_device
+ *
+ * returns IRQ_HANDLED, if interrupt was for driver, or IRQ_NONE, if no
+ * interrupt found raised by card.
+ *
+ * This is the interrupt handler, that turns off
+ * interrupts for this device and makes the stack poll the driver
+ */
+static irqreturn_t
+spider_net_interrupt(int irq, void *ptr)
+{
+       struct net_device *netdev = ptr;
+       struct spider_net_card *card = netdev_priv(netdev);
+       u32 status_reg, error_reg1, error_reg2;
+
+       status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
+       error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
+       error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
+
+       if (!(status_reg & SPIDER_NET_INT0_MASK_VALUE) &&
+           !(error_reg1 & SPIDER_NET_INT1_MASK_VALUE) &&
+           !(error_reg2 & SPIDER_NET_INT2_MASK_VALUE))
+               return IRQ_NONE;
+
+       if (status_reg & SPIDER_NET_RXINT ) {
+               spider_net_rx_irq_off(card);
+               napi_schedule(&card->napi);
+               card->num_rx_ints ++;
+       }
+       if (status_reg & SPIDER_NET_TXINT)
+               napi_schedule(&card->napi);
+
+       if (status_reg & SPIDER_NET_LINKINT)
+               spider_net_link_reset(netdev);
+
+       if (status_reg & SPIDER_NET_ERRINT )
+               spider_net_handle_error_irq(card, status_reg,
+                                           error_reg1, error_reg2);
+
+       /* clear interrupt sources */
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0STS, status_reg);
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * spider_net_poll_controller - artificial interrupt for netconsole etc.
+ * @netdev: interface device structure
+ *
+ * see Documentation/networking/netconsole.txt
+ */
+static void
+spider_net_poll_controller(struct net_device *netdev)
+{
+       disable_irq(netdev->irq);
+       spider_net_interrupt(netdev->irq, netdev);
+       enable_irq(netdev->irq);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+/**
+ * spider_net_enable_interrupts - enable interrupts
+ * @card: card structure
+ *
+ * spider_net_enable_interrupt enables several interrupts
+ */
+static void
+spider_net_enable_interrupts(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
+                            SPIDER_NET_INT0_MASK_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK,
+                            SPIDER_NET_INT1_MASK_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
+                            SPIDER_NET_INT2_MASK_VALUE);
+}
+
+/**
+ * spider_net_disable_interrupts - disable interrupts
+ * @card: card structure
+ *
+ * spider_net_disable_interrupts disables all the interrupts
+ */
+static void
+spider_net_disable_interrupts(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
+}
+
+/**
+ * spider_net_init_card - initializes the card
+ * @card: card structure
+ *
+ * spider_net_init_card initializes the card so that other registers can
+ * be used
+ */
+static void
+spider_net_init_card(struct spider_net_card *card)
+{
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_STOP_VALUE);
+
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+       /* trigger ETOMOD signal */
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
+               spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4);
+
+       spider_net_disable_interrupts(card);
+}
+
+/**
+ * spider_net_enable_card - enables the card by setting all kinds of regs
+ * @card: card structure
+ *
+ * spider_net_enable_card sets a lot of SMMIO registers to enable the device
+ */
+static void
+spider_net_enable_card(struct spider_net_card *card)
+{
+       int i;
+       /* the following array consists of (register),(value) pairs
+        * that are set in this function. A register of 0 ends the list */
+       u32 regs[][2] = {
+               { SPIDER_NET_GRESUMINTNUM, 0 },
+               { SPIDER_NET_GREINTNUM, 0 },
+
+               /* set interrupt frame number registers */
+               /* clear the single DMA engine registers first */
+               { SPIDER_NET_GFAFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               { SPIDER_NET_GFBFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               { SPIDER_NET_GFCFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               { SPIDER_NET_GFDFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
+               /* then set, what we really need */
+               { SPIDER_NET_GFFRMNUM, SPIDER_NET_FRAMENUM_VALUE },
+
+               /* timer counter registers and stuff */
+               { SPIDER_NET_GFREECNNUM, 0 },
+               { SPIDER_NET_GONETIMENUM, 0 },
+               { SPIDER_NET_GTOUTFRMNUM, 0 },
+
+               /* RX mode setting */
+               { SPIDER_NET_GRXMDSET, SPIDER_NET_RXMODE_VALUE },
+               /* TX mode setting */
+               { SPIDER_NET_GTXMDSET, SPIDER_NET_TXMODE_VALUE },
+               /* IPSEC mode setting */
+               { SPIDER_NET_GIPSECINIT, SPIDER_NET_IPSECINIT_VALUE },
+
+               { SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE },
+
+               { SPIDER_NET_GMRWOLCTRL, 0 },
+               { SPIDER_NET_GTESTMD, 0x10000000 },
+               { SPIDER_NET_GTTQMSK, 0x00400040 },
+
+               { SPIDER_NET_GMACINTEN, 0 },
+
+               /* flow control stuff */
+               { SPIDER_NET_GMACAPAUSE, SPIDER_NET_MACAPAUSE_VALUE },
+               { SPIDER_NET_GMACTXPAUSE, SPIDER_NET_TXPAUSE_VALUE },
+
+               { SPIDER_NET_GMACBSTLMT, SPIDER_NET_BURSTLMT_VALUE },
+               { 0, 0}
+       };
+
+       i = 0;
+       while (regs[i][0]) {
+               spider_net_write_reg(card, regs[i][0], regs[i][1]);
+               i++;
+       }
+
+       /* clear unicast filter table entries 1 to 14 */
+       for (i = 1; i <= 14; i++) {
+               spider_net_write_reg(card,
+                                    SPIDER_NET_GMRUAFILnR + i * 8,
+                                    0x00080000);
+               spider_net_write_reg(card,
+                                    SPIDER_NET_GMRUAFILnR + i * 8 + 4,
+                                    0x00000000);
+       }
+
+       spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R, 0x08080000);
+
+       spider_net_write_reg(card, SPIDER_NET_ECMODE, SPIDER_NET_ECMODE_VALUE);
+
+       /* set chain tail address for RX chains and
+        * enable DMA */
+       spider_net_enable_rxchtails(card);
+       spider_net_enable_rxdmac(card);
+
+       spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE);
+
+       spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
+                            SPIDER_NET_LENLMT_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
+                            SPIDER_NET_OPMODE_VALUE);
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+                            SPIDER_NET_GDTBSTA);
+}
+
+/**
+ * spider_net_download_firmware - loads firmware into the adapter
+ * @card: card structure
+ * @firmware_ptr: pointer to firmware data
+ *
+ * spider_net_download_firmware loads the firmware data into the
+ * adapter. It assumes the length etc. to be allright.
+ */
+static int
+spider_net_download_firmware(struct spider_net_card *card,
+                            const void *firmware_ptr)
+{
+       int sequencer, i;
+       const u32 *fw_ptr = firmware_ptr;
+
+       /* stop sequencers */
+       spider_net_write_reg(card, SPIDER_NET_GSINIT,
+                            SPIDER_NET_STOP_SEQ_VALUE);
+
+       for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
+            sequencer++) {
+               spider_net_write_reg(card,
+                                    SPIDER_NET_GSnPRGADR + sequencer * 8, 0);
+               for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
+                       spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+                                            sequencer * 8, *fw_ptr);
+                       fw_ptr++;
+               }
+       }
+
+       if (spider_net_read_reg(card, SPIDER_NET_GSINIT))
+               return -EIO;
+
+       spider_net_write_reg(card, SPIDER_NET_GSINIT,
+                            SPIDER_NET_RUN_SEQ_VALUE);
+
+       return 0;
+}
+
+/**
+ * spider_net_init_firmware - reads in firmware parts
+ * @card: card structure
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_init_firmware opens the sequencer firmware and does some basic
+ * checks. This function opens and releases the firmware structure. A call
+ * to download the firmware is performed before the release.
+ *
+ * Firmware format
+ * ===============
+ * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being
+ * the program for each sequencer. Use the command
+ *    tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt              \
+ *         Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt   \
+ *         Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin
+ *
+ * to generate spider_fw.bin, if you have sequencer programs with something
+ * like the following contents for each sequencer:
+ *    <ONE LINE COMMENT>
+ *    <FIRST 4-BYTES-WORD FOR SEQUENCER>
+ *    <SECOND 4-BYTES-WORD FOR SEQUENCER>
+ *     ...
+ *    <1024th 4-BYTES-WORD FOR SEQUENCER>
+ */
+static int
+spider_net_init_firmware(struct spider_net_card *card)
+{
+       struct firmware *firmware = NULL;
+       struct device_node *dn;
+       const u8 *fw_prop = NULL;
+       int err = -ENOENT;
+       int fw_size;
+
+       if (request_firmware((const struct firmware **)&firmware,
+                            SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
+               if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
+                    netif_msg_probe(card) ) {
+                       dev_err(&card->netdev->dev,
+                              "Incorrect size of spidernet firmware in " \
+                              "filesystem. Looking in host firmware...\n");
+                       goto try_host_fw;
+               }
+               err = spider_net_download_firmware(card, firmware->data);
+
+               release_firmware(firmware);
+               if (err)
+                       goto try_host_fw;
+
+               goto done;
+       }
+
+try_host_fw:
+       dn = pci_device_to_OF_node(card->pdev);
+       if (!dn)
+               goto out_err;
+
+       fw_prop = of_get_property(dn, "firmware", &fw_size);
+       if (!fw_prop)
+               goto out_err;
+
+       if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
+            netif_msg_probe(card) ) {
+               dev_err(&card->netdev->dev,
+                      "Incorrect size of spidernet firmware in host firmware\n");
+               goto done;
+       }
+
+       err = spider_net_download_firmware(card, fw_prop);
+
+done:
+       return err;
+out_err:
+       if (netif_msg_probe(card))
+               dev_err(&card->netdev->dev,
+                      "Couldn't find spidernet firmware in filesystem " \
+                      "or host firmware\n");
+       return err;
+}
+
+/**
+ * spider_net_open - called upon ifonfig up
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_open allocates all the descriptors and memory needed for
+ * operation, sets up multicast list and enables interrupts
+ */
+int
+spider_net_open(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+       int result;
+
+       result = spider_net_init_firmware(card);
+       if (result)
+               goto init_firmware_failed;
+
+       /* start probing with copper */
+       card->aneg_count = 0;
+       card->medium = BCM54XX_COPPER;
+       spider_net_setup_aneg(card);
+       if (card->phy.def->phy_id)
+               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
+       result = spider_net_init_chain(card, &card->tx_chain);
+       if (result)
+               goto alloc_tx_failed;
+       card->low_watermark = NULL;
+
+       result = spider_net_init_chain(card, &card->rx_chain);
+       if (result)
+               goto alloc_rx_failed;
+
+       /* Allocate rx skbs */
+       if (spider_net_alloc_rx_skbs(card))
+               goto alloc_skbs_failed;
+
+       spider_net_set_multi(netdev);
+
+       /* further enhancement: setup hw vlan, if needed */
+
+       result = -EBUSY;
+       if (request_irq(netdev->irq, spider_net_interrupt,
+                            IRQF_SHARED, netdev->name, netdev))
+               goto register_int_failed;
+
+       spider_net_enable_card(card);
+
+       netif_start_queue(netdev);
+       netif_carrier_on(netdev);
+       napi_enable(&card->napi);
+
+       spider_net_enable_interrupts(card);
+
+       return 0;
+
+register_int_failed:
+       spider_net_free_rx_chain_contents(card);
+alloc_skbs_failed:
+       spider_net_free_chain(card, &card->rx_chain);
+alloc_rx_failed:
+       spider_net_free_chain(card, &card->tx_chain);
+alloc_tx_failed:
+       del_timer_sync(&card->aneg_timer);
+init_firmware_failed:
+       return result;
+}
+
+/**
+ * spider_net_link_phy
+ * @data: used for pointer to card structure
+ *
+ */
+static void spider_net_link_phy(unsigned long data)
+{
+       struct spider_net_card *card = (struct spider_net_card *)data;
+       struct mii_phy *phy = &card->phy;
+
+       /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */
+       if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) {
+
+               pr_debug("%s: link is down trying to bring it up\n",
+                        card->netdev->name);
+
+               switch (card->medium) {
+               case BCM54XX_COPPER:
+                       /* enable fiber with autonegotiation first */
+                       if (phy->def->ops->enable_fiber)
+                               phy->def->ops->enable_fiber(phy, 1);
+                       card->medium = BCM54XX_FIBER;
+                       break;
+
+               case BCM54XX_FIBER:
+                       /* fiber didn't come up, try to disable fiber autoneg */
+                       if (phy->def->ops->enable_fiber)
+                               phy->def->ops->enable_fiber(phy, 0);
+                       card->medium = BCM54XX_UNKNOWN;
+                       break;
+
+               case BCM54XX_UNKNOWN:
+                       /* copper, fiber with and without failed,
+                        * retry from beginning */
+                       spider_net_setup_aneg(card);
+                       card->medium = BCM54XX_COPPER;
+                       break;
+               }
+
+               card->aneg_count = 0;
+               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+               return;
+       }
+
+       /* link still not up, try again later */
+       if (!(phy->def->ops->poll_link(phy))) {
+               card->aneg_count++;
+               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+               return;
+       }
+
+       /* link came up, get abilities */
+       phy->def->ops->read_link(phy);
+
+       spider_net_write_reg(card, SPIDER_NET_GMACST,
+                            spider_net_read_reg(card, SPIDER_NET_GMACST));
+       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4);
+
+       if (phy->speed == 1000)
+               spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001);
+       else
+               spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0);
+
+       card->aneg_count = 0;
+
+       pr_info("%s: link up, %i Mbps, %s-duplex %sautoneg.\n",
+               card->netdev->name, phy->speed,
+               phy->duplex == 1 ? "Full" : "Half",
+               phy->autoneg == 1 ? "" : "no ");
+}
+
+/**
+ * spider_net_setup_phy - setup PHY
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_setup_phy is used as part of spider_net_probe.
+ **/
+static int
+spider_net_setup_phy(struct spider_net_card *card)
+{
+       struct mii_phy *phy = &card->phy;
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
+                            SPIDER_NET_DMASEL_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
+                            SPIDER_NET_PHY_CTRL_VALUE);
+
+       phy->dev = card->netdev;
+       phy->mdio_read = spider_net_read_phy;
+       phy->mdio_write = spider_net_write_phy;
+
+       for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) {
+               unsigned short id;
+               id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+               if (id != 0x0000 && id != 0xffff) {
+                       if (!mii_phy_probe(phy, phy->mii_id)) {
+                               pr_info("Found %s.\n", phy->def->name);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * spider_net_workaround_rxramfull - work around firmware bug
+ * @card: card structure
+ *
+ * no return value
+ **/
+static void
+spider_net_workaround_rxramfull(struct spider_net_card *card)
+{
+       int i, sequencer = 0;
+
+       /* cancel reset */
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+       /* empty sequencer data */
+       for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
+            sequencer++) {
+               spider_net_write_reg(card, SPIDER_NET_GSnPRGADR +
+                                    sequencer * 8, 0x0);
+               for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
+                       spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+                                            sequencer * 8, 0x0);
+               }
+       }
+
+       /* set sequencer operation */
+       spider_net_write_reg(card, SPIDER_NET_GSINIT, 0x000000fe);
+
+       /* reset */
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_STOP_VALUE);
+}
+
+/**
+ * spider_net_stop - called upon ifconfig down
+ * @netdev: interface device structure
+ *
+ * always returns 0
+ */
+int
+spider_net_stop(struct net_device *netdev)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       napi_disable(&card->napi);
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+       del_timer_sync(&card->tx_timer);
+       del_timer_sync(&card->aneg_timer);
+
+       spider_net_disable_interrupts(card);
+
+       free_irq(netdev->irq, netdev);
+
+       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+                            SPIDER_NET_DMA_TX_FEND_VALUE);
+
+       /* turn off DMA, force end */
+       spider_net_disable_rxdmac(card);
+
+       /* release chains */
+       spider_net_release_tx_chain(card, 1);
+       spider_net_free_rx_chain_contents(card);
+
+       spider_net_free_chain(card, &card->tx_chain);
+       spider_net_free_chain(card, &card->rx_chain);
+
+       return 0;
+}
+
+/**
+ * spider_net_tx_timeout_task - task scheduled by the watchdog timeout
+ * function (to be called not under interrupt status)
+ * @data: data, is interface device structure
+ *
+ * called as task when tx hangs, resets interface (if interface is up)
+ */
+static void
+spider_net_tx_timeout_task(struct work_struct *work)
+{
+       struct spider_net_card *card =
+               container_of(work, struct spider_net_card, tx_timeout_task);
+       struct net_device *netdev = card->netdev;
+
+       if (!(netdev->flags & IFF_UP))
+               goto out;
+
+       netif_device_detach(netdev);
+       spider_net_stop(netdev);
+
+       spider_net_workaround_rxramfull(card);
+       spider_net_init_card(card);
+
+       if (spider_net_setup_phy(card))
+               goto out;
+
+       spider_net_open(netdev);
+       spider_net_kick_tx_dma(card);
+       netif_device_attach(netdev);
+
+out:
+       atomic_dec(&card->tx_timeout_task_counter);
+}
+
+/**
+ * spider_net_tx_timeout - called when the tx timeout watchdog kicks in.
+ * @netdev: interface device structure
+ *
+ * called, if tx hangs. Schedules a task that resets the interface
+ */
+static void
+spider_net_tx_timeout(struct net_device *netdev)
+{
+       struct spider_net_card *card;
+
+       card = netdev_priv(netdev);
+       atomic_inc(&card->tx_timeout_task_counter);
+       if (netdev->flags & IFF_UP)
+               schedule_work(&card->tx_timeout_task);
+       else
+               atomic_dec(&card->tx_timeout_task_counter);
+       card->spider_stats.tx_timeouts++;
+}
+
+static const struct net_device_ops spider_net_ops = {
+       .ndo_open               = spider_net_open,
+       .ndo_stop               = spider_net_stop,
+       .ndo_start_xmit         = spider_net_xmit,
+       .ndo_set_multicast_list = spider_net_set_multi,
+       .ndo_set_mac_address    = spider_net_set_mac,
+       .ndo_change_mtu         = spider_net_change_mtu,
+       .ndo_do_ioctl           = spider_net_do_ioctl,
+       .ndo_tx_timeout         = spider_net_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+       /* HW VLAN */
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       /* poll controller */
+       .ndo_poll_controller    = spider_net_poll_controller,
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+};
+
+/**
+ * spider_net_setup_netdev_ops - initialization of net_device operations
+ * @netdev: net_device structure
+ *
+ * fills out function pointers in the net_device structure
+ */
+static void
+spider_net_setup_netdev_ops(struct net_device *netdev)
+{
+       netdev->netdev_ops = &spider_net_ops;
+       netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
+       /* ethtool ops */
+       netdev->ethtool_ops = &spider_net_ethtool_ops;
+}
+
+/**
+ * spider_net_setup_netdev - initialization of net_device
+ * @card: card structure
+ *
+ * Returns 0 on success or <0 on failure
+ *
+ * spider_net_setup_netdev initializes the net_device structure
+ **/
+static int
+spider_net_setup_netdev(struct spider_net_card *card)
+{
+       int result;
+       struct net_device *netdev = card->netdev;
+       struct device_node *dn;
+       struct sockaddr addr;
+       const u8 *mac;
+
+       SET_NETDEV_DEV(netdev, &card->pdev->dev);
+
+       pci_set_drvdata(card->pdev, netdev);
+
+       init_timer(&card->tx_timer);
+       card->tx_timer.function =
+               (void (*)(unsigned long)) spider_net_cleanup_tx_ring;
+       card->tx_timer.data = (unsigned long) card;
+       netdev->irq = card->pdev->irq;
+
+       card->aneg_count = 0;
+       init_timer(&card->aneg_timer);
+       card->aneg_timer.function = spider_net_link_phy;
+       card->aneg_timer.data = (unsigned long) card;
+
+       netif_napi_add(netdev, &card->napi,
+                      spider_net_poll, SPIDER_NET_NAPI_WEIGHT);
+
+       spider_net_setup_netdev_ops(netdev);
+
+       netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
+       if (SPIDER_NET_RX_CSUM_DEFAULT)
+               netdev->features |= NETIF_F_RXCSUM;
+       netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX;
+       /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+        *              NETIF_F_HW_VLAN_FILTER */
+
+       netdev->irq = card->pdev->irq;
+       card->num_rx_ints = 0;
+       card->ignore_rx_ramfull = 0;
+
+       dn = pci_device_to_OF_node(card->pdev);
+       if (!dn)
+               return -EIO;
+
+       mac = of_get_property(dn, "local-mac-address", NULL);
+       if (!mac)
+               return -EIO;
+       memcpy(addr.sa_data, mac, ETH_ALEN);
+
+       result = spider_net_set_mac(netdev, &addr);
+       if ((result) && (netif_msg_probe(card)))
+               dev_err(&card->netdev->dev,
+                       "Failed to set MAC address: %i\n", result);
+
+       result = register_netdev(netdev);
+       if (result) {
+               if (netif_msg_probe(card))
+                       dev_err(&card->netdev->dev,
+                               "Couldn't register net_device: %i\n", result);
+               return result;
+       }
+
+       if (netif_msg_probe(card))
+               pr_info("Initialized device %s.\n", netdev->name);
+
+       return 0;
+}
+
+/**
+ * spider_net_alloc_card - allocates net_device and card structure
+ *
+ * returns the card structure or NULL in case of errors
+ *
+ * the card and net_device structures are linked to each other
+ */
+static struct spider_net_card *
+spider_net_alloc_card(void)
+{
+       struct net_device *netdev;
+       struct spider_net_card *card;
+       size_t alloc_size;
+
+       alloc_size = sizeof(struct spider_net_card) +
+          (tx_descriptors + rx_descriptors) * sizeof(struct spider_net_descr);
+       netdev = alloc_etherdev(alloc_size);
+       if (!netdev)
+               return NULL;
+
+       card = netdev_priv(netdev);
+       card->netdev = netdev;
+       card->msg_enable = SPIDER_NET_DEFAULT_MSG;
+       INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task);
+       init_waitqueue_head(&card->waitq);
+       atomic_set(&card->tx_timeout_task_counter, 0);
+
+       card->rx_chain.num_desc = rx_descriptors;
+       card->rx_chain.ring = card->darray;
+       card->tx_chain.num_desc = tx_descriptors;
+       card->tx_chain.ring = card->darray + rx_descriptors;
+
+       return card;
+}
+
+/**
+ * spider_net_undo_pci_setup - releases PCI ressources
+ * @card: card structure
+ *
+ * spider_net_undo_pci_setup releases the mapped regions
+ */
+static void
+spider_net_undo_pci_setup(struct spider_net_card *card)
+{
+       iounmap(card->regs);
+       pci_release_regions(card->pdev);
+}
+
+/**
+ * spider_net_setup_pci_dev - sets up the device in terms of PCI operations
+ * @pdev: PCI device
+ *
+ * Returns the card structure or NULL if any errors occur
+ *
+ * spider_net_setup_pci_dev initializes pdev and together with the
+ * functions called in spider_net_open configures the device so that
+ * data can be transferred over it
+ * The net_device structure is attached to the card structure, if the
+ * function returns without error.
+ **/
+static struct spider_net_card *
+spider_net_setup_pci_dev(struct pci_dev *pdev)
+{
+       struct spider_net_card *card;
+       unsigned long mmio_start, mmio_len;
+
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev, "Couldn't enable PCI device\n");
+               return NULL;
+       }
+
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+               dev_err(&pdev->dev,
+                       "Couldn't find proper PCI device base address.\n");
+               goto out_disable_dev;
+       }
+
+       if (pci_request_regions(pdev, spider_net_driver_name)) {
+               dev_err(&pdev->dev,
+                       "Couldn't obtain PCI resources, aborting.\n");
+               goto out_disable_dev;
+       }
+
+       pci_set_master(pdev);
+
+       card = spider_net_alloc_card();
+       if (!card) {
+               dev_err(&pdev->dev,
+                       "Couldn't allocate net_device structure, aborting.\n");
+               goto out_release_regions;
+       }
+       card->pdev = pdev;
+
+       /* fetch base address and length of first resource */
+       mmio_start = pci_resource_start(pdev, 0);
+       mmio_len = pci_resource_len(pdev, 0);
+
+       card->netdev->mem_start = mmio_start;
+       card->netdev->mem_end = mmio_start + mmio_len;
+       card->regs = ioremap(mmio_start, mmio_len);
+
+       if (!card->regs) {
+               dev_err(&pdev->dev,
+                       "Couldn't obtain PCI resources, aborting.\n");
+               goto out_release_regions;
+       }
+
+       return card;
+
+out_release_regions:
+       pci_release_regions(pdev);
+out_disable_dev:
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return NULL;
+}
+
+/**
+ * spider_net_probe - initialization of a device
+ * @pdev: PCI device
+ * @ent: entry in the device id list
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_probe initializes pdev and registers a net_device
+ * structure for it. After that, the device can be ifconfig'ed up
+ **/
+static int __devinit
+spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       int err = -EIO;
+       struct spider_net_card *card;
+
+       card = spider_net_setup_pci_dev(pdev);
+       if (!card)
+               goto out;
+
+       spider_net_workaround_rxramfull(card);
+       spider_net_init_card(card);
+
+       err = spider_net_setup_phy(card);
+       if (err)
+               goto out_undo_pci;
+
+       err = spider_net_setup_netdev(card);
+       if (err)
+               goto out_undo_pci;
+
+       return 0;
+
+out_undo_pci:
+       spider_net_undo_pci_setup(card);
+       free_netdev(card->netdev);
+out:
+       return err;
+}
+
+/**
+ * spider_net_remove - removal of a device
+ * @pdev: PCI device
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_remove is called to remove the device and unregisters the
+ * net_device
+ **/
+static void __devexit
+spider_net_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev;
+       struct spider_net_card *card;
+
+       netdev = pci_get_drvdata(pdev);
+       card = netdev_priv(netdev);
+
+       wait_event(card->waitq,
+                  atomic_read(&card->tx_timeout_task_counter) == 0);
+
+       unregister_netdev(netdev);
+
+       /* switch off card */
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_STOP_VALUE);
+       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
+                            SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+       spider_net_undo_pci_setup(card);
+       free_netdev(netdev);
+}
+
+static struct pci_driver spider_net_driver = {
+       .name           = spider_net_driver_name,
+       .id_table       = spider_net_pci_tbl,
+       .probe          = spider_net_probe,
+       .remove         = __devexit_p(spider_net_remove)
+};
+
+/**
+ * spider_net_init - init function when the driver is loaded
+ *
+ * spider_net_init registers the device driver
+ */
+static int __init spider_net_init(void)
+{
+       printk(KERN_INFO "Spidernet version %s.\n", VERSION);
+
+       if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) {
+               rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN;
+               pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
+       }
+       if (rx_descriptors > SPIDER_NET_RX_DESCRIPTORS_MAX) {
+               rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MAX;
+               pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
+       }
+       if (tx_descriptors < SPIDER_NET_TX_DESCRIPTORS_MIN) {
+               tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MIN;
+               pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
+       }
+       if (tx_descriptors > SPIDER_NET_TX_DESCRIPTORS_MAX) {
+               tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MAX;
+               pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
+       }
+
+       return pci_register_driver(&spider_net_driver);
+}
+
+/**
+ * spider_net_cleanup - exit function when driver is unloaded
+ *
+ * spider_net_cleanup unregisters the device driver
+ */
+static void __exit spider_net_cleanup(void)
+{
+       pci_unregister_driver(&spider_net_driver);
+}
+
+module_init(spider_net_init);
+module_exit(spider_net_cleanup);
diff --git a/drivers/net/ethernet/toshiba/spider_net.h b/drivers/net/ethernet/toshiba/spider_net.h
new file mode 100644 (file)
index 0000000..a891ad0
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * Network device driver for Cell Processor-Based Blade and Celleb platform
+ *
+ * (C) Copyright IBM Corp. 2005
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SPIDER_NET_H
+#define _SPIDER_NET_H
+
+#define VERSION "2.0 B"
+
+#include "./ethernet/sun/sungem_phy.h"
+
+extern int spider_net_stop(struct net_device *netdev);
+extern int spider_net_open(struct net_device *netdev);
+
+extern const struct ethtool_ops spider_net_ethtool_ops;
+
+extern char spider_net_driver_name[];
+
+#define SPIDER_NET_MAX_FRAME                   2312
+#define SPIDER_NET_MAX_MTU                     2294
+#define SPIDER_NET_MIN_MTU                     64
+
+#define SPIDER_NET_RXBUF_ALIGN                 128
+
+#define SPIDER_NET_RX_DESCRIPTORS_DEFAULT      256
+#define SPIDER_NET_RX_DESCRIPTORS_MIN          16
+#define SPIDER_NET_RX_DESCRIPTORS_MAX          512
+
+#define SPIDER_NET_TX_DESCRIPTORS_DEFAULT      256
+#define SPIDER_NET_TX_DESCRIPTORS_MIN          16
+#define SPIDER_NET_TX_DESCRIPTORS_MAX          512
+
+#define SPIDER_NET_TX_TIMER                    (HZ/5)
+#define SPIDER_NET_ANEG_TIMER                  (HZ)
+#define SPIDER_NET_ANEG_TIMEOUT                        5
+
+#define SPIDER_NET_RX_CSUM_DEFAULT             1
+
+#define SPIDER_NET_WATCHDOG_TIMEOUT            50*HZ
+#define SPIDER_NET_NAPI_WEIGHT                 64
+
+#define SPIDER_NET_FIRMWARE_SEQS       6
+#define SPIDER_NET_FIRMWARE_SEQWORDS   1024
+#define SPIDER_NET_FIRMWARE_LEN                (SPIDER_NET_FIRMWARE_SEQS * \
+                                        SPIDER_NET_FIRMWARE_SEQWORDS * \
+                                        sizeof(u32))
+#define SPIDER_NET_FIRMWARE_NAME       "spider_fw.bin"
+
+/** spider_net SMMIO registers */
+#define SPIDER_NET_GHIINT0STS          0x00000000
+#define SPIDER_NET_GHIINT1STS          0x00000004
+#define SPIDER_NET_GHIINT2STS          0x00000008
+#define SPIDER_NET_GHIINT0MSK          0x00000010
+#define SPIDER_NET_GHIINT1MSK          0x00000014
+#define SPIDER_NET_GHIINT2MSK          0x00000018
+
+#define SPIDER_NET_GRESUMINTNUM                0x00000020
+#define SPIDER_NET_GREINTNUM           0x00000024
+
+#define SPIDER_NET_GFFRMNUM            0x00000028
+#define SPIDER_NET_GFAFRMNUM           0x0000002c
+#define SPIDER_NET_GFBFRMNUM           0x00000030
+#define SPIDER_NET_GFCFRMNUM           0x00000034
+#define SPIDER_NET_GFDFRMNUM           0x00000038
+
+/* clear them (don't use it) */
+#define SPIDER_NET_GFREECNNUM          0x0000003c
+#define SPIDER_NET_GONETIMENUM         0x00000040
+
+#define SPIDER_NET_GTOUTFRMNUM         0x00000044
+
+#define SPIDER_NET_GTXMDSET            0x00000050
+#define SPIDER_NET_GPCCTRL             0x00000054
+#define SPIDER_NET_GRXMDSET            0x00000058
+#define SPIDER_NET_GIPSECINIT          0x0000005c
+#define SPIDER_NET_GFTRESTRT           0x00000060
+#define SPIDER_NET_GRXDMAEN            0x00000064
+#define SPIDER_NET_GMRWOLCTRL          0x00000068
+#define SPIDER_NET_GPCWOPCMD           0x0000006c
+#define SPIDER_NET_GPCROPCMD           0x00000070
+#define SPIDER_NET_GTTFRMCNT           0x00000078
+#define SPIDER_NET_GTESTMD             0x0000007c
+
+#define SPIDER_NET_GSINIT              0x00000080
+#define SPIDER_NET_GSnPRGADR           0x00000084
+#define SPIDER_NET_GSnPRGDAT           0x00000088
+
+#define SPIDER_NET_GMACOPEMD           0x00000100
+#define SPIDER_NET_GMACLENLMT          0x00000108
+#define SPIDER_NET_GMACST              0x00000110
+#define SPIDER_NET_GMACINTEN           0x00000118
+#define SPIDER_NET_GMACPHYCTRL         0x00000120
+
+#define SPIDER_NET_GMACAPAUSE          0x00000154
+#define SPIDER_NET_GMACTXPAUSE         0x00000164
+
+#define SPIDER_NET_GMACMODE            0x000001b0
+#define SPIDER_NET_GMACBSTLMT          0x000001b4
+
+#define SPIDER_NET_GMACUNIMACU         0x000001c0
+#define SPIDER_NET_GMACUNIMACL         0x000001c8
+
+#define SPIDER_NET_GMRMHFILnR          0x00000400
+#define SPIDER_NET_MULTICAST_HASHES    256
+
+#define SPIDER_NET_GMRUAFILnR          0x00000500
+#define SPIDER_NET_GMRUA0FIL15R                0x00000578
+
+#define SPIDER_NET_GTTQMSK             0x00000934
+
+/* RX DMA controller registers, all 0x00000a.. are for DMA controller A,
+ * 0x00000b.. for DMA controller B, etc. */
+#define SPIDER_NET_GDADCHA             0x00000a00
+#define SPIDER_NET_GDADMACCNTR         0x00000a04
+#define SPIDER_NET_GDACTDPA            0x00000a08
+#define SPIDER_NET_GDACTDCNT           0x00000a0c
+#define SPIDER_NET_GDACDBADDR          0x00000a20
+#define SPIDER_NET_GDACDBSIZE          0x00000a24
+#define SPIDER_NET_GDACNEXTDA          0x00000a28
+#define SPIDER_NET_GDACCOMST           0x00000a2c
+#define SPIDER_NET_GDAWBCOMST          0x00000a30
+#define SPIDER_NET_GDAWBRSIZE          0x00000a34
+#define SPIDER_NET_GDAWBVSIZE          0x00000a38
+#define SPIDER_NET_GDAWBTRST           0x00000a3c
+#define SPIDER_NET_GDAWBTRERR          0x00000a40
+
+/* TX DMA controller registers */
+#define SPIDER_NET_GDTDCHA             0x00000e00
+#define SPIDER_NET_GDTDMACCNTR         0x00000e04
+#define SPIDER_NET_GDTCDPA             0x00000e08
+#define SPIDER_NET_GDTDMASEL           0x00000e14
+
+#define SPIDER_NET_ECMODE              0x00000f00
+/* clock and reset control register */
+#define SPIDER_NET_CKRCTRL             0x00000ff0
+
+/** SCONFIG registers */
+#define SPIDER_NET_SCONFIG_IOACTE      0x00002810
+
+/** interrupt mask registers */
+#define SPIDER_NET_INT0_MASK_VALUE     0x3f7fe2c7
+#define SPIDER_NET_INT1_MASK_VALUE     0x0000fff2
+#define SPIDER_NET_INT2_MASK_VALUE     0x000003f1
+
+/* we rely on flagged descriptor interrupts */
+#define SPIDER_NET_FRAMENUM_VALUE      0x00000000
+/* set this first, then the FRAMENUM_VALUE */
+#define SPIDER_NET_GFXFRAMES_VALUE     0x00000000
+
+#define SPIDER_NET_STOP_SEQ_VALUE      0x00000000
+#define SPIDER_NET_RUN_SEQ_VALUE       0x0000007e
+
+#define SPIDER_NET_PHY_CTRL_VALUE      0x00040040
+/* #define SPIDER_NET_PHY_CTRL_VALUE   0x01070080*/
+#define SPIDER_NET_RXMODE_VALUE                0x00000011
+/* auto retransmission in case of MAC aborts */
+#define SPIDER_NET_TXMODE_VALUE                0x00010000
+#define SPIDER_NET_RESTART_VALUE       0x00000000
+#define SPIDER_NET_WOL_VALUE           0x00001111
+#if 0
+#define SPIDER_NET_WOL_VALUE           0x00000000
+#endif
+#define SPIDER_NET_IPSECINIT_VALUE     0x6f716f71
+
+/* pause frames: automatic, no upper retransmission count */
+/* outside loopback mode: ETOMOD signal dont matter, not connected */
+/* ETOMOD signal is brought to PHY reset. bit 2 must be 1 in Celleb */
+#define SPIDER_NET_OPMODE_VALUE                0x00000067
+/*#define SPIDER_NET_OPMODE_VALUE              0x001b0062*/
+#define SPIDER_NET_LENLMT_VALUE                0x00000908
+
+#define SPIDER_NET_MACAPAUSE_VALUE     0x00000800 /* about 1 ms */
+#define SPIDER_NET_TXPAUSE_VALUE       0x00000000
+
+#define SPIDER_NET_MACMODE_VALUE       0x00000001
+#define SPIDER_NET_BURSTLMT_VALUE      0x00000200 /* about 16 us */
+
+/* DMAC control register GDMACCNTR
+ *
+ * 1(0)                                enable r/tx dma
+ *  0000000                            fixed to 0
+ *
+ *         000000                      fixed to 0
+ *               0(1)                  en/disable descr writeback on force end
+ *                0(1)                 force end
+ *
+ *                 000000              fixed to 0
+ *                       00            burst alignment: 128 bytes
+ *                       11            burst alignment: 1024 bytes
+ *
+ *                         00000       fixed to 0
+ *                              0      descr writeback size 32 bytes
+ *                               0(1)  descr chain end interrupt enable
+ *                                0(1) descr status writeback enable */
+
+/* to set RX_DMA_EN */
+#define SPIDER_NET_DMA_RX_VALUE                0x80000000
+#define SPIDER_NET_DMA_RX_FEND_VALUE   0x00030003
+/* to set TX_DMA_EN */
+#define SPIDER_NET_TX_DMA_EN           0x80000000
+#define SPIDER_NET_GDTBSTA             0x00000300
+#define SPIDER_NET_GDTDCEIDIS          0x00000002
+#define SPIDER_NET_DMA_TX_VALUE        SPIDER_NET_TX_DMA_EN | \
+                                       SPIDER_NET_GDTDCEIDIS | \
+                                       SPIDER_NET_GDTBSTA
+
+#define SPIDER_NET_DMA_TX_FEND_VALUE   0x00030003
+
+/* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
+#define SPIDER_NET_UA_DESCR_VALUE      0x00080000
+#define SPIDER_NET_PROMISC_VALUE       0x00080000
+#define SPIDER_NET_NONPROMISC_VALUE    0x00000000
+
+#define SPIDER_NET_DMASEL_VALUE                0x00000001
+
+#define SPIDER_NET_ECMODE_VALUE                0x00000000
+
+#define SPIDER_NET_CKRCTRL_RUN_VALUE   0x1fff010f
+#define SPIDER_NET_CKRCTRL_STOP_VALUE  0x0000010f
+
+#define SPIDER_NET_SBIMSTATE_VALUE     0x00000000
+#define SPIDER_NET_SBTMSTATE_VALUE     0x00000000
+
+/* SPIDER_NET_GHIINT0STS bits, in reverse order so that they can be used
+ * with 1 << SPIDER_NET_... */
+enum spider_net_int0_status {
+       SPIDER_NET_GPHYINT = 0,
+       SPIDER_NET_GMAC2INT,
+       SPIDER_NET_GMAC1INT,
+       SPIDER_NET_GIPSINT,
+       SPIDER_NET_GFIFOINT,
+       SPIDER_NET_GDMACINT,
+       SPIDER_NET_GSYSINT,
+       SPIDER_NET_GPWOPCMPINT,
+       SPIDER_NET_GPROPCMPINT,
+       SPIDER_NET_GPWFFINT,
+       SPIDER_NET_GRMDADRINT,
+       SPIDER_NET_GRMARPINT,
+       SPIDER_NET_GRMMPINT,
+       SPIDER_NET_GDTDEN0INT,
+       SPIDER_NET_GDDDEN0INT,
+       SPIDER_NET_GDCDEN0INT,
+       SPIDER_NET_GDBDEN0INT,
+       SPIDER_NET_GDADEN0INT,
+       SPIDER_NET_GDTFDCINT,
+       SPIDER_NET_GDDFDCINT,
+       SPIDER_NET_GDCFDCINT,
+       SPIDER_NET_GDBFDCINT,
+       SPIDER_NET_GDAFDCINT,
+       SPIDER_NET_GTTEDINT,
+       SPIDER_NET_GDTDCEINT,
+       SPIDER_NET_GRFDNMINT,
+       SPIDER_NET_GRFCNMINT,
+       SPIDER_NET_GRFBNMINT,
+       SPIDER_NET_GRFANMINT,
+       SPIDER_NET_GRFNMINT,
+       SPIDER_NET_G1TMCNTINT,
+       SPIDER_NET_GFREECNTINT
+};
+/* GHIINT1STS bits */
+enum spider_net_int1_status {
+       SPIDER_NET_GTMFLLINT = 0,
+       SPIDER_NET_GRMFLLINT,
+       SPIDER_NET_GTMSHTINT,
+       SPIDER_NET_GDTINVDINT,
+       SPIDER_NET_GRFDFLLINT,
+       SPIDER_NET_GDDDCEINT,
+       SPIDER_NET_GDDINVDINT,
+       SPIDER_NET_GRFCFLLINT,
+       SPIDER_NET_GDCDCEINT,
+       SPIDER_NET_GDCINVDINT,
+       SPIDER_NET_GRFBFLLINT,
+       SPIDER_NET_GDBDCEINT,
+       SPIDER_NET_GDBINVDINT,
+       SPIDER_NET_GRFAFLLINT,
+       SPIDER_NET_GDADCEINT,
+       SPIDER_NET_GDAINVDINT,
+       SPIDER_NET_GDTRSERINT,
+       SPIDER_NET_GDDRSERINT,
+       SPIDER_NET_GDCRSERINT,
+       SPIDER_NET_GDBRSERINT,
+       SPIDER_NET_GDARSERINT,
+       SPIDER_NET_GDSERINT,
+       SPIDER_NET_GDTPTERINT,
+       SPIDER_NET_GDDPTERINT,
+       SPIDER_NET_GDCPTERINT,
+       SPIDER_NET_GDBPTERINT,
+       SPIDER_NET_GDAPTERINT
+};
+/* GHIINT2STS bits */
+enum spider_net_int2_status {
+       SPIDER_NET_GPROPERINT = 0,
+       SPIDER_NET_GMCTCRSNGINT,
+       SPIDER_NET_GMCTLCOLINT,
+       SPIDER_NET_GMCTTMOTINT,
+       SPIDER_NET_GMCRCAERINT,
+       SPIDER_NET_GMCRCALERINT,
+       SPIDER_NET_GMCRALNERINT,
+       SPIDER_NET_GMCROVRINT,
+       SPIDER_NET_GMCRRNTINT,
+       SPIDER_NET_GMCRRXERINT,
+       SPIDER_NET_GTITCSERINT,
+       SPIDER_NET_GTIFMTERINT,
+       SPIDER_NET_GTIPKTRVKINT,
+       SPIDER_NET_GTISPINGINT,
+       SPIDER_NET_GTISADNGINT,
+       SPIDER_NET_GTISPDNGINT,
+       SPIDER_NET_GRIFMTERINT,
+       SPIDER_NET_GRIPKTRVKINT,
+       SPIDER_NET_GRISPINGINT,
+       SPIDER_NET_GRISADNGINT,
+       SPIDER_NET_GRISPDNGINT
+};
+
+#define SPIDER_NET_TXINT       (1 << SPIDER_NET_GDTFDCINT)
+
+/* We rely on flagged descriptor interrupts */
+#define SPIDER_NET_RXINT       ( (1 << SPIDER_NET_GDAFDCINT) )
+
+#define SPIDER_NET_LINKINT     ( 1 << SPIDER_NET_GMAC2INT )
+
+#define SPIDER_NET_ERRINT      ( 0xffffffff & \
+                                 (~SPIDER_NET_TXINT) & \
+                                 (~SPIDER_NET_RXINT) & \
+                                 (~SPIDER_NET_LINKINT) )
+
+#define SPIDER_NET_GPREXEC                     0x80000000
+#define SPIDER_NET_GPRDAT_MASK                 0x0000ffff
+
+#define SPIDER_NET_DMAC_NOINTR_COMPLETE                0x00800000
+#define SPIDER_NET_DMAC_TXFRMTL                0x00040000
+#define SPIDER_NET_DMAC_TCP                    0x00020000
+#define SPIDER_NET_DMAC_UDP                    0x00030000
+#define SPIDER_NET_TXDCEST                     0x08000000
+
+#define SPIDER_NET_DESCR_RXFDIS        0x00000001
+#define SPIDER_NET_DESCR_RXDCEIS       0x00000002
+#define SPIDER_NET_DESCR_RXDEN0IS      0x00000004
+#define SPIDER_NET_DESCR_RXINVDIS      0x00000008
+#define SPIDER_NET_DESCR_RXRERRIS      0x00000010
+#define SPIDER_NET_DESCR_RXFDCIMS      0x00000100
+#define SPIDER_NET_DESCR_RXDCEIMS      0x00000200
+#define SPIDER_NET_DESCR_RXDEN0IMS     0x00000400
+#define SPIDER_NET_DESCR_RXINVDIMS     0x00000800
+#define SPIDER_NET_DESCR_RXRERRMIS     0x00001000
+#define SPIDER_NET_DESCR_UNUSED        0x077fe0e0
+
+#define SPIDER_NET_DESCR_IND_PROC_MASK         0xF0000000
+#define SPIDER_NET_DESCR_COMPLETE              0x00000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_RESPONSE_ERROR                0x10000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_PROTECTION_ERROR      0x20000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_FRAME_END             0x40000000 /* used in rx */
+#define SPIDER_NET_DESCR_FORCE_END             0x50000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_CARDOWNED             0xA0000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_NOT_IN_USE            0xF0000000
+#define SPIDER_NET_DESCR_TXDESFLG              0x00800000
+
+#define SPIDER_NET_DESCR_BAD_STATUS   (SPIDER_NET_DESCR_RXDEN0IS | \
+                                       SPIDER_NET_DESCR_RXRERRIS | \
+                                       SPIDER_NET_DESCR_RXDEN0IMS | \
+                                       SPIDER_NET_DESCR_RXINVDIMS | \
+                                       SPIDER_NET_DESCR_RXRERRMIS | \
+                                       SPIDER_NET_DESCR_UNUSED)
+
+/* Descriptor, as defined by the hardware */
+struct spider_net_hw_descr {
+       u32 buf_addr;
+       u32 buf_size;
+       u32 next_descr_addr;
+       u32 dmac_cmd_status;
+       u32 result_size;
+       u32 valid_size; /* all zeroes for tx */
+       u32 data_status;
+       u32 data_error; /* all zeroes for tx */
+} __attribute__((aligned(32)));
+
+struct spider_net_descr {
+       struct spider_net_hw_descr *hwdescr;
+       struct sk_buff *skb;
+       u32 bus_addr;
+       struct spider_net_descr *next;
+       struct spider_net_descr *prev;
+};
+
+struct spider_net_descr_chain {
+       spinlock_t lock;
+       struct spider_net_descr *head;
+       struct spider_net_descr *tail;
+       struct spider_net_descr *ring;
+       int num_desc;
+       struct spider_net_hw_descr *hwring;
+       dma_addr_t dma_addr;
+};
+
+/* descriptor data_status bits */
+#define SPIDER_NET_RX_IPCHK            29
+#define SPIDER_NET_RX_TCPCHK           28
+#define SPIDER_NET_VLAN_PACKET         21
+#define SPIDER_NET_DATA_STATUS_CKSUM_MASK ( (1 << SPIDER_NET_RX_IPCHK) | \
+                                         (1 << SPIDER_NET_RX_TCPCHK) )
+
+/* descriptor data_error bits */
+#define SPIDER_NET_RX_IPCHKERR         27
+#define SPIDER_NET_RX_RXTCPCHKERR      28
+
+#define SPIDER_NET_DATA_ERR_CKSUM_MASK (1 << SPIDER_NET_RX_IPCHKERR)
+
+/* the cases we don't pass the packet to the stack.
+ * 701b8000 would be correct, but every packets gets that flag */
+#define SPIDER_NET_DESTROY_RX_FLAGS    0x700b8000
+
+#define SPIDER_NET_DEFAULT_MSG         ( NETIF_MSG_DRV | \
+                                         NETIF_MSG_PROBE | \
+                                         NETIF_MSG_LINK | \
+                                         NETIF_MSG_TIMER | \
+                                         NETIF_MSG_IFDOWN | \
+                                         NETIF_MSG_IFUP | \
+                                         NETIF_MSG_RX_ERR | \
+                                         NETIF_MSG_TX_ERR | \
+                                         NETIF_MSG_TX_QUEUED | \
+                                         NETIF_MSG_INTR | \
+                                         NETIF_MSG_TX_DONE | \
+                                         NETIF_MSG_RX_STATUS | \
+                                         NETIF_MSG_PKTDATA | \
+                                         NETIF_MSG_HW | \
+                                         NETIF_MSG_WOL )
+
+struct spider_net_extra_stats {
+       unsigned long rx_desc_error;
+       unsigned long tx_timeouts;
+       unsigned long alloc_rx_skb_error;
+       unsigned long rx_iommu_map_error;
+       unsigned long tx_iommu_map_error;
+       unsigned long rx_desc_unk_state;
+};
+
+struct spider_net_card {
+       struct net_device *netdev;
+       struct pci_dev *pdev;
+       struct mii_phy phy;
+
+       struct napi_struct napi;
+
+       int medium;
+
+       void __iomem *regs;
+
+       struct spider_net_descr_chain tx_chain;
+       struct spider_net_descr_chain rx_chain;
+       struct spider_net_descr *low_watermark;
+
+       int aneg_count;
+       struct timer_list aneg_timer;
+       struct timer_list tx_timer;
+       struct work_struct tx_timeout_task;
+       atomic_t tx_timeout_task_counter;
+       wait_queue_head_t waitq;
+       int num_rx_ints;
+       int ignore_rx_ramfull;
+
+       /* for ethtool */
+       int msg_enable;
+       struct spider_net_extra_stats spider_stats;
+
+       /* Must be last item in struct */
+       struct spider_net_descr darray[0];
+};
+
+#endif
diff --git a/drivers/net/ethernet/toshiba/spider_net_ethtool.c b/drivers/net/ethernet/toshiba/spider_net_ethtool.c
new file mode 100644 (file)
index 0000000..9c288cd
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Network device driver for Cell Processor-Based Blade
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Authors : Utz Bacher <utz.bacher@de.ibm.com>
+ *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+
+#include "spider_net.h"
+
+
+static struct {
+       const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+       { "tx_packets" },
+       { "tx_bytes" },
+       { "rx_packets" },
+       { "rx_bytes" },
+       { "tx_errors" },
+       { "tx_dropped" },
+       { "rx_dropped" },
+       { "rx_descriptor_error" },
+       { "tx_timeouts" },
+       { "alloc_rx_skb_error" },
+       { "rx_iommu_map_error" },
+       { "tx_iommu_map_error" },
+       { "rx_desc_unk_state" },
+};
+
+static int
+spider_net_ethtool_get_settings(struct net_device *netdev,
+                              struct ethtool_cmd *cmd)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+
+       cmd->supported   = (SUPPORTED_1000baseT_Full |
+                            SUPPORTED_FIBRE);
+       cmd->advertising = (ADVERTISED_1000baseT_Full |
+                            ADVERTISED_FIBRE);
+       cmd->port = PORT_FIBRE;
+       ethtool_cmd_speed_set(cmd, card->phy.speed);
+       cmd->duplex = DUPLEX_FULL;
+
+       return 0;
+}
+
+static void
+spider_net_ethtool_get_drvinfo(struct net_device *netdev,
+                              struct ethtool_drvinfo *drvinfo)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+
+       /* clear and fill out info */
+       memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
+       strncpy(drvinfo->driver, spider_net_driver_name, 32);
+       strncpy(drvinfo->version, VERSION, 32);
+       strcpy(drvinfo->fw_version, "no information");
+       strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
+}
+
+static void
+spider_net_ethtool_get_wol(struct net_device *netdev,
+                          struct ethtool_wolinfo *wolinfo)
+{
+       /* no support for wol */
+       wolinfo->supported = 0;
+       wolinfo->wolopts = 0;
+}
+
+static u32
+spider_net_ethtool_get_msglevel(struct net_device *netdev)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+       return card->msg_enable;
+}
+
+static void
+spider_net_ethtool_set_msglevel(struct net_device *netdev,
+                               u32 level)
+{
+       struct spider_net_card *card;
+       card = netdev_priv(netdev);
+       card->msg_enable = level;
+}
+
+static int
+spider_net_ethtool_nway_reset(struct net_device *netdev)
+{
+       if (netif_running(netdev)) {
+               spider_net_stop(netdev);
+               spider_net_open(netdev);
+       }
+       return 0;
+}
+
+static void
+spider_net_ethtool_get_ringparam(struct net_device *netdev,
+                                struct ethtool_ringparam *ering)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
+       ering->tx_pending = card->tx_chain.num_desc;
+       ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
+       ering->rx_pending = card->rx_chain.num_desc;
+}
+
+static int spider_net_get_sset_count(struct net_device *netdev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(ethtool_stats_keys);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void spider_net_get_ethtool_stats(struct net_device *netdev,
+               struct ethtool_stats *stats, u64 *data)
+{
+       struct spider_net_card *card = netdev_priv(netdev);
+
+       data[0] = netdev->stats.tx_packets;
+       data[1] = netdev->stats.tx_bytes;
+       data[2] = netdev->stats.rx_packets;
+       data[3] = netdev->stats.rx_bytes;
+       data[4] = netdev->stats.tx_errors;
+       data[5] = netdev->stats.tx_dropped;
+       data[6] = netdev->stats.rx_dropped;
+       data[7] = card->spider_stats.rx_desc_error;
+       data[8] = card->spider_stats.tx_timeouts;
+       data[9] = card->spider_stats.alloc_rx_skb_error;
+       data[10] = card->spider_stats.rx_iommu_map_error;
+       data[11] = card->spider_stats.tx_iommu_map_error;
+       data[12] = card->spider_stats.rx_desc_unk_state;
+}
+
+static void spider_net_get_strings(struct net_device *netdev, u32 stringset,
+                                  u8 *data)
+{
+       memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+const struct ethtool_ops spider_net_ethtool_ops = {
+       .get_settings           = spider_net_ethtool_get_settings,
+       .get_drvinfo            = spider_net_ethtool_get_drvinfo,
+       .get_wol                = spider_net_ethtool_get_wol,
+       .get_msglevel           = spider_net_ethtool_get_msglevel,
+       .set_msglevel           = spider_net_ethtool_set_msglevel,
+       .get_link               = ethtool_op_get_link,
+       .nway_reset             = spider_net_ethtool_nway_reset,
+       .get_ringparam          = spider_net_ethtool_get_ringparam,
+       .get_strings            = spider_net_get_strings,
+       .get_sset_count         = spider_net_get_sset_count,
+       .get_ethtool_stats      = spider_net_get_ethtool_stats,
+};
+
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
new file mode 100644 (file)
index 0000000..4a55a16
--- /dev/null
@@ -0,0 +1,2228 @@
+/*
+ * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
+ *
+ * Based on skelton.c by Donald Becker.
+ *
+ * This driver is a replacement of older and less maintained version.
+ * This is a header of the older version:
+ *     -----<snip>-----
+ *     Copyright 2001 MontaVista Software Inc.
+ *     Author: MontaVista Software, Inc.
+ *             ahennessy@mvista.com
+ *     Copyright (C) 2000-2001 Toshiba Corporation
+ *     static const char *version =
+ *             "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+ *     -----<snip>-----
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * (C) Copyright TOSHIBA CORPORATION 2004-2005
+ * All Rights Reserved.
+ */
+
+#define DRV_VERSION    "1.39"
+static const char *version = "tc35815.c:v" DRV_VERSION "\n";
+#define MODNAME                        "tc35815"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/if_vlan.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/prefetch.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+enum tc35815_chiptype {
+       TC35815CF = 0,
+       TC35815_NWU,
+       TC35815_TX4939,
+};
+
+/* indexed by tc35815_chiptype, above */
+static const struct {
+       const char *name;
+} chip_info[] __devinitdata = {
+       { "TOSHIBA TC35815CF 10/100BaseTX" },
+       { "TOSHIBA TC35815 with Wake on LAN" },
+       { "TOSHIBA TC35815/TX4939" },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(tc35815_pci_tbl) = {
+       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
+       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
+       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
+       {0,}
+};
+MODULE_DEVICE_TABLE(pci, tc35815_pci_tbl);
+
+/* see MODULE_PARM_DESC */
+static struct tc35815_options {
+       int speed;
+       int duplex;
+} options;
+
+/*
+ * Registers
+ */
+struct tc35815_regs {
+       __u32 DMA_Ctl;          /* 0x00 */
+       __u32 TxFrmPtr;
+       __u32 TxThrsh;
+       __u32 TxPollCtr;
+       __u32 BLFrmPtr;
+       __u32 RxFragSize;
+       __u32 Int_En;
+       __u32 FDA_Bas;
+       __u32 FDA_Lim;          /* 0x20 */
+       __u32 Int_Src;
+       __u32 unused0[2];
+       __u32 PauseCnt;
+       __u32 RemPauCnt;
+       __u32 TxCtlFrmStat;
+       __u32 unused1;
+       __u32 MAC_Ctl;          /* 0x40 */
+       __u32 CAM_Ctl;
+       __u32 Tx_Ctl;
+       __u32 Tx_Stat;
+       __u32 Rx_Ctl;
+       __u32 Rx_Stat;
+       __u32 MD_Data;
+       __u32 MD_CA;
+       __u32 CAM_Adr;          /* 0x60 */
+       __u32 CAM_Data;
+       __u32 CAM_Ena;
+       __u32 PROM_Ctl;
+       __u32 PROM_Data;
+       __u32 Algn_Cnt;
+       __u32 CRC_Cnt;
+       __u32 Miss_Cnt;
+};
+
+/*
+ * Bit assignments
+ */
+/* DMA_Ctl bit assign ------------------------------------------------------- */
+#define DMA_RxAlign           0x00c00000 /* 1:Reception Alignment           */
+#define DMA_RxAlign_1         0x00400000
+#define DMA_RxAlign_2         0x00800000
+#define DMA_RxAlign_3         0x00c00000
+#define DMA_M66EnStat         0x00080000 /* 1:66MHz Enable State            */
+#define DMA_IntMask           0x00040000 /* 1:Interrupt mask                */
+#define DMA_SWIntReq          0x00020000 /* 1:Software Interrupt request    */
+#define DMA_TxWakeUp          0x00010000 /* 1:Transmit Wake Up              */
+#define DMA_RxBigE            0x00008000 /* 1:Receive Big Endian            */
+#define DMA_TxBigE            0x00004000 /* 1:Transmit Big Endian           */
+#define DMA_TestMode          0x00002000 /* 1:Test Mode                     */
+#define DMA_PowrMgmnt         0x00001000 /* 1:Power Management              */
+#define DMA_DmBurst_Mask       0x000001fc /* DMA Burst size                 */
+
+/* RxFragSize bit assign ---------------------------------------------------- */
+#define RxFrag_EnPack         0x00008000 /* 1:Enable Packing                */
+#define RxFrag_MinFragMask     0x00000ffc /* Minimum Fragment               */
+
+/* MAC_Ctl bit assign ------------------------------------------------------- */
+#define MAC_Link10            0x00008000 /* 1:Link Status 10Mbits           */
+#define MAC_EnMissRoll        0x00002000 /* 1:Enable Missed Roll            */
+#define MAC_MissRoll          0x00000400 /* 1:Missed Roll                   */
+#define MAC_Loop10            0x00000080 /* 1:Loop 10 Mbps                  */
+#define MAC_Conn_Auto         0x00000000 /*00:Connection mode (Automatic)   */
+#define MAC_Conn_10M          0x00000020 /*01:                (10Mbps endec)*/
+#define MAC_Conn_Mll          0x00000040 /*10:                (Mll clock)   */
+#define MAC_MacLoop           0x00000010 /* 1:MAC Loopback                  */
+#define MAC_FullDup           0x00000008 /* 1:Full Duplex 0:Half Duplex     */
+#define MAC_Reset             0x00000004 /* 1:Software Reset                */
+#define MAC_HaltImm           0x00000002 /* 1:Halt Immediate                */
+#define MAC_HaltReq           0x00000001 /* 1:Halt request                  */
+
+/* PROM_Ctl bit assign ------------------------------------------------------ */
+#define PROM_Busy             0x00008000 /* 1:Busy (Start Operation)        */
+#define PROM_Read             0x00004000 /*10:Read operation                */
+#define PROM_Write            0x00002000 /*01:Write operation               */
+#define PROM_Erase            0x00006000 /*11:Erase operation               */
+                                         /*00:Enable or Disable Writting,   */
+                                         /*      as specified in PROM_Addr. */
+#define PROM_Addr_Ena         0x00000030 /*11xxxx:PROM Write enable         */
+                                         /*00xxxx:           disable        */
+
+/* CAM_Ctl bit assign ------------------------------------------------------- */
+#define CAM_CompEn            0x00000010 /* 1:CAM Compare Enable            */
+#define CAM_NegCAM            0x00000008 /* 1:Reject packets CAM recognizes,*/
+                                         /*                    accept other */
+#define CAM_BroadAcc          0x00000004 /* 1:Broadcast assept              */
+#define CAM_GroupAcc          0x00000002 /* 1:Multicast assept              */
+#define CAM_StationAcc        0x00000001 /* 1:unicast accept                */
+
+/* CAM_Ena bit assign ------------------------------------------------------- */
+#define CAM_ENTRY_MAX                 21   /* CAM Data entry max count      */
+#define CAM_Ena_Mask ((1<<CAM_ENTRY_MAX)-1) /* CAM Enable bits (Max 21bits)  */
+#define CAM_Ena_Bit(index)     (1 << (index))
+#define CAM_ENTRY_DESTINATION  0
+#define CAM_ENTRY_SOURCE       1
+#define CAM_ENTRY_MACCTL       20
+
+/* Tx_Ctl bit assign -------------------------------------------------------- */
+#define Tx_En                 0x00000001 /* 1:Transmit enable               */
+#define Tx_TxHalt             0x00000002 /* 1:Transmit Halt Request         */
+#define Tx_NoPad              0x00000004 /* 1:Suppress Padding              */
+#define Tx_NoCRC              0x00000008 /* 1:Suppress Padding              */
+#define Tx_FBack              0x00000010 /* 1:Fast Back-off                 */
+#define Tx_EnUnder            0x00000100 /* 1:Enable Underrun               */
+#define Tx_EnExDefer          0x00000200 /* 1:Enable Excessive Deferral     */
+#define Tx_EnLCarr            0x00000400 /* 1:Enable Lost Carrier           */
+#define Tx_EnExColl           0x00000800 /* 1:Enable Excessive Collision    */
+#define Tx_EnLateColl         0x00001000 /* 1:Enable Late Collision         */
+#define Tx_EnTxPar            0x00002000 /* 1:Enable Transmit Parity        */
+#define Tx_EnComp             0x00004000 /* 1:Enable Completion             */
+
+/* Tx_Stat bit assign ------------------------------------------------------- */
+#define Tx_TxColl_MASK        0x0000000F /* Tx Collision Count              */
+#define Tx_ExColl             0x00000010 /* Excessive Collision             */
+#define Tx_TXDefer            0x00000020 /* Transmit Defered                */
+#define Tx_Paused             0x00000040 /* Transmit Paused                 */
+#define Tx_IntTx              0x00000080 /* Interrupt on Tx                 */
+#define Tx_Under              0x00000100 /* Underrun                        */
+#define Tx_Defer              0x00000200 /* Deferral                        */
+#define Tx_NCarr              0x00000400 /* No Carrier                      */
+#define Tx_10Stat             0x00000800 /* 10Mbps Status                   */
+#define Tx_LateColl           0x00001000 /* Late Collision                  */
+#define Tx_TxPar              0x00002000 /* Tx Parity Error                 */
+#define Tx_Comp                       0x00004000 /* Completion                      */
+#define Tx_Halted             0x00008000 /* Tx Halted                       */
+#define Tx_SQErr              0x00010000 /* Signal Quality Error(SQE)       */
+
+/* Rx_Ctl bit assign -------------------------------------------------------- */
+#define Rx_EnGood             0x00004000 /* 1:Enable Good                   */
+#define Rx_EnRxPar            0x00002000 /* 1:Enable Receive Parity         */
+#define Rx_EnLongErr          0x00000800 /* 1:Enable Long Error             */
+#define Rx_EnOver             0x00000400 /* 1:Enable OverFlow               */
+#define Rx_EnCRCErr           0x00000200 /* 1:Enable CRC Error              */
+#define Rx_EnAlign            0x00000100 /* 1:Enable Alignment              */
+#define Rx_IgnoreCRC          0x00000040 /* 1:Ignore CRC Value              */
+#define Rx_StripCRC           0x00000010 /* 1:Strip CRC Value               */
+#define Rx_ShortEn            0x00000008 /* 1:Short Enable                  */
+#define Rx_LongEn             0x00000004 /* 1:Long Enable                   */
+#define Rx_RxHalt             0x00000002 /* 1:Receive Halt Request          */
+#define Rx_RxEn                       0x00000001 /* 1:Receive Intrrupt Enable       */
+
+/* Rx_Stat bit assign ------------------------------------------------------- */
+#define Rx_Halted             0x00008000 /* Rx Halted                       */
+#define Rx_Good                       0x00004000 /* Rx Good                         */
+#define Rx_RxPar              0x00002000 /* Rx Parity Error                 */
+#define Rx_TypePkt            0x00001000 /* Rx Type Packet                  */
+#define Rx_LongErr            0x00000800 /* Rx Long Error                   */
+#define Rx_Over                       0x00000400 /* Rx Overflow                     */
+#define Rx_CRCErr             0x00000200 /* Rx CRC Error                    */
+#define Rx_Align              0x00000100 /* Rx Alignment Error              */
+#define Rx_10Stat             0x00000080 /* Rx 10Mbps Status                */
+#define Rx_IntRx              0x00000040 /* Rx Interrupt                    */
+#define Rx_CtlRecd            0x00000020 /* Rx Control Receive              */
+#define Rx_InLenErr           0x00000010 /* Rx In Range Frame Length Error  */
+
+#define Rx_Stat_Mask          0x0000FFF0 /* Rx All Status Mask              */
+
+/* Int_En bit assign -------------------------------------------------------- */
+#define Int_NRAbtEn           0x00000800 /* 1:Non-recoverable Abort Enable  */
+#define Int_TxCtlCmpEn        0x00000400 /* 1:Transmit Ctl Complete Enable  */
+#define Int_DmParErrEn        0x00000200 /* 1:DMA Parity Error Enable       */
+#define Int_DParDEn           0x00000100 /* 1:Data Parity Error Enable      */
+#define Int_EarNotEn          0x00000080 /* 1:Early Notify Enable           */
+#define Int_DParErrEn         0x00000040 /* 1:Detected Parity Error Enable  */
+#define Int_SSysErrEn         0x00000020 /* 1:Signalled System Error Enable */
+#define Int_RMasAbtEn         0x00000010 /* 1:Received Master Abort Enable  */
+#define Int_RTargAbtEn        0x00000008 /* 1:Received Target Abort Enable  */
+#define Int_STargAbtEn        0x00000004 /* 1:Signalled Target Abort Enable */
+#define Int_BLExEn            0x00000002 /* 1:Buffer List Exhausted Enable  */
+#define Int_FDAExEn           0x00000001 /* 1:Free Descriptor Area          */
+                                         /*               Exhausted Enable  */
+
+/* Int_Src bit assign ------------------------------------------------------- */
+#define Int_NRabt             0x00004000 /* 1:Non Recoverable error         */
+#define Int_DmParErrStat       0x00002000 /* 1:DMA Parity Error & Clear             */
+#define Int_BLEx              0x00001000 /* 1:Buffer List Empty & Clear     */
+#define Int_FDAEx             0x00000800 /* 1:FDA Empty & Clear             */
+#define Int_IntNRAbt          0x00000400 /* 1:Non Recoverable Abort         */
+#define Int_IntCmp            0x00000200 /* 1:MAC control packet complete   */
+#define Int_IntExBD           0x00000100 /* 1:Interrupt Extra BD & Clear    */
+#define Int_DmParErr          0x00000080 /* 1:DMA Parity Error & Clear      */
+#define Int_IntEarNot         0x00000040 /* 1:Receive Data write & Clear    */
+#define Int_SWInt             0x00000020 /* 1:Software request & Clear      */
+#define Int_IntBLEx           0x00000010 /* 1:Buffer List Empty & Clear     */
+#define Int_IntFDAEx          0x00000008 /* 1:FDA Empty & Clear             */
+#define Int_IntPCI            0x00000004 /* 1:PCI controller & Clear        */
+#define Int_IntMacRx          0x00000002 /* 1:Rx controller & Clear         */
+#define Int_IntMacTx          0x00000001 /* 1:Tx controller & Clear         */
+
+/* MD_CA bit assign --------------------------------------------------------- */
+#define MD_CA_PreSup          0x00001000 /* 1:Preamble Suppress                     */
+#define MD_CA_Busy            0x00000800 /* 1:Busy (Start Operation)        */
+#define MD_CA_Wr              0x00000400 /* 1:Write 0:Read                  */
+
+
+/*
+ * Descriptors
+ */
+
+/* Frame descripter */
+struct FDesc {
+       volatile __u32 FDNext;
+       volatile __u32 FDSystem;
+       volatile __u32 FDStat;
+       volatile __u32 FDCtl;
+};
+
+/* Buffer descripter */
+struct BDesc {
+       volatile __u32 BuffData;
+       volatile __u32 BDCtl;
+};
+
+#define FD_ALIGN       16
+
+/* Frame Descripter bit assign ---------------------------------------------- */
+#define FD_FDLength_MASK       0x0000FFFF /* Length MASK                    */
+#define FD_BDCnt_MASK         0x001F0000 /* BD count MASK in FD             */
+#define FD_FrmOpt_MASK        0x7C000000 /* Frame option MASK               */
+#define FD_FrmOpt_BigEndian    0x40000000 /* Tx/Rx */
+#define FD_FrmOpt_IntTx               0x20000000 /* Tx only */
+#define FD_FrmOpt_NoCRC               0x10000000 /* Tx only */
+#define FD_FrmOpt_NoPadding    0x08000000 /* Tx only */
+#define FD_FrmOpt_Packing      0x04000000 /* Rx only */
+#define FD_CownsFD            0x80000000 /* FD Controller owner bit         */
+#define FD_Next_EOL           0x00000001 /* FD EOL indicator                */
+#define FD_BDCnt_SHIFT        16
+
+/* Buffer Descripter bit assign --------------------------------------------- */
+#define BD_BuffLength_MASK     0x0000FFFF /* Receive Data Size              */
+#define BD_RxBDID_MASK        0x00FF0000 /* BD ID Number MASK               */
+#define BD_RxBDSeqN_MASK       0x7F000000 /* Rx BD Sequence Number          */
+#define BD_CownsBD            0x80000000 /* BD Controller owner bit         */
+#define BD_RxBDID_SHIFT               16
+#define BD_RxBDSeqN_SHIFT      24
+
+
+/* Some useful constants. */
+
+#define TX_CTL_CMD     (Tx_EnTxPar | Tx_EnLateColl | \
+       Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+       Tx_En)  /* maybe  0x7b01 */
+/* Do not use Rx_StripCRC -- it causes trouble on BLEx/FDAEx condition */
+#define RX_CTL_CMD     (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
+       | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */
+#define INT_EN_CMD  (Int_NRAbtEn | \
+       Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
+       Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
+       Int_STargAbtEn | \
+       Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
+#define DMA_CTL_CMD    DMA_BURST_SIZE
+#define HAVE_DMA_RXALIGN(lp)   likely((lp)->chiptype != TC35815CF)
+
+/* Tuning parameters */
+#define DMA_BURST_SIZE 32
+#define TX_THRESHOLD   1024
+/* used threshold with packet max byte for low pci transfer ability.*/
+#define TX_THRESHOLD_MAX 1536
+/* setting threshold max value when overrun error occurred this count. */
+#define TX_THRESHOLD_KEEP_LIMIT 10
+
+/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
+#define FD_PAGE_NUM 4
+#define RX_BUF_NUM     128     /* < 256 */
+#define RX_FD_NUM      256     /* >= 32 */
+#define TX_FD_NUM      128
+#if RX_CTL_CMD & Rx_LongEn
+#define RX_BUF_SIZE    PAGE_SIZE
+#elif RX_CTL_CMD & Rx_StripCRC
+#define RX_BUF_SIZE    \
+       L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + NET_IP_ALIGN)
+#else
+#define RX_BUF_SIZE    \
+       L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN + NET_IP_ALIGN)
+#endif
+#define RX_FD_RESERVE  (2 / 2) /* max 2 BD per RxFD */
+#define NAPI_WEIGHT    16
+
+struct TxFD {
+       struct FDesc fd;
+       struct BDesc bd;
+       struct BDesc unused;
+};
+
+struct RxFD {
+       struct FDesc fd;
+       struct BDesc bd[0];     /* variable length */
+};
+
+struct FrFD {
+       struct FDesc fd;
+       struct BDesc bd[RX_BUF_NUM];
+};
+
+
+#define tc_readl(addr) ioread32(addr)
+#define tc_writel(d, addr)     iowrite32(d, addr)
+
+#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)
+
+/* Information that need to be kept for each controller. */
+struct tc35815_local {
+       struct pci_dev *pci_dev;
+
+       struct net_device *dev;
+       struct napi_struct napi;
+
+       /* statistics */
+       struct {
+               int max_tx_qlen;
+               int tx_ints;
+               int rx_ints;
+               int tx_underrun;
+       } lstats;
+
+       /* Tx control lock.  This protects the transmit buffer ring
+        * state along with the "tx full" state of the driver.  This
+        * means all netif_queue flow control actions are protected
+        * by this lock as well.
+        */
+       spinlock_t lock;
+       spinlock_t rx_lock;
+
+       struct mii_bus *mii_bus;
+       struct phy_device *phy_dev;
+       int duplex;
+       int speed;
+       int link;
+       struct work_struct restart_work;
+
+       /*
+        * Transmitting: Batch Mode.
+        *      1 BD in 1 TxFD.
+        * Receiving: Non-Packing Mode.
+        *      1 circular FD for Free Buffer List.
+        *      RX_BUF_NUM BD in Free Buffer FD.
+        *      One Free Buffer BD has ETH_FRAME_LEN data buffer.
+        */
+       void *fd_buf;   /* for TxFD, RxFD, FrFD */
+       dma_addr_t fd_buf_dma;
+       struct TxFD *tfd_base;
+       unsigned int tfd_start;
+       unsigned int tfd_end;
+       struct RxFD *rfd_base;
+       struct RxFD *rfd_limit;
+       struct RxFD *rfd_cur;
+       struct FrFD *fbl_ptr;
+       unsigned int fbl_count;
+       struct {
+               struct sk_buff *skb;
+               dma_addr_t skb_dma;
+       } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
+       u32 msg_enable;
+       enum tc35815_chiptype chiptype;
+};
+
+static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
+{
+       return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
+}
+#ifdef DEBUG
+static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+       return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
+}
+#endif
+static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
+                                      struct pci_dev *hwdev,
+                                      dma_addr_t *dma_handle)
+{
+       struct sk_buff *skb;
+       skb = dev_alloc_skb(RX_BUF_SIZE);
+       if (!skb)
+               return NULL;
+       *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
+                                    PCI_DMA_FROMDEVICE);
+       if (pci_dma_mapping_error(hwdev, *dma_handle)) {
+               dev_kfree_skb_any(skb);
+               return NULL;
+       }
+       skb_reserve(skb, 2);    /* make IP header 4byte aligned */
+       return skb;
+}
+
+static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
+{
+       pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
+                        PCI_DMA_FROMDEVICE);
+       dev_kfree_skb_any(skb);
+}
+
+/* Index to functions, as function prototypes. */
+
+static int     tc35815_open(struct net_device *dev);
+static int     tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t     tc35815_interrupt(int irq, void *dev_id);
+static int     tc35815_rx(struct net_device *dev, int limit);
+static int     tc35815_poll(struct napi_struct *napi, int budget);
+static void    tc35815_txdone(struct net_device *dev);
+static int     tc35815_close(struct net_device *dev);
+static struct  net_device_stats *tc35815_get_stats(struct net_device *dev);
+static void    tc35815_set_multicast_list(struct net_device *dev);
+static void    tc35815_tx_timeout(struct net_device *dev);
+static int     tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void    tc35815_poll_controller(struct net_device *dev);
+#endif
+static const struct ethtool_ops tc35815_ethtool_ops;
+
+/* Example routines you must write ;->. */
+static void    tc35815_chip_reset(struct net_device *dev);
+static void    tc35815_chip_init(struct net_device *dev);
+
+#ifdef DEBUG
+static void    panic_queues(struct net_device *dev);
+#endif
+
+static void tc35815_restart_work(struct work_struct *work);
+
+static int tc_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       struct net_device *dev = bus->priv;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       unsigned long timeout = jiffies + HZ;
+
+       tc_writel(MD_CA_Busy | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA);
+       udelay(12); /* it takes 32 x 400ns at least */
+       while (tc_readl(&tr->MD_CA) & MD_CA_Busy) {
+               if (time_after(jiffies, timeout))
+                       return -EIO;
+               cpu_relax();
+       }
+       return tc_readl(&tr->MD_Data) & 0xffff;
+}
+
+static int tc_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val)
+{
+       struct net_device *dev = bus->priv;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       unsigned long timeout = jiffies + HZ;
+
+       tc_writel(val, &tr->MD_Data);
+       tc_writel(MD_CA_Busy | MD_CA_Wr | (mii_id << 5) | (regnum & 0x1f),
+                 &tr->MD_CA);
+       udelay(12); /* it takes 32 x 400ns at least */
+       while (tc_readl(&tr->MD_CA) & MD_CA_Busy) {
+               if (time_after(jiffies, timeout))
+                       return -EIO;
+               cpu_relax();
+       }
+       return 0;
+}
+
+static void tc_handle_link_change(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct phy_device *phydev = lp->phy_dev;
+       unsigned long flags;
+       int status_change = 0;
+
+       spin_lock_irqsave(&lp->lock, flags);
+       if (phydev->link &&
+           (lp->speed != phydev->speed || lp->duplex != phydev->duplex)) {
+               struct tc35815_regs __iomem *tr =
+                       (struct tc35815_regs __iomem *)dev->base_addr;
+               u32 reg;
+
+               reg = tc_readl(&tr->MAC_Ctl);
+               reg |= MAC_HaltReq;
+               tc_writel(reg, &tr->MAC_Ctl);
+               if (phydev->duplex == DUPLEX_FULL)
+                       reg |= MAC_FullDup;
+               else
+                       reg &= ~MAC_FullDup;
+               tc_writel(reg, &tr->MAC_Ctl);
+               reg &= ~MAC_HaltReq;
+               tc_writel(reg, &tr->MAC_Ctl);
+
+               /*
+                * TX4939 PCFG.SPEEDn bit will be changed on
+                * NETDEV_CHANGE event.
+                */
+               /*
+                * WORKAROUND: enable LostCrS only if half duplex
+                * operation.
+                * (TX4939 does not have EnLCarr)
+                */
+               if (phydev->duplex == DUPLEX_HALF &&
+                   lp->chiptype != TC35815_TX4939)
+                       tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr,
+                                 &tr->Tx_Ctl);
+
+               lp->speed = phydev->speed;
+               lp->duplex = phydev->duplex;
+               status_change = 1;
+       }
+
+       if (phydev->link != lp->link) {
+               if (phydev->link) {
+                       /* delayed promiscuous enabling */
+                       if (dev->flags & IFF_PROMISC)
+                               tc35815_set_multicast_list(dev);
+               } else {
+                       lp->speed = 0;
+                       lp->duplex = -1;
+               }
+               lp->link = phydev->link;
+
+               status_change = 1;
+       }
+       spin_unlock_irqrestore(&lp->lock, flags);
+
+       if (status_change && netif_msg_link(lp)) {
+               phy_print_status(phydev);
+               pr_debug("%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+                        dev->name,
+                        phy_read(phydev, MII_BMCR),
+                        phy_read(phydev, MII_BMSR),
+                        phy_read(phydev, MII_LPA));
+       }
+}
+
+static int tc_mii_probe(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+       int phy_addr;
+       u32 dropmask;
+
+       /* find the first phy */
+       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+               if (lp->mii_bus->phy_map[phy_addr]) {
+                       if (phydev) {
+                               printk(KERN_ERR "%s: multiple PHYs found\n",
+                                      dev->name);
+                               return -EINVAL;
+                       }
+                       phydev = lp->mii_bus->phy_map[phy_addr];
+                       break;
+               }
+       }
+
+       if (!phydev) {
+               printk(KERN_ERR "%s: no PHY found\n", dev->name);
+               return -ENODEV;
+       }
+
+       /* attach the mac to the phy */
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
+                            &tc_handle_link_change, 0,
+                            lp->chiptype == TC35815_TX4939 ?
+                            PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
+       if (IS_ERR(phydev)) {
+               printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+               return PTR_ERR(phydev);
+       }
+       printk(KERN_INFO "%s: attached PHY driver [%s] "
+               "(mii_bus:phy_addr=%s, id=%x)\n",
+               dev->name, phydev->drv->name, dev_name(&phydev->dev),
+               phydev->phy_id);
+
+       /* mask with MAC supported features */
+       phydev->supported &= PHY_BASIC_FEATURES;
+       dropmask = 0;
+       if (options.speed == 10)
+               dropmask |= SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+       else if (options.speed == 100)
+               dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full;
+       if (options.duplex == 1)
+               dropmask |= SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full;
+       else if (options.duplex == 2)
+               dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_100baseT_Half;
+       phydev->supported &= ~dropmask;
+       phydev->advertising = phydev->supported;
+
+       lp->link = 0;
+       lp->speed = 0;
+       lp->duplex = -1;
+       lp->phy_dev = phydev;
+
+       return 0;
+}
+
+static int tc_mii_init(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       int err;
+       int i;
+
+       lp->mii_bus = mdiobus_alloc();
+       if (lp->mii_bus == NULL) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       lp->mii_bus->name = "tc35815_mii_bus";
+       lp->mii_bus->read = tc_mdio_read;
+       lp->mii_bus->write = tc_mdio_write;
+       snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x",
+                (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn);
+       lp->mii_bus->priv = dev;
+       lp->mii_bus->parent = &lp->pci_dev->dev;
+       lp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+       if (!lp->mii_bus->irq) {
+               err = -ENOMEM;
+               goto err_out_free_mii_bus;
+       }
+
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               lp->mii_bus->irq[i] = PHY_POLL;
+
+       err = mdiobus_register(lp->mii_bus);
+       if (err)
+               goto err_out_free_mdio_irq;
+       err = tc_mii_probe(dev);
+       if (err)
+               goto err_out_unregister_bus;
+       return 0;
+
+err_out_unregister_bus:
+       mdiobus_unregister(lp->mii_bus);
+err_out_free_mdio_irq:
+       kfree(lp->mii_bus->irq);
+err_out_free_mii_bus:
+       mdiobus_free(lp->mii_bus);
+err_out:
+       return err;
+}
+
+#ifdef CONFIG_CPU_TX49XX
+/*
+ * Find a platform_device providing a MAC address.  The platform code
+ * should provide a "tc35815-mac" device with a MAC address in its
+ * platform_data.
+ */
+static int __devinit tc35815_mac_match(struct device *dev, void *data)
+{
+       struct platform_device *plat_dev = to_platform_device(dev);
+       struct pci_dev *pci_dev = data;
+       unsigned int id = pci_dev->irq;
+       return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;
+}
+
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct device *pd = bus_find_device(&platform_bus_type, NULL,
+                                           lp->pci_dev, tc35815_mac_match);
+       if (pd) {
+               if (pd->platform_data)
+                       memcpy(dev->dev_addr, pd->platform_data, ETH_ALEN);
+               put_device(pd);
+               return is_valid_ether_addr(dev->dev_addr) ? 0 : -ENODEV;
+       }
+       return -ENODEV;
+}
+#else
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
+{
+       return -ENODEV;
+}
+#endif
+
+static int __devinit tc35815_init_dev_addr(struct net_device *dev)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int i;
+
+       while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+               ;
+       for (i = 0; i < 6; i += 2) {
+               unsigned short data;
+               tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+               while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+                       ;
+               data = tc_readl(&tr->PROM_Data);
+               dev->dev_addr[i] = data & 0xff;
+               dev->dev_addr[i+1] = data >> 8;
+       }
+       if (!is_valid_ether_addr(dev->dev_addr))
+               return tc35815_read_plat_dev_addr(dev);
+       return 0;
+}
+
+static const struct net_device_ops tc35815_netdev_ops = {
+       .ndo_open               = tc35815_open,
+       .ndo_stop               = tc35815_close,
+       .ndo_start_xmit         = tc35815_send_packet,
+       .ndo_get_stats          = tc35815_get_stats,
+       .ndo_set_multicast_list = tc35815_set_multicast_list,
+       .ndo_tx_timeout         = tc35815_tx_timeout,
+       .ndo_do_ioctl           = tc35815_ioctl,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = tc35815_poll_controller,
+#endif
+};
+
+static int __devinit tc35815_init_one(struct pci_dev *pdev,
+                                     const struct pci_device_id *ent)
+{
+       void __iomem *ioaddr = NULL;
+       struct net_device *dev;
+       struct tc35815_local *lp;
+       int rc;
+
+       static int printed_version;
+       if (!printed_version++) {
+               printk(version);
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                          "speed:%d duplex:%d\n",
+                          options.speed, options.duplex);
+       }
+
+       if (!pdev->irq) {
+               dev_warn(&pdev->dev, "no IRQ assigned.\n");
+               return -ENODEV;
+       }
+
+       /* dev zeroed in alloc_etherdev */
+       dev = alloc_etherdev(sizeof(*lp));
+       if (dev == NULL) {
+               dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+               return -ENOMEM;
+       }
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       lp = netdev_priv(dev);
+       lp->dev = dev;
+
+       /* enable device (incl. PCI PM wakeup), and bus-mastering */
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               goto err_out;
+       rc = pcim_iomap_regions(pdev, 1 << 1, MODNAME);
+       if (rc)
+               goto err_out;
+       pci_set_master(pdev);
+       ioaddr = pcim_iomap_table(pdev)[1];
+
+       /* Initialize the device structure. */
+       dev->netdev_ops = &tc35815_netdev_ops;
+       dev->ethtool_ops = &tc35815_ethtool_ops;
+       dev->watchdog_timeo = TC35815_TX_TIMEOUT;
+       netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT);
+
+       dev->irq = pdev->irq;
+       dev->base_addr = (unsigned long)ioaddr;
+
+       INIT_WORK(&lp->restart_work, tc35815_restart_work);
+       spin_lock_init(&lp->lock);
+       spin_lock_init(&lp->rx_lock);
+       lp->pci_dev = pdev;
+       lp->chiptype = ent->driver_data;
+
+       lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
+       pci_set_drvdata(pdev, dev);
+
+       /* Soft reset the chip. */
+       tc35815_chip_reset(dev);
+
+       /* Retrieve the ethernet address. */
+       if (tc35815_init_dev_addr(dev)) {
+               dev_warn(&pdev->dev, "not valid ether addr\n");
+               random_ether_addr(dev->dev_addr);
+       }
+
+       rc = register_netdev(dev);
+       if (rc)
+               goto err_out;
+
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+       printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
+               dev->name,
+               chip_info[ent->driver_data].name,
+               dev->base_addr,
+               dev->dev_addr,
+               dev->irq);
+
+       rc = tc_mii_init(dev);
+       if (rc)
+               goto err_out_unregister;
+
+       return 0;
+
+err_out_unregister:
+       unregister_netdev(dev);
+err_out:
+       free_netdev(dev);
+       return rc;
+}
+
+
+static void __devexit tc35815_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       phy_disconnect(lp->phy_dev);
+       mdiobus_unregister(lp->mii_bus);
+       kfree(lp->mii_bus->irq);
+       mdiobus_free(lp->mii_bus);
+       unregister_netdev(dev);
+       free_netdev(dev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static int
+tc35815_init_queues(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       int i;
+       unsigned long fd_addr;
+
+       if (!lp->fd_buf) {
+               BUG_ON(sizeof(struct FDesc) +
+                      sizeof(struct BDesc) * RX_BUF_NUM +
+                      sizeof(struct FDesc) * RX_FD_NUM +
+                      sizeof(struct TxFD) * TX_FD_NUM >
+                      PAGE_SIZE * FD_PAGE_NUM);
+
+               lp->fd_buf = pci_alloc_consistent(lp->pci_dev,
+                                                 PAGE_SIZE * FD_PAGE_NUM,
+                                                 &lp->fd_buf_dma);
+               if (!lp->fd_buf)
+                       return -ENOMEM;
+               for (i = 0; i < RX_BUF_NUM; i++) {
+                       lp->rx_skbs[i].skb =
+                               alloc_rxbuf_skb(dev, lp->pci_dev,
+                                               &lp->rx_skbs[i].skb_dma);
+                       if (!lp->rx_skbs[i].skb) {
+                               while (--i >= 0) {
+                                       free_rxbuf_skb(lp->pci_dev,
+                                                      lp->rx_skbs[i].skb,
+                                                      lp->rx_skbs[i].skb_dma);
+                                       lp->rx_skbs[i].skb = NULL;
+                               }
+                               pci_free_consistent(lp->pci_dev,
+                                                   PAGE_SIZE * FD_PAGE_NUM,
+                                                   lp->fd_buf,
+                                                   lp->fd_buf_dma);
+                               lp->fd_buf = NULL;
+                               return -ENOMEM;
+                       }
+               }
+               printk(KERN_DEBUG "%s: FD buf %p DataBuf",
+                      dev->name, lp->fd_buf);
+               printk("\n");
+       } else {
+               for (i = 0; i < FD_PAGE_NUM; i++)
+                       clear_page((void *)((unsigned long)lp->fd_buf +
+                                           i * PAGE_SIZE));
+       }
+       fd_addr = (unsigned long)lp->fd_buf;
+
+       /* Free Descriptors (for Receive) */
+       lp->rfd_base = (struct RxFD *)fd_addr;
+       fd_addr += sizeof(struct RxFD) * RX_FD_NUM;
+       for (i = 0; i < RX_FD_NUM; i++)
+               lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
+       lp->rfd_cur = lp->rfd_base;
+       lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
+
+       /* Transmit Descriptors */
+       lp->tfd_base = (struct TxFD *)fd_addr;
+       fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
+       for (i = 0; i < TX_FD_NUM; i++) {
+               lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
+               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
+               lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
+       }
+       lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
+       lp->tfd_start = 0;
+       lp->tfd_end = 0;
+
+       /* Buffer List (for Receive) */
+       lp->fbl_ptr = (struct FrFD *)fd_addr;
+       lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
+       lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
+       /*
+        * move all allocated skbs to head of rx_skbs[] array.
+        * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
+        * tc35815_rx() had failed.
+        */
+       lp->fbl_count = 0;
+       for (i = 0; i < RX_BUF_NUM; i++) {
+               if (lp->rx_skbs[i].skb) {
+                       if (i != lp->fbl_count) {
+                               lp->rx_skbs[lp->fbl_count].skb =
+                                       lp->rx_skbs[i].skb;
+                               lp->rx_skbs[lp->fbl_count].skb_dma =
+                                       lp->rx_skbs[i].skb_dma;
+                       }
+                       lp->fbl_count++;
+               }
+       }
+       for (i = 0; i < RX_BUF_NUM; i++) {
+               if (i >= lp->fbl_count) {
+                       lp->fbl_ptr->bd[i].BuffData = 0;
+                       lp->fbl_ptr->bd[i].BDCtl = 0;
+                       continue;
+               }
+               lp->fbl_ptr->bd[i].BuffData =
+                       cpu_to_le32(lp->rx_skbs[i].skb_dma);
+               /* BDID is index of FrFD.bd[] */
+               lp->fbl_ptr->bd[i].BDCtl =
+                       cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
+                                   RX_BUF_SIZE);
+       }
+
+       printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
+              dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
+       return 0;
+}
+
+static void
+tc35815_clear_queues(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < TX_FD_NUM; i++) {
+               u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+               struct sk_buff *skb =
+                       fdsystem != 0xffffffff ?
+                       lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+               if (lp->tx_skbs[i].skb != skb) {
+                       printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+                       panic_queues(dev);
+               }
+#else
+               BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+               if (skb) {
+                       pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+                       lp->tx_skbs[i].skb = NULL;
+                       lp->tx_skbs[i].skb_dma = 0;
+                       dev_kfree_skb_any(skb);
+               }
+               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
+       }
+
+       tc35815_init_queues(dev);
+}
+
+static void
+tc35815_free_queues(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       int i;
+
+       if (lp->tfd_base) {
+               for (i = 0; i < TX_FD_NUM; i++) {
+                       u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+                       struct sk_buff *skb =
+                               fdsystem != 0xffffffff ?
+                               lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+                       if (lp->tx_skbs[i].skb != skb) {
+                               printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+                               panic_queues(dev);
+                       }
+#else
+                       BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+                       if (skb) {
+                               dev_kfree_skb(skb);
+                               pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+                               lp->tx_skbs[i].skb = NULL;
+                               lp->tx_skbs[i].skb_dma = 0;
+                       }
+                       lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
+               }
+       }
+
+       lp->rfd_base = NULL;
+       lp->rfd_limit = NULL;
+       lp->rfd_cur = NULL;
+       lp->fbl_ptr = NULL;
+
+       for (i = 0; i < RX_BUF_NUM; i++) {
+               if (lp->rx_skbs[i].skb) {
+                       free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
+                                      lp->rx_skbs[i].skb_dma);
+                       lp->rx_skbs[i].skb = NULL;
+               }
+       }
+       if (lp->fd_buf) {
+               pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
+                                   lp->fd_buf, lp->fd_buf_dma);
+               lp->fd_buf = NULL;
+       }
+}
+
+static void
+dump_txfd(struct TxFD *fd)
+{
+       printk("TxFD(%p): %08x %08x %08x %08x\n", fd,
+              le32_to_cpu(fd->fd.FDNext),
+              le32_to_cpu(fd->fd.FDSystem),
+              le32_to_cpu(fd->fd.FDStat),
+              le32_to_cpu(fd->fd.FDCtl));
+       printk("BD: ");
+       printk(" %08x %08x",
+              le32_to_cpu(fd->bd.BuffData),
+              le32_to_cpu(fd->bd.BDCtl));
+       printk("\n");
+}
+
+static int
+dump_rxfd(struct RxFD *fd)
+{
+       int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+       if (bd_count > 8)
+               bd_count = 8;
+       printk("RxFD(%p): %08x %08x %08x %08x\n", fd,
+              le32_to_cpu(fd->fd.FDNext),
+              le32_to_cpu(fd->fd.FDSystem),
+              le32_to_cpu(fd->fd.FDStat),
+              le32_to_cpu(fd->fd.FDCtl));
+       if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD)
+               return 0;
+       printk("BD: ");
+       for (i = 0; i < bd_count; i++)
+               printk(" %08x %08x",
+                      le32_to_cpu(fd->bd[i].BuffData),
+                      le32_to_cpu(fd->bd[i].BDCtl));
+       printk("\n");
+       return bd_count;
+}
+
+#ifdef DEBUG
+static void
+dump_frfd(struct FrFD *fd)
+{
+       int i;
+       printk("FrFD(%p): %08x %08x %08x %08x\n", fd,
+              le32_to_cpu(fd->fd.FDNext),
+              le32_to_cpu(fd->fd.FDSystem),
+              le32_to_cpu(fd->fd.FDStat),
+              le32_to_cpu(fd->fd.FDCtl));
+       printk("BD: ");
+       for (i = 0; i < RX_BUF_NUM; i++)
+               printk(" %08x %08x",
+                      le32_to_cpu(fd->bd[i].BuffData),
+                      le32_to_cpu(fd->bd[i].BDCtl));
+       printk("\n");
+}
+
+static void
+panic_queues(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       int i;
+
+       printk("TxFD base %p, start %u, end %u\n",
+              lp->tfd_base, lp->tfd_start, lp->tfd_end);
+       printk("RxFD base %p limit %p cur %p\n",
+              lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
+       printk("FrFD %p\n", lp->fbl_ptr);
+       for (i = 0; i < TX_FD_NUM; i++)
+               dump_txfd(&lp->tfd_base[i]);
+       for (i = 0; i < RX_FD_NUM; i++) {
+               int bd_count = dump_rxfd(&lp->rfd_base[i]);
+               i += (bd_count + 1) / 2;        /* skip BDs */
+       }
+       dump_frfd(lp->fbl_ptr);
+       panic("%s: Illegal queue state.", dev->name);
+}
+#endif
+
+static void print_eth(const u8 *add)
+{
+       printk(KERN_DEBUG "print_eth(%p)\n", add);
+       printk(KERN_DEBUG " %pM => %pM : %02x%02x\n",
+               add + 6, add, add[12], add[13]);
+}
+
+static int tc35815_tx_full(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       return (lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end;
+}
+
+static void tc35815_restart(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       if (lp->phy_dev) {
+               int timeout;
+
+               phy_write(lp->phy_dev, MII_BMCR, BMCR_RESET);
+               timeout = 100;
+               while (--timeout) {
+                       if (!(phy_read(lp->phy_dev, MII_BMCR) & BMCR_RESET))
+                               break;
+                       udelay(1);
+               }
+               if (!timeout)
+                       printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
+       }
+
+       spin_lock_bh(&lp->rx_lock);
+       spin_lock_irq(&lp->lock);
+       tc35815_chip_reset(dev);
+       tc35815_clear_queues(dev);
+       tc35815_chip_init(dev);
+       /* Reconfigure CAM again since tc35815_chip_init() initialize it. */
+       tc35815_set_multicast_list(dev);
+       spin_unlock_irq(&lp->lock);
+       spin_unlock_bh(&lp->rx_lock);
+
+       netif_wake_queue(dev);
+}
+
+static void tc35815_restart_work(struct work_struct *work)
+{
+       struct tc35815_local *lp =
+               container_of(work, struct tc35815_local, restart_work);
+       struct net_device *dev = lp->dev;
+
+       tc35815_restart(dev);
+}
+
+static void tc35815_schedule_restart(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       unsigned long flags;
+
+       /* disable interrupts */
+       spin_lock_irqsave(&lp->lock, flags);
+       tc_writel(0, &tr->Int_En);
+       tc_writel(tc_readl(&tr->DMA_Ctl) | DMA_IntMask, &tr->DMA_Ctl);
+       schedule_work(&lp->restart_work);
+       spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+
+       printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+              dev->name, tc_readl(&tr->Tx_Stat));
+
+       /* Try to restart the adaptor. */
+       tc35815_schedule_restart(dev);
+       dev->stats.tx_errors++;
+}
+
+/*
+ * Open/initialize the controller. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int
+tc35815_open(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       /*
+        * This is used if the interrupt line can turned off (shared).
+        * See 3c503.c for an example of selecting the IRQ at config-time.
+        */
+       if (request_irq(dev->irq, tc35815_interrupt, IRQF_SHARED,
+                       dev->name, dev))
+               return -EAGAIN;
+
+       tc35815_chip_reset(dev);
+
+       if (tc35815_init_queues(dev) != 0) {
+               free_irq(dev->irq, dev);
+               return -EAGAIN;
+       }
+
+       napi_enable(&lp->napi);
+
+       /* Reset the hardware here. Don't forget to set the station address. */
+       spin_lock_irq(&lp->lock);
+       tc35815_chip_init(dev);
+       spin_unlock_irq(&lp->lock);
+
+       netif_carrier_off(dev);
+       /* schedule a link state check */
+       phy_start(lp->phy_dev);
+
+       /* We are now ready to accept transmit requeusts from
+        * the queueing layer of the networking.
+        */
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct TxFD *txfd;
+       unsigned long flags;
+
+       /* If some error occurs while trying to transmit this
+        * packet, you should return '1' from this function.
+        * In such a case you _may not_ do anything to the
+        * SKB, it is still owned by the network queueing
+        * layer when an error is returned.  This means you
+        * may not modify any SKB fields, you may not free
+        * the SKB, etc.
+        */
+
+       /* This is the most common case for modern hardware.
+        * The spinlock protects this code from the TX complete
+        * hardware interrupt handler.  Queue flow control is
+        * thus managed under this lock as well.
+        */
+       spin_lock_irqsave(&lp->lock, flags);
+
+       /* failsafe... (handle txdone now if half of FDs are used) */
+       if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
+           TX_FD_NUM / 2)
+               tc35815_txdone(dev);
+
+       if (netif_msg_pktdata(lp))
+               print_eth(skb->data);
+#ifdef DEBUG
+       if (lp->tx_skbs[lp->tfd_start].skb) {
+               printk("%s: tx_skbs conflict.\n", dev->name);
+               panic_queues(dev);
+       }
+#else
+       BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
+#endif
+       lp->tx_skbs[lp->tfd_start].skb = skb;
+       lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+       /*add to ring */
+       txfd = &lp->tfd_base[lp->tfd_start];
+       txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
+       txfd->bd.BDCtl = cpu_to_le32(skb->len);
+       txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
+       txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+       if (lp->tfd_start == lp->tfd_end) {
+               struct tc35815_regs __iomem *tr =
+                       (struct tc35815_regs __iomem *)dev->base_addr;
+               /* Start DMA Transmitter. */
+               txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+               txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+               if (netif_msg_tx_queued(lp)) {
+                       printk("%s: starting TxFD.\n", dev->name);
+                       dump_txfd(txfd);
+               }
+               tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+       } else {
+               txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+               if (netif_msg_tx_queued(lp)) {
+                       printk("%s: queueing TxFD.\n", dev->name);
+                       dump_txfd(txfd);
+               }
+       }
+       lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+
+       /* If we just used up the very last entry in the
+        * TX ring on this device, tell the queueing
+        * layer to send no more.
+        */
+       if (tc35815_tx_full(dev)) {
+               if (netif_msg_tx_queued(lp))
+                       printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+               netif_stop_queue(dev);
+       }
+
+       /* When the TX completion hw interrupt arrives, this
+        * is when the transmit statistics are updated.
+        */
+
+       spin_unlock_irqrestore(&lp->lock, flags);
+       return NETDEV_TX_OK;
+}
+
+#define FATAL_ERROR_INT \
+       (Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
+{
+       static int count;
+       printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
+              dev->name, status);
+       if (status & Int_IntPCI)
+               printk(" IntPCI");
+       if (status & Int_DmParErr)
+               printk(" DmParErr");
+       if (status & Int_IntNRAbt)
+               printk(" IntNRAbt");
+       printk("\n");
+       if (count++ > 100)
+               panic("%s: Too many fatal errors.", dev->name);
+       printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
+       /* Try to restart the adaptor. */
+       tc35815_schedule_restart(dev);
+}
+
+static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       int ret = -1;
+
+       /* Fatal errors... */
+       if (status & FATAL_ERROR_INT) {
+               tc35815_fatal_error_interrupt(dev, status);
+               return 0;
+       }
+       /* recoverable errors */
+       if (status & Int_IntFDAEx) {
+               if (netif_msg_rx_err(lp))
+                       dev_warn(&dev->dev,
+                                "Free Descriptor Area Exhausted (%#x).\n",
+                                status);
+               dev->stats.rx_dropped++;
+               ret = 0;
+       }
+       if (status & Int_IntBLEx) {
+               if (netif_msg_rx_err(lp))
+                       dev_warn(&dev->dev,
+                                "Buffer List Exhausted (%#x).\n",
+                                status);
+               dev->stats.rx_dropped++;
+               ret = 0;
+       }
+       if (status & Int_IntExBD) {
+               if (netif_msg_rx_err(lp))
+                       dev_warn(&dev->dev,
+                                "Excessive Buffer Descriptiors (%#x).\n",
+                                status);
+               dev->stats.rx_length_errors++;
+               ret = 0;
+       }
+
+       /* normal notification */
+       if (status & Int_IntMacRx) {
+               /* Got a packet(s). */
+               ret = tc35815_rx(dev, limit);
+               lp->lstats.rx_ints++;
+       }
+       if (status & Int_IntMacTx) {
+               /* Transmit complete. */
+               lp->lstats.tx_ints++;
+               spin_lock_irq(&lp->lock);
+               tc35815_txdone(dev);
+               spin_unlock_irq(&lp->lock);
+               if (ret < 0)
+                       ret = 0;
+       }
+       return ret;
+}
+
+/*
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       u32 dmactl = tc_readl(&tr->DMA_Ctl);
+
+       if (!(dmactl & DMA_IntMask)) {
+               /* disable interrupts */
+               tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
+               if (napi_schedule_prep(&lp->napi))
+                       __napi_schedule(&lp->napi);
+               else {
+                       printk(KERN_ERR "%s: interrupt taken in poll\n",
+                              dev->name);
+                       BUG();
+               }
+               (void)tc_readl(&tr->Int_Src);   /* flush */
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       tc35815_interrupt(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+#endif
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static int
+tc35815_rx(struct net_device *dev, int limit)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       unsigned int fdctl;
+       int i;
+       int received = 0;
+
+       while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
+               int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
+               int pkt_len = fdctl & FD_FDLength_MASK;
+               int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+#ifdef DEBUG
+               struct RxFD *next_rfd;
+#endif
+#if (RX_CTL_CMD & Rx_StripCRC) == 0
+               pkt_len -= ETH_FCS_LEN;
+#endif
+
+               if (netif_msg_rx_status(lp))
+                       dump_rxfd(lp->rfd_cur);
+               if (status & Rx_Good) {
+                       struct sk_buff *skb;
+                       unsigned char *data;
+                       int cur_bd;
+
+                       if (--limit < 0)
+                               break;
+                       BUG_ON(bd_count > 1);
+                       cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
+                                 & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+#ifdef DEBUG
+                       if (cur_bd >= RX_BUF_NUM) {
+                               printk("%s: invalid BDID.\n", dev->name);
+                               panic_queues(dev);
+                       }
+                       BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
+                              (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
+                       if (!lp->rx_skbs[cur_bd].skb) {
+                               printk("%s: NULL skb.\n", dev->name);
+                               panic_queues(dev);
+                       }
+#else
+                       BUG_ON(cur_bd >= RX_BUF_NUM);
+#endif
+                       skb = lp->rx_skbs[cur_bd].skb;
+                       prefetch(skb->data);
+                       lp->rx_skbs[cur_bd].skb = NULL;
+                       pci_unmap_single(lp->pci_dev,
+                                        lp->rx_skbs[cur_bd].skb_dma,
+                                        RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN)
+                               memmove(skb->data, skb->data - NET_IP_ALIGN,
+                                       pkt_len);
+                       data = skb_put(skb, pkt_len);
+                       if (netif_msg_pktdata(lp))
+                               print_eth(data);
+                       skb->protocol = eth_type_trans(skb, dev);
+                       netif_receive_skb(skb);
+                       received++;
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_len;
+               } else {
+                       dev->stats.rx_errors++;
+                       if (netif_msg_rx_err(lp))
+                               dev_info(&dev->dev, "Rx error (status %x)\n",
+                                        status & Rx_Stat_Mask);
+                       /* WORKAROUND: LongErr and CRCErr means Overflow. */
+                       if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
+                               status &= ~(Rx_LongErr|Rx_CRCErr);
+                               status |= Rx_Over;
+                       }
+                       if (status & Rx_LongErr)
+                               dev->stats.rx_length_errors++;
+                       if (status & Rx_Over)
+                               dev->stats.rx_fifo_errors++;
+                       if (status & Rx_CRCErr)
+                               dev->stats.rx_crc_errors++;
+                       if (status & Rx_Align)
+                               dev->stats.rx_frame_errors++;
+               }
+
+               if (bd_count > 0) {
+                       /* put Free Buffer back to controller */
+                       int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
+                       unsigned char id =
+                               (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+#ifdef DEBUG
+                       if (id >= RX_BUF_NUM) {
+                               printk("%s: invalid BDID.\n", dev->name);
+                               panic_queues(dev);
+                       }
+#else
+                       BUG_ON(id >= RX_BUF_NUM);
+#endif
+                       /* free old buffers */
+                       lp->fbl_count--;
+                       while (lp->fbl_count < RX_BUF_NUM)
+                       {
+                               unsigned char curid =
+                                       (id + 1 + lp->fbl_count) % RX_BUF_NUM;
+                               struct BDesc *bd = &lp->fbl_ptr->bd[curid];
+#ifdef DEBUG
+                               bdctl = le32_to_cpu(bd->BDCtl);
+                               if (bdctl & BD_CownsBD) {
+                                       printk("%s: Freeing invalid BD.\n",
+                                              dev->name);
+                                       panic_queues(dev);
+                               }
+#endif
+                               /* pass BD to controller */
+                               if (!lp->rx_skbs[curid].skb) {
+                                       lp->rx_skbs[curid].skb =
+                                               alloc_rxbuf_skb(dev,
+                                                               lp->pci_dev,
+                                                               &lp->rx_skbs[curid].skb_dma);
+                                       if (!lp->rx_skbs[curid].skb)
+                                               break; /* try on next reception */
+                                       bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
+                               }
+                               /* Note: BDLength was modified by chip. */
+                               bd->BDCtl = cpu_to_le32(BD_CownsBD |
+                                                       (curid << BD_RxBDID_SHIFT) |
+                                                       RX_BUF_SIZE);
+                               lp->fbl_count++;
+                       }
+               }
+
+               /* put RxFD back to controller */
+#ifdef DEBUG
+               next_rfd = fd_bus_to_virt(lp,
+                                         le32_to_cpu(lp->rfd_cur->fd.FDNext));
+               if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
+                       printk("%s: RxFD FDNext invalid.\n", dev->name);
+                       panic_queues(dev);
+               }
+#endif
+               for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
+                       /* pass FD to controller */
+#ifdef DEBUG
+                       lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
+#else
+                       lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
+#endif
+                       lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
+                       lp->rfd_cur++;
+               }
+               if (lp->rfd_cur > lp->rfd_limit)
+                       lp->rfd_cur = lp->rfd_base;
+#ifdef DEBUG
+               if (lp->rfd_cur != next_rfd)
+                       printk("rfd_cur = %p, next_rfd %p\n",
+                              lp->rfd_cur, next_rfd);
+#endif
+       }
+
+       return received;
+}
+
+static int tc35815_poll(struct napi_struct *napi, int budget)
+{
+       struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi);
+       struct net_device *dev = lp->dev;
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int received = 0, handled;
+       u32 status;
+
+       spin_lock(&lp->rx_lock);
+       status = tc_readl(&tr->Int_Src);
+       do {
+               /* BLEx, FDAEx will be cleared later */
+               tc_writel(status & ~(Int_BLEx | Int_FDAEx),
+                         &tr->Int_Src);        /* write to clear */
+
+               handled = tc35815_do_interrupt(dev, status, budget - received);
+               if (status & (Int_BLEx | Int_FDAEx))
+                       tc_writel(status & (Int_BLEx | Int_FDAEx),
+                                 &tr->Int_Src);
+               if (handled >= 0) {
+                       received += handled;
+                       if (received >= budget)
+                               break;
+               }
+               status = tc_readl(&tr->Int_Src);
+       } while (status);
+       spin_unlock(&lp->rx_lock);
+
+       if (received < budget) {
+               napi_complete(napi);
+               /* enable interrupts */
+               tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+       }
+       return received;
+}
+
+#define TX_STA_ERR     (Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)
+
+static void
+tc35815_check_tx_stat(struct net_device *dev, int status)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       const char *msg = NULL;
+
+       /* count collisions */
+       if (status & Tx_ExColl)
+               dev->stats.collisions += 16;
+       if (status & Tx_TxColl_MASK)
+               dev->stats.collisions += status & Tx_TxColl_MASK;
+
+       /* TX4939 does not have NCarr */
+       if (lp->chiptype == TC35815_TX4939)
+               status &= ~Tx_NCarr;
+       /* WORKAROUND: ignore LostCrS in full duplex operation */
+       if (!lp->link || lp->duplex == DUPLEX_FULL)
+               status &= ~Tx_NCarr;
+
+       if (!(status & TX_STA_ERR)) {
+               /* no error. */
+               dev->stats.tx_packets++;
+               return;
+       }
+
+       dev->stats.tx_errors++;
+       if (status & Tx_ExColl) {
+               dev->stats.tx_aborted_errors++;
+               msg = "Excessive Collision.";
+       }
+       if (status & Tx_Under) {
+               dev->stats.tx_fifo_errors++;
+               msg = "Tx FIFO Underrun.";
+               if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
+                       lp->lstats.tx_underrun++;
+                       if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
+                               struct tc35815_regs __iomem *tr =
+                                       (struct tc35815_regs __iomem *)dev->base_addr;
+                               tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
+                               msg = "Tx FIFO Underrun.Change Tx threshold to max.";
+                       }
+               }
+       }
+       if (status & Tx_Defer) {
+               dev->stats.tx_fifo_errors++;
+               msg = "Excessive Deferral.";
+       }
+       if (status & Tx_NCarr) {
+               dev->stats.tx_carrier_errors++;
+               msg = "Lost Carrier Sense.";
+       }
+       if (status & Tx_LateColl) {
+               dev->stats.tx_aborted_errors++;
+               msg = "Late Collision.";
+       }
+       if (status & Tx_TxPar) {
+               dev->stats.tx_fifo_errors++;
+               msg = "Transmit Parity Error.";
+       }
+       if (status & Tx_SQErr) {
+               dev->stats.tx_heartbeat_errors++;
+               msg = "Signal Quality Error.";
+       }
+       if (msg && netif_msg_tx_err(lp))
+               printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
+}
+
+/* This handles TX complete events posted by the device
+ * via interrupts.
+ */
+static void
+tc35815_txdone(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct TxFD *txfd;
+       unsigned int fdctl;
+
+       txfd = &lp->tfd_base[lp->tfd_end];
+       while (lp->tfd_start != lp->tfd_end &&
+              !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {
+               int status = le32_to_cpu(txfd->fd.FDStat);
+               struct sk_buff *skb;
+               unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+               u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
+
+               if (netif_msg_tx_done(lp)) {
+                       printk("%s: complete TxFD.\n", dev->name);
+                       dump_txfd(txfd);
+               }
+               tc35815_check_tx_stat(dev, status);
+
+               skb = fdsystem != 0xffffffff ?
+                       lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+               if (lp->tx_skbs[lp->tfd_end].skb != skb) {
+                       printk("%s: tx_skbs mismatch.\n", dev->name);
+                       panic_queues(dev);
+               }
+#else
+               BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
+#endif
+               if (skb) {
+                       dev->stats.tx_bytes += skb->len;
+                       pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
+                       lp->tx_skbs[lp->tfd_end].skb = NULL;
+                       lp->tx_skbs[lp->tfd_end].skb_dma = 0;
+                       dev_kfree_skb_any(skb);
+               }
+               txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
+
+               lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
+               txfd = &lp->tfd_base[lp->tfd_end];
+#ifdef DEBUG
+               if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
+                       printk("%s: TxFD FDNext invalid.\n", dev->name);
+                       panic_queues(dev);
+               }
+#endif
+               if (fdnext & FD_Next_EOL) {
+                       /* DMA Transmitter has been stopping... */
+                       if (lp->tfd_end != lp->tfd_start) {
+                               struct tc35815_regs __iomem *tr =
+                                       (struct tc35815_regs __iomem *)dev->base_addr;
+                               int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
+                               struct TxFD *txhead = &lp->tfd_base[head];
+                               int qlen = (lp->tfd_start + TX_FD_NUM
+                                           - lp->tfd_end) % TX_FD_NUM;
+
+#ifdef DEBUG
+                               if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
+                                       printk("%s: TxFD FDCtl invalid.\n", dev->name);
+                                       panic_queues(dev);
+                               }
+#endif
+                               /* log max queue length */
+                               if (lp->lstats.max_tx_qlen < qlen)
+                                       lp->lstats.max_tx_qlen = qlen;
+
+
+                               /* start DMA Transmitter again */
+                               txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+                               txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+                               if (netif_msg_tx_queued(lp)) {
+                                       printk("%s: start TxFD on queue.\n",
+                                              dev->name);
+                                       dump_txfd(txfd);
+                               }
+                               tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+                       }
+                       break;
+               }
+       }
+
+       /* If we had stopped the queue due to a "tx full"
+        * condition, and space has now been made available,
+        * wake up the queue.
+        */
+       if (netif_queue_stopped(dev) && !tc35815_tx_full(dev))
+               netif_wake_queue(dev);
+}
+
+/* The inverse routine to tc35815_open(). */
+static int
+tc35815_close(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+       napi_disable(&lp->napi);
+       if (lp->phy_dev)
+               phy_stop(lp->phy_dev);
+       cancel_work_sync(&lp->restart_work);
+
+       /* Flush the Tx and disable Rx here. */
+       tc35815_chip_reset(dev);
+       free_irq(dev->irq, dev);
+
+       tc35815_free_queues(dev);
+
+       return 0;
+
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       if (netif_running(dev))
+               /* Update the statistics from the device registers. */
+               dev->stats.rx_missed_errors += tc_readl(&tr->Miss_Cnt);
+
+       return &dev->stats;
+}
+
+static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int cam_index = index * 6;
+       u32 cam_data;
+       u32 saved_addr;
+
+       saved_addr = tc_readl(&tr->CAM_Adr);
+
+       if (netif_msg_hw(lp))
+               printk(KERN_DEBUG "%s: CAM %d: %pM\n",
+                       dev->name, index, addr);
+       if (index & 1) {
+               /* read modify write */
+               tc_writel(cam_index - 2, &tr->CAM_Adr);
+               cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;
+               cam_data |= addr[0] << 8 | addr[1];
+               tc_writel(cam_data, &tr->CAM_Data);
+               /* write whole word */
+               tc_writel(cam_index + 2, &tr->CAM_Adr);
+               cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+               tc_writel(cam_data, &tr->CAM_Data);
+       } else {
+               /* write whole word */
+               tc_writel(cam_index, &tr->CAM_Adr);
+               cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
+               tc_writel(cam_data, &tr->CAM_Data);
+               /* read modify write */
+               tc_writel(cam_index + 4, &tr->CAM_Adr);
+               cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;
+               cam_data |= addr[4] << 24 | (addr[5] << 16);
+               tc_writel(cam_data, &tr->CAM_Data);
+       }
+
+       tc_writel(saved_addr, &tr->CAM_Adr);
+}
+
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1     Promiscuous mode, receive all packets
+ * num_addrs == 0      Normal mode, clear multicast list
+ * num_addrs > 0       Multicast mode, receive normal and MC packets,
+ *                     and do best-effort filtering.
+ */
+static void
+tc35815_set_multicast_list(struct net_device *dev)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+
+       if (dev->flags & IFF_PROMISC) {
+               /* With some (all?) 100MHalf HUB, controller will hang
+                * if we enabled promiscuous mode before linkup... */
+               struct tc35815_local *lp = netdev_priv(dev);
+
+               if (!lp->link)
+                       return;
+               /* Enable promiscuous mode */
+               tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
+       } else if ((dev->flags & IFF_ALLMULTI) ||
+                 netdev_mc_count(dev) > CAM_ENTRY_MAX - 3) {
+               /* CAM 0, 1, 20 are reserved. */
+               /* Disable promiscuous mode, use normal mode. */
+               tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
+       } else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+               int i;
+               int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
+
+               tc_writel(0, &tr->CAM_Ctl);
+               /* Walk the address list, and load the filter */
+               i = 0;
+               netdev_for_each_mc_addr(ha, dev) {
+                       /* entry 0,1 is reserved. */
+                       tc35815_set_cam_entry(dev, i + 2, ha->addr);
+                       ena_bits |= CAM_Ena_Bit(i + 2);
+                       i++;
+               }
+               tc_writel(ena_bits, &tr->CAM_Ena);
+               tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+       } else {
+               tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+               tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+       }
+}
+
+static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       strcpy(info->driver, MODNAME);
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, pci_name(lp->pci_dev));
+}
+
+static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       if (!lp->phy_dev)
+               return -ENODEV;
+       return phy_ethtool_gset(lp->phy_dev, cmd);
+}
+
+static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       if (!lp->phy_dev)
+               return -ENODEV;
+       return phy_ethtool_sset(lp->phy_dev, cmd);
+}
+
+static u32 tc35815_get_msglevel(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       return lp->msg_enable;
+}
+
+static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       lp->msg_enable = datum;
+}
+
+static int tc35815_get_sset_count(struct net_device *dev, int sset)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       switch (sset) {
+       case ETH_SS_STATS:
+               return sizeof(lp->lstats) / sizeof(int);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       data[0] = lp->lstats.max_tx_qlen;
+       data[1] = lp->lstats.tx_ints;
+       data[2] = lp->lstats.rx_ints;
+       data[3] = lp->lstats.tx_underrun;
+}
+
+static struct {
+       const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+       { "max_tx_qlen" },
+       { "tx_ints" },
+       { "rx_ints" },
+       { "tx_underrun" },
+};
+
+static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static const struct ethtool_ops tc35815_ethtool_ops = {
+       .get_drvinfo            = tc35815_get_drvinfo,
+       .get_settings           = tc35815_get_settings,
+       .set_settings           = tc35815_set_settings,
+       .get_link               = ethtool_op_get_link,
+       .get_msglevel           = tc35815_get_msglevel,
+       .set_msglevel           = tc35815_set_msglevel,
+       .get_strings            = tc35815_get_strings,
+       .get_sset_count         = tc35815_get_sset_count,
+       .get_ethtool_stats      = tc35815_get_ethtool_stats,
+};
+
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       if (!netif_running(dev))
+               return -EINVAL;
+       if (!lp->phy_dev)
+               return -ENODEV;
+       return phy_mii_ioctl(lp->phy_dev, rq, cmd);
+}
+
+static void tc35815_chip_reset(struct net_device *dev)
+{
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       int i;
+       /* reset the controller */
+       tc_writel(MAC_Reset, &tr->MAC_Ctl);
+       udelay(4); /* 3200ns */
+       i = 0;
+       while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
+               if (i++ > 100) {
+                       printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
+                       break;
+               }
+               mdelay(1);
+       }
+       tc_writel(0, &tr->MAC_Ctl);
+
+       /* initialize registers to default value */
+       tc_writel(0, &tr->DMA_Ctl);
+       tc_writel(0, &tr->TxThrsh);
+       tc_writel(0, &tr->TxPollCtr);
+       tc_writel(0, &tr->RxFragSize);
+       tc_writel(0, &tr->Int_En);
+       tc_writel(0, &tr->FDA_Bas);
+       tc_writel(0, &tr->FDA_Lim);
+       tc_writel(0xffffffff, &tr->Int_Src);    /* Write 1 to clear */
+       tc_writel(0, &tr->CAM_Ctl);
+       tc_writel(0, &tr->Tx_Ctl);
+       tc_writel(0, &tr->Rx_Ctl);
+       tc_writel(0, &tr->CAM_Ena);
+       (void)tc_readl(&tr->Miss_Cnt);  /* Read to clear */
+
+       /* initialize internal SRAM */
+       tc_writel(DMA_TestMode, &tr->DMA_Ctl);
+       for (i = 0; i < 0x1000; i += 4) {
+               tc_writel(i, &tr->CAM_Adr);
+               tc_writel(0, &tr->CAM_Data);
+       }
+       tc_writel(0, &tr->DMA_Ctl);
+}
+
+static void tc35815_chip_init(struct net_device *dev)
+{
+       struct tc35815_local *lp = netdev_priv(dev);
+       struct tc35815_regs __iomem *tr =
+               (struct tc35815_regs __iomem *)dev->base_addr;
+       unsigned long txctl = TX_CTL_CMD;
+
+       /* load station address to CAM */
+       tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
+
+       /* Enable CAM (broadcast and unicast) */
+       tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+       tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+
+       /* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
+       if (HAVE_DMA_RXALIGN(lp))
+               tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
+       else
+               tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+       tc_writel(0, &tr->TxPollCtr);   /* Batch mode */
+       tc_writel(TX_THRESHOLD, &tr->TxThrsh);
+       tc_writel(INT_EN_CMD, &tr->Int_En);
+
+       /* set queues */
+       tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
+       tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
+                 &tr->FDA_Lim);
+       /*
+        * Activation method:
+        * First, enable the MAC Transmitter and the DMA Receive circuits.
+        * Then enable the DMA Transmitter and the MAC Receive circuits.
+        */
+       tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);      /* start DMA receiver */
+       tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);     /* start MAC receiver */
+
+       /* start MAC transmitter */
+       /* TX4939 does not have EnLCarr */
+       if (lp->chiptype == TC35815_TX4939)
+               txctl &= ~Tx_EnLCarr;
+       /* WORKAROUND: ignore LostCrS in full duplex operation */
+       if (!lp->phy_dev || !lp->link || lp->duplex == DUPLEX_FULL)
+               txctl &= ~Tx_EnLCarr;
+       tc_writel(txctl, &tr->Tx_Ctl);
+}
+
+#ifdef CONFIG_PM
+static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct tc35815_local *lp = netdev_priv(dev);
+       unsigned long flags;
+
+       pci_save_state(pdev);
+       if (!netif_running(dev))
+               return 0;
+       netif_device_detach(dev);
+       if (lp->phy_dev)
+               phy_stop(lp->phy_dev);
+       spin_lock_irqsave(&lp->lock, flags);
+       tc35815_chip_reset(dev);
+       spin_unlock_irqrestore(&lp->lock, flags);
+       pci_set_power_state(pdev, PCI_D3hot);
+       return 0;
+}
+
+static int tc35815_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct tc35815_local *lp = netdev_priv(dev);
+
+       pci_restore_state(pdev);
+       if (!netif_running(dev))
+               return 0;
+       pci_set_power_state(pdev, PCI_D0);
+       tc35815_restart(dev);
+       netif_carrier_off(dev);
+       if (lp->phy_dev)
+               phy_start(lp->phy_dev);
+       netif_device_attach(dev);
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver tc35815_pci_driver = {
+       .name           = MODNAME,
+       .id_table       = tc35815_pci_tbl,
+       .probe          = tc35815_init_one,
+       .remove         = __devexit_p(tc35815_remove_one),
+#ifdef CONFIG_PM
+       .suspend        = tc35815_suspend,
+       .resume         = tc35815_resume,
+#endif
+};
+
+module_param_named(speed, options.speed, int, 0);
+MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
+module_param_named(duplex, options.duplex, int, 0);
+MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
+
+static int __init tc35815_init_module(void)
+{
+       return pci_register_driver(&tc35815_pci_driver);
+}
+
+static void __exit tc35815_cleanup_module(void)
+{
+       pci_unregister_driver(&tc35815_pci_driver);
+}
+
+module_init(tc35815_init_module);
+module_exit(tc35815_cleanup_module);
+
+MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
deleted file mode 100644 (file)
index d82a82d..0000000
+++ /dev/null
@@ -1,1896 +0,0 @@
-/*
- *  PS3 gelic network driver.
- *
- * Copyright (C) 2007 Sony Computer Entertainment Inc.
- * Copyright 2006, 2007 Sony Corporation
- *
- * This file is based on: spider_net.c
- *
- * (C) Copyright IBM Corp. 2005
- *
- * Authors : Utz Bacher <utz.bacher@de.ibm.com>
- *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#undef DEBUG
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/if_vlan.h>
-
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-
-#include <linux/dma-mapping.h>
-#include <net/checksum.h>
-#include <asm/firmware.h>
-#include <asm/ps3.h>
-#include <asm/lv1call.h>
-
-#include "ps3_gelic_net.h"
-#include "ps3_gelic_wireless.h"
-
-#define DRV_NAME "Gelic Network Driver"
-#define DRV_VERSION "2.0"
-
-MODULE_AUTHOR("SCE Inc.");
-MODULE_DESCRIPTION("Gelic Network driver");
-MODULE_LICENSE("GPL");
-
-
-static inline void gelic_card_enable_rxdmac(struct gelic_card *card);
-static inline void gelic_card_disable_rxdmac(struct gelic_card *card);
-static inline void gelic_card_disable_txdmac(struct gelic_card *card);
-static inline void gelic_card_reset_chain(struct gelic_card *card,
-                                         struct gelic_descr_chain *chain,
-                                         struct gelic_descr *start_descr);
-
-/* set irq_mask */
-int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask)
-{
-       int status;
-
-       status = lv1_net_set_interrupt_mask(bus_id(card), dev_id(card),
-                                           mask, 0);
-       if (status)
-               dev_info(ctodev(card),
-                        "%s failed %d\n", __func__, status);
-       return status;
-}
-
-static inline void gelic_card_rx_irq_on(struct gelic_card *card)
-{
-       card->irq_mask |= GELIC_CARD_RXINT;
-       gelic_card_set_irq_mask(card, card->irq_mask);
-}
-static inline void gelic_card_rx_irq_off(struct gelic_card *card)
-{
-       card->irq_mask &= ~GELIC_CARD_RXINT;
-       gelic_card_set_irq_mask(card, card->irq_mask);
-}
-
-static void gelic_card_get_ether_port_status(struct gelic_card *card,
-                                            int inform)
-{
-       u64 v2;
-       struct net_device *ether_netdev;
-
-       lv1_net_control(bus_id(card), dev_id(card),
-                       GELIC_LV1_GET_ETH_PORT_STATUS,
-                       GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0,
-                       &card->ether_port_status, &v2);
-
-       if (inform) {
-               ether_netdev = card->netdev[GELIC_PORT_ETHERNET_0];
-               if (card->ether_port_status & GELIC_LV1_ETHER_LINK_UP)
-                       netif_carrier_on(ether_netdev);
-               else
-                       netif_carrier_off(ether_netdev);
-       }
-}
-
-static int gelic_card_set_link_mode(struct gelic_card *card, int mode)
-{
-       int status;
-       u64 v1, v2;
-
-       status = lv1_net_control(bus_id(card), dev_id(card),
-                                GELIC_LV1_SET_NEGOTIATION_MODE,
-                                GELIC_LV1_PHY_ETHERNET_0, mode, 0, &v1, &v2);
-       if (status) {
-               pr_info("%s: failed setting negotiation mode %d\n", __func__,
-                       status);
-               return -EBUSY;
-       }
-
-       card->link_mode = mode;
-       return 0;
-}
-
-void gelic_card_up(struct gelic_card *card)
-{
-       pr_debug("%s: called\n", __func__);
-       mutex_lock(&card->updown_lock);
-       if (atomic_inc_return(&card->users) == 1) {
-               pr_debug("%s: real do\n", __func__);
-               /* enable irq */
-               gelic_card_set_irq_mask(card, card->irq_mask);
-               /* start rx */
-               gelic_card_enable_rxdmac(card);
-
-               napi_enable(&card->napi);
-       }
-       mutex_unlock(&card->updown_lock);
-       pr_debug("%s: done\n", __func__);
-}
-
-void gelic_card_down(struct gelic_card *card)
-{
-       u64 mask;
-       pr_debug("%s: called\n", __func__);
-       mutex_lock(&card->updown_lock);
-       if (atomic_dec_if_positive(&card->users) == 0) {
-               pr_debug("%s: real do\n", __func__);
-               napi_disable(&card->napi);
-               /*
-                * Disable irq. Wireless interrupts will
-                * be disabled later if any
-                */
-               mask = card->irq_mask & (GELIC_CARD_WLAN_EVENT_RECEIVED |
-                                        GELIC_CARD_WLAN_COMMAND_COMPLETED);
-               gelic_card_set_irq_mask(card, mask);
-               /* stop rx */
-               gelic_card_disable_rxdmac(card);
-               gelic_card_reset_chain(card, &card->rx_chain,
-                                      card->descr + GELIC_NET_TX_DESCRIPTORS);
-               /* stop tx */
-               gelic_card_disable_txdmac(card);
-       }
-       mutex_unlock(&card->updown_lock);
-       pr_debug("%s: done\n", __func__);
-}
-
-/**
- * gelic_descr_get_status -- returns the status of a descriptor
- * @descr: descriptor to look at
- *
- * returns the status as in the dmac_cmd_status field of the descriptor
- */
-static enum gelic_descr_dma_status
-gelic_descr_get_status(struct gelic_descr *descr)
-{
-       return be32_to_cpu(descr->dmac_cmd_status) & GELIC_DESCR_DMA_STAT_MASK;
-}
-
-/**
- * gelic_descr_set_status -- sets the status of a descriptor
- * @descr: descriptor to change
- * @status: status to set in the descriptor
- *
- * changes the status to the specified value. Doesn't change other bits
- * in the status
- */
-static void gelic_descr_set_status(struct gelic_descr *descr,
-                                  enum gelic_descr_dma_status status)
-{
-       descr->dmac_cmd_status = cpu_to_be32(status |
-                       (be32_to_cpu(descr->dmac_cmd_status) &
-                        ~GELIC_DESCR_DMA_STAT_MASK));
-       /*
-        * dma_cmd_status field is used to indicate whether the descriptor
-        * is valid or not.
-        * Usually caller of this function wants to inform that to the
-        * hardware, so we assure here the hardware sees the change.
-        */
-       wmb();
-}
-
-/**
- * gelic_card_free_chain - free descriptor chain
- * @card: card structure
- * @descr_in: address of desc
- */
-static void gelic_card_free_chain(struct gelic_card *card,
-                                 struct gelic_descr *descr_in)
-{
-       struct gelic_descr *descr;
-
-       for (descr = descr_in; descr && descr->bus_addr; descr = descr->next) {
-               dma_unmap_single(ctodev(card), descr->bus_addr,
-                                GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL);
-               descr->bus_addr = 0;
-       }
-}
-
-/**
- * gelic_card_init_chain - links descriptor chain
- * @card: card structure
- * @chain: address of chain
- * @start_descr: address of descriptor array
- * @no: number of descriptors
- *
- * we manage a circular list that mirrors the hardware structure,
- * except that the hardware uses bus addresses.
- *
- * returns 0 on success, <0 on failure
- */
-static int __devinit gelic_card_init_chain(struct gelic_card *card,
-                                          struct gelic_descr_chain *chain,
-                                          struct gelic_descr *start_descr,
-                                          int no)
-{
-       int i;
-       struct gelic_descr *descr;
-
-       descr = start_descr;
-       memset(descr, 0, sizeof(*descr) * no);
-
-       /* set up the hardware pointers in each descriptor */
-       for (i = 0; i < no; i++, descr++) {
-               gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
-               descr->bus_addr =
-                       dma_map_single(ctodev(card), descr,
-                                      GELIC_DESCR_SIZE,
-                                      DMA_BIDIRECTIONAL);
-
-               if (!descr->bus_addr)
-                       goto iommu_error;
-
-               descr->next = descr + 1;
-               descr->prev = descr - 1;
-       }
-       /* make them as ring */
-       (descr - 1)->next = start_descr;
-       start_descr->prev = (descr - 1);
-
-       /* chain bus addr of hw descriptor */
-       descr = start_descr;
-       for (i = 0; i < no; i++, descr++) {
-               descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
-       }
-
-       chain->head = start_descr;
-       chain->tail = start_descr;
-
-       /* do not chain last hw descriptor */
-       (descr - 1)->next_descr_addr = 0;
-
-       return 0;
-
-iommu_error:
-       for (i--, descr--; 0 <= i; i--, descr--)
-               if (descr->bus_addr)
-                       dma_unmap_single(ctodev(card), descr->bus_addr,
-                                        GELIC_DESCR_SIZE,
-                                        DMA_BIDIRECTIONAL);
-       return -ENOMEM;
-}
-
-/**
- * gelic_card_reset_chain - reset status of a descriptor chain
- * @card: card structure
- * @chain: address of chain
- * @start_descr: address of descriptor array
- *
- * Reset the status of dma descriptors to ready state
- * and re-initialize the hardware chain for later use
- */
-static void gelic_card_reset_chain(struct gelic_card *card,
-                                  struct gelic_descr_chain *chain,
-                                  struct gelic_descr *start_descr)
-{
-       struct gelic_descr *descr;
-
-       for (descr = start_descr; start_descr != descr->next; descr++) {
-               gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
-               descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
-       }
-
-       chain->head = start_descr;
-       chain->tail = (descr - 1);
-
-       (descr - 1)->next_descr_addr = 0;
-}
-/**
- * gelic_descr_prepare_rx - reinitializes a rx descriptor
- * @card: card structure
- * @descr: descriptor to re-init
- *
- * return 0 on success, <0 on failure
- *
- * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
- * Activate the descriptor state-wise
- */
-static int gelic_descr_prepare_rx(struct gelic_card *card,
-                                 struct gelic_descr *descr)
-{
-       int offset;
-       unsigned int bufsize;
-
-       if (gelic_descr_get_status(descr) !=  GELIC_DESCR_DMA_NOT_IN_USE)
-               dev_info(ctodev(card), "%s: ERROR status\n", __func__);
-       /* we need to round up the buffer size to a multiple of 128 */
-       bufsize = ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN);
-
-       /* and we need to have it 128 byte aligned, therefore we allocate a
-        * bit more */
-       descr->skb = dev_alloc_skb(bufsize + GELIC_NET_RXBUF_ALIGN - 1);
-       if (!descr->skb) {
-               descr->buf_addr = 0; /* tell DMAC don't touch memory */
-               dev_info(ctodev(card),
-                        "%s:allocate skb failed !!\n", __func__);
-               return -ENOMEM;
-       }
-       descr->buf_size = cpu_to_be32(bufsize);
-       descr->dmac_cmd_status = 0;
-       descr->result_size = 0;
-       descr->valid_size = 0;
-       descr->data_error = 0;
-
-       offset = ((unsigned long)descr->skb->data) &
-               (GELIC_NET_RXBUF_ALIGN - 1);
-       if (offset)
-               skb_reserve(descr->skb, GELIC_NET_RXBUF_ALIGN - offset);
-       /* io-mmu-map the skb */
-       descr->buf_addr = cpu_to_be32(dma_map_single(ctodev(card),
-                                                    descr->skb->data,
-                                                    GELIC_NET_MAX_MTU,
-                                                    DMA_FROM_DEVICE));
-       if (!descr->buf_addr) {
-               dev_kfree_skb_any(descr->skb);
-               descr->skb = NULL;
-               dev_info(ctodev(card),
-                        "%s:Could not iommu-map rx buffer\n", __func__);
-               gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
-               return -ENOMEM;
-       } else {
-               gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
-               return 0;
-       }
-}
-
-/**
- * gelic_card_release_rx_chain - free all skb of rx descr
- * @card: card structure
- *
- */
-static void gelic_card_release_rx_chain(struct gelic_card *card)
-{
-       struct gelic_descr *descr = card->rx_chain.head;
-
-       do {
-               if (descr->skb) {
-                       dma_unmap_single(ctodev(card),
-                                        be32_to_cpu(descr->buf_addr),
-                                        descr->skb->len,
-                                        DMA_FROM_DEVICE);
-                       descr->buf_addr = 0;
-                       dev_kfree_skb_any(descr->skb);
-                       descr->skb = NULL;
-                       gelic_descr_set_status(descr,
-                                              GELIC_DESCR_DMA_NOT_IN_USE);
-               }
-               descr = descr->next;
-       } while (descr != card->rx_chain.head);
-}
-
-/**
- * gelic_card_fill_rx_chain - fills descriptors/skbs in the rx chains
- * @card: card structure
- *
- * fills all descriptors in the rx chain: allocates skbs
- * and iommu-maps them.
- * returns 0 on success, < 0 on failure
- */
-static int gelic_card_fill_rx_chain(struct gelic_card *card)
-{
-       struct gelic_descr *descr = card->rx_chain.head;
-       int ret;
-
-       do {
-               if (!descr->skb) {
-                       ret = gelic_descr_prepare_rx(card, descr);
-                       if (ret)
-                               goto rewind;
-               }
-               descr = descr->next;
-       } while (descr != card->rx_chain.head);
-
-       return 0;
-rewind:
-       gelic_card_release_rx_chain(card);
-       return ret;
-}
-
-/**
- * gelic_card_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
- * @card: card structure
- *
- * returns 0 on success, < 0 on failure
- */
-static int __devinit gelic_card_alloc_rx_skbs(struct gelic_card *card)
-{
-       struct gelic_descr_chain *chain;
-       int ret;
-       chain = &card->rx_chain;
-       ret = gelic_card_fill_rx_chain(card);
-       chain->tail = card->rx_top->prev; /* point to the last */
-       return ret;
-}
-
-/**
- * gelic_descr_release_tx - processes a used tx descriptor
- * @card: card structure
- * @descr: descriptor to release
- *
- * releases a used tx descriptor (unmapping, freeing of skb)
- */
-static void gelic_descr_release_tx(struct gelic_card *card,
-                                      struct gelic_descr *descr)
-{
-       struct sk_buff *skb = descr->skb;
-
-       BUG_ON(!(be32_to_cpu(descr->data_status) & GELIC_DESCR_TX_TAIL));
-
-       dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr), skb->len,
-                        DMA_TO_DEVICE);
-       dev_kfree_skb_any(skb);
-
-       descr->buf_addr = 0;
-       descr->buf_size = 0;
-       descr->next_descr_addr = 0;
-       descr->result_size = 0;
-       descr->valid_size = 0;
-       descr->data_status = 0;
-       descr->data_error = 0;
-       descr->skb = NULL;
-
-       /* set descr status */
-       gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
-}
-
-static void gelic_card_stop_queues(struct gelic_card *card)
-{
-       netif_stop_queue(card->netdev[GELIC_PORT_ETHERNET_0]);
-
-       if (card->netdev[GELIC_PORT_WIRELESS])
-               netif_stop_queue(card->netdev[GELIC_PORT_WIRELESS]);
-}
-static void gelic_card_wake_queues(struct gelic_card *card)
-{
-       netif_wake_queue(card->netdev[GELIC_PORT_ETHERNET_0]);
-
-       if (card->netdev[GELIC_PORT_WIRELESS])
-               netif_wake_queue(card->netdev[GELIC_PORT_WIRELESS]);
-}
-/**
- * gelic_card_release_tx_chain - processes sent tx descriptors
- * @card: adapter structure
- * @stop: net_stop sequence
- *
- * releases the tx descriptors that gelic has finished with
- */
-static void gelic_card_release_tx_chain(struct gelic_card *card, int stop)
-{
-       struct gelic_descr_chain *tx_chain;
-       enum gelic_descr_dma_status status;
-       struct net_device *netdev;
-       int release = 0;
-
-       for (tx_chain = &card->tx_chain;
-            tx_chain->head != tx_chain->tail && tx_chain->tail;
-            tx_chain->tail = tx_chain->tail->next) {
-               status = gelic_descr_get_status(tx_chain->tail);
-               netdev = tx_chain->tail->skb->dev;
-               switch (status) {
-               case GELIC_DESCR_DMA_RESPONSE_ERROR:
-               case GELIC_DESCR_DMA_PROTECTION_ERROR:
-               case GELIC_DESCR_DMA_FORCE_END:
-                       if (printk_ratelimit())
-                               dev_info(ctodev(card),
-                                        "%s: forcing end of tx descriptor " \
-                                        "with status %x\n",
-                                        __func__, status);
-                       netdev->stats.tx_dropped++;
-                       break;
-
-               case GELIC_DESCR_DMA_COMPLETE:
-                       if (tx_chain->tail->skb) {
-                               netdev->stats.tx_packets++;
-                               netdev->stats.tx_bytes +=
-                                       tx_chain->tail->skb->len;
-                       }
-                       break;
-
-               case GELIC_DESCR_DMA_CARDOWNED:
-                       /* pending tx request */
-               default:
-                       /* any other value (== GELIC_DESCR_DMA_NOT_IN_USE) */
-                       if (!stop)
-                               goto out;
-               }
-               gelic_descr_release_tx(card, tx_chain->tail);
-               release ++;
-       }
-out:
-       if (!stop && release)
-               gelic_card_wake_queues(card);
-}
-
-/**
- * gelic_net_set_multi - sets multicast addresses and promisc flags
- * @netdev: interface device structure
- *
- * gelic_net_set_multi configures multicast addresses as needed for the
- * netdev interface. It also sets up multicast, allmulti and promisc
- * flags appropriately
- */
-void gelic_net_set_multi(struct net_device *netdev)
-{
-       struct gelic_card *card = netdev_card(netdev);
-       struct netdev_hw_addr *ha;
-       unsigned int i;
-       uint8_t *p;
-       u64 addr;
-       int status;
-
-       /* clear all multicast address */
-       status = lv1_net_remove_multicast_address(bus_id(card), dev_id(card),
-                                                 0, 1);
-       if (status)
-               dev_err(ctodev(card),
-                       "lv1_net_remove_multicast_address failed %d\n",
-                       status);
-       /* set broadcast address */
-       status = lv1_net_add_multicast_address(bus_id(card), dev_id(card),
-                                              GELIC_NET_BROADCAST_ADDR, 0);
-       if (status)
-               dev_err(ctodev(card),
-                       "lv1_net_add_multicast_address failed, %d\n",
-                       status);
-
-       if ((netdev->flags & IFF_ALLMULTI) ||
-           (netdev_mc_count(netdev) > GELIC_NET_MC_COUNT_MAX)) {
-               status = lv1_net_add_multicast_address(bus_id(card),
-                                                      dev_id(card),
-                                                      0, 1);
-               if (status)
-                       dev_err(ctodev(card),
-                               "lv1_net_add_multicast_address failed, %d\n",
-                               status);
-               return;
-       }
-
-       /* set multicast addresses */
-       netdev_for_each_mc_addr(ha, netdev) {
-               addr = 0;
-               p = ha->addr;
-               for (i = 0; i < ETH_ALEN; i++) {
-                       addr <<= 8;
-                       addr |= *p++;
-               }
-               status = lv1_net_add_multicast_address(bus_id(card),
-                                                      dev_id(card),
-                                                      addr, 0);
-               if (status)
-                       dev_err(ctodev(card),
-                               "lv1_net_add_multicast_address failed, %d\n",
-                               status);
-       }
-}
-
-/**
- * gelic_card_enable_rxdmac - enables the receive DMA controller
- * @card: card structure
- *
- * gelic_card_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
- * in the GDADMACCNTR register
- */
-static inline void gelic_card_enable_rxdmac(struct gelic_card *card)
-{
-       int status;
-
-#ifdef DEBUG
-       if (gelic_descr_get_status(card->rx_chain.head) !=
-           GELIC_DESCR_DMA_CARDOWNED) {
-               printk(KERN_ERR "%s: status=%x\n", __func__,
-                      be32_to_cpu(card->rx_chain.head->dmac_cmd_status));
-               printk(KERN_ERR "%s: nextphy=%x\n", __func__,
-                      be32_to_cpu(card->rx_chain.head->next_descr_addr));
-               printk(KERN_ERR "%s: head=%p\n", __func__,
-                      card->rx_chain.head);
-       }
-#endif
-       status = lv1_net_start_rx_dma(bus_id(card), dev_id(card),
-                               card->rx_chain.head->bus_addr, 0);
-       if (status)
-               dev_info(ctodev(card),
-                        "lv1_net_start_rx_dma failed, status=%d\n", status);
-}
-
-/**
- * gelic_card_disable_rxdmac - disables the receive DMA controller
- * @card: card structure
- *
- * gelic_card_disable_rxdmac terminates processing on the DMA controller by
- * turing off DMA and issuing a force end
- */
-static inline void gelic_card_disable_rxdmac(struct gelic_card *card)
-{
-       int status;
-
-       /* this hvc blocks until the DMA in progress really stopped */
-       status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card), 0);
-       if (status)
-               dev_err(ctodev(card),
-                       "lv1_net_stop_rx_dma failed, %d\n", status);
-}
-
-/**
- * gelic_card_disable_txdmac - disables the transmit DMA controller
- * @card: card structure
- *
- * gelic_card_disable_txdmac terminates processing on the DMA controller by
- * turing off DMA and issuing a force end
- */
-static inline void gelic_card_disable_txdmac(struct gelic_card *card)
-{
-       int status;
-
-       /* this hvc blocks until the DMA in progress really stopped */
-       status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card), 0);
-       if (status)
-               dev_err(ctodev(card),
-                       "lv1_net_stop_tx_dma failed, status=%d\n", status);
-}
-
-/**
- * gelic_net_stop - called upon ifconfig down
- * @netdev: interface device structure
- *
- * always returns 0
- */
-int gelic_net_stop(struct net_device *netdev)
-{
-       struct gelic_card *card;
-
-       pr_debug("%s: start\n", __func__);
-
-       netif_stop_queue(netdev);
-       netif_carrier_off(netdev);
-
-       card = netdev_card(netdev);
-       gelic_card_down(card);
-
-       pr_debug("%s: done\n", __func__);
-       return 0;
-}
-
-/**
- * gelic_card_get_next_tx_descr - returns the next available tx descriptor
- * @card: device structure to get descriptor from
- *
- * returns the address of the next descriptor, or NULL if not available.
- */
-static struct gelic_descr *
-gelic_card_get_next_tx_descr(struct gelic_card *card)
-{
-       if (!card->tx_chain.head)
-               return NULL;
-       /*  see if the next descriptor is free */
-       if (card->tx_chain.tail != card->tx_chain.head->next &&
-           gelic_descr_get_status(card->tx_chain.head) ==
-           GELIC_DESCR_DMA_NOT_IN_USE)
-               return card->tx_chain.head;
-       else
-               return NULL;
-
-}
-
-/**
- * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
- * @descr: descriptor structure to fill out
- * @skb: packet to consider
- *
- * fills out the command and status field of the descriptor structure,
- * depending on hardware checksum settings. This function assumes a wmb()
- * has executed before.
- */
-static void gelic_descr_set_tx_cmdstat(struct gelic_descr *descr,
-                                      struct sk_buff *skb)
-{
-       if (skb->ip_summed != CHECKSUM_PARTIAL)
-               descr->dmac_cmd_status =
-                       cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM |
-                                   GELIC_DESCR_TX_DMA_FRAME_TAIL);
-       else {
-               /* is packet ip?
-                * if yes: tcp? udp? */
-               if (skb->protocol == htons(ETH_P_IP)) {
-                       if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-                               descr->dmac_cmd_status =
-                               cpu_to_be32(GELIC_DESCR_DMA_CMD_TCP_CHKSUM |
-                                           GELIC_DESCR_TX_DMA_FRAME_TAIL);
-
-                       else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
-                               descr->dmac_cmd_status =
-                               cpu_to_be32(GELIC_DESCR_DMA_CMD_UDP_CHKSUM |
-                                           GELIC_DESCR_TX_DMA_FRAME_TAIL);
-                       else    /*
-                                * the stack should checksum non-tcp and non-udp
-                                * packets on his own: NETIF_F_IP_CSUM
-                                */
-                               descr->dmac_cmd_status =
-                               cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM |
-                                           GELIC_DESCR_TX_DMA_FRAME_TAIL);
-               }
-       }
-}
-
-static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
-                                                unsigned short tag)
-{
-       struct vlan_ethhdr *veth;
-       static unsigned int c;
-
-       if (skb_headroom(skb) < VLAN_HLEN) {
-               struct sk_buff *sk_tmp = skb;
-               pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c);
-               skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
-               if (!skb)
-                       return NULL;
-               dev_kfree_skb_any(sk_tmp);
-       }
-       veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
-
-       /* Move the mac addresses to the top of buffer */
-       memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
-
-       veth->h_vlan_proto = cpu_to_be16(ETH_P_8021Q);
-       veth->h_vlan_TCI = htons(tag);
-
-       return skb;
-}
-
-/**
- * gelic_descr_prepare_tx - setup a descriptor for sending packets
- * @card: card structure
- * @descr: descriptor structure
- * @skb: packet to use
- *
- * returns 0 on success, <0 on failure.
- *
- */
-static int gelic_descr_prepare_tx(struct gelic_card *card,
-                                 struct gelic_descr *descr,
-                                 struct sk_buff *skb)
-{
-       dma_addr_t buf;
-
-       if (card->vlan_required) {
-               struct sk_buff *skb_tmp;
-               enum gelic_port_type type;
-
-               type = netdev_port(skb->dev)->type;
-               skb_tmp = gelic_put_vlan_tag(skb,
-                                            card->vlan[type].tx);
-               if (!skb_tmp)
-                       return -ENOMEM;
-               skb = skb_tmp;
-       }
-
-       buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE);
-
-       if (!buf) {
-               dev_err(ctodev(card),
-                       "dma map 2 failed (%p, %i). Dropping packet\n",
-                       skb->data, skb->len);
-               return -ENOMEM;
-       }
-
-       descr->buf_addr = cpu_to_be32(buf);
-       descr->buf_size = cpu_to_be32(skb->len);
-       descr->skb = skb;
-       descr->data_status = 0;
-       descr->next_descr_addr = 0; /* terminate hw descr */
-       gelic_descr_set_tx_cmdstat(descr, skb);
-
-       /* bump free descriptor pointer */
-       card->tx_chain.head = descr->next;
-       return 0;
-}
-
-/**
- * gelic_card_kick_txdma - enables TX DMA processing
- * @card: card structure
- * @descr: descriptor address to enable TX processing at
- *
- */
-static int gelic_card_kick_txdma(struct gelic_card *card,
-                                struct gelic_descr *descr)
-{
-       int status = 0;
-
-       if (card->tx_dma_progress)
-               return 0;
-
-       if (gelic_descr_get_status(descr) == GELIC_DESCR_DMA_CARDOWNED) {
-               card->tx_dma_progress = 1;
-               status = lv1_net_start_tx_dma(bus_id(card), dev_id(card),
-                                             descr->bus_addr, 0);
-               if (status) {
-                       card->tx_dma_progress = 0;
-                       dev_info(ctodev(card), "lv1_net_start_txdma failed," \
-                                "status=%d\n", status);
-               }
-       }
-       return status;
-}
-
-/**
- * gelic_net_xmit - transmits a frame over the device
- * @skb: packet to send out
- * @netdev: interface device structure
- *
- * returns 0 on success, <0 on failure
- */
-int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
-       struct gelic_card *card = netdev_card(netdev);
-       struct gelic_descr *descr;
-       int result;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->tx_lock, flags);
-
-       gelic_card_release_tx_chain(card, 0);
-
-       descr = gelic_card_get_next_tx_descr(card);
-       if (!descr) {
-               /*
-                * no more descriptors free
-                */
-               gelic_card_stop_queues(card);
-               spin_unlock_irqrestore(&card->tx_lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-
-       result = gelic_descr_prepare_tx(card, descr, skb);
-       if (result) {
-               /*
-                * DMA map failed.  As chances are that failure
-                * would continue, just release skb and return
-                */
-               netdev->stats.tx_dropped++;
-               dev_kfree_skb_any(skb);
-               spin_unlock_irqrestore(&card->tx_lock, flags);
-               return NETDEV_TX_OK;
-       }
-       /*
-        * link this prepared descriptor to previous one
-        * to achieve high performance
-        */
-       descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
-       /*
-        * as hardware descriptor is modified in the above lines,
-        * ensure that the hardware sees it
-        */
-       wmb();
-       if (gelic_card_kick_txdma(card, descr)) {
-               /*
-                * kick failed.
-                * release descriptor which was just prepared
-                */
-               netdev->stats.tx_dropped++;
-               /* don't trigger BUG_ON() in gelic_descr_release_tx */
-               descr->data_status = cpu_to_be32(GELIC_DESCR_TX_TAIL);
-               gelic_descr_release_tx(card, descr);
-               /* reset head */
-               card->tx_chain.head = descr;
-               /* reset hw termination */
-               descr->prev->next_descr_addr = 0;
-               dev_info(ctodev(card), "%s: kick failure\n", __func__);
-       }
-
-       spin_unlock_irqrestore(&card->tx_lock, flags);
-       return NETDEV_TX_OK;
-}
-
-/**
- * gelic_net_pass_skb_up - takes an skb from a descriptor and passes it on
- * @descr: descriptor to process
- * @card: card structure
- * @netdev: net_device structure to be passed packet
- *
- * iommu-unmaps the skb, fills out skb structure and passes the data to the
- * stack. The descriptor state is not changed.
- */
-static void gelic_net_pass_skb_up(struct gelic_descr *descr,
-                                 struct gelic_card *card,
-                                 struct net_device *netdev)
-
-{
-       struct sk_buff *skb = descr->skb;
-       u32 data_status, data_error;
-
-       data_status = be32_to_cpu(descr->data_status);
-       data_error = be32_to_cpu(descr->data_error);
-       /* unmap skb buffer */
-       dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr),
-                        GELIC_NET_MAX_MTU,
-                        DMA_FROM_DEVICE);
-
-       skb_put(skb, be32_to_cpu(descr->valid_size)?
-               be32_to_cpu(descr->valid_size) :
-               be32_to_cpu(descr->result_size));
-       if (!descr->valid_size)
-               dev_info(ctodev(card), "buffer full %x %x %x\n",
-                        be32_to_cpu(descr->result_size),
-                        be32_to_cpu(descr->buf_size),
-                        be32_to_cpu(descr->dmac_cmd_status));
-
-       descr->skb = NULL;
-       /*
-        * the card put 2 bytes vlan tag in front
-        * of the ethernet frame
-        */
-       skb_pull(skb, 2);
-       skb->protocol = eth_type_trans(skb, netdev);
-
-       /* checksum offload */
-       if (netdev->features & NETIF_F_RXCSUM) {
-               if ((data_status & GELIC_DESCR_DATA_STATUS_CHK_MASK) &&
-                   (!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK)))
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-               else
-                       skb_checksum_none_assert(skb);
-       } else
-               skb_checksum_none_assert(skb);
-
-       /* update netdevice statistics */
-       netdev->stats.rx_packets++;
-       netdev->stats.rx_bytes += skb->len;
-
-       /* pass skb up to stack */
-       netif_receive_skb(skb);
-}
-
-/**
- * gelic_card_decode_one_descr - processes an rx descriptor
- * @card: card structure
- *
- * returns 1 if a packet has been sent to the stack, otherwise 0
- *
- * processes an rx descriptor by iommu-unmapping the data buffer and passing
- * the packet up to the stack
- */
-static int gelic_card_decode_one_descr(struct gelic_card *card)
-{
-       enum gelic_descr_dma_status status;
-       struct gelic_descr_chain *chain = &card->rx_chain;
-       struct gelic_descr *descr = chain->head;
-       struct net_device *netdev = NULL;
-       int dmac_chain_ended;
-
-       status = gelic_descr_get_status(descr);
-
-       if (status == GELIC_DESCR_DMA_CARDOWNED)
-               return 0;
-
-       if (status == GELIC_DESCR_DMA_NOT_IN_USE) {
-               dev_dbg(ctodev(card), "dormant descr? %p\n", descr);
-               return 0;
-       }
-
-       /* netdevice select */
-       if (card->vlan_required) {
-               unsigned int i;
-               u16 vid;
-               vid = *(u16 *)(descr->skb->data) & VLAN_VID_MASK;
-               for (i = 0; i < GELIC_PORT_MAX; i++) {
-                       if (card->vlan[i].rx == vid) {
-                               netdev = card->netdev[i];
-                               break;
-                       }
-               }
-               if (GELIC_PORT_MAX <= i) {
-                       pr_info("%s: unknown packet vid=%x\n", __func__, vid);
-                       goto refill;
-               }
-       } else
-               netdev = card->netdev[GELIC_PORT_ETHERNET_0];
-
-       if ((status == GELIC_DESCR_DMA_RESPONSE_ERROR) ||
-           (status == GELIC_DESCR_DMA_PROTECTION_ERROR) ||
-           (status == GELIC_DESCR_DMA_FORCE_END)) {
-               dev_info(ctodev(card), "dropping RX descriptor with state %x\n",
-                        status);
-               netdev->stats.rx_dropped++;
-               goto refill;
-       }
-
-       if (status == GELIC_DESCR_DMA_BUFFER_FULL) {
-               /*
-                * Buffer full would occur if and only if
-                * the frame length was longer than the size of this
-                * descriptor's buffer.  If the frame length was equal
-                * to or shorter than buffer'size, FRAME_END condition
-                * would occur.
-                * Anyway this frame was longer than the MTU,
-                * just drop it.
-                */
-               dev_info(ctodev(card), "overlength frame\n");
-               goto refill;
-       }
-       /*
-        * descriptors any other than FRAME_END here should
-        * be treated as error.
-        */
-       if (status != GELIC_DESCR_DMA_FRAME_END) {
-               dev_dbg(ctodev(card), "RX descriptor with state %x\n",
-                       status);
-               goto refill;
-       }
-
-       /* ok, we've got a packet in descr */
-       gelic_net_pass_skb_up(descr, card, netdev);
-refill:
-
-       /* is the current descriptor terminated with next_descr == NULL? */
-       dmac_chain_ended =
-               be32_to_cpu(descr->dmac_cmd_status) &
-               GELIC_DESCR_RX_DMA_CHAIN_END;
-       /*
-        * So that always DMAC can see the end
-        * of the descriptor chain to avoid
-        * from unwanted DMAC overrun.
-        */
-       descr->next_descr_addr = 0;
-
-       /* change the descriptor state: */
-       gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
-
-       /*
-        * this call can fail, but for now, just leave this
-        * decriptor without skb
-        */
-       gelic_descr_prepare_rx(card, descr);
-
-       chain->tail = descr;
-       chain->head = descr->next;
-
-       /*
-        * Set this descriptor the end of the chain.
-        */
-       descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
-
-       /*
-        * If dmac chain was met, DMAC stopped.
-        * thus re-enable it
-        */
-
-       if (dmac_chain_ended)
-               gelic_card_enable_rxdmac(card);
-
-       return 1;
-}
-
-/**
- * gelic_net_poll - NAPI poll function called by the stack to return packets
- * @napi: napi structure
- * @budget: number of packets we can pass to the stack at most
- *
- * returns the number of the processed packets
- *
- */
-static int gelic_net_poll(struct napi_struct *napi, int budget)
-{
-       struct gelic_card *card = container_of(napi, struct gelic_card, napi);
-       int packets_done = 0;
-
-       while (packets_done < budget) {
-               if (!gelic_card_decode_one_descr(card))
-                       break;
-
-               packets_done++;
-       }
-
-       if (packets_done < budget) {
-               napi_complete(napi);
-               gelic_card_rx_irq_on(card);
-       }
-       return packets_done;
-}
-/**
- * gelic_net_change_mtu - changes the MTU of an interface
- * @netdev: interface device structure
- * @new_mtu: new MTU value
- *
- * returns 0 on success, <0 on failure
- */
-int gelic_net_change_mtu(struct net_device *netdev, int new_mtu)
-{
-       /* no need to re-alloc skbs or so -- the max mtu is about 2.3k
-        * and mtu is outbound only anyway */
-       if ((new_mtu < GELIC_NET_MIN_MTU) ||
-           (new_mtu > GELIC_NET_MAX_MTU)) {
-               return -EINVAL;
-       }
-       netdev->mtu = new_mtu;
-       return 0;
-}
-
-/**
- * gelic_card_interrupt - event handler for gelic_net
- */
-static irqreturn_t gelic_card_interrupt(int irq, void *ptr)
-{
-       unsigned long flags;
-       struct gelic_card *card = ptr;
-       u64 status;
-
-       status = card->irq_status;
-
-       if (!status)
-               return IRQ_NONE;
-
-       status &= card->irq_mask;
-
-       if (status & GELIC_CARD_RXINT) {
-               gelic_card_rx_irq_off(card);
-               napi_schedule(&card->napi);
-       }
-
-       if (status & GELIC_CARD_TXINT) {
-               spin_lock_irqsave(&card->tx_lock, flags);
-               card->tx_dma_progress = 0;
-               gelic_card_release_tx_chain(card, 0);
-               /* kick outstanding tx descriptor if any */
-               gelic_card_kick_txdma(card, card->tx_chain.tail);
-               spin_unlock_irqrestore(&card->tx_lock, flags);
-       }
-
-       /* ether port status changed */
-       if (status & GELIC_CARD_PORT_STATUS_CHANGED)
-               gelic_card_get_ether_port_status(card, 1);
-
-#ifdef CONFIG_GELIC_WIRELESS
-       if (status & (GELIC_CARD_WLAN_EVENT_RECEIVED |
-                     GELIC_CARD_WLAN_COMMAND_COMPLETED))
-               gelic_wl_interrupt(card->netdev[GELIC_PORT_WIRELESS], status);
-#endif
-
-       return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/**
- * gelic_net_poll_controller - artificial interrupt for netconsole etc.
- * @netdev: interface device structure
- *
- * see Documentation/networking/netconsole.txt
- */
-void gelic_net_poll_controller(struct net_device *netdev)
-{
-       struct gelic_card *card = netdev_card(netdev);
-
-       gelic_card_set_irq_mask(card, 0);
-       gelic_card_interrupt(netdev->irq, netdev);
-       gelic_card_set_irq_mask(card, card->irq_mask);
-}
-#endif /* CONFIG_NET_POLL_CONTROLLER */
-
-/**
- * gelic_net_open - called upon ifconfig up
- * @netdev: interface device structure
- *
- * returns 0 on success, <0 on failure
- *
- * gelic_net_open allocates all the descriptors and memory needed for
- * operation, sets up multicast list and enables interrupts
- */
-int gelic_net_open(struct net_device *netdev)
-{
-       struct gelic_card *card = netdev_card(netdev);
-
-       dev_dbg(ctodev(card), " -> %s %p\n", __func__, netdev);
-
-       gelic_card_up(card);
-
-       netif_start_queue(netdev);
-       gelic_card_get_ether_port_status(card, 1);
-
-       dev_dbg(ctodev(card), " <- %s\n", __func__);
-       return 0;
-}
-
-void gelic_net_get_drvinfo(struct net_device *netdev,
-                          struct ethtool_drvinfo *info)
-{
-       strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
-       strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
-}
-
-static int gelic_ether_get_settings(struct net_device *netdev,
-                                   struct ethtool_cmd *cmd)
-{
-       struct gelic_card *card = netdev_card(netdev);
-
-       gelic_card_get_ether_port_status(card, 0);
-
-       if (card->ether_port_status & GELIC_LV1_ETHER_FULL_DUPLEX)
-               cmd->duplex = DUPLEX_FULL;
-       else
-               cmd->duplex = DUPLEX_HALF;
-
-       switch (card->ether_port_status & GELIC_LV1_ETHER_SPEED_MASK) {
-       case GELIC_LV1_ETHER_SPEED_10:
-               ethtool_cmd_speed_set(cmd, SPEED_10);
-               break;
-       case GELIC_LV1_ETHER_SPEED_100:
-               ethtool_cmd_speed_set(cmd, SPEED_100);
-               break;
-       case GELIC_LV1_ETHER_SPEED_1000:
-               ethtool_cmd_speed_set(cmd, SPEED_1000);
-               break;
-       default:
-               pr_info("%s: speed unknown\n", __func__);
-               ethtool_cmd_speed_set(cmd, SPEED_10);
-               break;
-       }
-
-       cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg |
-                       SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
-                       SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
-                       SUPPORTED_1000baseT_Full;
-       cmd->advertising = cmd->supported;
-       if (card->link_mode & GELIC_LV1_ETHER_AUTO_NEG) {
-               cmd->autoneg = AUTONEG_ENABLE;
-       } else {
-               cmd->autoneg = AUTONEG_DISABLE;
-               cmd->advertising &= ~ADVERTISED_Autoneg;
-       }
-       cmd->port = PORT_TP;
-
-       return 0;
-}
-
-static int gelic_ether_set_settings(struct net_device *netdev,
-                                   struct ethtool_cmd *cmd)
-{
-       struct gelic_card *card = netdev_card(netdev);
-       u64 mode;
-       int ret;
-
-       if (cmd->autoneg == AUTONEG_ENABLE) {
-               mode = GELIC_LV1_ETHER_AUTO_NEG;
-       } else {
-               switch (cmd->speed) {
-               case SPEED_10:
-                       mode = GELIC_LV1_ETHER_SPEED_10;
-                       break;
-               case SPEED_100:
-                       mode = GELIC_LV1_ETHER_SPEED_100;
-                       break;
-               case SPEED_1000:
-                       mode = GELIC_LV1_ETHER_SPEED_1000;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               if (cmd->duplex == DUPLEX_FULL)
-                       mode |= GELIC_LV1_ETHER_FULL_DUPLEX;
-               else if (cmd->speed == SPEED_1000) {
-                       pr_info("1000 half duplex is not supported.\n");
-                       return -EINVAL;
-               }
-       }
-
-       ret = gelic_card_set_link_mode(card, mode);
-
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static void gelic_net_get_wol(struct net_device *netdev,
-                             struct ethtool_wolinfo *wol)
-{
-       if (0 <= ps3_compare_firmware_version(2, 2, 0))
-               wol->supported = WAKE_MAGIC;
-       else
-               wol->supported = 0;
-
-       wol->wolopts = ps3_sys_manager_get_wol() ? wol->supported : 0;
-       memset(&wol->sopass, 0, sizeof(wol->sopass));
-}
-static int gelic_net_set_wol(struct net_device *netdev,
-                            struct ethtool_wolinfo *wol)
-{
-       int status;
-       struct gelic_card *card;
-       u64 v1, v2;
-
-       if (ps3_compare_firmware_version(2, 2, 0) < 0 ||
-           !capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       if (wol->wolopts & ~WAKE_MAGIC)
-               return -EINVAL;
-
-       card = netdev_card(netdev);
-       if (wol->wolopts & WAKE_MAGIC) {
-               status = lv1_net_control(bus_id(card), dev_id(card),
-                                        GELIC_LV1_SET_WOL,
-                                        GELIC_LV1_WOL_MAGIC_PACKET,
-                                        0, GELIC_LV1_WOL_MP_ENABLE,
-                                        &v1, &v2);
-               if (status) {
-                       pr_info("%s: enabling WOL failed %d\n", __func__,
-                               status);
-                       status = -EIO;
-                       goto done;
-               }
-               status = lv1_net_control(bus_id(card), dev_id(card),
-                                        GELIC_LV1_SET_WOL,
-                                        GELIC_LV1_WOL_ADD_MATCH_ADDR,
-                                        0, GELIC_LV1_WOL_MATCH_ALL,
-                                        &v1, &v2);
-               if (!status)
-                       ps3_sys_manager_set_wol(1);
-               else {
-                       pr_info("%s: enabling WOL filter failed %d\n",
-                               __func__, status);
-                       status = -EIO;
-               }
-       } else {
-               status = lv1_net_control(bus_id(card), dev_id(card),
-                                        GELIC_LV1_SET_WOL,
-                                        GELIC_LV1_WOL_MAGIC_PACKET,
-                                        0, GELIC_LV1_WOL_MP_DISABLE,
-                                        &v1, &v2);
-               if (status) {
-                       pr_info("%s: disabling WOL failed %d\n", __func__,
-                               status);
-                       status = -EIO;
-                       goto done;
-               }
-               status = lv1_net_control(bus_id(card), dev_id(card),
-                                        GELIC_LV1_SET_WOL,
-                                        GELIC_LV1_WOL_DELETE_MATCH_ADDR,
-                                        0, GELIC_LV1_WOL_MATCH_ALL,
-                                        &v1, &v2);
-               if (!status)
-                       ps3_sys_manager_set_wol(0);
-               else {
-                       pr_info("%s: removing WOL filter failed %d\n",
-                               __func__, status);
-                       status = -EIO;
-               }
-       }
-done:
-       return status;
-}
-
-static const struct ethtool_ops gelic_ether_ethtool_ops = {
-       .get_drvinfo    = gelic_net_get_drvinfo,
-       .get_settings   = gelic_ether_get_settings,
-       .set_settings   = gelic_ether_set_settings,
-       .get_link       = ethtool_op_get_link,
-       .get_wol        = gelic_net_get_wol,
-       .set_wol        = gelic_net_set_wol,
-};
-
-/**
- * gelic_net_tx_timeout_task - task scheduled by the watchdog timeout
- * function (to be called not under interrupt status)
- * @work: work is context of tx timout task
- *
- * called as task when tx hangs, resets interface (if interface is up)
- */
-static void gelic_net_tx_timeout_task(struct work_struct *work)
-{
-       struct gelic_card *card =
-               container_of(work, struct gelic_card, tx_timeout_task);
-       struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET_0];
-
-       dev_info(ctodev(card), "%s:Timed out. Restarting...\n", __func__);
-
-       if (!(netdev->flags & IFF_UP))
-               goto out;
-
-       netif_device_detach(netdev);
-       gelic_net_stop(netdev);
-
-       gelic_net_open(netdev);
-       netif_device_attach(netdev);
-
-out:
-       atomic_dec(&card->tx_timeout_task_counter);
-}
-
-/**
- * gelic_net_tx_timeout - called when the tx timeout watchdog kicks in.
- * @netdev: interface device structure
- *
- * called, if tx hangs. Schedules a task that resets the interface
- */
-void gelic_net_tx_timeout(struct net_device *netdev)
-{
-       struct gelic_card *card;
-
-       card = netdev_card(netdev);
-       atomic_inc(&card->tx_timeout_task_counter);
-       if (netdev->flags & IFF_UP)
-               schedule_work(&card->tx_timeout_task);
-       else
-               atomic_dec(&card->tx_timeout_task_counter);
-}
-
-static const struct net_device_ops gelic_netdevice_ops = {
-       .ndo_open = gelic_net_open,
-       .ndo_stop = gelic_net_stop,
-       .ndo_start_xmit = gelic_net_xmit,
-       .ndo_set_multicast_list = gelic_net_set_multi,
-       .ndo_change_mtu = gelic_net_change_mtu,
-       .ndo_tx_timeout = gelic_net_tx_timeout,
-       .ndo_set_mac_address = eth_mac_addr,
-       .ndo_validate_addr = eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller = gelic_net_poll_controller,
-#endif
-};
-
-/**
- * gelic_ether_setup_netdev_ops - initialization of net_device operations
- * @netdev: net_device structure
- *
- * fills out function pointers in the net_device structure
- */
-static void __devinit gelic_ether_setup_netdev_ops(struct net_device *netdev,
-                                                  struct napi_struct *napi)
-{
-       netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
-       /* NAPI */
-       netif_napi_add(netdev, napi,
-                      gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
-       netdev->ethtool_ops = &gelic_ether_ethtool_ops;
-       netdev->netdev_ops = &gelic_netdevice_ops;
-}
-
-/**
- * gelic_ether_setup_netdev - initialization of net_device
- * @netdev: net_device structure
- * @card: card structure
- *
- * Returns 0 on success or <0 on failure
- *
- * gelic_ether_setup_netdev initializes the net_device structure
- * and register it.
- **/
-int __devinit gelic_net_setup_netdev(struct net_device *netdev,
-                                    struct gelic_card *card)
-{
-       int status;
-       u64 v1, v2;
-
-       netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
-
-       netdev->features = NETIF_F_IP_CSUM;
-       if (GELIC_CARD_RX_CSUM_DEFAULT)
-               netdev->features |= NETIF_F_RXCSUM;
-
-       status = lv1_net_control(bus_id(card), dev_id(card),
-                                GELIC_LV1_GET_MAC_ADDRESS,
-                                0, 0, 0, &v1, &v2);
-       v1 <<= 16;
-       if (status || !is_valid_ether_addr((u8 *)&v1)) {
-               dev_info(ctodev(card),
-                        "%s:lv1_net_control GET_MAC_ADDR failed %d\n",
-                        __func__, status);
-               return -EINVAL;
-       }
-       memcpy(netdev->dev_addr, &v1, ETH_ALEN);
-
-       if (card->vlan_required) {
-               netdev->hard_header_len += VLAN_HLEN;
-               /*
-                * As vlan is internally used,
-                * we can not receive vlan packets
-                */
-               netdev->features |= NETIF_F_VLAN_CHALLENGED;
-       }
-
-       status = register_netdev(netdev);
-       if (status) {
-               dev_err(ctodev(card), "%s:Couldn't register %s %d\n",
-                       __func__, netdev->name, status);
-               return status;
-       }
-       dev_info(ctodev(card), "%s: MAC addr %pM\n",
-                netdev->name, netdev->dev_addr);
-
-       return 0;
-}
-
-/**
- * gelic_alloc_card_net - allocates net_device and card structure
- *
- * returns the card structure or NULL in case of errors
- *
- * the card and net_device structures are linked to each other
- */
-#define GELIC_ALIGN (32)
-static struct gelic_card * __devinit gelic_alloc_card_net(struct net_device **netdev)
-{
-       struct gelic_card *card;
-       struct gelic_port *port;
-       void *p;
-       size_t alloc_size;
-       /*
-        * gelic requires dma descriptor is 32 bytes aligned and
-        * the hypervisor requires irq_status is 8 bytes aligned.
-        */
-       BUILD_BUG_ON(offsetof(struct gelic_card, irq_status) % 8);
-       BUILD_BUG_ON(offsetof(struct gelic_card, descr) % 32);
-       alloc_size =
-               sizeof(struct gelic_card) +
-               sizeof(struct gelic_descr) * GELIC_NET_RX_DESCRIPTORS +
-               sizeof(struct gelic_descr) * GELIC_NET_TX_DESCRIPTORS +
-               GELIC_ALIGN - 1;
-
-       p  = kzalloc(alloc_size, GFP_KERNEL);
-       if (!p)
-               return NULL;
-       card = PTR_ALIGN(p, GELIC_ALIGN);
-       card->unalign = p;
-
-       /*
-        * alloc netdev
-        */
-       *netdev = alloc_etherdev(sizeof(struct gelic_port));
-       if (!netdev) {
-               kfree(card->unalign);
-               return NULL;
-       }
-       port = netdev_priv(*netdev);
-
-       /* gelic_port */
-       port->netdev = *netdev;
-       port->card = card;
-       port->type = GELIC_PORT_ETHERNET_0;
-
-       /* gelic_card */
-       card->netdev[GELIC_PORT_ETHERNET_0] = *netdev;
-
-       INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
-       init_waitqueue_head(&card->waitq);
-       atomic_set(&card->tx_timeout_task_counter, 0);
-       mutex_init(&card->updown_lock);
-       atomic_set(&card->users, 0);
-
-       return card;
-}
-
-static void __devinit gelic_card_get_vlan_info(struct gelic_card *card)
-{
-       u64 v1, v2;
-       int status;
-       unsigned int i;
-       struct {
-               int tx;
-               int rx;
-       } vlan_id_ix[2] = {
-               [GELIC_PORT_ETHERNET_0] = {
-                       .tx = GELIC_LV1_VLAN_TX_ETHERNET_0,
-                       .rx = GELIC_LV1_VLAN_RX_ETHERNET_0
-               },
-               [GELIC_PORT_WIRELESS] = {
-                       .tx = GELIC_LV1_VLAN_TX_WIRELESS,
-                       .rx = GELIC_LV1_VLAN_RX_WIRELESS
-               }
-       };
-
-       for (i = 0; i < ARRAY_SIZE(vlan_id_ix); i++) {
-               /* tx tag */
-               status = lv1_net_control(bus_id(card), dev_id(card),
-                                        GELIC_LV1_GET_VLAN_ID,
-                                        vlan_id_ix[i].tx,
-                                        0, 0, &v1, &v2);
-               if (status || !v1) {
-                       if (status != LV1_NO_ENTRY)
-                               dev_dbg(ctodev(card),
-                                       "get vlan id for tx(%d) failed(%d)\n",
-                                       vlan_id_ix[i].tx, status);
-                       card->vlan[i].tx = 0;
-                       card->vlan[i].rx = 0;
-                       continue;
-               }
-               card->vlan[i].tx = (u16)v1;
-
-               /* rx tag */
-               status = lv1_net_control(bus_id(card), dev_id(card),
-                                        GELIC_LV1_GET_VLAN_ID,
-                                        vlan_id_ix[i].rx,
-                                        0, 0, &v1, &v2);
-               if (status || !v1) {
-                       if (status != LV1_NO_ENTRY)
-                               dev_info(ctodev(card),
-                                        "get vlan id for rx(%d) failed(%d)\n",
-                                        vlan_id_ix[i].rx, status);
-                       card->vlan[i].tx = 0;
-                       card->vlan[i].rx = 0;
-                       continue;
-               }
-               card->vlan[i].rx = (u16)v1;
-
-               dev_dbg(ctodev(card), "vlan_id[%d] tx=%02x rx=%02x\n",
-                       i, card->vlan[i].tx, card->vlan[i].rx);
-       }
-
-       if (card->vlan[GELIC_PORT_ETHERNET_0].tx) {
-               BUG_ON(!card->vlan[GELIC_PORT_WIRELESS].tx);
-               card->vlan_required = 1;
-       } else
-               card->vlan_required = 0;
-
-       /* check wirelss capable firmware */
-       if (ps3_compare_firmware_version(1, 6, 0) < 0) {
-               card->vlan[GELIC_PORT_WIRELESS].tx = 0;
-               card->vlan[GELIC_PORT_WIRELESS].rx = 0;
-       }
-
-       dev_info(ctodev(card), "internal vlan %s\n",
-                card->vlan_required? "enabled" : "disabled");
-}
-/**
- * ps3_gelic_driver_probe - add a device to the control of this driver
- */
-static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
-{
-       struct gelic_card *card;
-       struct net_device *netdev;
-       int result;
-
-       pr_debug("%s: called\n", __func__);
-       result = ps3_open_hv_device(dev);
-
-       if (result) {
-               dev_dbg(&dev->core, "%s:ps3_open_hv_device failed\n",
-                       __func__);
-               goto fail_open;
-       }
-
-       result = ps3_dma_region_create(dev->d_region);
-
-       if (result) {
-               dev_dbg(&dev->core, "%s:ps3_dma_region_create failed(%d)\n",
-                       __func__, result);
-               BUG_ON("check region type");
-               goto fail_dma_region;
-       }
-
-       /* alloc card/netdevice */
-       card = gelic_alloc_card_net(&netdev);
-       if (!card) {
-               dev_info(&dev->core, "%s:gelic_net_alloc_card failed\n",
-                        __func__);
-               result = -ENOMEM;
-               goto fail_alloc_card;
-       }
-       ps3_system_bus_set_drvdata(dev, card);
-       card->dev = dev;
-
-       /* get internal vlan info */
-       gelic_card_get_vlan_info(card);
-
-       card->link_mode = GELIC_LV1_ETHER_AUTO_NEG;
-
-       /* setup interrupt */
-       result = lv1_net_set_interrupt_status_indicator(bus_id(card),
-                                                       dev_id(card),
-               ps3_mm_phys_to_lpar(__pa(&card->irq_status)),
-               0);
-
-       if (result) {
-               dev_dbg(&dev->core,
-                       "%s:set_interrupt_status_indicator failed: %s\n",
-                       __func__, ps3_result(result));
-               result = -EIO;
-               goto fail_status_indicator;
-       }
-
-       result = ps3_sb_event_receive_port_setup(dev, PS3_BINDING_CPU_ANY,
-               &card->irq);
-
-       if (result) {
-               dev_info(ctodev(card),
-                        "%s:gelic_net_open_device failed (%d)\n",
-                        __func__, result);
-               result = -EPERM;
-               goto fail_alloc_irq;
-       }
-       result = request_irq(card->irq, gelic_card_interrupt,
-                            IRQF_DISABLED, netdev->name, card);
-
-       if (result) {
-               dev_info(ctodev(card), "%s:request_irq failed (%d)\n",
-                       __func__, result);
-               goto fail_request_irq;
-       }
-
-       /* setup card structure */
-       card->irq_mask = GELIC_CARD_RXINT | GELIC_CARD_TXINT |
-               GELIC_CARD_PORT_STATUS_CHANGED;
-
-
-       if (gelic_card_init_chain(card, &card->tx_chain,
-                       card->descr, GELIC_NET_TX_DESCRIPTORS))
-               goto fail_alloc_tx;
-       if (gelic_card_init_chain(card, &card->rx_chain,
-                                card->descr + GELIC_NET_TX_DESCRIPTORS,
-                                GELIC_NET_RX_DESCRIPTORS))
-               goto fail_alloc_rx;
-
-       /* head of chain */
-       card->tx_top = card->tx_chain.head;
-       card->rx_top = card->rx_chain.head;
-       dev_dbg(ctodev(card), "descr rx %p, tx %p, size %#lx, num %#x\n",
-               card->rx_top, card->tx_top, sizeof(struct gelic_descr),
-               GELIC_NET_RX_DESCRIPTORS);
-       /* allocate rx skbs */
-       if (gelic_card_alloc_rx_skbs(card))
-               goto fail_alloc_skbs;
-
-       spin_lock_init(&card->tx_lock);
-       card->tx_dma_progress = 0;
-
-       /* setup net_device structure */
-       netdev->irq = card->irq;
-       SET_NETDEV_DEV(netdev, &card->dev->core);
-       gelic_ether_setup_netdev_ops(netdev, &card->napi);
-       result = gelic_net_setup_netdev(netdev, card);
-       if (result) {
-               dev_dbg(&dev->core, "%s: setup_netdev failed %d",
-                       __func__, result);
-               goto fail_setup_netdev;
-       }
-
-#ifdef CONFIG_GELIC_WIRELESS
-       if (gelic_wl_driver_probe(card)) {
-               dev_dbg(&dev->core, "%s: WL init failed\n", __func__);
-               goto fail_setup_netdev;
-       }
-#endif
-       pr_debug("%s: done\n", __func__);
-       return 0;
-
-fail_setup_netdev:
-fail_alloc_skbs:
-       gelic_card_free_chain(card, card->rx_chain.head);
-fail_alloc_rx:
-       gelic_card_free_chain(card, card->tx_chain.head);
-fail_alloc_tx:
-       free_irq(card->irq, card);
-       netdev->irq = NO_IRQ;
-fail_request_irq:
-       ps3_sb_event_receive_port_destroy(dev, card->irq);
-fail_alloc_irq:
-       lv1_net_set_interrupt_status_indicator(bus_id(card),
-                                              bus_id(card),
-                                              0, 0);
-fail_status_indicator:
-       ps3_system_bus_set_drvdata(dev, NULL);
-       kfree(netdev_card(netdev)->unalign);
-       free_netdev(netdev);
-fail_alloc_card:
-       ps3_dma_region_free(dev->d_region);
-fail_dma_region:
-       ps3_close_hv_device(dev);
-fail_open:
-       return result;
-}
-
-/**
- * ps3_gelic_driver_remove - remove a device from the control of this driver
- */
-
-static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
-{
-       struct gelic_card *card = ps3_system_bus_get_drvdata(dev);
-       struct net_device *netdev0;
-       pr_debug("%s: called\n", __func__);
-
-       /* set auto-negotiation */
-       gelic_card_set_link_mode(card, GELIC_LV1_ETHER_AUTO_NEG);
-
-#ifdef CONFIG_GELIC_WIRELESS
-       gelic_wl_driver_remove(card);
-#endif
-       /* stop interrupt */
-       gelic_card_set_irq_mask(card, 0);
-
-       /* turn off DMA, force end */
-       gelic_card_disable_rxdmac(card);
-       gelic_card_disable_txdmac(card);
-
-       /* release chains */
-       gelic_card_release_tx_chain(card, 1);
-       gelic_card_release_rx_chain(card);
-
-       gelic_card_free_chain(card, card->tx_top);
-       gelic_card_free_chain(card, card->rx_top);
-
-       netdev0 = card->netdev[GELIC_PORT_ETHERNET_0];
-       /* disconnect event port */
-       free_irq(card->irq, card);
-       netdev0->irq = NO_IRQ;
-       ps3_sb_event_receive_port_destroy(card->dev, card->irq);
-
-       wait_event(card->waitq,
-                  atomic_read(&card->tx_timeout_task_counter) == 0);
-
-       lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card),
-                                              0 , 0);
-
-       unregister_netdev(netdev0);
-       kfree(netdev_card(netdev0)->unalign);
-       free_netdev(netdev0);
-
-       ps3_system_bus_set_drvdata(dev, NULL);
-
-       ps3_dma_region_free(dev->d_region);
-
-       ps3_close_hv_device(dev);
-
-       pr_debug("%s: done\n", __func__);
-       return 0;
-}
-
-static struct ps3_system_bus_driver ps3_gelic_driver = {
-       .match_id = PS3_MATCH_ID_GELIC,
-       .probe = ps3_gelic_driver_probe,
-       .remove = ps3_gelic_driver_remove,
-       .shutdown = ps3_gelic_driver_remove,
-       .core.name = "ps3_gelic_driver",
-       .core.owner = THIS_MODULE,
-};
-
-static int __init ps3_gelic_driver_init (void)
-{
-       return firmware_has_feature(FW_FEATURE_PS3_LV1)
-               ? ps3_system_bus_driver_register(&ps3_gelic_driver)
-               : -ENODEV;
-}
-
-static void __exit ps3_gelic_driver_exit (void)
-{
-       ps3_system_bus_driver_unregister(&ps3_gelic_driver);
-}
-
-module_init(ps3_gelic_driver_init);
-module_exit(ps3_gelic_driver_exit);
-
-MODULE_ALIAS(PS3_MODULE_ALIAS_GELIC);
-
diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h
deleted file mode 100644 (file)
index d3fadfb..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- *  PS3 Platfom gelic network driver.
- *
- * Copyright (C) 2007 Sony Computer Entertainment Inc.
- * Copyright 2006, 2007 Sony Corporation.
- *
- * This file is based on: spider_net.h
- *
- * (C) Copyright IBM Corp. 2005
- *
- * Authors : Utz Bacher <utz.bacher@de.ibm.com>
- *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef _GELIC_NET_H
-#define _GELIC_NET_H
-
-/* descriptors */
-#define GELIC_NET_RX_DESCRIPTORS        128 /* num of descriptors */
-#define GELIC_NET_TX_DESCRIPTORS        128 /* num of descriptors */
-
-#define GELIC_NET_MAX_MTU               VLAN_ETH_FRAME_LEN
-#define GELIC_NET_MIN_MTU               VLAN_ETH_ZLEN
-#define GELIC_NET_RXBUF_ALIGN           128
-#define GELIC_CARD_RX_CSUM_DEFAULT      1 /* hw chksum */
-#define GELIC_NET_WATCHDOG_TIMEOUT      5*HZ
-#define GELIC_NET_NAPI_WEIGHT           (GELIC_NET_RX_DESCRIPTORS)
-#define GELIC_NET_BROADCAST_ADDR        0xffffffffffffL
-
-#define GELIC_NET_MC_COUNT_MAX          32 /* multicast address list */
-
-/* virtual interrupt status register bits */
-       /* INT1 */
-#define GELIC_CARD_TX_RAM_FULL_ERR           0x0000000000000001L
-#define GELIC_CARD_RX_RAM_FULL_ERR           0x0000000000000002L
-#define GELIC_CARD_TX_SHORT_FRAME_ERR        0x0000000000000004L
-#define GELIC_CARD_TX_INVALID_DESCR_ERR      0x0000000000000008L
-#define GELIC_CARD_RX_FIFO_FULL_ERR          0x0000000000002000L
-#define GELIC_CARD_RX_DESCR_CHAIN_END        0x0000000000004000L
-#define GELIC_CARD_RX_INVALID_DESCR_ERR      0x0000000000008000L
-#define GELIC_CARD_TX_RESPONCE_ERR           0x0000000000010000L
-#define GELIC_CARD_RX_RESPONCE_ERR           0x0000000000100000L
-#define GELIC_CARD_TX_PROTECTION_ERR         0x0000000000400000L
-#define GELIC_CARD_RX_PROTECTION_ERR         0x0000000004000000L
-#define GELIC_CARD_TX_TCP_UDP_CHECKSUM_ERR   0x0000000008000000L
-#define GELIC_CARD_PORT_STATUS_CHANGED       0x0000000020000000L
-#define GELIC_CARD_WLAN_EVENT_RECEIVED       0x0000000040000000L
-#define GELIC_CARD_WLAN_COMMAND_COMPLETED    0x0000000080000000L
-       /* INT 0 */
-#define GELIC_CARD_TX_FLAGGED_DESCR          0x0004000000000000L
-#define GELIC_CARD_RX_FLAGGED_DESCR          0x0040000000000000L
-#define GELIC_CARD_TX_TRANSFER_END           0x0080000000000000L
-#define GELIC_CARD_TX_DESCR_CHAIN_END        0x0100000000000000L
-#define GELIC_CARD_NUMBER_OF_RX_FRAME        0x1000000000000000L
-#define GELIC_CARD_ONE_TIME_COUNT_TIMER      0x4000000000000000L
-#define GELIC_CARD_FREE_RUN_COUNT_TIMER      0x8000000000000000L
-
-/* initial interrupt mask */
-#define GELIC_CARD_TXINT       GELIC_CARD_TX_DESCR_CHAIN_END
-
-#define GELIC_CARD_RXINT       (GELIC_CARD_RX_DESCR_CHAIN_END | \
-                                GELIC_CARD_NUMBER_OF_RX_FRAME)
-
- /* RX descriptor data_status bits */
-enum gelic_descr_rx_status {
-       GELIC_DESCR_RXDMADU     = 0x80000000, /* destination MAC addr unknown */
-       GELIC_DESCR_RXLSTFBF    = 0x40000000, /* last frame buffer            */
-       GELIC_DESCR_RXIPCHK     = 0x20000000, /* IP checksum performed        */
-       GELIC_DESCR_RXTCPCHK    = 0x10000000, /* TCP/UDP checksup performed   */
-       GELIC_DESCR_RXWTPKT     = 0x00C00000, /*
-                                              * wakeup trigger packet
-                                              * 01: Magic Packet (TM)
-                                              * 10: ARP packet
-                                              * 11: Multicast MAC addr
-                                              */
-       GELIC_DESCR_RXVLNPKT    = 0x00200000, /* VLAN packet */
-       /* bit 20..16 reserved */
-       GELIC_DESCR_RXRRECNUM   = 0x0000ff00, /* reception receipt number */
-       /* bit 7..0 reserved */
-};
-
-#define GELIC_DESCR_DATA_STATUS_CHK_MASK       \
-       (GELIC_DESCR_RXIPCHK | GELIC_DESCR_RXTCPCHK)
-
- /* TX descriptor data_status bits */
-enum gelic_descr_tx_status {
-       GELIC_DESCR_TX_TAIL     = 0x00000001, /* gelic treated this
-                                              * descriptor was end of
-                                              * a tx frame
-                                              */
-};
-
-/* RX descriptor data error bits */
-enum gelic_descr_rx_error {
-       /* bit 31 reserved */
-       GELIC_DESCR_RXALNERR    = 0x40000000, /* alignement error 10/100M */
-       GELIC_DESCR_RXOVERERR   = 0x20000000, /* oversize error */
-       GELIC_DESCR_RXRNTERR    = 0x10000000, /* Runt error */
-       GELIC_DESCR_RXIPCHKERR  = 0x08000000, /* IP checksum  error */
-       GELIC_DESCR_RXTCPCHKERR = 0x04000000, /* TCP/UDP checksum  error */
-       GELIC_DESCR_RXDRPPKT    = 0x00100000, /* drop packet */
-       GELIC_DESCR_RXIPFMTERR  = 0x00080000, /* IP packet format error */
-       /* bit 18 reserved */
-       GELIC_DESCR_RXDATAERR   = 0x00020000, /* IP packet format error */
-       GELIC_DESCR_RXCALERR    = 0x00010000, /* cariier extension length
-                                             * error */
-       GELIC_DESCR_RXCREXERR   = 0x00008000, /* carrier extension error */
-       GELIC_DESCR_RXMLTCST    = 0x00004000, /* multicast address frame */
-       /* bit 13..0 reserved */
-};
-#define GELIC_DESCR_DATA_ERROR_CHK_MASK                \
-       (GELIC_DESCR_RXIPCHKERR | GELIC_DESCR_RXTCPCHKERR)
-
-/* DMA command and status (RX and TX)*/
-enum gelic_descr_dma_status {
-       GELIC_DESCR_DMA_COMPLETE            = 0x00000000, /* used in tx */
-       GELIC_DESCR_DMA_BUFFER_FULL         = 0x00000000, /* used in rx */
-       GELIC_DESCR_DMA_RESPONSE_ERROR      = 0x10000000, /* used in rx, tx */
-       GELIC_DESCR_DMA_PROTECTION_ERROR    = 0x20000000, /* used in rx, tx */
-       GELIC_DESCR_DMA_FRAME_END           = 0x40000000, /* used in rx */
-       GELIC_DESCR_DMA_FORCE_END           = 0x50000000, /* used in rx, tx */
-       GELIC_DESCR_DMA_CARDOWNED           = 0xa0000000, /* used in rx, tx */
-       GELIC_DESCR_DMA_NOT_IN_USE          = 0xb0000000, /* any other value */
-};
-
-#define GELIC_DESCR_DMA_STAT_MASK      (0xf0000000)
-
-/* tx descriptor command and status */
-enum gelic_descr_tx_dma_status {
-       /* [19] */
-       GELIC_DESCR_TX_DMA_IKE          = 0x00080000, /* IPSEC off */
-       /* [18] */
-       GELIC_DESCR_TX_DMA_FRAME_TAIL   = 0x00040000, /* last descriptor of
-                                                      * the packet
-                                                      */
-       /* [17..16] */
-       GELIC_DESCR_TX_DMA_TCP_CHKSUM   = 0x00020000, /* TCP packet */
-       GELIC_DESCR_TX_DMA_UDP_CHKSUM   = 0x00030000, /* UDP packet */
-       GELIC_DESCR_TX_DMA_NO_CHKSUM    = 0x00000000, /* no checksum */
-
-       /* [1] */
-       GELIC_DESCR_TX_DMA_CHAIN_END    = 0x00000002, /* DMA terminated
-                                                      * due to chain end
-                                                      */
-};
-
-#define GELIC_DESCR_DMA_CMD_NO_CHKSUM  \
-       (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \
-       GELIC_DESCR_TX_DMA_NO_CHKSUM)
-
-#define GELIC_DESCR_DMA_CMD_TCP_CHKSUM \
-       (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \
-       GELIC_DESCR_TX_DMA_TCP_CHKSUM)
-
-#define GELIC_DESCR_DMA_CMD_UDP_CHKSUM \
-       (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \
-       GELIC_DESCR_TX_DMA_UDP_CHKSUM)
-
-enum gelic_descr_rx_dma_status {
-       /* [ 1 ] */
-       GELIC_DESCR_RX_DMA_CHAIN_END    = 0x00000002, /* DMA terminated
-                                                      * due to chain end
-                                                      */
-};
-
-/* for lv1_net_control */
-enum gelic_lv1_net_control_code {
-       GELIC_LV1_GET_MAC_ADDRESS       = 1,
-       GELIC_LV1_GET_ETH_PORT_STATUS   = 2,
-       GELIC_LV1_SET_NEGOTIATION_MODE  = 3,
-       GELIC_LV1_GET_VLAN_ID           = 4,
-       GELIC_LV1_SET_WOL               = 5,
-       GELIC_LV1_GET_CHANNEL           = 6,
-       GELIC_LV1_POST_WLAN_CMD         = 9,
-       GELIC_LV1_GET_WLAN_CMD_RESULT   = 10,
-       GELIC_LV1_GET_WLAN_EVENT        = 11,
-};
-
-/* for GELIC_LV1_SET_WOL */
-enum gelic_lv1_wol_command {
-       GELIC_LV1_WOL_MAGIC_PACKET      = 1,
-       GELIC_LV1_WOL_ADD_MATCH_ADDR    = 6,
-       GELIC_LV1_WOL_DELETE_MATCH_ADDR = 7,
-};
-
-/* for GELIC_LV1_WOL_MAGIC_PACKET */
-enum gelic_lv1_wol_mp_arg {
-       GELIC_LV1_WOL_MP_DISABLE        = 0,
-       GELIC_LV1_WOL_MP_ENABLE         = 1,
-};
-
-/* for GELIC_LV1_WOL_{ADD,DELETE}_MATCH_ADDR */
-enum gelic_lv1_wol_match_arg {
-       GELIC_LV1_WOL_MATCH_INDIVIDUAL  = 0,
-       GELIC_LV1_WOL_MATCH_ALL         = 1,
-};
-
-/* status returened from GET_ETH_PORT_STATUS */
-enum gelic_lv1_ether_port_status {
-       GELIC_LV1_ETHER_LINK_UP         = 0x0000000000000001L,
-       GELIC_LV1_ETHER_FULL_DUPLEX     = 0x0000000000000002L,
-       GELIC_LV1_ETHER_AUTO_NEG        = 0x0000000000000004L,
-
-       GELIC_LV1_ETHER_SPEED_10        = 0x0000000000000010L,
-       GELIC_LV1_ETHER_SPEED_100       = 0x0000000000000020L,
-       GELIC_LV1_ETHER_SPEED_1000      = 0x0000000000000040L,
-       GELIC_LV1_ETHER_SPEED_MASK      = 0x0000000000000070L,
-};
-
-enum gelic_lv1_vlan_index {
-       /* for outgoing packets */
-       GELIC_LV1_VLAN_TX_ETHERNET_0    = 0x0000000000000002L,
-       GELIC_LV1_VLAN_TX_WIRELESS      = 0x0000000000000003L,
-
-       /* for incoming packets */
-       GELIC_LV1_VLAN_RX_ETHERNET_0    = 0x0000000000000012L,
-       GELIC_LV1_VLAN_RX_WIRELESS      = 0x0000000000000013L,
-};
-
-enum gelic_lv1_phy {
-       GELIC_LV1_PHY_ETHERNET_0        = 0x0000000000000002L,
-};
-
-/* size of hardware part of gelic descriptor */
-#define GELIC_DESCR_SIZE       (32)
-
-enum gelic_port_type {
-       GELIC_PORT_ETHERNET_0   = 0,
-       GELIC_PORT_WIRELESS     = 1,
-       GELIC_PORT_MAX
-};
-
-struct gelic_descr {
-       /* as defined by the hardware */
-       __be32 buf_addr;
-       __be32 buf_size;
-       __be32 next_descr_addr;
-       __be32 dmac_cmd_status;
-       __be32 result_size;
-       __be32 valid_size;      /* all zeroes for tx */
-       __be32 data_status;
-       __be32 data_error;      /* all zeroes for tx */
-
-       /* used in the driver */
-       struct sk_buff *skb;
-       dma_addr_t bus_addr;
-       struct gelic_descr *next;
-       struct gelic_descr *prev;
-} __attribute__((aligned(32)));
-
-struct gelic_descr_chain {
-       /* we walk from tail to head */
-       struct gelic_descr *head;
-       struct gelic_descr *tail;
-};
-
-struct gelic_vlan_id {
-       u16 tx;
-       u16 rx;
-};
-
-struct gelic_card {
-       struct napi_struct napi;
-       struct net_device *netdev[GELIC_PORT_MAX];
-       /*
-        * hypervisor requires irq_status should be
-        * 8 bytes aligned, but u64 member is
-        * always disposed in that manner
-        */
-       u64 irq_status;
-       u64 irq_mask;
-
-       struct ps3_system_bus_device *dev;
-       struct gelic_vlan_id vlan[GELIC_PORT_MAX];
-       int vlan_required;
-
-       struct gelic_descr_chain tx_chain;
-       struct gelic_descr_chain rx_chain;
-       /*
-        * tx_lock guards tx descriptor list and
-        * tx_dma_progress.
-        */
-       spinlock_t tx_lock;
-       int tx_dma_progress;
-
-       struct work_struct tx_timeout_task;
-       atomic_t tx_timeout_task_counter;
-       wait_queue_head_t waitq;
-
-       /* only first user should up the card */
-       struct mutex updown_lock;
-       atomic_t users;
-
-       u64 ether_port_status;
-       int link_mode;
-
-       /* original address returned by kzalloc */
-       void *unalign;
-
-       /*
-        * each netdevice has copy of irq
-        */
-       unsigned int irq;
-       struct gelic_descr *tx_top, *rx_top;
-       struct gelic_descr descr[0]; /* must be the last */
-};
-
-struct gelic_port {
-       struct gelic_card *card;
-       struct net_device *netdev;
-       enum gelic_port_type type;
-       long priv[0]; /* long for alignment */
-};
-
-static inline struct gelic_card *port_to_card(struct gelic_port *p)
-{
-       return p->card;
-}
-static inline struct net_device *port_to_netdev(struct gelic_port *p)
-{
-       return p->netdev;
-}
-static inline struct gelic_card *netdev_card(struct net_device *d)
-{
-       return ((struct gelic_port *)netdev_priv(d))->card;
-}
-static inline struct gelic_port *netdev_port(struct net_device *d)
-{
-       return (struct gelic_port *)netdev_priv(d);
-}
-static inline struct device *ctodev(struct gelic_card *card)
-{
-       return &card->dev->core;
-}
-static inline u64 bus_id(struct gelic_card *card)
-{
-       return card->dev->bus_id;
-}
-static inline u64 dev_id(struct gelic_card *card)
-{
-       return card->dev->dev_id;
-}
-
-static inline void *port_priv(struct gelic_port *port)
-{
-       return port->priv;
-}
-
-extern int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask);
-/* shared netdev ops */
-extern void gelic_card_up(struct gelic_card *card);
-extern void gelic_card_down(struct gelic_card *card);
-extern int gelic_net_open(struct net_device *netdev);
-extern int gelic_net_stop(struct net_device *netdev);
-extern int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev);
-extern void gelic_net_set_multi(struct net_device *netdev);
-extern void gelic_net_tx_timeout(struct net_device *netdev);
-extern int gelic_net_change_mtu(struct net_device *netdev, int new_mtu);
-extern int gelic_net_setup_netdev(struct net_device *netdev,
-                                 struct gelic_card *card);
-
-/* shared ethtool ops */
-extern void gelic_net_get_drvinfo(struct net_device *netdev,
-                                 struct ethtool_drvinfo *info);
-extern void gelic_net_poll_controller(struct net_device *netdev);
-
-#endif /* _GELIC_NET_H */
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
deleted file mode 100644 (file)
index 2e62938..0000000
+++ /dev/null
@@ -1,2681 +0,0 @@
-/*
- *  PS3 gelic network driver.
- *
- * Copyright (C) 2007 Sony Computer Entertainment Inc.
- * Copyright 2007 Sony Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/if_vlan.h>
-
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <linux/if_arp.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <net/iw_handler.h>
-
-#include <linux/dma-mapping.h>
-#include <net/checksum.h>
-#include <asm/firmware.h>
-#include <asm/ps3.h>
-#include <asm/lv1call.h>
-
-#include "ps3_gelic_net.h"
-#include "ps3_gelic_wireless.h"
-
-
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
-                              u8 *essid, size_t essid_len);
-static int gelic_wl_try_associate(struct net_device *netdev);
-
-/*
- * tables
- */
-
-/* 802.11b/g channel to freq in MHz */
-static const int channel_freq[] = {
-       2412, 2417, 2422, 2427, 2432,
-       2437, 2442, 2447, 2452, 2457,
-       2462, 2467, 2472, 2484
-};
-#define NUM_CHANNELS ARRAY_SIZE(channel_freq)
-
-/* in bps */
-static const int bitrate_list[] = {
-         1000000,
-         2000000,
-         5500000,
-        11000000,
-         6000000,
-         9000000,
-        12000000,
-        18000000,
-        24000000,
-        36000000,
-        48000000,
-        54000000
-};
-#define NUM_BITRATES ARRAY_SIZE(bitrate_list)
-
-/*
- * wpa2 support requires the hypervisor version 2.0 or later
- */
-static inline int wpa2_capable(void)
-{
-       return 0 <= ps3_compare_firmware_version(2, 0, 0);
-}
-
-static inline int precise_ie(void)
-{
-       return 0 <= ps3_compare_firmware_version(2, 2, 0);
-}
-/*
- * post_eurus_cmd helpers
- */
-struct eurus_cmd_arg_info {
-       int pre_arg; /* command requires arg1, arg2 at POST COMMAND */
-       int post_arg; /* command requires arg1, arg2 at GET_RESULT */
-};
-
-static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = {
-       [GELIC_EURUS_CMD_SET_COMMON_CFG] = { .pre_arg = 1},
-       [GELIC_EURUS_CMD_SET_WEP_CFG]    = { .pre_arg = 1},
-       [GELIC_EURUS_CMD_SET_WPA_CFG]    = { .pre_arg = 1},
-       [GELIC_EURUS_CMD_GET_COMMON_CFG] = { .post_arg = 1},
-       [GELIC_EURUS_CMD_GET_WEP_CFG]    = { .post_arg = 1},
-       [GELIC_EURUS_CMD_GET_WPA_CFG]    = { .post_arg = 1},
-       [GELIC_EURUS_CMD_GET_RSSI_CFG]   = { .post_arg = 1},
-       [GELIC_EURUS_CMD_START_SCAN]     = { .pre_arg = 1},
-       [GELIC_EURUS_CMD_GET_SCAN]       = { .post_arg = 1},
-};
-
-#ifdef DEBUG
-static const char *cmdstr(enum gelic_eurus_command ix)
-{
-       switch (ix) {
-       case GELIC_EURUS_CMD_ASSOC:
-               return "ASSOC";
-       case GELIC_EURUS_CMD_DISASSOC:
-               return "DISASSOC";
-       case GELIC_EURUS_CMD_START_SCAN:
-               return "SCAN";
-       case GELIC_EURUS_CMD_GET_SCAN:
-               return "GET SCAN";
-       case GELIC_EURUS_CMD_SET_COMMON_CFG:
-               return "SET_COMMON_CFG";
-       case GELIC_EURUS_CMD_GET_COMMON_CFG:
-               return "GET_COMMON_CFG";
-       case GELIC_EURUS_CMD_SET_WEP_CFG:
-               return "SET_WEP_CFG";
-       case GELIC_EURUS_CMD_GET_WEP_CFG:
-               return "GET_WEP_CFG";
-       case GELIC_EURUS_CMD_SET_WPA_CFG:
-               return "SET_WPA_CFG";
-       case GELIC_EURUS_CMD_GET_WPA_CFG:
-               return "GET_WPA_CFG";
-       case GELIC_EURUS_CMD_GET_RSSI_CFG:
-               return "GET_RSSI";
-       default:
-               break;
-       }
-       return "";
-};
-#else
-static inline const char *cmdstr(enum gelic_eurus_command ix)
-{
-       return "";
-}
-#endif
-
-/* synchronously do eurus commands */
-static void gelic_eurus_sync_cmd_worker(struct work_struct *work)
-{
-       struct gelic_eurus_cmd *cmd;
-       struct gelic_card *card;
-       struct gelic_wl_info *wl;
-
-       u64 arg1, arg2;
-
-       pr_debug("%s: <-\n", __func__);
-       cmd = container_of(work, struct gelic_eurus_cmd, work);
-       BUG_ON(cmd_info[cmd->cmd].pre_arg &&
-              cmd_info[cmd->cmd].post_arg);
-       wl = cmd->wl;
-       card = port_to_card(wl_port(wl));
-
-       if (cmd_info[cmd->cmd].pre_arg) {
-               arg1 = (cmd->buffer) ?
-                       ps3_mm_phys_to_lpar(__pa(cmd->buffer)) :
-                       0;
-               arg2 = cmd->buf_size;
-       } else {
-               arg1 = 0;
-               arg2 = 0;
-       }
-       init_completion(&wl->cmd_done_intr);
-       pr_debug("%s: cmd='%s' start\n", __func__, cmdstr(cmd->cmd));
-       cmd->status = lv1_net_control(bus_id(card), dev_id(card),
-                                     GELIC_LV1_POST_WLAN_CMD,
-                                     cmd->cmd, arg1, arg2,
-                                     &cmd->tag, &cmd->size);
-       if (cmd->status) {
-               complete(&cmd->done);
-               pr_info("%s: cmd issue failed\n", __func__);
-               return;
-       }
-
-       wait_for_completion(&wl->cmd_done_intr);
-
-       if (cmd_info[cmd->cmd].post_arg) {
-               arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
-               arg2 = cmd->buf_size;
-       } else {
-               arg1 = 0;
-               arg2 = 0;
-       }
-
-       cmd->status = lv1_net_control(bus_id(card), dev_id(card),
-                                     GELIC_LV1_GET_WLAN_CMD_RESULT,
-                                     cmd->tag, arg1, arg2,
-                                     &cmd->cmd_status, &cmd->size);
-#ifdef DEBUG
-       if (cmd->status || cmd->cmd_status) {
-       pr_debug("%s: cmd done tag=%#lx arg1=%#lx, arg2=%#lx\n", __func__,
-                cmd->tag, arg1, arg2);
-       pr_debug("%s: cmd done status=%#x cmd_status=%#lx size=%#lx\n",
-                __func__, cmd->status, cmd->cmd_status, cmd->size);
-       }
-#endif
-       complete(&cmd->done);
-       pr_debug("%s: cmd='%s' done\n", __func__, cmdstr(cmd->cmd));
-}
-
-static struct gelic_eurus_cmd *gelic_eurus_sync_cmd(struct gelic_wl_info *wl,
-                                                   unsigned int eurus_cmd,
-                                                   void *buffer,
-                                                   unsigned int buf_size)
-{
-       struct gelic_eurus_cmd *cmd;
-
-       /* allocate cmd */
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (!cmd)
-               return NULL;
-
-       /* initialize members */
-       cmd->cmd = eurus_cmd;
-       cmd->buffer = buffer;
-       cmd->buf_size = buf_size;
-       cmd->wl = wl;
-       INIT_WORK(&cmd->work, gelic_eurus_sync_cmd_worker);
-       init_completion(&cmd->done);
-       queue_work(wl->eurus_cmd_queue, &cmd->work);
-
-       /* wait for command completion */
-       wait_for_completion(&cmd->done);
-
-       return cmd;
-}
-
-static u32 gelic_wl_get_link(struct net_device *netdev)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
-       u32 ret;
-
-       pr_debug("%s: <-\n", __func__);
-       mutex_lock(&wl->assoc_stat_lock);
-       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
-               ret = 1;
-       else
-               ret = 0;
-       mutex_unlock(&wl->assoc_stat_lock);
-       pr_debug("%s: ->\n", __func__);
-       return ret;
-}
-
-static void gelic_wl_send_iwap_event(struct gelic_wl_info *wl, u8 *bssid)
-{
-       union iwreq_data data;
-
-       memset(&data, 0, sizeof(data));
-       if (bssid)
-               memcpy(data.ap_addr.sa_data, bssid, ETH_ALEN);
-       data.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWAP,
-                           &data, NULL);
-}
-
-/*
- * wireless extension handlers and helpers
- */
-
-/* SIOGIWNAME */
-static int gelic_wl_get_name(struct net_device *dev,
-                            struct iw_request_info *info,
-                            union iwreq_data *iwreq, char *extra)
-{
-       strcpy(iwreq->name, "IEEE 802.11bg");
-       return 0;
-}
-
-static void gelic_wl_get_ch_info(struct gelic_wl_info *wl)
-{
-       struct gelic_card *card = port_to_card(wl_port(wl));
-       u64 ch_info_raw, tmp;
-       int status;
-
-       if (!test_and_set_bit(GELIC_WL_STAT_CH_INFO, &wl->stat)) {
-               status = lv1_net_control(bus_id(card), dev_id(card),
-                                        GELIC_LV1_GET_CHANNEL, 0, 0, 0,
-                                        &ch_info_raw,
-                                        &tmp);
-               /* some fw versions may return error */
-               if (status) {
-                       if (status != LV1_NO_ENTRY)
-                               pr_info("%s: available ch unknown\n", __func__);
-                       wl->ch_info = 0x07ff;/* 11 ch */
-               } else
-                       /* 16 bits of MSB has available channels */
-                       wl->ch_info = ch_info_raw >> 48;
-       }
-}
-
-/* SIOGIWRANGE */
-static int gelic_wl_get_range(struct net_device *netdev,
-                             struct iw_request_info *info,
-                             union iwreq_data *iwreq, char *extra)
-{
-       struct iw_point *point = &iwreq->data;
-       struct iw_range *range = (struct iw_range *)extra;
-       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
-       unsigned int i, chs;
-
-       pr_debug("%s: <-\n", __func__);
-       point->length = sizeof(struct iw_range);
-       memset(range, 0, sizeof(struct iw_range));
-
-       range->we_version_compiled = WIRELESS_EXT;
-       range->we_version_source = 22;
-
-       /* available channels and frequencies */
-       gelic_wl_get_ch_info(wl);
-
-       for (i = 0, chs = 0;
-            i < NUM_CHANNELS && chs < IW_MAX_FREQUENCIES; i++)
-               if (wl->ch_info & (1 << i)) {
-                       range->freq[chs].i = i + 1;
-                       range->freq[chs].m = channel_freq[i];
-                       range->freq[chs].e = 6;
-                       chs++;
-               }
-       range->num_frequency = chs;
-       range->old_num_frequency = chs;
-       range->num_channels = chs;
-       range->old_num_channels = chs;
-
-       /* bitrates */
-       for (i = 0; i < NUM_BITRATES; i++)
-               range->bitrate[i] = bitrate_list[i];
-       range->num_bitrates = i;
-
-       /* signal levels */
-       range->max_qual.qual = 100; /* relative value */
-       range->max_qual.level = 100;
-       range->avg_qual.qual = 50;
-       range->avg_qual.level = 50;
-       range->sensitivity = 0;
-
-       /* Event capability */
-       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-
-       /* encryption capability */
-       range->enc_capa = IW_ENC_CAPA_WPA |
-               IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP |
-               IW_ENC_CAPA_4WAY_HANDSHAKE;
-       if (wpa2_capable())
-               range->enc_capa |= IW_ENC_CAPA_WPA2;
-       range->encoding_size[0] = 5;    /* 40bit WEP */
-       range->encoding_size[1] = 13;   /* 104bit WEP */
-       range->encoding_size[2] = 32;   /* WPA-PSK */
-       range->num_encoding_sizes = 3;
-       range->max_encoding_tokens = GELIC_WEP_KEYS;
-
-       /* scan capability */
-       range->scan_capa = IW_SCAN_CAPA_ESSID;
-
-       pr_debug("%s: ->\n", __func__);
-       return 0;
-
-}
-
-/* SIOC{G,S}IWSCAN */
-static int gelic_wl_set_scan(struct net_device *netdev,
-                          struct iw_request_info *info,
-                          union iwreq_data *wrqu, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       struct iw_scan_req *req;
-       u8 *essid = NULL;
-       size_t essid_len = 0;
-
-       if (wrqu->data.length == sizeof(struct iw_scan_req) &&
-           wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-               req = (struct iw_scan_req*)extra;
-               essid = req->essid;
-               essid_len = req->essid_len;
-               pr_debug("%s: ESSID scan =%s\n", __func__, essid);
-       }
-       return gelic_wl_start_scan(wl, 1, essid, essid_len);
-}
-
-#define OUI_LEN 3
-static const u8 rsn_oui[OUI_LEN] = { 0x00, 0x0f, 0xac };
-static const u8 wpa_oui[OUI_LEN] = { 0x00, 0x50, 0xf2 };
-
-/*
- * synthesize WPA/RSN IE data
- * See WiFi WPA specification and IEEE 802.11-2007 7.3.2.25
- * for the format
- */
-static size_t gelic_wl_synthesize_ie(u8 *buf,
-                                    struct gelic_eurus_scan_info *scan)
-{
-
-       const u8 *oui_header;
-       u8 *start = buf;
-       int rsn;
-       int ccmp;
-
-       pr_debug("%s: <- sec=%16x\n", __func__, scan->security);
-       switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_MASK) {
-       case GELIC_EURUS_SCAN_SEC_WPA:
-               rsn = 0;
-               break;
-       case GELIC_EURUS_SCAN_SEC_WPA2:
-               rsn = 1;
-               break;
-       default:
-               /* WEP or none.  No IE returned */
-               return 0;
-       }
-
-       switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_WPA_MASK) {
-       case GELIC_EURUS_SCAN_SEC_WPA_TKIP:
-               ccmp = 0;
-               break;
-       case GELIC_EURUS_SCAN_SEC_WPA_AES:
-               ccmp = 1;
-               break;
-       default:
-               if (rsn) {
-                       ccmp = 1;
-                       pr_info("%s: no cipher info. defaulted to CCMP\n",
-                               __func__);
-               } else {
-                       ccmp = 0;
-                       pr_info("%s: no cipher info. defaulted to TKIP\n",
-                               __func__);
-               }
-       }
-
-       if (rsn)
-               oui_header = rsn_oui;
-       else
-               oui_header = wpa_oui;
-
-       /* element id */
-       if (rsn)
-               *buf++ = WLAN_EID_RSN;
-       else
-               *buf++ = WLAN_EID_GENERIC;
-
-       /* length filed; set later */
-       buf++;
-
-       /* wpa special header */
-       if (!rsn) {
-               memcpy(buf, wpa_oui, OUI_LEN);
-               buf += OUI_LEN;
-               *buf++ = 0x01;
-       }
-
-       /* version */
-       *buf++ = 0x01; /* version 1.0 */
-       *buf++ = 0x00;
-
-       /* group cipher */
-       memcpy(buf, oui_header, OUI_LEN);
-       buf += OUI_LEN;
-
-       if (ccmp)
-               *buf++ = 0x04; /* CCMP */
-       else
-               *buf++ = 0x02; /* TKIP */
-
-       /* pairwise key count always 1 */
-       *buf++ = 0x01;
-       *buf++ = 0x00;
-
-       /* pairwise key suit */
-       memcpy(buf, oui_header, OUI_LEN);
-       buf += OUI_LEN;
-       if (ccmp)
-               *buf++ = 0x04; /* CCMP */
-       else
-               *buf++ = 0x02; /* TKIP */
-
-       /* AKM count is 1 */
-       *buf++ = 0x01;
-       *buf++ = 0x00;
-
-       /* AKM suite is assumed as PSK*/
-       memcpy(buf, oui_header, OUI_LEN);
-       buf += OUI_LEN;
-       *buf++ = 0x02; /* PSK */
-
-       /* RSN capabilities is 0 */
-       *buf++ = 0x00;
-       *buf++ = 0x00;
-
-       /* set length field */
-       start[1] = (buf - start - 2);
-
-       pr_debug("%s: ->\n", __func__);
-       return buf - start;
-}
-
-struct ie_item {
-       u8 *data;
-       u8 len;
-};
-
-struct ie_info {
-       struct ie_item wpa;
-       struct ie_item rsn;
-};
-
-static void gelic_wl_parse_ie(u8 *data, size_t len,
-                             struct ie_info *ie_info)
-{
-       size_t data_left = len;
-       u8 *pos = data;
-       u8 item_len;
-       u8 item_id;
-
-       pr_debug("%s: data=%p len=%ld\n", __func__,
-                data, len);
-       memset(ie_info, 0, sizeof(struct ie_info));
-
-       while (2 <= data_left) {
-               item_id = *pos++;
-               item_len = *pos++;
-               data_left -= 2;
-
-               if (data_left < item_len)
-                       break;
-
-               switch (item_id) {
-               case WLAN_EID_GENERIC:
-                       if ((OUI_LEN + 1 <= item_len) &&
-                           !memcmp(pos, wpa_oui, OUI_LEN) &&
-                           pos[OUI_LEN] == 0x01) {
-                               ie_info->wpa.data = pos - 2;
-                               ie_info->wpa.len = item_len + 2;
-                       }
-                       break;
-               case WLAN_EID_RSN:
-                       ie_info->rsn.data = pos - 2;
-                       /* length includes the header */
-                       ie_info->rsn.len = item_len + 2;
-                       break;
-               default:
-                       pr_debug("%s: ignore %#x,%d\n", __func__,
-                                item_id, item_len);
-                       break;
-               }
-               pos += item_len;
-               data_left -= item_len;
-       }
-       pr_debug("%s: wpa=%p,%d wpa2=%p,%d\n", __func__,
-                ie_info->wpa.data, ie_info->wpa.len,
-                ie_info->rsn.data, ie_info->rsn.len);
-}
-
-
-/*
- * translate the scan informations from hypervisor to a
- * independent format
- */
-static char *gelic_wl_translate_scan(struct net_device *netdev,
-                                    struct iw_request_info *info,
-                                    char *ev,
-                                    char *stop,
-                                    struct gelic_wl_scan_info *network)
-{
-       struct iw_event iwe;
-       struct gelic_eurus_scan_info *scan = network->hwinfo;
-       char *tmp;
-       u8 rate;
-       unsigned int i, j, len;
-       u8 buf[64]; /* arbitrary size large enough */
-
-       pr_debug("%s: <-\n", __func__);
-
-       /* first entry should be AP's mac address */
-       iwe.cmd = SIOCGIWAP;
-       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-       memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
-       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_ADDR_LEN);
-
-       /* ESSID */
-       iwe.cmd = SIOCGIWESSID;
-       iwe.u.data.flags = 1;
-       iwe.u.data.length = strnlen(scan->essid, 32);
-       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
-
-       /* FREQUENCY */
-       iwe.cmd = SIOCGIWFREQ;
-       iwe.u.freq.m = be16_to_cpu(scan->channel);
-       iwe.u.freq.e = 0; /* table value in MHz */
-       iwe.u.freq.i = 0;
-       ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_FREQ_LEN);
-
-       /* RATES */
-       iwe.cmd = SIOCGIWRATE;
-       iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-       /* to stuff multiple values in one event */
-       tmp = ev + iwe_stream_lcp_len(info);
-       /* put them in ascendant order (older is first) */
-       i = 0;
-       j = 0;
-       pr_debug("%s: rates=%d rate=%d\n", __func__,
-                network->rate_len, network->rate_ext_len);
-       while (i < network->rate_len) {
-               if (j < network->rate_ext_len &&
-                   ((scan->ext_rate[j] & 0x7f) < (scan->rate[i] & 0x7f)))
-                   rate = scan->ext_rate[j++] & 0x7f;
-               else
-                   rate = scan->rate[i++] & 0x7f;
-               iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
-               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
-                                          IW_EV_PARAM_LEN);
-       }
-       while (j < network->rate_ext_len) {
-               iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
-               tmp = iwe_stream_add_value(info, ev, tmp, stop, &iwe,
-                                          IW_EV_PARAM_LEN);
-       }
-       /* Check if we added any rate */
-       if (iwe_stream_lcp_len(info) < (tmp - ev))
-               ev = tmp;
-
-       /* ENCODE */
-       iwe.cmd = SIOCGIWENCODE;
-       if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_PRIVACY)
-               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-       else
-               iwe.u.data.flags = IW_ENCODE_DISABLED;
-       iwe.u.data.length = 0;
-       ev = iwe_stream_add_point(info, ev, stop, &iwe, scan->essid);
-
-       /* MODE */
-       iwe.cmd = SIOCGIWMODE;
-       if (be16_to_cpu(scan->capability) &
-           (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
-               if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_ESS)
-                       iwe.u.mode = IW_MODE_MASTER;
-               else
-                       iwe.u.mode = IW_MODE_ADHOC;
-               ev = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_UINT_LEN);
-       }
-
-       /* QUAL */
-       iwe.cmd = IWEVQUAL;
-       iwe.u.qual.updated  = IW_QUAL_ALL_UPDATED |
-                       IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
-       iwe.u.qual.level = be16_to_cpu(scan->rssi);
-       iwe.u.qual.qual = be16_to_cpu(scan->rssi);
-       iwe.u.qual.noise = 0;
-       ev  = iwe_stream_add_event(info, ev, stop, &iwe, IW_EV_QUAL_LEN);
-
-       /* RSN */
-       memset(&iwe, 0, sizeof(iwe));
-       if (be16_to_cpu(scan->size) <= sizeof(*scan)) {
-               /* If wpa[2] capable station, synthesize IE and put it */
-               len = gelic_wl_synthesize_ie(buf, scan);
-               if (len) {
-                       iwe.cmd = IWEVGENIE;
-                       iwe.u.data.length = len;
-                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
-               }
-       } else {
-               /* this scan info has IE data */
-               struct ie_info ie_info;
-               size_t data_len;
-
-               data_len = be16_to_cpu(scan->size) - sizeof(*scan);
-
-               gelic_wl_parse_ie(scan->elements, data_len, &ie_info);
-
-               if (ie_info.wpa.len && (ie_info.wpa.len <= sizeof(buf))) {
-                       memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
-                       iwe.cmd = IWEVGENIE;
-                       iwe.u.data.length = ie_info.wpa.len;
-                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
-               }
-
-               if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
-                       memset(&iwe, 0, sizeof(iwe));
-                       memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
-                       iwe.cmd = IWEVGENIE;
-                       iwe.u.data.length = ie_info.rsn.len;
-                       ev = iwe_stream_add_point(info, ev, stop, &iwe, buf);
-               }
-       }
-
-       pr_debug("%s: ->\n", __func__);
-       return ev;
-}
-
-
-static int gelic_wl_get_scan(struct net_device *netdev,
-                            struct iw_request_info *info,
-                            union iwreq_data *wrqu, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       struct gelic_wl_scan_info *scan_info;
-       char *ev = extra;
-       char *stop = ev + wrqu->data.length;
-       int ret = 0;
-       unsigned long this_time = jiffies;
-
-       pr_debug("%s: <-\n", __func__);
-       if (mutex_lock_interruptible(&wl->scan_lock))
-               return -EAGAIN;
-
-       switch (wl->scan_stat) {
-       case GELIC_WL_SCAN_STAT_SCANNING:
-               /* If a scan in progress, caller should call me again */
-               ret = -EAGAIN;
-               goto out;
-               break;
-
-       case GELIC_WL_SCAN_STAT_INIT:
-               /* last scan request failed or never issued */
-               ret = -ENODEV;
-               goto out;
-               break;
-       case GELIC_WL_SCAN_STAT_GOT_LIST:
-               /* ok, use current list */
-               break;
-       }
-
-       list_for_each_entry(scan_info, &wl->network_list, list) {
-               if (wl->scan_age == 0 ||
-                   time_after(scan_info->last_scanned + wl->scan_age,
-                              this_time))
-                       ev = gelic_wl_translate_scan(netdev, info,
-                                                    ev, stop,
-                                                    scan_info);
-               else
-                       pr_debug("%s:entry too old\n", __func__);
-
-               if (stop - ev <= IW_EV_ADDR_LEN) {
-                       ret = -E2BIG;
-                       goto out;
-               }
-       }
-
-       wrqu->data.length = ev - extra;
-       wrqu->data.flags = 0;
-out:
-       mutex_unlock(&wl->scan_lock);
-       pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length);
-       return ret;
-}
-
-#ifdef DEBUG
-static void scan_list_dump(struct gelic_wl_info *wl)
-{
-       struct gelic_wl_scan_info *scan_info;
-       int i;
-
-       i = 0;
-       list_for_each_entry(scan_info, &wl->network_list, list) {
-               pr_debug("%s: item %d\n", __func__, i++);
-               pr_debug("valid=%d eurusindex=%d last=%lx\n",
-                        scan_info->valid, scan_info->eurus_index,
-                        scan_info->last_scanned);
-               pr_debug("r_len=%d r_ext_len=%d essid_len=%d\n",
-                        scan_info->rate_len, scan_info->rate_ext_len,
-                        scan_info->essid_len);
-               /* -- */
-               pr_debug("bssid=%pM\n", &scan_info->hwinfo->bssid[2]);
-               pr_debug("essid=%s\n", scan_info->hwinfo->essid);
-       }
-}
-#endif
-
-static int gelic_wl_set_auth(struct net_device *netdev,
-                            struct iw_request_info *info,
-                            union iwreq_data *data, char *extra)
-{
-       struct iw_param *param = &data->param;
-       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
-       unsigned long irqflag;
-       int ret = 0;
-
-       pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
-       spin_lock_irqsave(&wl->lock, irqflag);
-       switch (param->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_WPA_VERSION:
-               if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
-                       pr_debug("%s: NO WPA selected\n", __func__);
-                       wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
-                       wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
-               }
-               if (param->value & IW_AUTH_WPA_VERSION_WPA) {
-                       pr_debug("%s: WPA version 1 selected\n", __func__);
-                       wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
-                       wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
-                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
-               }
-               if (param->value & IW_AUTH_WPA_VERSION_WPA2) {
-                       /*
-                        * As the hypervisor may not tell the cipher
-                        * information of the AP if it is WPA2,
-                        * you will not decide suitable cipher from
-                        * its beacon.
-                        * You should have knowledge about the AP's
-                        * cipher information in other method prior to
-                        * the association.
-                        */
-                       if (!precise_ie())
-                               pr_info("%s: WPA2 may not work\n", __func__);
-                       if (wpa2_capable()) {
-                               wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
-                               wl->group_cipher_method = GELIC_WL_CIPHER_AES;
-                               wl->pairwise_cipher_method =
-                                       GELIC_WL_CIPHER_AES;
-                               wl->auth_method = GELIC_EURUS_AUTH_OPEN;
-                       } else
-                               ret = -EINVAL;
-               }
-               break;
-
-       case IW_AUTH_CIPHER_PAIRWISE:
-               if (param->value &
-                   (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
-                       pr_debug("%s: WEP selected\n", __func__);
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
-               }
-               if (param->value & IW_AUTH_CIPHER_TKIP) {
-                       pr_debug("%s: TKIP selected\n", __func__);
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
-               }
-               if (param->value & IW_AUTH_CIPHER_CCMP) {
-                       pr_debug("%s: CCMP selected\n", __func__);
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
-               }
-               if (param->value & IW_AUTH_CIPHER_NONE) {
-                       pr_debug("%s: no auth selected\n", __func__);
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
-               }
-               break;
-       case IW_AUTH_CIPHER_GROUP:
-               if (param->value &
-                   (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
-                       pr_debug("%s: WEP selected\n", __func__);
-                       wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
-               }
-               if (param->value & IW_AUTH_CIPHER_TKIP) {
-                       pr_debug("%s: TKIP selected\n", __func__);
-                       wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
-               }
-               if (param->value & IW_AUTH_CIPHER_CCMP) {
-                       pr_debug("%s: CCMP selected\n", __func__);
-                       wl->group_cipher_method = GELIC_WL_CIPHER_AES;
-               }
-               if (param->value & IW_AUTH_CIPHER_NONE) {
-                       pr_debug("%s: no auth selected\n", __func__);
-                       wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
-               }
-               break;
-       case IW_AUTH_80211_AUTH_ALG:
-               if (param->value & IW_AUTH_ALG_SHARED_KEY) {
-                       pr_debug("%s: shared key specified\n", __func__);
-                       wl->auth_method = GELIC_EURUS_AUTH_SHARED;
-               } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
-                       pr_debug("%s: open system specified\n", __func__);
-                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
-               } else
-                       ret = -EINVAL;
-               break;
-
-       case IW_AUTH_WPA_ENABLED:
-               if (param->value) {
-                       pr_debug("%s: WPA enabled\n", __func__);
-                       wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
-               } else {
-                       pr_debug("%s: WPA disabled\n", __func__);
-                       wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
-               }
-               break;
-
-       case IW_AUTH_KEY_MGMT:
-               if (param->value & IW_AUTH_KEY_MGMT_PSK)
-                       break;
-               /* intentionally fall through */
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-       if (!ret)
-               set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: -> %d\n", __func__, ret);
-       return ret;
-}
-
-static int gelic_wl_get_auth(struct net_device *netdev,
-                            struct iw_request_info *info,
-                            union iwreq_data *iwreq, char *extra)
-{
-       struct iw_param *param = &iwreq->param;
-       struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
-       unsigned long irqflag;
-       int ret = 0;
-
-       pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
-       spin_lock_irqsave(&wl->lock, irqflag);
-       switch (param->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_WPA_VERSION:
-               switch (wl->wpa_level) {
-               case GELIC_WL_WPA_LEVEL_WPA:
-                       param->value |= IW_AUTH_WPA_VERSION_WPA;
-                       break;
-               case GELIC_WL_WPA_LEVEL_WPA2:
-                       param->value |= IW_AUTH_WPA_VERSION_WPA2;
-                       break;
-               default:
-                       param->value |= IW_AUTH_WPA_VERSION_DISABLED;
-               }
-               break;
-
-       case IW_AUTH_80211_AUTH_ALG:
-               if (wl->auth_method == GELIC_EURUS_AUTH_SHARED)
-                       param->value = IW_AUTH_ALG_SHARED_KEY;
-               else if (wl->auth_method == GELIC_EURUS_AUTH_OPEN)
-                       param->value = IW_AUTH_ALG_OPEN_SYSTEM;
-               break;
-
-       case IW_AUTH_WPA_ENABLED:
-               switch (wl->wpa_level) {
-               case GELIC_WL_WPA_LEVEL_WPA:
-               case GELIC_WL_WPA_LEVEL_WPA2:
-                       param->value = 1;
-                       break;
-               default:
-                       param->value = 0;
-                       break;
-               }
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-       }
-
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: -> %d\n", __func__, ret);
-       return ret;
-}
-
-/* SIOC{S,G}IWESSID */
-static int gelic_wl_set_essid(struct net_device *netdev,
-                             struct iw_request_info *info,
-                             union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       unsigned long irqflag;
-
-       pr_debug("%s: <- l=%d f=%d\n", __func__,
-                data->essid.length, data->essid.flags);
-       if (IW_ESSID_MAX_SIZE < data->essid.length)
-               return -EINVAL;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (data->essid.flags) {
-               wl->essid_len = data->essid.length;
-               memcpy(wl->essid, extra, wl->essid_len);
-               pr_debug("%s: essid = '%s'\n", __func__, extra);
-               set_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
-       } else {
-               pr_debug("%s: ESSID any\n", __func__);
-               clear_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
-       }
-       set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-
-
-       gelic_wl_try_associate(netdev); /* FIXME */
-       pr_debug("%s: ->\n", __func__);
-       return 0;
-}
-
-static int gelic_wl_get_essid(struct net_device *netdev,
-                             struct iw_request_info *info,
-                             union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       unsigned long irqflag;
-
-       pr_debug("%s: <-\n", __func__);
-       mutex_lock(&wl->assoc_stat_lock);
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) ||
-           wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
-               memcpy(extra, wl->essid, wl->essid_len);
-               data->essid.length = wl->essid_len;
-               data->essid.flags = 1;
-       } else
-               data->essid.flags = 0;
-
-       mutex_unlock(&wl->assoc_stat_lock);
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: -> len=%d\n", __func__, data->essid.length);
-
-       return 0;
-}
-
-/* SIO{S,G}IWENCODE */
-static int gelic_wl_set_encode(struct net_device *netdev,
-                              struct iw_request_info *info,
-                              union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       struct iw_point *enc = &data->encoding;
-       __u16 flags;
-       unsigned long irqflag;
-       int key_index, index_specified;
-       int ret = 0;
-
-       pr_debug("%s: <-\n", __func__);
-       flags = enc->flags & IW_ENCODE_FLAGS;
-       key_index = enc->flags & IW_ENCODE_INDEX;
-
-       pr_debug("%s: key_index = %d\n", __func__, key_index);
-       pr_debug("%s: key_len = %d\n", __func__, enc->length);
-       pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
-
-       if (GELIC_WEP_KEYS < key_index)
-               return -EINVAL;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (key_index) {
-               index_specified = 1;
-               key_index--;
-       } else {
-               index_specified = 0;
-               key_index = wl->current_key;
-       }
-
-       if (flags & IW_ENCODE_NOKEY) {
-               /* if just IW_ENCODE_NOKEY, change current key index */
-               if (!flags && index_specified) {
-                       wl->current_key = key_index;
-                       goto done;
-               }
-
-               if (flags & IW_ENCODE_DISABLED) {
-                       if (!index_specified) {
-                               /* disable encryption */
-                               wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
-                               wl->pairwise_cipher_method =
-                                       GELIC_WL_CIPHER_NONE;
-                               /* invalidate all key */
-                               wl->key_enabled = 0;
-                       } else
-                               clear_bit(key_index, &wl->key_enabled);
-               }
-
-               if (flags & IW_ENCODE_OPEN)
-                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
-               if (flags & IW_ENCODE_RESTRICTED) {
-                       pr_info("%s: shared key mode enabled\n", __func__);
-                       wl->auth_method = GELIC_EURUS_AUTH_SHARED;
-               }
-       } else {
-               if (IW_ENCODING_TOKEN_MAX < enc->length) {
-                       ret = -EINVAL;
-                       goto done;
-               }
-               wl->key_len[key_index] = enc->length;
-               memcpy(wl->key[key_index], extra, enc->length);
-               set_bit(key_index, &wl->key_enabled);
-               wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
-               wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
-       }
-       set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-done:
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: ->\n", __func__);
-       return ret;
-}
-
-static int gelic_wl_get_encode(struct net_device *netdev,
-                              struct iw_request_info *info,
-                              union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       struct iw_point *enc = &data->encoding;
-       unsigned long irqflag;
-       unsigned int key_index, index_specified;
-       int ret = 0;
-
-       pr_debug("%s: <-\n", __func__);
-       key_index = enc->flags & IW_ENCODE_INDEX;
-       pr_debug("%s: flag=%#x point=%p len=%d extra=%p\n", __func__,
-                enc->flags, enc->pointer, enc->length, extra);
-       if (GELIC_WEP_KEYS < key_index)
-               return -EINVAL;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (key_index) {
-               index_specified = 1;
-               key_index--;
-       } else {
-               index_specified = 0;
-               key_index = wl->current_key;
-       }
-
-       if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
-               switch (wl->auth_method) {
-               case GELIC_EURUS_AUTH_OPEN:
-                       enc->flags = IW_ENCODE_OPEN;
-                       break;
-               case GELIC_EURUS_AUTH_SHARED:
-                       enc->flags = IW_ENCODE_RESTRICTED;
-                       break;
-               }
-       } else
-               enc->flags = IW_ENCODE_DISABLED;
-
-       if (test_bit(key_index, &wl->key_enabled)) {
-               if (enc->length < wl->key_len[key_index]) {
-                       ret = -EINVAL;
-                       goto done;
-               }
-               enc->length = wl->key_len[key_index];
-               memcpy(extra, wl->key[key_index], wl->key_len[key_index]);
-       } else {
-               enc->length = 0;
-               enc->flags |= IW_ENCODE_NOKEY;
-       }
-       enc->flags |= key_index + 1;
-       pr_debug("%s: -> flag=%x len=%d\n", __func__,
-                enc->flags, enc->length);
-
-done:
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       return ret;
-}
-
-/* SIOC{S,G}IWAP */
-static int gelic_wl_set_ap(struct net_device *netdev,
-                          struct iw_request_info *info,
-                          union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       unsigned long irqflag;
-
-       pr_debug("%s: <-\n", __func__);
-       if (data->ap_addr.sa_family != ARPHRD_ETHER)
-               return -EINVAL;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (is_valid_ether_addr(data->ap_addr.sa_data)) {
-               memcpy(wl->bssid, data->ap_addr.sa_data,
-                      ETH_ALEN);
-               set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
-               set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-               pr_debug("%s: bss=%pM\n", __func__, wl->bssid);
-       } else {
-               pr_debug("%s: clear bssid\n", __func__);
-               clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
-               memset(wl->bssid, 0, ETH_ALEN);
-       }
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: ->\n", __func__);
-       return 0;
-}
-
-static int gelic_wl_get_ap(struct net_device *netdev,
-                          struct iw_request_info *info,
-                          union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       unsigned long irqflag;
-
-       pr_debug("%s: <-\n", __func__);
-       mutex_lock(&wl->assoc_stat_lock);
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
-               data->ap_addr.sa_family = ARPHRD_ETHER;
-               memcpy(data->ap_addr.sa_data, wl->active_bssid,
-                      ETH_ALEN);
-       } else
-               memset(data->ap_addr.sa_data, 0, ETH_ALEN);
-
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       mutex_unlock(&wl->assoc_stat_lock);
-       pr_debug("%s: ->\n", __func__);
-       return 0;
-}
-
-/* SIOC{S,G}IWENCODEEXT */
-static int gelic_wl_set_encodeext(struct net_device *netdev,
-                                 struct iw_request_info *info,
-                                 union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       struct iw_point *enc = &data->encoding;
-       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       __u16 alg;
-       __u16 flags;
-       unsigned long irqflag;
-       int key_index;
-       int ret = 0;
-
-       pr_debug("%s: <-\n", __func__);
-       flags = enc->flags & IW_ENCODE_FLAGS;
-       alg = ext->alg;
-       key_index = enc->flags & IW_ENCODE_INDEX;
-
-       pr_debug("%s: key_index = %d\n", __func__, key_index);
-       pr_debug("%s: key_len = %d\n", __func__, enc->length);
-       pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
-       pr_debug("%s: ext_flag=%x\n", __func__, ext->ext_flags);
-       pr_debug("%s: ext_key_len=%x\n", __func__, ext->key_len);
-
-       if (GELIC_WEP_KEYS < key_index)
-               return -EINVAL;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (key_index)
-               key_index--;
-       else
-               key_index = wl->current_key;
-
-       if (!enc->length && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
-               /* reques to change default key index */
-               pr_debug("%s: request to change default key to %d\n",
-                        __func__, key_index);
-               wl->current_key = key_index;
-               goto done;
-       }
-
-       if (alg == IW_ENCODE_ALG_NONE || (flags & IW_ENCODE_DISABLED)) {
-               pr_debug("%s: alg disabled\n", __func__);
-               wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
-               wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
-               wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
-               wl->auth_method = GELIC_EURUS_AUTH_OPEN; /* should be open */
-       } else if (alg == IW_ENCODE_ALG_WEP) {
-               pr_debug("%s: WEP requested\n", __func__);
-               if (flags & IW_ENCODE_OPEN) {
-                       pr_debug("%s: open key mode\n", __func__);
-                       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
-               }
-               if (flags & IW_ENCODE_RESTRICTED) {
-                       pr_debug("%s: shared key mode\n", __func__);
-                       wl->auth_method = GELIC_EURUS_AUTH_SHARED;
-               }
-               if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
-                       pr_info("%s: key is too long %d\n", __func__,
-                               ext->key_len);
-                       ret = -EINVAL;
-                       goto done;
-               }
-               /* OK, update the key */
-               wl->key_len[key_index] = ext->key_len;
-               memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
-               memcpy(wl->key[key_index], ext->key, ext->key_len);
-               set_bit(key_index, &wl->key_enabled);
-               /* remember wep info changed */
-               set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-       } else if (alg == IW_ENCODE_ALG_PMK) {
-               if (ext->key_len != WPA_PSK_LEN) {
-                       pr_err("%s: PSK length wrong %d\n", __func__,
-                              ext->key_len);
-                       ret = -EINVAL;
-                       goto done;
-               }
-               memset(wl->psk, 0, sizeof(wl->psk));
-               memcpy(wl->psk, ext->key, ext->key_len);
-               wl->psk_len = ext->key_len;
-               wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
-               /* remember PSK configured */
-               set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
-       }
-done:
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: ->\n", __func__);
-       return ret;
-}
-
-static int gelic_wl_get_encodeext(struct net_device *netdev,
-                                 struct iw_request_info *info,
-                                 union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       struct iw_point *enc = &data->encoding;
-       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       unsigned long irqflag;
-       int key_index;
-       int ret = 0;
-       int max_key_len;
-
-       pr_debug("%s: <-\n", __func__);
-
-       max_key_len = enc->length - sizeof(struct iw_encode_ext);
-       if (max_key_len < 0)
-               return -EINVAL;
-       key_index = enc->flags & IW_ENCODE_INDEX;
-
-       pr_debug("%s: key_index = %d\n", __func__, key_index);
-       pr_debug("%s: key_len = %d\n", __func__, enc->length);
-       pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
-
-       if (GELIC_WEP_KEYS < key_index)
-               return -EINVAL;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (key_index)
-               key_index--;
-       else
-               key_index = wl->current_key;
-
-       memset(ext, 0, sizeof(struct iw_encode_ext));
-       switch (wl->group_cipher_method) {
-       case GELIC_WL_CIPHER_WEP:
-               ext->alg = IW_ENCODE_ALG_WEP;
-               enc->flags |= IW_ENCODE_ENABLED;
-               break;
-       case GELIC_WL_CIPHER_TKIP:
-               ext->alg = IW_ENCODE_ALG_TKIP;
-               enc->flags |= IW_ENCODE_ENABLED;
-               break;
-       case GELIC_WL_CIPHER_AES:
-               ext->alg = IW_ENCODE_ALG_CCMP;
-               enc->flags |= IW_ENCODE_ENABLED;
-               break;
-       case GELIC_WL_CIPHER_NONE:
-       default:
-               ext->alg = IW_ENCODE_ALG_NONE;
-               enc->flags |= IW_ENCODE_NOKEY;
-               break;
-       }
-
-       if (!(enc->flags & IW_ENCODE_NOKEY)) {
-               if (max_key_len < wl->key_len[key_index]) {
-                       ret = -E2BIG;
-                       goto out;
-               }
-               if (test_bit(key_index, &wl->key_enabled))
-                       memcpy(ext->key, wl->key[key_index],
-                              wl->key_len[key_index]);
-               else
-                       pr_debug("%s: disabled key requested ix=%d\n",
-                                __func__, key_index);
-       }
-out:
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: ->\n", __func__);
-       return ret;
-}
-/* SIOC{S,G}IWMODE */
-static int gelic_wl_set_mode(struct net_device *netdev,
-                            struct iw_request_info *info,
-                            union iwreq_data *data, char *extra)
-{
-       __u32 mode = data->mode;
-       int ret;
-
-       pr_debug("%s: <-\n", __func__);
-       if (mode == IW_MODE_INFRA)
-               ret = 0;
-       else
-               ret = -EOPNOTSUPP;
-       pr_debug("%s: -> %d\n", __func__, ret);
-       return ret;
-}
-
-static int gelic_wl_get_mode(struct net_device *netdev,
-                            struct iw_request_info *info,
-                            union iwreq_data *data, char *extra)
-{
-       __u32 *mode = &data->mode;
-       pr_debug("%s: <-\n", __func__);
-       *mode = IW_MODE_INFRA;
-       pr_debug("%s: ->\n", __func__);
-       return 0;
-}
-
-/* SIOCGIWNICKN */
-static int gelic_wl_get_nick(struct net_device *net_dev,
-                                 struct iw_request_info *info,
-                                 union iwreq_data *data, char *extra)
-{
-       strcpy(extra, "gelic_wl");
-       data->data.length = strlen(extra);
-       data->data.flags = 1;
-       return 0;
-}
-
-
-/* --- */
-
-static struct iw_statistics *gelic_wl_get_wireless_stats(
-       struct net_device *netdev)
-{
-
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       struct gelic_eurus_cmd *cmd;
-       struct iw_statistics *is;
-       struct gelic_eurus_rssi_info *rssi;
-       void *buf;
-
-       pr_debug("%s: <-\n", __func__);
-
-       buf = (void *)__get_free_page(GFP_KERNEL);
-       if (!buf)
-               return NULL;
-
-       is = &wl->iwstat;
-       memset(is, 0, sizeof(*is));
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG,
-                                  buf, sizeof(*rssi));
-       if (cmd && !cmd->status && !cmd->cmd_status) {
-               rssi = buf;
-               is->qual.level = be16_to_cpu(rssi->rssi);
-               is->qual.updated = IW_QUAL_LEVEL_UPDATED |
-                       IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
-       } else
-               /* not associated */
-               is->qual.updated = IW_QUAL_ALL_INVALID;
-
-       kfree(cmd);
-       free_page((unsigned long)buf);
-       pr_debug("%s: ->\n", __func__);
-       return is;
-}
-
-/*
- *  scanning helpers
- */
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
-                              u8 *essid, size_t essid_len)
-{
-       struct gelic_eurus_cmd *cmd;
-       int ret = 0;
-       void *buf = NULL;
-       size_t len;
-
-       pr_debug("%s: <- always=%d\n", __func__, always_scan);
-       if (mutex_lock_interruptible(&wl->scan_lock))
-               return -ERESTARTSYS;
-
-       /*
-        * If already a scan in progress, do not trigger more
-        */
-       if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING) {
-               pr_debug("%s: scanning now\n", __func__);
-               goto out;
-       }
-
-       init_completion(&wl->scan_done);
-       /*
-        * If we have already a bss list, don't try to get new
-        * unless we are doing an ESSID scan
-        */
-       if ((!essid_len && !always_scan)
-           && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
-               pr_debug("%s: already has the list\n", __func__);
-               complete(&wl->scan_done);
-               goto out;
-       }
-
-       /* ESSID scan ? */
-       if (essid_len && essid) {
-               buf = (void *)__get_free_page(GFP_KERNEL);
-               if (!buf) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */
-               memset(buf, 0, len);
-               memcpy(buf, essid, essid_len);
-               pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf);
-       } else
-               len = 0;
-
-       /*
-        * issue start scan request
-        */
-       wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
-                                  buf, len);
-       if (!cmd || cmd->status || cmd->cmd_status) {
-               wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
-               complete(&wl->scan_done);
-               ret = -ENOMEM;
-               goto out;
-       }
-       kfree(cmd);
-out:
-       free_page((unsigned long)buf);
-       mutex_unlock(&wl->scan_lock);
-       pr_debug("%s: ->\n", __func__);
-       return ret;
-}
-
-/*
- * retrieve scan result from the chip (hypervisor)
- * this function is invoked by schedule work.
- */
-static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
-{
-       struct gelic_eurus_cmd *cmd = NULL;
-       struct gelic_wl_scan_info *target, *tmp;
-       struct gelic_wl_scan_info *oldest = NULL;
-       struct gelic_eurus_scan_info *scan_info;
-       unsigned int scan_info_size;
-       union iwreq_data data;
-       unsigned long this_time = jiffies;
-       unsigned int data_len, i, found, r;
-       void *buf;
-
-       pr_debug("%s:start\n", __func__);
-       mutex_lock(&wl->scan_lock);
-
-       buf = (void *)__get_free_page(GFP_KERNEL);
-       if (!buf) {
-               pr_info("%s: scan buffer alloc failed\n", __func__);
-               goto out;
-       }
-
-       if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) {
-               /*
-                * stop() may be called while scanning, ignore result
-                */
-               pr_debug("%s: scan complete when stat != scanning(%d)\n",
-                        __func__, wl->scan_stat);
-               goto out;
-       }
-
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN,
-                                  buf, PAGE_SIZE);
-       if (!cmd || cmd->status || cmd->cmd_status) {
-               wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
-               pr_info("%s:cmd failed\n", __func__);
-               kfree(cmd);
-               goto out;
-       }
-       data_len = cmd->size;
-       pr_debug("%s: data_len = %d\n", __func__, data_len);
-       kfree(cmd);
-
-       /* OK, bss list retrieved */
-       wl->scan_stat = GELIC_WL_SCAN_STAT_GOT_LIST;
-
-       /* mark all entries are old */
-       list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
-               target->valid = 0;
-               /* expire too old entries */
-               if (time_before(target->last_scanned + wl->scan_age,
-                               this_time)) {
-                       kfree(target->hwinfo);
-                       target->hwinfo = NULL;
-                       list_move_tail(&target->list, &wl->network_free_list);
-               }
-       }
-
-       /* put them in the network_list */
-       for (i = 0, scan_info_size = 0, scan_info = buf;
-            scan_info_size < data_len;
-            i++, scan_info_size += be16_to_cpu(scan_info->size),
-            scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
-               pr_debug("%s:size=%d bssid=%pM scan_info=%p\n", __func__,
-                        be16_to_cpu(scan_info->size),
-                        &scan_info->bssid[2], scan_info);
-
-               /*
-                * The wireless firmware may return invalid channel 0 and/or
-                * invalid rate if the AP emits zero length SSID ie. As this
-                * scan information is useless, ignore it
-                */
-               if (!be16_to_cpu(scan_info->channel) || !scan_info->rate[0]) {
-                       pr_debug("%s: invalid scan info\n", __func__);
-                       continue;
-               }
-
-               found = 0;
-               oldest = NULL;
-               list_for_each_entry(target, &wl->network_list, list) {
-                       if (!compare_ether_addr(&target->hwinfo->bssid[2],
-                                               &scan_info->bssid[2])) {
-                               found = 1;
-                               pr_debug("%s: same BBS found scanned list\n",
-                                        __func__);
-                               break;
-                       }
-                       if (!oldest ||
-                           (target->last_scanned < oldest->last_scanned))
-                               oldest = target;
-               }
-
-               if (!found) {
-                       /* not found in the list */
-                       if (list_empty(&wl->network_free_list)) {
-                               /* expire oldest */
-                               target = oldest;
-                       } else {
-                               target = list_entry(wl->network_free_list.next,
-                                                   struct gelic_wl_scan_info,
-                                                   list);
-                       }
-               }
-
-               /* update the item */
-               target->last_scanned = this_time;
-               target->valid = 1;
-               target->eurus_index = i;
-               kfree(target->hwinfo);
-               target->hwinfo = kzalloc(be16_to_cpu(scan_info->size),
-                                        GFP_KERNEL);
-               if (!target->hwinfo) {
-                       pr_info("%s: kzalloc failed\n", __func__);
-                       continue;
-               }
-               /* copy hw scan info */
-               memcpy(target->hwinfo, scan_info, scan_info->size);
-               target->essid_len = strnlen(scan_info->essid,
-                                           sizeof(scan_info->essid));
-               target->rate_len = 0;
-               for (r = 0; r < 12; r++)
-                       if (scan_info->rate[r])
-                               target->rate_len++;
-               if (8 < target->rate_len)
-                       pr_info("%s: AP returns %d rates\n", __func__,
-                               target->rate_len);
-               target->rate_ext_len = 0;
-               for (r = 0; r < 16; r++)
-                       if (scan_info->ext_rate[r])
-                               target->rate_ext_len++;
-               list_move_tail(&target->list, &wl->network_list);
-       }
-       memset(&data, 0, sizeof(data));
-       wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data,
-                           NULL);
-out:
-       free_page((unsigned long)buf);
-       complete(&wl->scan_done);
-       mutex_unlock(&wl->scan_lock);
-       pr_debug("%s:end\n", __func__);
-}
-
-/*
- * Select an appropriate bss from current scan list regarding
- * current settings from userspace.
- * The caller must hold wl->scan_lock,
- * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
- */
-static void update_best(struct gelic_wl_scan_info **best,
-                       struct gelic_wl_scan_info *candid,
-                       int *best_weight,
-                       int *weight)
-{
-       if (*best_weight < ++(*weight)) {
-               *best_weight = *weight;
-               *best = candid;
-       }
-}
-
-static
-struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl)
-{
-       struct gelic_wl_scan_info *scan_info;
-       struct gelic_wl_scan_info *best_bss;
-       int weight, best_weight;
-       u16 security;
-
-       pr_debug("%s: <-\n", __func__);
-
-       best_bss = NULL;
-       best_weight = 0;
-
-       list_for_each_entry(scan_info, &wl->network_list, list) {
-               pr_debug("%s: station %p\n", __func__, scan_info);
-
-               if (!scan_info->valid) {
-                       pr_debug("%s: station invalid\n", __func__);
-                       continue;
-               }
-
-               /* If bss specified, check it only */
-               if (test_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat)) {
-                       if (!compare_ether_addr(&scan_info->hwinfo->bssid[2],
-                                               wl->bssid)) {
-                               best_bss = scan_info;
-                               pr_debug("%s: bssid matched\n", __func__);
-                               break;
-                       } else {
-                               pr_debug("%s: bssid unmached\n", __func__);
-                               continue;
-                       }
-               }
-
-               weight = 0;
-
-               /* security */
-               security = be16_to_cpu(scan_info->hwinfo->security) &
-                       GELIC_EURUS_SCAN_SEC_MASK;
-               if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
-                       if (security == GELIC_EURUS_SCAN_SEC_WPA2)
-                               update_best(&best_bss, scan_info,
-                                           &best_weight, &weight);
-                       else
-                               continue;
-               } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA) {
-                       if (security == GELIC_EURUS_SCAN_SEC_WPA)
-                               update_best(&best_bss, scan_info,
-                                           &best_weight, &weight);
-                       else
-                               continue;
-               } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_NONE &&
-                          wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
-                       if (security == GELIC_EURUS_SCAN_SEC_WEP)
-                               update_best(&best_bss, scan_info,
-                                           &best_weight, &weight);
-                       else
-                               continue;
-               }
-
-               /* If ESSID is set, check it */
-               if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
-                       if ((scan_info->essid_len == wl->essid_len) &&
-                           !strncmp(wl->essid,
-                                    scan_info->hwinfo->essid,
-                                    scan_info->essid_len))
-                               update_best(&best_bss, scan_info,
-                                           &best_weight, &weight);
-                       else
-                               continue;
-               }
-       }
-
-#ifdef DEBUG
-       pr_debug("%s: -> bss=%p\n", __func__, best_bss);
-       if (best_bss) {
-               pr_debug("%s:addr=%pM\n", __func__,
-                        &best_bss->hwinfo->bssid[2]);
-       }
-#endif
-       return best_bss;
-}
-
-/*
- * Setup WEP configuration to the chip
- * The caller must hold wl->scan_lock,
- * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
- */
-static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
-{
-       unsigned int i;
-       struct gelic_eurus_wep_cfg *wep;
-       struct gelic_eurus_cmd *cmd;
-       int wep104 = 0;
-       int have_key = 0;
-       int ret = 0;
-
-       pr_debug("%s: <-\n", __func__);
-       /* we can assume no one should uses the buffer */
-       wep = (struct gelic_eurus_wep_cfg *)__get_free_page(GFP_KERNEL);
-       if (!wep)
-               return -ENOMEM;
-
-       memset(wep, 0, sizeof(*wep));
-
-       if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
-               pr_debug("%s: WEP mode\n", __func__);
-               for (i = 0; i < GELIC_WEP_KEYS; i++) {
-                       if (!test_bit(i, &wl->key_enabled))
-                               continue;
-
-                       pr_debug("%s: key#%d enabled\n", __func__, i);
-                       have_key = 1;
-                       if (wl->key_len[i] == 13)
-                               wep104 = 1;
-                       else if (wl->key_len[i] != 5) {
-                               pr_info("%s: wrong wep key[%d]=%d\n",
-                                       __func__, i, wl->key_len[i]);
-                               ret = -EINVAL;
-                               goto out;
-                       }
-                       memcpy(wep->key[i], wl->key[i], wl->key_len[i]);
-               }
-
-               if (!have_key) {
-                       pr_info("%s: all wep key disabled\n", __func__);
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               if (wep104) {
-                       pr_debug("%s: 104bit key\n", __func__);
-                       wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_104BIT);
-               } else {
-                       pr_debug("%s: 40bit key\n", __func__);
-                       wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_40BIT);
-               }
-       } else {
-               pr_debug("%s: NO encryption\n", __func__);
-               wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_NONE);
-       }
-
-       /* issue wep setup */
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WEP_CFG,
-                                  wep, sizeof(*wep));
-       if (!cmd)
-               ret = -ENOMEM;
-       else if (cmd->status || cmd->cmd_status)
-               ret = -ENXIO;
-
-       kfree(cmd);
-out:
-       free_page((unsigned long)wep);
-       pr_debug("%s: ->\n", __func__);
-       return ret;
-}
-
-#ifdef DEBUG
-static const char *wpasecstr(enum gelic_eurus_wpa_security sec)
-{
-       switch (sec) {
-       case GELIC_EURUS_WPA_SEC_NONE:
-               return "NONE";
-               break;
-       case GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP:
-               return "WPA_TKIP_TKIP";
-               break;
-       case GELIC_EURUS_WPA_SEC_WPA_TKIP_AES:
-               return "WPA_TKIP_AES";
-               break;
-       case GELIC_EURUS_WPA_SEC_WPA_AES_AES:
-               return "WPA_AES_AES";
-               break;
-       case GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP:
-               return "WPA2_TKIP_TKIP";
-               break;
-       case GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES:
-               return "WPA2_TKIP_AES";
-               break;
-       case GELIC_EURUS_WPA_SEC_WPA2_AES_AES:
-               return "WPA2_AES_AES";
-               break;
-       }
-       return "";
-};
-#endif
-
-static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
-{
-       struct gelic_eurus_wpa_cfg *wpa;
-       struct gelic_eurus_cmd *cmd;
-       u16 security;
-       int ret = 0;
-
-       pr_debug("%s: <-\n", __func__);
-       /* we can assume no one should uses the buffer */
-       wpa = (struct gelic_eurus_wpa_cfg *)__get_free_page(GFP_KERNEL);
-       if (!wpa)
-               return -ENOMEM;
-
-       memset(wpa, 0, sizeof(*wpa));
-
-       if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat))
-               pr_info("%s: PSK not configured yet\n", __func__);
-
-       /* copy key */
-       memcpy(wpa->psk, wl->psk, wl->psk_len);
-
-       /* set security level */
-       if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
-               if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
-                       security = GELIC_EURUS_WPA_SEC_WPA2_AES_AES;
-               } else {
-                       if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
-                           precise_ie())
-                               security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES;
-                       else
-                               security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP;
-               }
-       } else {
-               if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
-                       security = GELIC_EURUS_WPA_SEC_WPA_AES_AES;
-               } else {
-                       if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
-                           precise_ie())
-                               security = GELIC_EURUS_WPA_SEC_WPA_TKIP_AES;
-                       else
-                               security = GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP;
-               }
-       }
-       wpa->security = cpu_to_be16(security);
-
-       /* PSK type */
-       wpa->psk_type = cpu_to_be16(wl->psk_type);
-#ifdef DEBUG
-       pr_debug("%s: sec=%s psktype=%s\n", __func__,
-                wpasecstr(wpa->security),
-                (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
-                "BIN" : "passphrase");
-#if 0
-       /*
-        * don't enable here if you plan to submit
-        * the debug log because this dumps your precious
-        * passphrase/key.
-        */
-       pr_debug("%s: psk=%s\n", __func__,
-                (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
-                "N/A" : wpa->psk);
-#endif
-#endif
-       /* issue wpa setup */
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WPA_CFG,
-                                  wpa, sizeof(*wpa));
-       if (!cmd)
-               ret = -ENOMEM;
-       else if (cmd->status || cmd->cmd_status)
-               ret = -ENXIO;
-       kfree(cmd);
-       free_page((unsigned long)wpa);
-       pr_debug("%s: --> %d\n", __func__, ret);
-       return ret;
-}
-
-/*
- * Start association. caller must hold assoc_stat_lock
- */
-static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
-                                 struct gelic_wl_scan_info *bss)
-{
-       struct gelic_eurus_cmd *cmd;
-       struct gelic_eurus_common_cfg *common;
-       int ret = 0;
-       unsigned long rc;
-
-       pr_debug("%s: <-\n", __func__);
-
-       /* do common config */
-       common = (struct gelic_eurus_common_cfg *)__get_free_page(GFP_KERNEL);
-       if (!common)
-               return -ENOMEM;
-
-       memset(common, 0, sizeof(*common));
-       common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA);
-       common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG);
-
-       common->scan_index = cpu_to_be16(bss->eurus_index);
-       switch (wl->auth_method) {
-       case GELIC_EURUS_AUTH_OPEN:
-               common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_OPEN);
-               break;
-       case GELIC_EURUS_AUTH_SHARED:
-               common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_SHARED);
-               break;
-       }
-
-#ifdef DEBUG
-       scan_list_dump(wl);
-#endif
-       pr_debug("%s: common cfg index=%d bsstype=%d auth=%d\n", __func__,
-                be16_to_cpu(common->scan_index),
-                be16_to_cpu(common->bss_type),
-                be16_to_cpu(common->auth_method));
-
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_COMMON_CFG,
-                                  common, sizeof(*common));
-       if (!cmd || cmd->status || cmd->cmd_status) {
-               ret = -ENOMEM;
-               kfree(cmd);
-               goto out;
-       }
-       kfree(cmd);
-
-       /* WEP/WPA */
-       switch (wl->wpa_level) {
-       case GELIC_WL_WPA_LEVEL_NONE:
-               /* If WEP or no security, setup WEP config */
-               ret = gelic_wl_do_wep_setup(wl);
-               break;
-       case GELIC_WL_WPA_LEVEL_WPA:
-       case GELIC_WL_WPA_LEVEL_WPA2:
-               ret = gelic_wl_do_wpa_setup(wl);
-               break;
-       }
-
-       if (ret) {
-               pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
-                        ret);
-               ret = -EPERM;
-               gelic_wl_send_iwap_event(wl, NULL);
-               goto out;
-       }
-
-       /* start association */
-       init_completion(&wl->assoc_done);
-       wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATING;
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_ASSOC,
-                                  NULL, 0);
-       if (!cmd || cmd->status || cmd->cmd_status) {
-               pr_debug("%s: assoc request failed\n", __func__);
-               wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
-               kfree(cmd);
-               ret = -ENOMEM;
-               gelic_wl_send_iwap_event(wl, NULL);
-               goto out;
-       }
-       kfree(cmd);
-
-       /* wait for connected event */
-       rc = wait_for_completion_timeout(&wl->assoc_done, HZ * 4);/*FIXME*/
-
-       if (!rc) {
-               /* timeouted.  Maybe key or cyrpt mode is wrong */
-               pr_info("%s: connect timeout\n", __func__);
-               cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC,
-                                          NULL, 0);
-               kfree(cmd);
-               wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
-               gelic_wl_send_iwap_event(wl, NULL);
-               ret = -ENXIO;
-       } else {
-               wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATED;
-               /* copy bssid */
-               memcpy(wl->active_bssid, &bss->hwinfo->bssid[2], ETH_ALEN);
-
-               /* send connect event */
-               gelic_wl_send_iwap_event(wl, wl->active_bssid);
-               pr_info("%s: connected\n", __func__);
-       }
-out:
-       free_page((unsigned long)common);
-       pr_debug("%s: ->\n", __func__);
-       return ret;
-}
-
-/*
- * connected event
- */
-static void gelic_wl_connected_event(struct gelic_wl_info *wl,
-                                    u64 event)
-{
-       u64 desired_event = 0;
-
-       switch (wl->wpa_level) {
-       case GELIC_WL_WPA_LEVEL_NONE:
-               desired_event = GELIC_LV1_WL_EVENT_CONNECTED;
-               break;
-       case GELIC_WL_WPA_LEVEL_WPA:
-       case GELIC_WL_WPA_LEVEL_WPA2:
-               desired_event = GELIC_LV1_WL_EVENT_WPA_CONNECTED;
-               break;
-       }
-
-       if (desired_event == event) {
-               pr_debug("%s: completed\n", __func__);
-               complete(&wl->assoc_done);
-               netif_carrier_on(port_to_netdev(wl_port(wl)));
-       } else
-               pr_debug("%s: event %#llx under wpa\n",
-                                __func__, event);
-}
-
-/*
- * disconnect event
- */
-static void gelic_wl_disconnect_event(struct gelic_wl_info *wl,
-                                     u64 event)
-{
-       struct gelic_eurus_cmd *cmd;
-       int lock;
-
-       /*
-        * If we fall here in the middle of association,
-        * associate_bss() should be waiting for complation of
-        * wl->assoc_done.
-        * As it waits with timeout, just leave assoc_done
-        * uncompleted, then it terminates with timeout
-        */
-       if (!mutex_trylock(&wl->assoc_stat_lock)) {
-               pr_debug("%s: already locked\n", __func__);
-               lock = 0;
-       } else {
-               pr_debug("%s: obtain lock\n", __func__);
-               lock = 1;
-       }
-
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
-       kfree(cmd);
-
-       /* send disconnected event to the supplicant */
-       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
-               gelic_wl_send_iwap_event(wl, NULL);
-
-       wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
-       netif_carrier_off(port_to_netdev(wl_port(wl)));
-
-       if (lock)
-               mutex_unlock(&wl->assoc_stat_lock);
-}
-/*
- * event worker
- */
-#ifdef DEBUG
-static const char *eventstr(enum gelic_lv1_wl_event event)
-{
-       static char buf[32];
-       char *ret;
-       if (event & GELIC_LV1_WL_EVENT_DEVICE_READY)
-               ret = "EURUS_READY";
-       else if (event & GELIC_LV1_WL_EVENT_SCAN_COMPLETED)
-               ret = "SCAN_COMPLETED";
-       else if (event & GELIC_LV1_WL_EVENT_DEAUTH)
-               ret = "DEAUTH";
-       else if (event & GELIC_LV1_WL_EVENT_BEACON_LOST)
-               ret = "BEACON_LOST";
-       else if (event & GELIC_LV1_WL_EVENT_CONNECTED)
-               ret = "CONNECTED";
-       else if (event & GELIC_LV1_WL_EVENT_WPA_CONNECTED)
-               ret = "WPA_CONNECTED";
-       else if (event & GELIC_LV1_WL_EVENT_WPA_ERROR)
-               ret = "WPA_ERROR";
-       else {
-               sprintf(buf, "Unknown(%#x)", event);
-               ret = buf;
-       }
-       return ret;
-}
-#else
-static const char *eventstr(enum gelic_lv1_wl_event event)
-{
-       return NULL;
-}
-#endif
-static void gelic_wl_event_worker(struct work_struct *work)
-{
-       struct gelic_wl_info *wl;
-       struct gelic_port *port;
-       u64 event, tmp;
-       int status;
-
-       pr_debug("%s:start\n", __func__);
-       wl = container_of(work, struct gelic_wl_info, event_work.work);
-       port = wl_port(wl);
-       while (1) {
-               status = lv1_net_control(bus_id(port->card), dev_id(port->card),
-                                        GELIC_LV1_GET_WLAN_EVENT, 0, 0, 0,
-                                        &event, &tmp);
-               if (status) {
-                       if (status != LV1_NO_ENTRY)
-                               pr_debug("%s:wlan event failed %d\n",
-                                        __func__, status);
-                       /* got all events */
-                       pr_debug("%s:end\n", __func__);
-                       return;
-               }
-               pr_debug("%s: event=%s\n", __func__, eventstr(event));
-               switch (event) {
-               case GELIC_LV1_WL_EVENT_SCAN_COMPLETED:
-                       gelic_wl_scan_complete_event(wl);
-                       break;
-               case GELIC_LV1_WL_EVENT_BEACON_LOST:
-               case GELIC_LV1_WL_EVENT_DEAUTH:
-                       gelic_wl_disconnect_event(wl, event);
-                       break;
-               case GELIC_LV1_WL_EVENT_CONNECTED:
-               case GELIC_LV1_WL_EVENT_WPA_CONNECTED:
-                       gelic_wl_connected_event(wl, event);
-                       break;
-               default:
-                       break;
-               }
-       } /* while */
-}
-/*
- * association worker
- */
-static void gelic_wl_assoc_worker(struct work_struct *work)
-{
-       struct gelic_wl_info *wl;
-
-       struct gelic_wl_scan_info *best_bss;
-       int ret;
-       unsigned long irqflag;
-       u8 *essid;
-       size_t essid_len;
-
-       wl = container_of(work, struct gelic_wl_info, assoc_work.work);
-
-       mutex_lock(&wl->assoc_stat_lock);
-
-       if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
-               goto out;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
-               pr_debug("%s: assoc ESSID configured %s\n", __func__,
-                        wl->essid);
-               essid = wl->essid;
-               essid_len = wl->essid_len;
-       } else {
-               essid = NULL;
-               essid_len = 0;
-       }
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-
-       ret = gelic_wl_start_scan(wl, 0, essid, essid_len);
-       if (ret == -ERESTARTSYS) {
-               pr_debug("%s: scan start failed association\n", __func__);
-               schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
-               goto out;
-       } else if (ret) {
-               pr_info("%s: scan prerequisite failed\n", __func__);
-               goto out;
-       }
-
-       /*
-        * Wait for bss scan completion
-        * If we have scan list already, gelic_wl_start_scan()
-        * returns OK and raises the complete.  Thus,
-        * it's ok to wait unconditionally here
-        */
-       wait_for_completion(&wl->scan_done);
-
-       pr_debug("%s: scan done\n", __func__);
-       mutex_lock(&wl->scan_lock);
-       if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) {
-               gelic_wl_send_iwap_event(wl, NULL);
-               pr_info("%s: no scan list. association failed\n", __func__);
-               goto scan_lock_out;
-       }
-
-       /* find best matching bss */
-       best_bss = gelic_wl_find_best_bss(wl);
-       if (!best_bss) {
-               gelic_wl_send_iwap_event(wl, NULL);
-               pr_info("%s: no bss matched. association failed\n", __func__);
-               goto scan_lock_out;
-       }
-
-       /* ok, do association */
-       ret = gelic_wl_associate_bss(wl, best_bss);
-       if (ret)
-               pr_info("%s: association failed %d\n", __func__, ret);
-scan_lock_out:
-       mutex_unlock(&wl->scan_lock);
-out:
-       mutex_unlock(&wl->assoc_stat_lock);
-}
-/*
- * Interrupt handler
- * Called from the ethernet interrupt handler
- * Processes wireless specific virtual interrupts only
- */
-void gelic_wl_interrupt(struct net_device *netdev, u64 status)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-
-       if (status & GELIC_CARD_WLAN_COMMAND_COMPLETED) {
-               pr_debug("%s:cmd complete\n", __func__);
-               complete(&wl->cmd_done_intr);
-       }
-
-       if (status & GELIC_CARD_WLAN_EVENT_RECEIVED) {
-               pr_debug("%s:event received\n", __func__);
-               queue_delayed_work(wl->event_queue, &wl->event_work, 0);
-       }
-}
-
-/*
- * driver helpers
- */
-static const iw_handler gelic_wl_wext_handler[] =
-{
-       IW_HANDLER(SIOCGIWNAME, gelic_wl_get_name),
-       IW_HANDLER(SIOCGIWRANGE, gelic_wl_get_range),
-       IW_HANDLER(SIOCSIWSCAN, gelic_wl_set_scan),
-       IW_HANDLER(SIOCGIWSCAN, gelic_wl_get_scan),
-       IW_HANDLER(SIOCSIWAUTH, gelic_wl_set_auth),
-       IW_HANDLER(SIOCGIWAUTH, gelic_wl_get_auth),
-       IW_HANDLER(SIOCSIWESSID, gelic_wl_set_essid),
-       IW_HANDLER(SIOCGIWESSID, gelic_wl_get_essid),
-       IW_HANDLER(SIOCSIWENCODE, gelic_wl_set_encode),
-       IW_HANDLER(SIOCGIWENCODE, gelic_wl_get_encode),
-       IW_HANDLER(SIOCSIWAP, gelic_wl_set_ap),
-       IW_HANDLER(SIOCGIWAP, gelic_wl_get_ap),
-       IW_HANDLER(SIOCSIWENCODEEXT, gelic_wl_set_encodeext),
-       IW_HANDLER(SIOCGIWENCODEEXT, gelic_wl_get_encodeext),
-       IW_HANDLER(SIOCSIWMODE, gelic_wl_set_mode),
-       IW_HANDLER(SIOCGIWMODE, gelic_wl_get_mode),
-       IW_HANDLER(SIOCGIWNICKN, gelic_wl_get_nick),
-};
-
-static const struct iw_handler_def gelic_wl_wext_handler_def = {
-       .num_standard           = ARRAY_SIZE(gelic_wl_wext_handler),
-       .standard               = gelic_wl_wext_handler,
-       .get_wireless_stats     = gelic_wl_get_wireless_stats,
-};
-
-static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card)
-{
-       struct net_device *netdev;
-       struct gelic_port *port;
-       struct gelic_wl_info *wl;
-       unsigned int i;
-
-       pr_debug("%s:start\n", __func__);
-       netdev = alloc_etherdev(sizeof(struct gelic_port) +
-                               sizeof(struct gelic_wl_info));
-       pr_debug("%s: netdev =%p card=%p\n", __func__, netdev, card);
-       if (!netdev)
-               return NULL;
-
-       strcpy(netdev->name, "wlan%d");
-
-       port = netdev_priv(netdev);
-       port->netdev = netdev;
-       port->card = card;
-       port->type = GELIC_PORT_WIRELESS;
-
-       wl = port_wl(port);
-       pr_debug("%s: wl=%p port=%p\n", __func__, wl, port);
-
-       /* allocate scan list */
-       wl->networks = kzalloc(sizeof(struct gelic_wl_scan_info) *
-                              GELIC_WL_BSS_MAX_ENT, GFP_KERNEL);
-
-       if (!wl->networks)
-               goto fail_bss;
-
-       wl->eurus_cmd_queue = create_singlethread_workqueue("gelic_cmd");
-       if (!wl->eurus_cmd_queue)
-               goto fail_cmd_workqueue;
-
-       wl->event_queue = create_singlethread_workqueue("gelic_event");
-       if (!wl->event_queue)
-               goto fail_event_workqueue;
-
-       INIT_LIST_HEAD(&wl->network_free_list);
-       INIT_LIST_HEAD(&wl->network_list);
-       for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++)
-               list_add_tail(&wl->networks[i].list,
-                             &wl->network_free_list);
-       init_completion(&wl->cmd_done_intr);
-
-       INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker);
-       INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker);
-       mutex_init(&wl->scan_lock);
-       mutex_init(&wl->assoc_stat_lock);
-
-       init_completion(&wl->scan_done);
-       /* for the case that no scan request is issued and stop() is called */
-       complete(&wl->scan_done);
-
-       spin_lock_init(&wl->lock);
-
-       wl->scan_age = 5*HZ; /* FIXME */
-
-       /* buffer for receiving scanned list etc */
-       BUILD_BUG_ON(PAGE_SIZE <
-                    sizeof(struct gelic_eurus_scan_info) *
-                    GELIC_EURUS_MAX_SCAN);
-       pr_debug("%s:end\n", __func__);
-       return netdev;
-
-fail_event_workqueue:
-       destroy_workqueue(wl->eurus_cmd_queue);
-fail_cmd_workqueue:
-       kfree(wl->networks);
-fail_bss:
-       free_netdev(netdev);
-       pr_debug("%s:end error\n", __func__);
-       return NULL;
-
-}
-
-static void gelic_wl_free(struct gelic_wl_info *wl)
-{
-       struct gelic_wl_scan_info *scan_info;
-       unsigned int i;
-
-       pr_debug("%s: <-\n", __func__);
-
-       pr_debug("%s: destroy queues\n", __func__);
-       destroy_workqueue(wl->eurus_cmd_queue);
-       destroy_workqueue(wl->event_queue);
-
-       scan_info = wl->networks;
-       for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++, scan_info++)
-               kfree(scan_info->hwinfo);
-       kfree(wl->networks);
-
-       free_netdev(port_to_netdev(wl_port(wl)));
-
-       pr_debug("%s: ->\n", __func__);
-}
-
-static int gelic_wl_try_associate(struct net_device *netdev)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-       int ret = -1;
-       unsigned int i;
-
-       pr_debug("%s: <-\n", __func__);
-
-       /* check constraits for start association */
-       /* for no access restriction AP */
-       if (wl->group_cipher_method == GELIC_WL_CIPHER_NONE) {
-               if (test_bit(GELIC_WL_STAT_CONFIGURED,
-                            &wl->stat))
-                       goto do_associate;
-               else {
-                       pr_debug("%s: no wep, not configured\n", __func__);
-                       return ret;
-               }
-       }
-
-       /* for WEP, one of four keys should be set */
-       if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
-               /* one of keys set */
-               for (i = 0; i < GELIC_WEP_KEYS; i++) {
-                       if (test_bit(i, &wl->key_enabled))
-                           goto do_associate;
-               }
-               pr_debug("%s: WEP, but no key specified\n", __func__);
-               return ret;
-       }
-
-       /* for WPA[2], psk should be set */
-       if ((wl->group_cipher_method == GELIC_WL_CIPHER_TKIP) ||
-           (wl->group_cipher_method == GELIC_WL_CIPHER_AES)) {
-               if (test_bit(GELIC_WL_STAT_WPA_PSK_SET,
-                            &wl->stat))
-                       goto do_associate;
-               else {
-                       pr_debug("%s: AES/TKIP, but PSK not configured\n",
-                                __func__);
-                       return ret;
-               }
-       }
-
-do_associate:
-       ret = schedule_delayed_work(&wl->assoc_work, 0);
-       pr_debug("%s: start association work %d\n", __func__, ret);
-       return ret;
-}
-
-/*
- * netdev handlers
- */
-static int gelic_wl_open(struct net_device *netdev)
-{
-       struct gelic_card *card = netdev_card(netdev);
-
-       pr_debug("%s:->%p\n", __func__, netdev);
-
-       gelic_card_up(card);
-
-       /* try to associate */
-       gelic_wl_try_associate(netdev);
-
-       netif_start_queue(netdev);
-
-       pr_debug("%s:<-\n", __func__);
-       return 0;
-}
-
-/*
- * reset state machine
- */
-static int gelic_wl_reset_state(struct gelic_wl_info *wl)
-{
-       struct gelic_wl_scan_info *target;
-       struct gelic_wl_scan_info *tmp;
-
-       /* empty scan list */
-       list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
-               list_move_tail(&target->list, &wl->network_free_list);
-       }
-       wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
-
-       /* clear configuration */
-       wl->auth_method = GELIC_EURUS_AUTH_OPEN;
-       wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
-       wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
-       wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
-
-       wl->key_enabled = 0;
-       wl->current_key = 0;
-
-       wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
-       wl->psk_len = 0;
-
-       wl->essid_len = 0;
-       memset(wl->essid, 0, sizeof(wl->essid));
-       memset(wl->bssid, 0, sizeof(wl->bssid));
-       memset(wl->active_bssid, 0, sizeof(wl->active_bssid));
-
-       wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
-
-       memset(&wl->iwstat, 0, sizeof(wl->iwstat));
-       /* all status bit clear */
-       wl->stat = 0;
-       return 0;
-}
-
-/*
- * Tell eurus to terminate association
- */
-static void gelic_wl_disconnect(struct net_device *netdev)
-{
-       struct gelic_port *port = netdev_priv(netdev);
-       struct gelic_wl_info *wl = port_wl(port);
-       struct gelic_eurus_cmd *cmd;
-
-       /*
-        * If scann process is running on chip,
-        * further requests will be rejected
-        */
-       if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING)
-               wait_for_completion_timeout(&wl->scan_done, HZ);
-
-       cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
-       kfree(cmd);
-       gelic_wl_send_iwap_event(wl, NULL);
-};
-
-static int gelic_wl_stop(struct net_device *netdev)
-{
-       struct gelic_port *port = netdev_priv(netdev);
-       struct gelic_wl_info *wl = port_wl(port);
-       struct gelic_card *card = netdev_card(netdev);
-
-       pr_debug("%s:<-\n", __func__);
-
-       /*
-        * Cancel pending association work.
-        * event work can run after netdev down
-        */
-       cancel_delayed_work(&wl->assoc_work);
-
-       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
-               gelic_wl_disconnect(netdev);
-
-       /* reset our state machine */
-       gelic_wl_reset_state(wl);
-
-       netif_stop_queue(netdev);
-
-       gelic_card_down(card);
-
-       pr_debug("%s:->\n", __func__);
-       return 0;
-}
-
-/* -- */
-
-static const struct net_device_ops gelic_wl_netdevice_ops = {
-       .ndo_open = gelic_wl_open,
-       .ndo_stop = gelic_wl_stop,
-       .ndo_start_xmit = gelic_net_xmit,
-       .ndo_set_multicast_list = gelic_net_set_multi,
-       .ndo_change_mtu = gelic_net_change_mtu,
-       .ndo_tx_timeout = gelic_net_tx_timeout,
-       .ndo_set_mac_address = eth_mac_addr,
-       .ndo_validate_addr = eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller = gelic_net_poll_controller,
-#endif
-};
-
-static const struct ethtool_ops gelic_wl_ethtool_ops = {
-       .get_drvinfo    = gelic_net_get_drvinfo,
-       .get_link       = gelic_wl_get_link,
-};
-
-static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev)
-{
-       struct gelic_wl_info *wl;
-       wl = port_wl(netdev_priv(netdev));
-       BUG_ON(!wl);
-       netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
-
-       netdev->ethtool_ops = &gelic_wl_ethtool_ops;
-       netdev->netdev_ops = &gelic_wl_netdevice_ops;
-       netdev->wireless_data = &wl->wireless_data;
-       netdev->wireless_handlers = &gelic_wl_wext_handler_def;
-}
-
-/*
- * driver probe/remove
- */
-int __devinit gelic_wl_driver_probe(struct gelic_card *card)
-{
-       int ret;
-       struct net_device *netdev;
-
-       pr_debug("%s:start\n", __func__);
-
-       if (ps3_compare_firmware_version(1, 6, 0) < 0)
-               return 0;
-       if (!card->vlan[GELIC_PORT_WIRELESS].tx)
-               return 0;
-
-       /* alloc netdevice for wireless */
-       netdev = gelic_wl_alloc(card);
-       if (!netdev)
-               return -ENOMEM;
-
-       /* setup net_device structure */
-       SET_NETDEV_DEV(netdev, &card->dev->core);
-       gelic_wl_setup_netdev_ops(netdev);
-
-       /* setup some of net_device and register it */
-       ret = gelic_net_setup_netdev(netdev, card);
-       if (ret)
-               goto fail_setup;
-       card->netdev[GELIC_PORT_WIRELESS] = netdev;
-
-       /* add enable wireless interrupt */
-       card->irq_mask |= GELIC_CARD_WLAN_EVENT_RECEIVED |
-               GELIC_CARD_WLAN_COMMAND_COMPLETED;
-       /* to allow wireless commands while both interfaces are down */
-       gelic_card_set_irq_mask(card, GELIC_CARD_WLAN_EVENT_RECEIVED |
-                               GELIC_CARD_WLAN_COMMAND_COMPLETED);
-       pr_debug("%s:end\n", __func__);
-       return 0;
-
-fail_setup:
-       gelic_wl_free(port_wl(netdev_port(netdev)));
-
-       return ret;
-}
-
-int gelic_wl_driver_remove(struct gelic_card *card)
-{
-       struct gelic_wl_info *wl;
-       struct net_device *netdev;
-
-       pr_debug("%s:start\n", __func__);
-
-       if (ps3_compare_firmware_version(1, 6, 0) < 0)
-               return 0;
-       if (!card->vlan[GELIC_PORT_WIRELESS].tx)
-               return 0;
-
-       netdev = card->netdev[GELIC_PORT_WIRELESS];
-       wl = port_wl(netdev_priv(netdev));
-
-       /* if the interface was not up, but associated */
-       if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
-               gelic_wl_disconnect(netdev);
-
-       complete(&wl->cmd_done_intr);
-
-       /* cancel all work queue */
-       cancel_delayed_work(&wl->assoc_work);
-       cancel_delayed_work(&wl->event_work);
-       flush_workqueue(wl->eurus_cmd_queue);
-       flush_workqueue(wl->event_queue);
-
-       unregister_netdev(netdev);
-
-       /* disable wireless interrupt */
-       pr_debug("%s: disable intr\n", __func__);
-       card->irq_mask &= ~(GELIC_CARD_WLAN_EVENT_RECEIVED |
-                           GELIC_CARD_WLAN_COMMAND_COMPLETED);
-       /* free bss list, netdev*/
-       gelic_wl_free(wl);
-       pr_debug("%s:end\n", __func__);
-       return 0;
-}
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
deleted file mode 100644 (file)
index f7e51b7..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *  PS3 gelic network driver.
- *
- * Copyright (C) 2007 Sony Computer Entertainment Inc.
- * Copyright 2007 Sony Corporation
- *
- * 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 version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef _GELIC_WIRELESS_H
-#define _GELIC_WIRELESS_H
-
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-
-/* return value from  GELIC_LV1_GET_WLAN_EVENT netcontrol */
-enum gelic_lv1_wl_event {
-       GELIC_LV1_WL_EVENT_DEVICE_READY   = 0x01, /* Eurus ready */
-       GELIC_LV1_WL_EVENT_SCAN_COMPLETED = 0x02, /* Scan has completed */
-       GELIC_LV1_WL_EVENT_DEAUTH         = 0x04, /* Deauthed by the AP */
-       GELIC_LV1_WL_EVENT_BEACON_LOST    = 0x08, /* Beacon lost detected */
-       GELIC_LV1_WL_EVENT_CONNECTED      = 0x10, /* Connected to AP */
-       GELIC_LV1_WL_EVENT_WPA_CONNECTED  = 0x20, /* WPA connection */
-       GELIC_LV1_WL_EVENT_WPA_ERROR      = 0x40, /* MIC error */
-};
-
-/* arguments for GELIC_LV1_POST_WLAN_COMMAND netcontrol */
-enum gelic_eurus_command {
-       GELIC_EURUS_CMD_ASSOC           =  1, /* association start */
-       GELIC_EURUS_CMD_DISASSOC        =  2, /* disassociate      */
-       GELIC_EURUS_CMD_START_SCAN      =  3, /* scan start        */
-       GELIC_EURUS_CMD_GET_SCAN        =  4, /* get scan result   */
-       GELIC_EURUS_CMD_SET_COMMON_CFG  =  5, /* set common config */
-       GELIC_EURUS_CMD_GET_COMMON_CFG  =  6, /* set common config */
-       GELIC_EURUS_CMD_SET_WEP_CFG     =  7, /* set WEP config    */
-       GELIC_EURUS_CMD_GET_WEP_CFG     =  8, /* get WEP config    */
-       GELIC_EURUS_CMD_SET_WPA_CFG     =  9, /* set WPA config    */
-       GELIC_EURUS_CMD_GET_WPA_CFG     = 10, /* get WPA config    */
-       GELIC_EURUS_CMD_GET_RSSI_CFG    = 11, /* get RSSI info.    */
-       GELIC_EURUS_CMD_MAX_INDEX
-};
-
-/* for GELIC_EURUS_CMD_COMMON_CFG */
-enum gelic_eurus_bss_type {
-       GELIC_EURUS_BSS_INFRA = 0,
-       GELIC_EURUS_BSS_ADHOC = 1, /* not supported */
-};
-
-enum gelic_eurus_auth_method {
-       GELIC_EURUS_AUTH_OPEN = 0, /* FIXME: WLAN_AUTH_OPEN */
-       GELIC_EURUS_AUTH_SHARED = 1, /* not supported */
-};
-
-enum gelic_eurus_opmode {
-       GELIC_EURUS_OPMODE_11BG = 0, /* 802.11b/g */
-       GELIC_EURUS_OPMODE_11B = 1, /* 802.11b only */
-       GELIC_EURUS_OPMODE_11G = 2, /* 802.11g only */
-};
-
-struct gelic_eurus_common_cfg {
-       /* all fields are big endian */
-       u16 scan_index;
-       u16 bss_type;    /* infra or adhoc */
-       u16 auth_method; /* shared key or open */
-       u16 op_mode; /* B/G */
-} __packed;
-
-
-/* for GELIC_EURUS_CMD_WEP_CFG */
-enum gelic_eurus_wep_security {
-       GELIC_EURUS_WEP_SEC_NONE        = 0,
-       GELIC_EURUS_WEP_SEC_40BIT       = 1,
-       GELIC_EURUS_WEP_SEC_104BIT      = 2,
-};
-
-struct gelic_eurus_wep_cfg {
-       /* all fields are big endian */
-       u16 security;
-       u8 key[4][16];
-} __packed;
-
-/* for GELIC_EURUS_CMD_WPA_CFG */
-enum gelic_eurus_wpa_security {
-       GELIC_EURUS_WPA_SEC_NONE                = 0x0000,
-       /* group=TKIP, pairwise=TKIP */
-       GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP       = 0x0001,
-       /* group=AES, pairwise=AES */
-       GELIC_EURUS_WPA_SEC_WPA_AES_AES         = 0x0002,
-       /* group=TKIP, pairwise=TKIP */
-       GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP      = 0x0004,
-       /* group=AES, pairwise=AES */
-       GELIC_EURUS_WPA_SEC_WPA2_AES_AES        = 0x0008,
-       /* group=TKIP, pairwise=AES */
-       GELIC_EURUS_WPA_SEC_WPA_TKIP_AES        = 0x0010,
-       /* group=TKIP, pairwise=AES */
-       GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES       = 0x0020,
-};
-
-enum gelic_eurus_wpa_psk_type {
-       GELIC_EURUS_WPA_PSK_PASSPHRASE  = 0, /* passphrase string   */
-       GELIC_EURUS_WPA_PSK_BIN         = 1, /* 32 bytes binary key */
-};
-
-#define GELIC_WL_EURUS_PSK_MAX_LEN     64
-#define WPA_PSK_LEN                    32 /* WPA spec says 256bit */
-
-struct gelic_eurus_wpa_cfg {
-       /* all fields are big endian */
-       u16 security;
-       u16 psk_type; /* psk key encoding type */
-       u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */
-} __packed;
-
-/* for GELIC_EURUS_CMD_{START,GET}_SCAN */
-enum gelic_eurus_scan_capability {
-       GELIC_EURUS_SCAN_CAP_ADHOC      = 0x0000,
-       GELIC_EURUS_SCAN_CAP_INFRA      = 0x0001,
-       GELIC_EURUS_SCAN_CAP_MASK       = 0x0001,
-};
-
-enum gelic_eurus_scan_sec_type {
-       GELIC_EURUS_SCAN_SEC_NONE       = 0x0000,
-       GELIC_EURUS_SCAN_SEC_WEP        = 0x0100,
-       GELIC_EURUS_SCAN_SEC_WPA        = 0x0200,
-       GELIC_EURUS_SCAN_SEC_WPA2       = 0x0400,
-       GELIC_EURUS_SCAN_SEC_MASK       = 0x0f00,
-};
-
-enum gelic_eurus_scan_sec_wep_type {
-       GELIC_EURUS_SCAN_SEC_WEP_UNKNOWN        = 0x0000,
-       GELIC_EURUS_SCAN_SEC_WEP_40             = 0x0001,
-       GELIC_EURUS_SCAN_SEC_WEP_104            = 0x0002,
-       GELIC_EURUS_SCAN_SEC_WEP_MASK           = 0x0003,
-};
-
-enum gelic_eurus_scan_sec_wpa_type {
-       GELIC_EURUS_SCAN_SEC_WPA_UNKNOWN        = 0x0000,
-       GELIC_EURUS_SCAN_SEC_WPA_TKIP           = 0x0001,
-       GELIC_EURUS_SCAN_SEC_WPA_AES            = 0x0002,
-       GELIC_EURUS_SCAN_SEC_WPA_MASK           = 0x0003,
-};
-
-/*
- * hw BSS information structure returned from GELIC_EURUS_CMD_GET_SCAN
- */
-struct gelic_eurus_scan_info {
-       /* all fields are big endian */
-       __be16 size;
-       __be16 rssi; /* percentage */
-       __be16 channel; /* channel number */
-       __be16 beacon_period; /* FIXME: in msec unit */
-       __be16 capability;
-       __be16 security;
-       u8  bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */
-       u8  essid[32]; /* IW_ESSID_MAX_SIZE */
-       u8  rate[16]; /* first 12 are valid */
-       u8  ext_rate[16]; /* first 16 are valid */
-       __be32 reserved1;
-       __be32 reserved2;
-       __be32 reserved3;
-       __be32 reserved4;
-       u8 elements[0]; /* ie */
-} __packed;
-
-/* the hypervisor returns bbs up to 16 */
-#define GELIC_EURUS_MAX_SCAN  (16)
-struct gelic_wl_scan_info {
-       struct list_head list;
-       struct gelic_eurus_scan_info *hwinfo;
-
-       int valid; /* set 1 if this entry was in latest scanned list
-                    * from Eurus */
-       unsigned int eurus_index; /* index in the Eurus list */
-       unsigned long last_scanned; /* acquired time */
-
-       unsigned int rate_len;
-       unsigned int rate_ext_len;
-       unsigned int essid_len;
-};
-
-/* for GELIC_EURUS_CMD_GET_RSSI */
-struct gelic_eurus_rssi_info {
-       /* big endian */
-       __be16 rssi;
-} __packed;
-
-
-/* for 'stat' member of gelic_wl_info */
-enum gelic_wl_info_status_bit {
-       GELIC_WL_STAT_CONFIGURED,
-       GELIC_WL_STAT_CH_INFO,   /* ch info acquired */
-       GELIC_WL_STAT_ESSID_SET, /* ESSID specified by userspace */
-       GELIC_WL_STAT_BSSID_SET, /* BSSID specified by userspace */
-       GELIC_WL_STAT_WPA_PSK_SET, /* PMK specified by userspace */
-       GELIC_WL_STAT_WPA_LEVEL_SET, /* WEP or WPA[2] selected */
-};
-
-/* for 'scan_stat' member of gelic_wl_info */
-enum gelic_wl_scan_state {
-       /* just initialized or get last scan result failed */
-       GELIC_WL_SCAN_STAT_INIT,
-       /* scan request issued, accepted or chip is scanning */
-       GELIC_WL_SCAN_STAT_SCANNING,
-       /* scan results retrieved */
-       GELIC_WL_SCAN_STAT_GOT_LIST,
-};
-
-/* for 'cipher_method' */
-enum gelic_wl_cipher_method {
-       GELIC_WL_CIPHER_NONE,
-       GELIC_WL_CIPHER_WEP,
-       GELIC_WL_CIPHER_TKIP,
-       GELIC_WL_CIPHER_AES,
-};
-
-/* for 'wpa_level' */
-enum gelic_wl_wpa_level {
-       GELIC_WL_WPA_LEVEL_NONE,
-       GELIC_WL_WPA_LEVEL_WPA,
-       GELIC_WL_WPA_LEVEL_WPA2,
-};
-
-/* for 'assoc_stat' */
-enum gelic_wl_assoc_state {
-       GELIC_WL_ASSOC_STAT_DISCONN,
-       GELIC_WL_ASSOC_STAT_ASSOCIATING,
-       GELIC_WL_ASSOC_STAT_ASSOCIATED,
-};
-/* part of private data alloc_etherdev() allocated */
-#define GELIC_WEP_KEYS 4
-struct gelic_wl_info {
-       /* bss list */
-       struct mutex scan_lock;
-       struct list_head network_list;
-       struct list_head network_free_list;
-       struct gelic_wl_scan_info *networks;
-
-       unsigned long scan_age; /* last scanned time */
-       enum gelic_wl_scan_state scan_stat;
-       struct completion scan_done;
-
-       /* eurus command queue */
-       struct workqueue_struct *eurus_cmd_queue;
-       struct completion cmd_done_intr;
-
-       /* eurus event handling */
-       struct workqueue_struct *event_queue;
-       struct delayed_work event_work;
-
-       /* wl status bits */
-       unsigned long stat;
-       enum gelic_eurus_auth_method auth_method; /* open/shared */
-       enum gelic_wl_cipher_method group_cipher_method;
-       enum gelic_wl_cipher_method pairwise_cipher_method;
-       enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */
-
-       /* association handling */
-       struct mutex assoc_stat_lock;
-       struct delayed_work assoc_work;
-       enum gelic_wl_assoc_state assoc_stat;
-       struct completion assoc_done;
-
-       spinlock_t lock;
-       u16 ch_info; /* available channels. bit0 = ch1 */
-       /* WEP keys */
-       u8 key[GELIC_WEP_KEYS][IW_ENCODING_TOKEN_MAX];
-       unsigned long key_enabled;
-       unsigned int key_len[GELIC_WEP_KEYS];
-       unsigned int current_key;
-       /* WWPA PSK */
-       u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN];
-       enum gelic_eurus_wpa_psk_type psk_type;
-       unsigned int psk_len;
-
-       u8 essid[IW_ESSID_MAX_SIZE];
-       u8 bssid[ETH_ALEN]; /* userland requested */
-       u8 active_bssid[ETH_ALEN]; /* associated bssid */
-       unsigned int essid_len;
-
-       struct iw_public_data wireless_data;
-       struct iw_statistics iwstat;
-};
-
-#define GELIC_WL_BSS_MAX_ENT 32
-#define GELIC_WL_ASSOC_RETRY 50
-static inline struct gelic_port *wl_port(struct gelic_wl_info *wl)
-{
-       return container_of((void *)wl, struct gelic_port, priv);
-}
-static inline struct gelic_wl_info *port_wl(struct gelic_port *port)
-{
-       return port_priv(port);
-}
-
-struct gelic_eurus_cmd {
-       struct work_struct work;
-       struct gelic_wl_info *wl;
-       unsigned int cmd; /* command code */
-       u64 tag;
-       u64 size;
-       void *buffer;
-       unsigned int buf_size;
-       struct completion done;
-       int status;
-       u64 cmd_status;
-};
-
-/* private ioctls to pass PSK */
-#define GELIC_WL_PRIV_SET_PSK          (SIOCIWFIRSTPRIV + 0)
-#define GELIC_WL_PRIV_GET_PSK          (SIOCIWFIRSTPRIV + 1)
-
-extern int gelic_wl_driver_probe(struct gelic_card *card);
-extern int gelic_wl_driver_remove(struct gelic_card *card);
-extern void gelic_wl_interrupt(struct net_device *netdev, u64 status);
-#endif /* _GELIC_WIRELESS_H */
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
deleted file mode 100644 (file)
index 1ff3491..0000000
+++ /dev/null
@@ -1,2603 +0,0 @@
-/*
- * Network device driver for Cell Processor-Based Blade and Celleb platform
- *
- * (C) Copyright IBM Corp. 2005
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * Authors : Utz Bacher <utz.bacher@de.ibm.com>
- *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/compiler.h>
-#include <linux/crc32.h>
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/firmware.h>
-#include <linux/if_vlan.h>
-#include <linux/in.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/gfp.h>
-#include <linux/ioport.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/mii.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/device.h>
-#include <linux/pci.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/bitops.h>
-#include <asm/pci-bridge.h>
-#include <net/checksum.h>
-
-#include "spider_net.h"
-
-MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \
-             "<Jens.Osterkamp@de.ibm.com>");
-MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(VERSION);
-MODULE_FIRMWARE(SPIDER_NET_FIRMWARE_NAME);
-
-static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;
-static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;
-
-module_param(rx_descriptors, int, 0444);
-module_param(tx_descriptors, int, 0444);
-
-MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \
-                "in rx chains");
-MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \
-                "in tx chain");
-
-char spider_net_driver_name[] = "spidernet";
-
-static DEFINE_PCI_DEVICE_TABLE(spider_net_pci_tbl) = {
-       { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
-
-/**
- * spider_net_read_reg - reads an SMMIO register of a card
- * @card: device structure
- * @reg: register to read from
- *
- * returns the content of the specified SMMIO register.
- */
-static inline u32
-spider_net_read_reg(struct spider_net_card *card, u32 reg)
-{
-       /* We use the powerpc specific variants instead of readl_be() because
-        * we know spidernet is not a real PCI device and we can thus avoid the
-        * performance hit caused by the PCI workarounds.
-        */
-       return in_be32(card->regs + reg);
-}
-
-/**
- * spider_net_write_reg - writes to an SMMIO register of a card
- * @card: device structure
- * @reg: register to write to
- * @value: value to write into the specified SMMIO register
- */
-static inline void
-spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
-{
-       /* We use the powerpc specific variants instead of writel_be() because
-        * we know spidernet is not a real PCI device and we can thus avoid the
-        * performance hit caused by the PCI workarounds.
-        */
-       out_be32(card->regs + reg, value);
-}
-
-/** spider_net_write_phy - write to phy register
- * @netdev: adapter to be written to
- * @mii_id: id of MII
- * @reg: PHY register
- * @val: value to be written to phy register
- *
- * spider_net_write_phy_register writes to an arbitrary PHY
- * register via the spider GPCWOPCMD register. We assume the queue does
- * not run full (not more than 15 commands outstanding).
- **/
-static void
-spider_net_write_phy(struct net_device *netdev, int mii_id,
-                    int reg, int val)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-       u32 writevalue;
-
-       writevalue = ((u32)mii_id << 21) |
-               ((u32)reg << 16) | ((u32)val);
-
-       spider_net_write_reg(card, SPIDER_NET_GPCWOPCMD, writevalue);
-}
-
-/** spider_net_read_phy - read from phy register
- * @netdev: network device to be read from
- * @mii_id: id of MII
- * @reg: PHY register
- *
- * Returns value read from PHY register
- *
- * spider_net_write_phy reads from an arbitrary PHY
- * register via the spider GPCROPCMD register
- **/
-static int
-spider_net_read_phy(struct net_device *netdev, int mii_id, int reg)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-       u32 readvalue;
-
-       readvalue = ((u32)mii_id << 21) | ((u32)reg << 16);
-       spider_net_write_reg(card, SPIDER_NET_GPCROPCMD, readvalue);
-
-       /* we don't use semaphores to wait for an SPIDER_NET_GPROPCMPINT
-        * interrupt, as we poll for the completion of the read operation
-        * in spider_net_read_phy. Should take about 50 us */
-       do {
-               readvalue = spider_net_read_reg(card, SPIDER_NET_GPCROPCMD);
-       } while (readvalue & SPIDER_NET_GPREXEC);
-
-       readvalue &= SPIDER_NET_GPRDAT_MASK;
-
-       return readvalue;
-}
-
-/**
- * spider_net_setup_aneg - initial auto-negotiation setup
- * @card: device structure
- **/
-static void
-spider_net_setup_aneg(struct spider_net_card *card)
-{
-       struct mii_phy *phy = &card->phy;
-       u32 advertise = 0;
-       u16 bmsr, estat;
-
-       bmsr  = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
-       estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS);
-
-       if (bmsr & BMSR_10HALF)
-               advertise |= ADVERTISED_10baseT_Half;
-       if (bmsr & BMSR_10FULL)
-               advertise |= ADVERTISED_10baseT_Full;
-       if (bmsr & BMSR_100HALF)
-               advertise |= ADVERTISED_100baseT_Half;
-       if (bmsr & BMSR_100FULL)
-               advertise |= ADVERTISED_100baseT_Full;
-
-       if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL))
-               advertise |= SUPPORTED_1000baseT_Full;
-       if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
-               advertise |= SUPPORTED_1000baseT_Half;
-
-       mii_phy_probe(phy, phy->mii_id);
-       phy->def->ops->setup_aneg(phy, advertise);
-
-}
-
-/**
- * spider_net_rx_irq_off - switch off rx irq on this spider card
- * @card: device structure
- *
- * switches off rx irq by masking them out in the GHIINTnMSK register
- */
-static void
-spider_net_rx_irq_off(struct spider_net_card *card)
-{
-       u32 regvalue;
-
-       regvalue = SPIDER_NET_INT0_MASK_VALUE & (~SPIDER_NET_RXINT);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);
-}
-
-/**
- * spider_net_rx_irq_on - switch on rx irq on this spider card
- * @card: device structure
- *
- * switches on rx irq by enabling them in the GHIINTnMSK register
- */
-static void
-spider_net_rx_irq_on(struct spider_net_card *card)
-{
-       u32 regvalue;
-
-       regvalue = SPIDER_NET_INT0_MASK_VALUE | SPIDER_NET_RXINT;
-       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);
-}
-
-/**
- * spider_net_set_promisc - sets the unicast address or the promiscuous mode
- * @card: card structure
- *
- * spider_net_set_promisc sets the unicast destination address filter and
- * thus either allows for non-promisc mode or promisc mode
- */
-static void
-spider_net_set_promisc(struct spider_net_card *card)
-{
-       u32 macu, macl;
-       struct net_device *netdev = card->netdev;
-
-       if (netdev->flags & IFF_PROMISC) {
-               /* clear destination entry 0 */
-               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, 0);
-               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, 0);
-               spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
-                                    SPIDER_NET_PROMISC_VALUE);
-       } else {
-               macu = netdev->dev_addr[0];
-               macu <<= 8;
-               macu |= netdev->dev_addr[1];
-               memcpy(&macl, &netdev->dev_addr[2], sizeof(macl));
-
-               macu |= SPIDER_NET_UA_DESCR_VALUE;
-               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, macu);
-               spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, macl);
-               spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
-                                    SPIDER_NET_NONPROMISC_VALUE);
-       }
-}
-
-/**
- * spider_net_get_mac_address - read mac address from spider card
- * @card: device structure
- *
- * reads MAC address from GMACUNIMACU and GMACUNIMACL registers
- */
-static int
-spider_net_get_mac_address(struct net_device *netdev)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-       u32 macl, macu;
-
-       macl = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACL);
-       macu = spider_net_read_reg(card, SPIDER_NET_GMACUNIMACU);
-
-       netdev->dev_addr[0] = (macu >> 24) & 0xff;
-       netdev->dev_addr[1] = (macu >> 16) & 0xff;
-       netdev->dev_addr[2] = (macu >> 8) & 0xff;
-       netdev->dev_addr[3] = macu & 0xff;
-       netdev->dev_addr[4] = (macl >> 8) & 0xff;
-       netdev->dev_addr[5] = macl & 0xff;
-
-       if (!is_valid_ether_addr(&netdev->dev_addr[0]))
-               return -EINVAL;
-
-       return 0;
-}
-
-/**
- * spider_net_get_descr_status -- returns the status of a descriptor
- * @descr: descriptor to look at
- *
- * returns the status as in the dmac_cmd_status field of the descriptor
- */
-static inline int
-spider_net_get_descr_status(struct spider_net_hw_descr *hwdescr)
-{
-       return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
-}
-
-/**
- * spider_net_free_chain - free descriptor chain
- * @card: card structure
- * @chain: address of chain
- *
- */
-static void
-spider_net_free_chain(struct spider_net_card *card,
-                     struct spider_net_descr_chain *chain)
-{
-       struct spider_net_descr *descr;
-
-       descr = chain->ring;
-       do {
-               descr->bus_addr = 0;
-               descr->hwdescr->next_descr_addr = 0;
-               descr = descr->next;
-       } while (descr != chain->ring);
-
-       dma_free_coherent(&card->pdev->dev, chain->num_desc,
-           chain->hwring, chain->dma_addr);
-}
-
-/**
- * spider_net_init_chain - alloc and link descriptor chain
- * @card: card structure
- * @chain: address of chain
- *
- * We manage a circular list that mirrors the hardware structure,
- * except that the hardware uses bus addresses.
- *
- * Returns 0 on success, <0 on failure
- */
-static int
-spider_net_init_chain(struct spider_net_card *card,
-                      struct spider_net_descr_chain *chain)
-{
-       int i;
-       struct spider_net_descr *descr;
-       struct spider_net_hw_descr *hwdescr;
-       dma_addr_t buf;
-       size_t alloc_size;
-
-       alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);
-
-       chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
-               &chain->dma_addr, GFP_KERNEL);
-
-       if (!chain->hwring)
-               return -ENOMEM;
-
-       memset(chain->ring, 0, chain->num_desc * sizeof(struct spider_net_descr));
-
-       /* Set up the hardware pointers in each descriptor */
-       descr = chain->ring;
-       hwdescr = chain->hwring;
-       buf = chain->dma_addr;
-       for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) {
-               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
-               hwdescr->next_descr_addr = 0;
-
-               descr->hwdescr = hwdescr;
-               descr->bus_addr = buf;
-               descr->next = descr + 1;
-               descr->prev = descr - 1;
-
-               buf += sizeof(struct spider_net_hw_descr);
-       }
-       /* do actual circular list */
-       (descr-1)->next = chain->ring;
-       chain->ring->prev = descr-1;
-
-       spin_lock_init(&chain->lock);
-       chain->head = chain->ring;
-       chain->tail = chain->ring;
-       return 0;
-}
-
-/**
- * spider_net_free_rx_chain_contents - frees descr contents in rx chain
- * @card: card structure
- *
- * returns 0 on success, <0 on failure
- */
-static void
-spider_net_free_rx_chain_contents(struct spider_net_card *card)
-{
-       struct spider_net_descr *descr;
-
-       descr = card->rx_chain.head;
-       do {
-               if (descr->skb) {
-                       pci_unmap_single(card->pdev, descr->hwdescr->buf_addr,
-                                        SPIDER_NET_MAX_FRAME,
-                                        PCI_DMA_BIDIRECTIONAL);
-                       dev_kfree_skb(descr->skb);
-                       descr->skb = NULL;
-               }
-               descr = descr->next;
-       } while (descr != card->rx_chain.head);
-}
-
-/**
- * spider_net_prepare_rx_descr - Reinitialize RX descriptor
- * @card: card structure
- * @descr: descriptor to re-init
- *
- * Return 0 on success, <0 on failure.
- *
- * Allocates a new rx skb, iommu-maps it and attaches it to the
- * descriptor. Mark the descriptor as activated, ready-to-use.
- */
-static int
-spider_net_prepare_rx_descr(struct spider_net_card *card,
-                           struct spider_net_descr *descr)
-{
-       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
-       dma_addr_t buf;
-       int offset;
-       int bufsize;
-
-       /* we need to round up the buffer size to a multiple of 128 */
-       bufsize = (SPIDER_NET_MAX_FRAME + SPIDER_NET_RXBUF_ALIGN - 1) &
-               (~(SPIDER_NET_RXBUF_ALIGN - 1));
-
-       /* and we need to have it 128 byte aligned, therefore we allocate a
-        * bit more */
-       /* allocate an skb */
-       descr->skb = netdev_alloc_skb(card->netdev,
-                                     bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
-       if (!descr->skb) {
-               if (netif_msg_rx_err(card) && net_ratelimit())
-                       dev_err(&card->netdev->dev,
-                               "Not enough memory to allocate rx buffer\n");
-               card->spider_stats.alloc_rx_skb_error++;
-               return -ENOMEM;
-       }
-       hwdescr->buf_size = bufsize;
-       hwdescr->result_size = 0;
-       hwdescr->valid_size = 0;
-       hwdescr->data_status = 0;
-       hwdescr->data_error = 0;
-
-       offset = ((unsigned long)descr->skb->data) &
-               (SPIDER_NET_RXBUF_ALIGN - 1);
-       if (offset)
-               skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
-       /* iommu-map the skb */
-       buf = pci_map_single(card->pdev, descr->skb->data,
-                       SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(card->pdev, buf)) {
-               dev_kfree_skb_any(descr->skb);
-               descr->skb = NULL;
-               if (netif_msg_rx_err(card) && net_ratelimit())
-                       dev_err(&card->netdev->dev, "Could not iommu-map rx buffer\n");
-               card->spider_stats.rx_iommu_map_error++;
-               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
-       } else {
-               hwdescr->buf_addr = buf;
-               wmb();
-               hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
-                                        SPIDER_NET_DMAC_NOINTR_COMPLETE;
-       }
-
-       return 0;
-}
-
-/**
- * spider_net_enable_rxchtails - sets RX dmac chain tail addresses
- * @card: card structure
- *
- * spider_net_enable_rxchtails sets the RX DMAC chain tail addresses in the
- * chip by writing to the appropriate register. DMA is enabled in
- * spider_net_enable_rxdmac.
- */
-static inline void
-spider_net_enable_rxchtails(struct spider_net_card *card)
-{
-       /* assume chain is aligned correctly */
-       spider_net_write_reg(card, SPIDER_NET_GDADCHA ,
-                            card->rx_chain.tail->bus_addr);
-}
-
-/**
- * spider_net_enable_rxdmac - enables a receive DMA controller
- * @card: card structure
- *
- * spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
- * in the GDADMACCNTR register
- */
-static inline void
-spider_net_enable_rxdmac(struct spider_net_card *card)
-{
-       wmb();
-       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
-                            SPIDER_NET_DMA_RX_VALUE);
-}
-
-/**
- * spider_net_disable_rxdmac - disables the receive DMA controller
- * @card: card structure
- *
- * spider_net_disable_rxdmac terminates processing on the DMA controller
- * by turing off the DMA controller, with the force-end flag set.
- */
-static inline void
-spider_net_disable_rxdmac(struct spider_net_card *card)
-{
-       spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
-                            SPIDER_NET_DMA_RX_FEND_VALUE);
-}
-
-/**
- * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
- * @card: card structure
- *
- * refills descriptors in the rx chain: allocates skbs and iommu-maps them.
- */
-static void
-spider_net_refill_rx_chain(struct spider_net_card *card)
-{
-       struct spider_net_descr_chain *chain = &card->rx_chain;
-       unsigned long flags;
-
-       /* one context doing the refill (and a second context seeing that
-        * and omitting it) is ok. If called by NAPI, we'll be called again
-        * as spider_net_decode_one_descr is called several times. If some
-        * interrupt calls us, the NAPI is about to clean up anyway. */
-       if (!spin_trylock_irqsave(&chain->lock, flags))
-               return;
-
-       while (spider_net_get_descr_status(chain->head->hwdescr) ==
-                       SPIDER_NET_DESCR_NOT_IN_USE) {
-               if (spider_net_prepare_rx_descr(card, chain->head))
-                       break;
-               chain->head = chain->head->next;
-       }
-
-       spin_unlock_irqrestore(&chain->lock, flags);
-}
-
-/**
- * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
- * @card: card structure
- *
- * Returns 0 on success, <0 on failure.
- */
-static int
-spider_net_alloc_rx_skbs(struct spider_net_card *card)
-{
-       struct spider_net_descr_chain *chain = &card->rx_chain;
-       struct spider_net_descr *start = chain->tail;
-       struct spider_net_descr *descr = start;
-
-       /* Link up the hardware chain pointers */
-       do {
-               descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
-               descr = descr->next;
-       } while (descr != start);
-
-       /* Put at least one buffer into the chain. if this fails,
-        * we've got a problem. If not, spider_net_refill_rx_chain
-        * will do the rest at the end of this function. */
-       if (spider_net_prepare_rx_descr(card, chain->head))
-               goto error;
-       else
-               chain->head = chain->head->next;
-
-       /* This will allocate the rest of the rx buffers;
-        * if not, it's business as usual later on. */
-       spider_net_refill_rx_chain(card);
-       spider_net_enable_rxdmac(card);
-       return 0;
-
-error:
-       spider_net_free_rx_chain_contents(card);
-       return -ENOMEM;
-}
-
-/**
- * spider_net_get_multicast_hash - generates hash for multicast filter table
- * @addr: multicast address
- *
- * returns the hash value.
- *
- * spider_net_get_multicast_hash calculates a hash value for a given multicast
- * address, that is used to set the multicast filter tables
- */
-static u8
-spider_net_get_multicast_hash(struct net_device *netdev, __u8 *addr)
-{
-       u32 crc;
-       u8 hash;
-       char addr_for_crc[ETH_ALEN] = { 0, };
-       int i, bit;
-
-       for (i = 0; i < ETH_ALEN * 8; i++) {
-               bit = (addr[i / 8] >> (i % 8)) & 1;
-               addr_for_crc[ETH_ALEN - 1 - i / 8] += bit << (7 - (i % 8));
-       }
-
-       crc = crc32_be(~0, addr_for_crc, netdev->addr_len);
-
-       hash = (crc >> 27);
-       hash <<= 3;
-       hash |= crc & 7;
-       hash &= 0xff;
-
-       return hash;
-}
-
-/**
- * spider_net_set_multi - sets multicast addresses and promisc flags
- * @netdev: interface device structure
- *
- * spider_net_set_multi configures multicast addresses as needed for the
- * netdev interface. It also sets up multicast, allmulti and promisc
- * flags appropriately
- */
-static void
-spider_net_set_multi(struct net_device *netdev)
-{
-       struct netdev_hw_addr *ha;
-       u8 hash;
-       int i;
-       u32 reg;
-       struct spider_net_card *card = netdev_priv(netdev);
-       unsigned long bitmask[SPIDER_NET_MULTICAST_HASHES / BITS_PER_LONG] =
-               {0, };
-
-       spider_net_set_promisc(card);
-
-       if (netdev->flags & IFF_ALLMULTI) {
-               for (i = 0; i < SPIDER_NET_MULTICAST_HASHES; i++) {
-                       set_bit(i, bitmask);
-               }
-               goto write_hash;
-       }
-
-       /* well, we know, what the broadcast hash value is: it's xfd
-       hash = spider_net_get_multicast_hash(netdev, netdev->broadcast); */
-       set_bit(0xfd, bitmask);
-
-       netdev_for_each_mc_addr(ha, netdev) {
-               hash = spider_net_get_multicast_hash(netdev, ha->addr);
-               set_bit(hash, bitmask);
-       }
-
-write_hash:
-       for (i = 0; i < SPIDER_NET_MULTICAST_HASHES / 4; i++) {
-               reg = 0;
-               if (test_bit(i * 4, bitmask))
-                       reg += 0x08;
-               reg <<= 8;
-               if (test_bit(i * 4 + 1, bitmask))
-                       reg += 0x08;
-               reg <<= 8;
-               if (test_bit(i * 4 + 2, bitmask))
-                       reg += 0x08;
-               reg <<= 8;
-               if (test_bit(i * 4 + 3, bitmask))
-                       reg += 0x08;
-
-               spider_net_write_reg(card, SPIDER_NET_GMRMHFILnR + i * 4, reg);
-       }
-}
-
-/**
- * spider_net_prepare_tx_descr - fill tx descriptor with skb data
- * @card: card structure
- * @skb: packet to use
- *
- * returns 0 on success, <0 on failure.
- *
- * fills out the descriptor structure with skb data and len. Copies data,
- * if needed (32bit DMA!)
- */
-static int
-spider_net_prepare_tx_descr(struct spider_net_card *card,
-                           struct sk_buff *skb)
-{
-       struct spider_net_descr_chain *chain = &card->tx_chain;
-       struct spider_net_descr *descr;
-       struct spider_net_hw_descr *hwdescr;
-       dma_addr_t buf;
-       unsigned long flags;
-
-       buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(card->pdev, buf)) {
-               if (netif_msg_tx_err(card) && net_ratelimit())
-                       dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). "
-                                 "Dropping packet\n", skb->data, skb->len);
-               card->spider_stats.tx_iommu_map_error++;
-               return -ENOMEM;
-       }
-
-       spin_lock_irqsave(&chain->lock, flags);
-       descr = card->tx_chain.head;
-       if (descr->next == chain->tail->prev) {
-               spin_unlock_irqrestore(&chain->lock, flags);
-               pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE);
-               return -ENOMEM;
-       }
-       hwdescr = descr->hwdescr;
-       chain->head = descr->next;
-
-       descr->skb = skb;
-       hwdescr->buf_addr = buf;
-       hwdescr->buf_size = skb->len;
-       hwdescr->next_descr_addr = 0;
-       hwdescr->data_status = 0;
-
-       hwdescr->dmac_cmd_status =
-                       SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_TXFRMTL;
-       spin_unlock_irqrestore(&chain->lock, flags);
-
-       if (skb->ip_summed == CHECKSUM_PARTIAL)
-               switch (ip_hdr(skb)->protocol) {
-               case IPPROTO_TCP:
-                       hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
-                       break;
-               case IPPROTO_UDP:
-                       hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
-                       break;
-               }
-
-       /* Chain the bus address, so that the DMA engine finds this descr. */
-       wmb();
-       descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
-
-       card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
-       return 0;
-}
-
-static int
-spider_net_set_low_watermark(struct spider_net_card *card)
-{
-       struct spider_net_descr *descr = card->tx_chain.tail;
-       struct spider_net_hw_descr *hwdescr;
-       unsigned long flags;
-       int status;
-       int cnt=0;
-       int i;
-
-       /* Measure the length of the queue. Measurement does not
-        * need to be precise -- does not need a lock. */
-       while (descr != card->tx_chain.head) {
-               status = descr->hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
-               if (status == SPIDER_NET_DESCR_NOT_IN_USE)
-                       break;
-               descr = descr->next;
-               cnt++;
-       }
-
-       /* If TX queue is short, don't even bother with interrupts */
-       if (cnt < card->tx_chain.num_desc/4)
-               return cnt;
-
-       /* Set low-watermark 3/4th's of the way into the queue. */
-       descr = card->tx_chain.tail;
-       cnt = (cnt*3)/4;
-       for (i=0;i<cnt; i++)
-               descr = descr->next;
-
-       /* Set the new watermark, clear the old watermark */
-       spin_lock_irqsave(&card->tx_chain.lock, flags);
-       descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
-       if (card->low_watermark && card->low_watermark != descr) {
-               hwdescr = card->low_watermark->hwdescr;
-               hwdescr->dmac_cmd_status =
-                    hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
-       }
-       card->low_watermark = descr;
-       spin_unlock_irqrestore(&card->tx_chain.lock, flags);
-       return cnt;
-}
-
-/**
- * spider_net_release_tx_chain - processes sent tx descriptors
- * @card: adapter structure
- * @brutal: if set, don't care about whether descriptor seems to be in use
- *
- * returns 0 if the tx ring is empty, otherwise 1.
- *
- * spider_net_release_tx_chain releases the tx descriptors that spider has
- * finished with (if non-brutal) or simply release tx descriptors (if brutal).
- * If some other context is calling this function, we return 1 so that we're
- * scheduled again (if we were scheduled) and will not lose initiative.
- */
-static int
-spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
-{
-       struct net_device *dev = card->netdev;
-       struct spider_net_descr_chain *chain = &card->tx_chain;
-       struct spider_net_descr *descr;
-       struct spider_net_hw_descr *hwdescr;
-       struct sk_buff *skb;
-       u32 buf_addr;
-       unsigned long flags;
-       int status;
-
-       while (1) {
-               spin_lock_irqsave(&chain->lock, flags);
-               if (chain->tail == chain->head) {
-                       spin_unlock_irqrestore(&chain->lock, flags);
-                       return 0;
-               }
-               descr = chain->tail;
-               hwdescr = descr->hwdescr;
-
-               status = spider_net_get_descr_status(hwdescr);
-               switch (status) {
-               case SPIDER_NET_DESCR_COMPLETE:
-                       dev->stats.tx_packets++;
-                       dev->stats.tx_bytes += descr->skb->len;
-                       break;
-
-               case SPIDER_NET_DESCR_CARDOWNED:
-                       if (!brutal) {
-                               spin_unlock_irqrestore(&chain->lock, flags);
-                               return 1;
-                       }
-
-                       /* fallthrough, if we release the descriptors
-                        * brutally (then we don't care about
-                        * SPIDER_NET_DESCR_CARDOWNED) */
-
-               case SPIDER_NET_DESCR_RESPONSE_ERROR:
-               case SPIDER_NET_DESCR_PROTECTION_ERROR:
-               case SPIDER_NET_DESCR_FORCE_END:
-                       if (netif_msg_tx_err(card))
-                               dev_err(&card->netdev->dev, "forcing end of tx descriptor "
-                                      "with status x%02x\n", status);
-                       dev->stats.tx_errors++;
-                       break;
-
-               default:
-                       dev->stats.tx_dropped++;
-                       if (!brutal) {
-                               spin_unlock_irqrestore(&chain->lock, flags);
-                               return 1;
-                       }
-               }
-
-               chain->tail = descr->next;
-               hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
-               skb = descr->skb;
-               descr->skb = NULL;
-               buf_addr = hwdescr->buf_addr;
-               spin_unlock_irqrestore(&chain->lock, flags);
-
-               /* unmap the skb */
-               if (skb) {
-                       pci_unmap_single(card->pdev, buf_addr, skb->len,
-                                       PCI_DMA_TODEVICE);
-                       dev_kfree_skb(skb);
-               }
-       }
-       return 0;
-}
-
-/**
- * spider_net_kick_tx_dma - enables TX DMA processing
- * @card: card structure
- *
- * This routine will start the transmit DMA running if
- * it is not already running. This routine ned only be
- * called when queueing a new packet to an empty tx queue.
- * Writes the current tx chain head as start address
- * of the tx descriptor chain and enables the transmission
- * DMA engine.
- */
-static inline void
-spider_net_kick_tx_dma(struct spider_net_card *card)
-{
-       struct spider_net_descr *descr;
-
-       if (spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR) &
-                       SPIDER_NET_TX_DMA_EN)
-               goto out;
-
-       descr = card->tx_chain.tail;
-       for (;;) {
-               if (spider_net_get_descr_status(descr->hwdescr) ==
-                               SPIDER_NET_DESCR_CARDOWNED) {
-                       spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
-                                       descr->bus_addr);
-                       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
-                                       SPIDER_NET_DMA_TX_VALUE);
-                       break;
-               }
-               if (descr == card->tx_chain.head)
-                       break;
-               descr = descr->next;
-       }
-
-out:
-       mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
-}
-
-/**
- * spider_net_xmit - transmits a frame over the device
- * @skb: packet to send out
- * @netdev: interface device structure
- *
- * returns 0 on success, !0 on failure
- */
-static int
-spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
-       int cnt;
-       struct spider_net_card *card = netdev_priv(netdev);
-
-       spider_net_release_tx_chain(card, 0);
-
-       if (spider_net_prepare_tx_descr(card, skb) != 0) {
-               netdev->stats.tx_dropped++;
-               netif_stop_queue(netdev);
-               return NETDEV_TX_BUSY;
-       }
-
-       cnt = spider_net_set_low_watermark(card);
-       if (cnt < 5)
-               spider_net_kick_tx_dma(card);
-       return NETDEV_TX_OK;
-}
-
-/**
- * spider_net_cleanup_tx_ring - cleans up the TX ring
- * @card: card structure
- *
- * spider_net_cleanup_tx_ring is called by either the tx_timer
- * or from the NAPI polling routine.
- * This routine releases resources associted with transmitted
- * packets, including updating the queue tail pointer.
- */
-static void
-spider_net_cleanup_tx_ring(struct spider_net_card *card)
-{
-       if ((spider_net_release_tx_chain(card, 0) != 0) &&
-           (card->netdev->flags & IFF_UP)) {
-               spider_net_kick_tx_dma(card);
-               netif_wake_queue(card->netdev);
-       }
-}
-
-/**
- * spider_net_do_ioctl - called for device ioctls
- * @netdev: interface device structure
- * @ifr: request parameter structure for ioctl
- * @cmd: command code for ioctl
- *
- * returns 0 on success, <0 on failure. Currently, we have no special ioctls.
- * -EOPNOTSUPP is returned, if an unknown ioctl was requested
- */
-static int
-spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
-{
-       switch (cmd) {
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-/**
- * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
- * @descr: descriptor to process
- * @card: card structure
- *
- * Fills out skb structure and passes the data to the stack.
- * The descriptor state is not changed.
- */
-static void
-spider_net_pass_skb_up(struct spider_net_descr *descr,
-                      struct spider_net_card *card)
-{
-       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
-       struct sk_buff *skb = descr->skb;
-       struct net_device *netdev = card->netdev;
-       u32 data_status = hwdescr->data_status;
-       u32 data_error = hwdescr->data_error;
-
-       skb_put(skb, hwdescr->valid_size);
-
-       /* the card seems to add 2 bytes of junk in front
-        * of the ethernet frame */
-#define SPIDER_MISALIGN                2
-       skb_pull(skb, SPIDER_MISALIGN);
-       skb->protocol = eth_type_trans(skb, netdev);
-
-       /* checksum offload */
-       skb_checksum_none_assert(skb);
-       if (netdev->features & NETIF_F_RXCSUM) {
-               if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) ==
-                      SPIDER_NET_DATA_STATUS_CKSUM_MASK) &&
-                    !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK))
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-       }
-
-       if (data_status & SPIDER_NET_VLAN_PACKET) {
-               /* further enhancements: HW-accel VLAN */
-       }
-
-       /* update netdevice statistics */
-       netdev->stats.rx_packets++;
-       netdev->stats.rx_bytes += skb->len;
-
-       /* pass skb up to stack */
-       netif_receive_skb(skb);
-}
-
-static void show_rx_chain(struct spider_net_card *card)
-{
-       struct spider_net_descr_chain *chain = &card->rx_chain;
-       struct spider_net_descr *start= chain->tail;
-       struct spider_net_descr *descr= start;
-       struct spider_net_hw_descr *hwd = start->hwdescr;
-       struct device *dev = &card->netdev->dev;
-       u32 curr_desc, next_desc;
-       int status;
-
-       int tot = 0;
-       int cnt = 0;
-       int off = start - chain->ring;
-       int cstat = hwd->dmac_cmd_status;
-
-       dev_info(dev, "Total number of descrs=%d\n",
-               chain->num_desc);
-       dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n",
-               off, cstat);
-
-       curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA);
-       next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA);
-
-       status = cstat;
-       do
-       {
-               hwd = descr->hwdescr;
-               off = descr - chain->ring;
-               status = hwd->dmac_cmd_status;
-
-               if (descr == chain->head)
-                       dev_info(dev, "Chain head is at %d, head status=0x%x\n",
-                                off, status);
-
-               if (curr_desc == descr->bus_addr)
-                       dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n",
-                                off, status);
-
-               if (next_desc == descr->bus_addr)
-                       dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n",
-                                off, status);
-
-               if (hwd->next_descr_addr == 0)
-                       dev_info(dev, "chain is cut at %d\n", off);
-
-               if (cstat != status) {
-                       int from = (chain->num_desc + off - cnt) % chain->num_desc;
-                       int to = (chain->num_desc + off - 1) % chain->num_desc;
-                       dev_info(dev, "Have %d (from %d to %d) descrs "
-                                "with stat=0x%08x\n", cnt, from, to, cstat);
-                       cstat = status;
-                       cnt = 0;
-               }
-
-               cnt ++;
-               tot ++;
-               descr = descr->next;
-       } while (descr != start);
-
-       dev_info(dev, "Last %d descrs with stat=0x%08x "
-                "for a total of %d descrs\n", cnt, cstat, tot);
-
-#ifdef DEBUG
-       /* Now dump the whole ring */
-       descr = start;
-       do
-       {
-               struct spider_net_hw_descr *hwd = descr->hwdescr;
-               status = spider_net_get_descr_status(hwd);
-               cnt = descr - chain->ring;
-               dev_info(dev, "Descr %d stat=0x%08x skb=%p\n",
-                        cnt, status, descr->skb);
-               dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n",
-                        descr->bus_addr, hwd->buf_addr, hwd->buf_size);
-               dev_info(dev, "next=%08x result sz=%d valid sz=%d\n",
-                        hwd->next_descr_addr, hwd->result_size,
-                        hwd->valid_size);
-               dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n",
-                        hwd->dmac_cmd_status, hwd->data_status,
-                        hwd->data_error);
-               dev_info(dev, "\n");
-
-               descr = descr->next;
-       } while (descr != start);
-#endif
-
-}
-
-/**
- * spider_net_resync_head_ptr - Advance head ptr past empty descrs
- *
- * If the driver fails to keep up and empty the queue, then the
- * hardware wil run out of room to put incoming packets. This
- * will cause the hardware to skip descrs that are full (instead
- * of halting/retrying). Thus, once the driver runs, it wil need
- * to "catch up" to where the hardware chain pointer is at.
- */
-static void spider_net_resync_head_ptr(struct spider_net_card *card)
-{
-       unsigned long flags;
-       struct spider_net_descr_chain *chain = &card->rx_chain;
-       struct spider_net_descr *descr;
-       int i, status;
-
-       /* Advance head pointer past any empty descrs */
-       descr = chain->head;
-       status = spider_net_get_descr_status(descr->hwdescr);
-
-       if (status == SPIDER_NET_DESCR_NOT_IN_USE)
-               return;
-
-       spin_lock_irqsave(&chain->lock, flags);
-
-       descr = chain->head;
-       status = spider_net_get_descr_status(descr->hwdescr);
-       for (i=0; i<chain->num_desc; i++) {
-               if (status != SPIDER_NET_DESCR_CARDOWNED) break;
-               descr = descr->next;
-               status = spider_net_get_descr_status(descr->hwdescr);
-       }
-       chain->head = descr;
-
-       spin_unlock_irqrestore(&chain->lock, flags);
-}
-
-static int spider_net_resync_tail_ptr(struct spider_net_card *card)
-{
-       struct spider_net_descr_chain *chain = &card->rx_chain;
-       struct spider_net_descr *descr;
-       int i, status;
-
-       /* Advance tail pointer past any empty and reaped descrs */
-       descr = chain->tail;
-       status = spider_net_get_descr_status(descr->hwdescr);
-
-       for (i=0; i<chain->num_desc; i++) {
-               if ((status != SPIDER_NET_DESCR_CARDOWNED) &&
-                   (status != SPIDER_NET_DESCR_NOT_IN_USE)) break;
-               descr = descr->next;
-               status = spider_net_get_descr_status(descr->hwdescr);
-       }
-       chain->tail = descr;
-
-       if ((i == chain->num_desc) || (i == 0))
-               return 1;
-       return 0;
-}
-
-/**
- * spider_net_decode_one_descr - processes an RX descriptor
- * @card: card structure
- *
- * Returns 1 if a packet has been sent to the stack, otherwise 0.
- *
- * Processes an RX descriptor by iommu-unmapping the data buffer
- * and passing the packet up to the stack. This function is called
- * in softirq context, e.g. either bottom half from interrupt or
- * NAPI polling context.
- */
-static int
-spider_net_decode_one_descr(struct spider_net_card *card)
-{
-       struct net_device *dev = card->netdev;
-       struct spider_net_descr_chain *chain = &card->rx_chain;
-       struct spider_net_descr *descr = chain->tail;
-       struct spider_net_hw_descr *hwdescr = descr->hwdescr;
-       u32 hw_buf_addr;
-       int status;
-
-       status = spider_net_get_descr_status(hwdescr);
-
-       /* Nothing in the descriptor, or ring must be empty */
-       if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
-           (status == SPIDER_NET_DESCR_NOT_IN_USE))
-               return 0;
-
-       /* descriptor definitively used -- move on tail */
-       chain->tail = descr->next;
-
-       /* unmap descriptor */
-       hw_buf_addr = hwdescr->buf_addr;
-       hwdescr->buf_addr = 0xffffffff;
-       pci_unmap_single(card->pdev, hw_buf_addr,
-                       SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
-
-       if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
-            (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
-            (status == SPIDER_NET_DESCR_FORCE_END) ) {
-               if (netif_msg_rx_err(card))
-                       dev_err(&dev->dev,
-                              "dropping RX descriptor with state %d\n", status);
-               dev->stats.rx_dropped++;
-               goto bad_desc;
-       }
-
-       if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
-            (status != SPIDER_NET_DESCR_FRAME_END) ) {
-               if (netif_msg_rx_err(card))
-                       dev_err(&card->netdev->dev,
-                              "RX descriptor with unknown state %d\n", status);
-               card->spider_stats.rx_desc_unk_state++;
-               goto bad_desc;
-       }
-
-       /* The cases we'll throw away the packet immediately */
-       if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
-               if (netif_msg_rx_err(card))
-                       dev_err(&card->netdev->dev,
-                              "error in received descriptor found, "
-                              "data_status=x%08x, data_error=x%08x\n",
-                              hwdescr->data_status, hwdescr->data_error);
-               goto bad_desc;
-       }
-
-       if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) {
-               dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n",
-                              hwdescr->dmac_cmd_status);
-               pr_err("buf_addr=x%08x\n", hw_buf_addr);
-               pr_err("buf_size=x%08x\n", hwdescr->buf_size);
-               pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
-               pr_err("result_size=x%08x\n", hwdescr->result_size);
-               pr_err("valid_size=x%08x\n", hwdescr->valid_size);
-               pr_err("data_status=x%08x\n", hwdescr->data_status);
-               pr_err("data_error=x%08x\n", hwdescr->data_error);
-               pr_err("which=%ld\n", descr - card->rx_chain.ring);
-
-               card->spider_stats.rx_desc_error++;
-               goto bad_desc;
-       }
-
-       /* Ok, we've got a packet in descr */
-       spider_net_pass_skb_up(descr, card);
-       descr->skb = NULL;
-       hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
-       return 1;
-
-bad_desc:
-       if (netif_msg_rx_err(card))
-               show_rx_chain(card);
-       dev_kfree_skb_irq(descr->skb);
-       descr->skb = NULL;
-       hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
-       return 0;
-}
-
-/**
- * spider_net_poll - NAPI poll function called by the stack to return packets
- * @netdev: interface device structure
- * @budget: number of packets we can pass to the stack at most
- *
- * returns 0 if no more packets available to the driver/stack. Returns 1,
- * if the quota is exceeded, but the driver has still packets.
- *
- * spider_net_poll returns all packets from the rx descriptors to the stack
- * (using netif_receive_skb). If all/enough packets are up, the driver
- * reenables interrupts and returns 0. If not, 1 is returned.
- */
-static int spider_net_poll(struct napi_struct *napi, int budget)
-{
-       struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
-       int packets_done = 0;
-
-       while (packets_done < budget) {
-               if (!spider_net_decode_one_descr(card))
-                       break;
-
-               packets_done++;
-       }
-
-       if ((packets_done == 0) && (card->num_rx_ints != 0)) {
-               if (!spider_net_resync_tail_ptr(card))
-                       packets_done = budget;
-               spider_net_resync_head_ptr(card);
-       }
-       card->num_rx_ints = 0;
-
-       spider_net_refill_rx_chain(card);
-       spider_net_enable_rxdmac(card);
-
-       spider_net_cleanup_tx_ring(card);
-
-       /* if all packets are in the stack, enable interrupts and return 0 */
-       /* if not, return 1 */
-       if (packets_done < budget) {
-               napi_complete(napi);
-               spider_net_rx_irq_on(card);
-               card->ignore_rx_ramfull = 0;
-       }
-
-       return packets_done;
-}
-
-/**
- * spider_net_change_mtu - changes the MTU of an interface
- * @netdev: interface device structure
- * @new_mtu: new MTU value
- *
- * returns 0 on success, <0 on failure
- */
-static int
-spider_net_change_mtu(struct net_device *netdev, int new_mtu)
-{
-       /* no need to re-alloc skbs or so -- the max mtu is about 2.3k
-        * and mtu is outbound only anyway */
-       if ( (new_mtu < SPIDER_NET_MIN_MTU ) ||
-               (new_mtu > SPIDER_NET_MAX_MTU) )
-               return -EINVAL;
-       netdev->mtu = new_mtu;
-       return 0;
-}
-
-/**
- * spider_net_set_mac - sets the MAC of an interface
- * @netdev: interface device structure
- * @ptr: pointer to new MAC address
- *
- * Returns 0 on success, <0 on failure. Currently, we don't support this
- * and will always return EOPNOTSUPP.
- */
-static int
-spider_net_set_mac(struct net_device *netdev, void *p)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-       u32 macl, macu, regvalue;
-       struct sockaddr *addr = p;
-
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
-
-       /* switch off GMACTPE and GMACRPE */
-       regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
-       regvalue &= ~((1 << 5) | (1 << 6));
-       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
-
-       /* write mac */
-       macu = (addr->sa_data[0]<<24) + (addr->sa_data[1]<<16) +
-               (addr->sa_data[2]<<8) + (addr->sa_data[3]);
-       macl = (addr->sa_data[4]<<8) + (addr->sa_data[5]);
-       spider_net_write_reg(card, SPIDER_NET_GMACUNIMACU, macu);
-       spider_net_write_reg(card, SPIDER_NET_GMACUNIMACL, macl);
-
-       /* switch GMACTPE and GMACRPE back on */
-       regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
-       regvalue |= ((1 << 5) | (1 << 6));
-       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
-
-       spider_net_set_promisc(card);
-
-       /* look up, whether we have been successful */
-       if (spider_net_get_mac_address(netdev))
-               return -EADDRNOTAVAIL;
-       if (memcmp(netdev->dev_addr,addr->sa_data,netdev->addr_len))
-               return -EADDRNOTAVAIL;
-
-       return 0;
-}
-
-/**
- * spider_net_link_reset
- * @netdev: net device structure
- *
- * This is called when the PHY_LINK signal is asserted. For the blade this is
- * not connected so we should never get here.
- *
- */
-static void
-spider_net_link_reset(struct net_device *netdev)
-{
-
-       struct spider_net_card *card = netdev_priv(netdev);
-
-       del_timer_sync(&card->aneg_timer);
-
-       /* clear interrupt, block further interrupts */
-       spider_net_write_reg(card, SPIDER_NET_GMACST,
-                            spider_net_read_reg(card, SPIDER_NET_GMACST));
-       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
-
-       /* reset phy and setup aneg */
-       card->aneg_count = 0;
-       card->medium = BCM54XX_COPPER;
-       spider_net_setup_aneg(card);
-       mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
-
-}
-
-/**
- * spider_net_handle_error_irq - handles errors raised by an interrupt
- * @card: card structure
- * @status_reg: interrupt status register 0 (GHIINT0STS)
- *
- * spider_net_handle_error_irq treats or ignores all error conditions
- * found when an interrupt is presented
- */
-static void
-spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
-                           u32 error_reg1, u32 error_reg2)
-{
-       u32 i;
-       int show_error = 1;
-
-       /* check GHIINT0STS ************************************/
-       if (status_reg)
-               for (i = 0; i < 32; i++)
-                       if (status_reg & (1<<i))
-                               switch (i)
-       {
-       /* let error_reg1 and error_reg2 evaluation decide, what to do
-       case SPIDER_NET_PHYINT:
-       case SPIDER_NET_GMAC2INT:
-       case SPIDER_NET_GMAC1INT:
-       case SPIDER_NET_GFIFOINT:
-       case SPIDER_NET_DMACINT:
-       case SPIDER_NET_GSYSINT:
-               break; */
-
-       case SPIDER_NET_GIPSINT:
-               show_error = 0;
-               break;
-
-       case SPIDER_NET_GPWOPCMPINT:
-               /* PHY write operation completed */
-               show_error = 0;
-               break;
-       case SPIDER_NET_GPROPCMPINT:
-               /* PHY read operation completed */
-               /* we don't use semaphores, as we poll for the completion
-                * of the read operation in spider_net_read_phy. Should take
-                * about 50 us */
-               show_error = 0;
-               break;
-       case SPIDER_NET_GPWFFINT:
-               /* PHY command queue full */
-               if (netif_msg_intr(card))
-                       dev_err(&card->netdev->dev, "PHY write queue full\n");
-               show_error = 0;
-               break;
-
-       /* case SPIDER_NET_GRMDADRINT: not used. print a message */
-       /* case SPIDER_NET_GRMARPINT: not used. print a message */
-       /* case SPIDER_NET_GRMMPINT: not used. print a message */
-
-       case SPIDER_NET_GDTDEN0INT:
-               /* someone has set TX_DMA_EN to 0 */
-               show_error = 0;
-               break;
-
-       case SPIDER_NET_GDDDEN0INT: /* fallthrough */
-       case SPIDER_NET_GDCDEN0INT: /* fallthrough */
-       case SPIDER_NET_GDBDEN0INT: /* fallthrough */
-       case SPIDER_NET_GDADEN0INT:
-               /* someone has set RX_DMA_EN to 0 */
-               show_error = 0;
-               break;
-
-       /* RX interrupts */
-       case SPIDER_NET_GDDFDCINT:
-       case SPIDER_NET_GDCFDCINT:
-       case SPIDER_NET_GDBFDCINT:
-       case SPIDER_NET_GDAFDCINT:
-       /* case SPIDER_NET_GDNMINT: not used. print a message */
-       /* case SPIDER_NET_GCNMINT: not used. print a message */
-       /* case SPIDER_NET_GBNMINT: not used. print a message */
-       /* case SPIDER_NET_GANMINT: not used. print a message */
-       /* case SPIDER_NET_GRFNMINT: not used. print a message */
-               show_error = 0;
-               break;
-
-       /* TX interrupts */
-       case SPIDER_NET_GDTFDCINT:
-               show_error = 0;
-               break;
-       case SPIDER_NET_GTTEDINT:
-               show_error = 0;
-               break;
-       case SPIDER_NET_GDTDCEINT:
-               /* chain end. If a descriptor should be sent, kick off
-                * tx dma
-               if (card->tx_chain.tail != card->tx_chain.head)
-                       spider_net_kick_tx_dma(card);
-               */
-               show_error = 0;
-               break;
-
-       /* case SPIDER_NET_G1TMCNTINT: not used. print a message */
-       /* case SPIDER_NET_GFREECNTINT: not used. print a message */
-       }
-
-       /* check GHIINT1STS ************************************/
-       if (error_reg1)
-               for (i = 0; i < 32; i++)
-                       if (error_reg1 & (1<<i))
-                               switch (i)
-       {
-       case SPIDER_NET_GTMFLLINT:
-               /* TX RAM full may happen on a usual case.
-                * Logging is not needed. */
-               show_error = 0;
-               break;
-       case SPIDER_NET_GRFDFLLINT: /* fallthrough */
-       case SPIDER_NET_GRFCFLLINT: /* fallthrough */
-       case SPIDER_NET_GRFBFLLINT: /* fallthrough */
-       case SPIDER_NET_GRFAFLLINT: /* fallthrough */
-       case SPIDER_NET_GRMFLLINT:
-               /* Could happen when rx chain is full */
-               if (card->ignore_rx_ramfull == 0) {
-                       card->ignore_rx_ramfull = 1;
-                       spider_net_resync_head_ptr(card);
-                       spider_net_refill_rx_chain(card);
-                       spider_net_enable_rxdmac(card);
-                       card->num_rx_ints ++;
-                       napi_schedule(&card->napi);
-               }
-               show_error = 0;
-               break;
-
-       /* case SPIDER_NET_GTMSHTINT: problem, print a message */
-       case SPIDER_NET_GDTINVDINT:
-               /* allrighty. tx from previous descr ok */
-               show_error = 0;
-               break;
-
-       /* chain end */
-       case SPIDER_NET_GDDDCEINT: /* fallthrough */
-       case SPIDER_NET_GDCDCEINT: /* fallthrough */
-       case SPIDER_NET_GDBDCEINT: /* fallthrough */
-       case SPIDER_NET_GDADCEINT:
-               spider_net_resync_head_ptr(card);
-               spider_net_refill_rx_chain(card);
-               spider_net_enable_rxdmac(card);
-               card->num_rx_ints ++;
-               napi_schedule(&card->napi);
-               show_error = 0;
-               break;
-
-       /* invalid descriptor */
-       case SPIDER_NET_GDDINVDINT: /* fallthrough */
-       case SPIDER_NET_GDCINVDINT: /* fallthrough */
-       case SPIDER_NET_GDBINVDINT: /* fallthrough */
-       case SPIDER_NET_GDAINVDINT:
-               /* Could happen when rx chain is full */
-               spider_net_resync_head_ptr(card);
-               spider_net_refill_rx_chain(card);
-               spider_net_enable_rxdmac(card);
-               card->num_rx_ints ++;
-               napi_schedule(&card->napi);
-               show_error = 0;
-               break;
-
-       /* case SPIDER_NET_GDTRSERINT: problem, print a message */
-       /* case SPIDER_NET_GDDRSERINT: problem, print a message */
-       /* case SPIDER_NET_GDCRSERINT: problem, print a message */
-       /* case SPIDER_NET_GDBRSERINT: problem, print a message */
-       /* case SPIDER_NET_GDARSERINT: problem, print a message */
-       /* case SPIDER_NET_GDSERINT: problem, print a message */
-       /* case SPIDER_NET_GDTPTERINT: problem, print a message */
-       /* case SPIDER_NET_GDDPTERINT: problem, print a message */
-       /* case SPIDER_NET_GDCPTERINT: problem, print a message */
-       /* case SPIDER_NET_GDBPTERINT: problem, print a message */
-       /* case SPIDER_NET_GDAPTERINT: problem, print a message */
-       default:
-               show_error = 1;
-               break;
-       }
-
-       /* check GHIINT2STS ************************************/
-       if (error_reg2)
-               for (i = 0; i < 32; i++)
-                       if (error_reg2 & (1<<i))
-                               switch (i)
-       {
-       /* there is nothing we can (want  to) do at this time. Log a
-        * message, we can switch on and off the specific values later on
-       case SPIDER_NET_GPROPERINT:
-       case SPIDER_NET_GMCTCRSNGINT:
-       case SPIDER_NET_GMCTLCOLINT:
-       case SPIDER_NET_GMCTTMOTINT:
-       case SPIDER_NET_GMCRCAERINT:
-       case SPIDER_NET_GMCRCALERINT:
-       case SPIDER_NET_GMCRALNERINT:
-       case SPIDER_NET_GMCROVRINT:
-       case SPIDER_NET_GMCRRNTINT:
-       case SPIDER_NET_GMCRRXERINT:
-       case SPIDER_NET_GTITCSERINT:
-       case SPIDER_NET_GTIFMTERINT:
-       case SPIDER_NET_GTIPKTRVKINT:
-       case SPIDER_NET_GTISPINGINT:
-       case SPIDER_NET_GTISADNGINT:
-       case SPIDER_NET_GTISPDNGINT:
-       case SPIDER_NET_GRIFMTERINT:
-       case SPIDER_NET_GRIPKTRVKINT:
-       case SPIDER_NET_GRISPINGINT:
-       case SPIDER_NET_GRISADNGINT:
-       case SPIDER_NET_GRISPDNGINT:
-               break;
-       */
-               default:
-                       break;
-       }
-
-       if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
-               dev_err(&card->netdev->dev, "Error interrupt, GHIINT0STS = 0x%08x, "
-                      "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
-                      status_reg, error_reg1, error_reg2);
-
-       /* clear interrupt sources */
-       spider_net_write_reg(card, SPIDER_NET_GHIINT1STS, error_reg1);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT2STS, error_reg2);
-}
-
-/**
- * spider_net_interrupt - interrupt handler for spider_net
- * @irq: interrupt number
- * @ptr: pointer to net_device
- *
- * returns IRQ_HANDLED, if interrupt was for driver, or IRQ_NONE, if no
- * interrupt found raised by card.
- *
- * This is the interrupt handler, that turns off
- * interrupts for this device and makes the stack poll the driver
- */
-static irqreturn_t
-spider_net_interrupt(int irq, void *ptr)
-{
-       struct net_device *netdev = ptr;
-       struct spider_net_card *card = netdev_priv(netdev);
-       u32 status_reg, error_reg1, error_reg2;
-
-       status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
-       error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
-       error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
-
-       if (!(status_reg & SPIDER_NET_INT0_MASK_VALUE) &&
-           !(error_reg1 & SPIDER_NET_INT1_MASK_VALUE) &&
-           !(error_reg2 & SPIDER_NET_INT2_MASK_VALUE))
-               return IRQ_NONE;
-
-       if (status_reg & SPIDER_NET_RXINT ) {
-               spider_net_rx_irq_off(card);
-               napi_schedule(&card->napi);
-               card->num_rx_ints ++;
-       }
-       if (status_reg & SPIDER_NET_TXINT)
-               napi_schedule(&card->napi);
-
-       if (status_reg & SPIDER_NET_LINKINT)
-               spider_net_link_reset(netdev);
-
-       if (status_reg & SPIDER_NET_ERRINT )
-               spider_net_handle_error_irq(card, status_reg,
-                                           error_reg1, error_reg2);
-
-       /* clear interrupt sources */
-       spider_net_write_reg(card, SPIDER_NET_GHIINT0STS, status_reg);
-
-       return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/**
- * spider_net_poll_controller - artificial interrupt for netconsole etc.
- * @netdev: interface device structure
- *
- * see Documentation/networking/netconsole.txt
- */
-static void
-spider_net_poll_controller(struct net_device *netdev)
-{
-       disable_irq(netdev->irq);
-       spider_net_interrupt(netdev->irq, netdev);
-       enable_irq(netdev->irq);
-}
-#endif /* CONFIG_NET_POLL_CONTROLLER */
-
-/**
- * spider_net_enable_interrupts - enable interrupts
- * @card: card structure
- *
- * spider_net_enable_interrupt enables several interrupts
- */
-static void
-spider_net_enable_interrupts(struct spider_net_card *card)
-{
-       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
-                            SPIDER_NET_INT0_MASK_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK,
-                            SPIDER_NET_INT1_MASK_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
-                            SPIDER_NET_INT2_MASK_VALUE);
-}
-
-/**
- * spider_net_disable_interrupts - disable interrupts
- * @card: card structure
- *
- * spider_net_disable_interrupts disables all the interrupts
- */
-static void
-spider_net_disable_interrupts(struct spider_net_card *card)
-{
-       spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
-       spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
-       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
-}
-
-/**
- * spider_net_init_card - initializes the card
- * @card: card structure
- *
- * spider_net_init_card initializes the card so that other registers can
- * be used
- */
-static void
-spider_net_init_card(struct spider_net_card *card)
-{
-       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
-                            SPIDER_NET_CKRCTRL_STOP_VALUE);
-
-       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
-                            SPIDER_NET_CKRCTRL_RUN_VALUE);
-
-       /* trigger ETOMOD signal */
-       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
-               spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4);
-
-       spider_net_disable_interrupts(card);
-}
-
-/**
- * spider_net_enable_card - enables the card by setting all kinds of regs
- * @card: card structure
- *
- * spider_net_enable_card sets a lot of SMMIO registers to enable the device
- */
-static void
-spider_net_enable_card(struct spider_net_card *card)
-{
-       int i;
-       /* the following array consists of (register),(value) pairs
-        * that are set in this function. A register of 0 ends the list */
-       u32 regs[][2] = {
-               { SPIDER_NET_GRESUMINTNUM, 0 },
-               { SPIDER_NET_GREINTNUM, 0 },
-
-               /* set interrupt frame number registers */
-               /* clear the single DMA engine registers first */
-               { SPIDER_NET_GFAFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
-               { SPIDER_NET_GFBFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
-               { SPIDER_NET_GFCFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
-               { SPIDER_NET_GFDFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
-               /* then set, what we really need */
-               { SPIDER_NET_GFFRMNUM, SPIDER_NET_FRAMENUM_VALUE },
-
-               /* timer counter registers and stuff */
-               { SPIDER_NET_GFREECNNUM, 0 },
-               { SPIDER_NET_GONETIMENUM, 0 },
-               { SPIDER_NET_GTOUTFRMNUM, 0 },
-
-               /* RX mode setting */
-               { SPIDER_NET_GRXMDSET, SPIDER_NET_RXMODE_VALUE },
-               /* TX mode setting */
-               { SPIDER_NET_GTXMDSET, SPIDER_NET_TXMODE_VALUE },
-               /* IPSEC mode setting */
-               { SPIDER_NET_GIPSECINIT, SPIDER_NET_IPSECINIT_VALUE },
-
-               { SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE },
-
-               { SPIDER_NET_GMRWOLCTRL, 0 },
-               { SPIDER_NET_GTESTMD, 0x10000000 },
-               { SPIDER_NET_GTTQMSK, 0x00400040 },
-
-               { SPIDER_NET_GMACINTEN, 0 },
-
-               /* flow control stuff */
-               { SPIDER_NET_GMACAPAUSE, SPIDER_NET_MACAPAUSE_VALUE },
-               { SPIDER_NET_GMACTXPAUSE, SPIDER_NET_TXPAUSE_VALUE },
-
-               { SPIDER_NET_GMACBSTLMT, SPIDER_NET_BURSTLMT_VALUE },
-               { 0, 0}
-       };
-
-       i = 0;
-       while (regs[i][0]) {
-               spider_net_write_reg(card, regs[i][0], regs[i][1]);
-               i++;
-       }
-
-       /* clear unicast filter table entries 1 to 14 */
-       for (i = 1; i <= 14; i++) {
-               spider_net_write_reg(card,
-                                    SPIDER_NET_GMRUAFILnR + i * 8,
-                                    0x00080000);
-               spider_net_write_reg(card,
-                                    SPIDER_NET_GMRUAFILnR + i * 8 + 4,
-                                    0x00000000);
-       }
-
-       spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R, 0x08080000);
-
-       spider_net_write_reg(card, SPIDER_NET_ECMODE, SPIDER_NET_ECMODE_VALUE);
-
-       /* set chain tail address for RX chains and
-        * enable DMA */
-       spider_net_enable_rxchtails(card);
-       spider_net_enable_rxdmac(card);
-
-       spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE);
-
-       spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
-                            SPIDER_NET_LENLMT_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
-                            SPIDER_NET_OPMODE_VALUE);
-
-       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
-                            SPIDER_NET_GDTBSTA);
-}
-
-/**
- * spider_net_download_firmware - loads firmware into the adapter
- * @card: card structure
- * @firmware_ptr: pointer to firmware data
- *
- * spider_net_download_firmware loads the firmware data into the
- * adapter. It assumes the length etc. to be allright.
- */
-static int
-spider_net_download_firmware(struct spider_net_card *card,
-                            const void *firmware_ptr)
-{
-       int sequencer, i;
-       const u32 *fw_ptr = firmware_ptr;
-
-       /* stop sequencers */
-       spider_net_write_reg(card, SPIDER_NET_GSINIT,
-                            SPIDER_NET_STOP_SEQ_VALUE);
-
-       for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
-            sequencer++) {
-               spider_net_write_reg(card,
-                                    SPIDER_NET_GSnPRGADR + sequencer * 8, 0);
-               for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
-                       spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
-                                            sequencer * 8, *fw_ptr);
-                       fw_ptr++;
-               }
-       }
-
-       if (spider_net_read_reg(card, SPIDER_NET_GSINIT))
-               return -EIO;
-
-       spider_net_write_reg(card, SPIDER_NET_GSINIT,
-                            SPIDER_NET_RUN_SEQ_VALUE);
-
-       return 0;
-}
-
-/**
- * spider_net_init_firmware - reads in firmware parts
- * @card: card structure
- *
- * Returns 0 on success, <0 on failure
- *
- * spider_net_init_firmware opens the sequencer firmware and does some basic
- * checks. This function opens and releases the firmware structure. A call
- * to download the firmware is performed before the release.
- *
- * Firmware format
- * ===============
- * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being
- * the program for each sequencer. Use the command
- *    tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt              \
- *         Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt   \
- *         Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin
- *
- * to generate spider_fw.bin, if you have sequencer programs with something
- * like the following contents for each sequencer:
- *    <ONE LINE COMMENT>
- *    <FIRST 4-BYTES-WORD FOR SEQUENCER>
- *    <SECOND 4-BYTES-WORD FOR SEQUENCER>
- *     ...
- *    <1024th 4-BYTES-WORD FOR SEQUENCER>
- */
-static int
-spider_net_init_firmware(struct spider_net_card *card)
-{
-       struct firmware *firmware = NULL;
-       struct device_node *dn;
-       const u8 *fw_prop = NULL;
-       int err = -ENOENT;
-       int fw_size;
-
-       if (request_firmware((const struct firmware **)&firmware,
-                            SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
-               if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
-                    netif_msg_probe(card) ) {
-                       dev_err(&card->netdev->dev,
-                              "Incorrect size of spidernet firmware in " \
-                              "filesystem. Looking in host firmware...\n");
-                       goto try_host_fw;
-               }
-               err = spider_net_download_firmware(card, firmware->data);
-
-               release_firmware(firmware);
-               if (err)
-                       goto try_host_fw;
-
-               goto done;
-       }
-
-try_host_fw:
-       dn = pci_device_to_OF_node(card->pdev);
-       if (!dn)
-               goto out_err;
-
-       fw_prop = of_get_property(dn, "firmware", &fw_size);
-       if (!fw_prop)
-               goto out_err;
-
-       if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
-            netif_msg_probe(card) ) {
-               dev_err(&card->netdev->dev,
-                      "Incorrect size of spidernet firmware in host firmware\n");
-               goto done;
-       }
-
-       err = spider_net_download_firmware(card, fw_prop);
-
-done:
-       return err;
-out_err:
-       if (netif_msg_probe(card))
-               dev_err(&card->netdev->dev,
-                      "Couldn't find spidernet firmware in filesystem " \
-                      "or host firmware\n");
-       return err;
-}
-
-/**
- * spider_net_open - called upon ifonfig up
- * @netdev: interface device structure
- *
- * returns 0 on success, <0 on failure
- *
- * spider_net_open allocates all the descriptors and memory needed for
- * operation, sets up multicast list and enables interrupts
- */
-int
-spider_net_open(struct net_device *netdev)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-       int result;
-
-       result = spider_net_init_firmware(card);
-       if (result)
-               goto init_firmware_failed;
-
-       /* start probing with copper */
-       card->aneg_count = 0;
-       card->medium = BCM54XX_COPPER;
-       spider_net_setup_aneg(card);
-       if (card->phy.def->phy_id)
-               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
-
-       result = spider_net_init_chain(card, &card->tx_chain);
-       if (result)
-               goto alloc_tx_failed;
-       card->low_watermark = NULL;
-
-       result = spider_net_init_chain(card, &card->rx_chain);
-       if (result)
-               goto alloc_rx_failed;
-
-       /* Allocate rx skbs */
-       if (spider_net_alloc_rx_skbs(card))
-               goto alloc_skbs_failed;
-
-       spider_net_set_multi(netdev);
-
-       /* further enhancement: setup hw vlan, if needed */
-
-       result = -EBUSY;
-       if (request_irq(netdev->irq, spider_net_interrupt,
-                            IRQF_SHARED, netdev->name, netdev))
-               goto register_int_failed;
-
-       spider_net_enable_card(card);
-
-       netif_start_queue(netdev);
-       netif_carrier_on(netdev);
-       napi_enable(&card->napi);
-
-       spider_net_enable_interrupts(card);
-
-       return 0;
-
-register_int_failed:
-       spider_net_free_rx_chain_contents(card);
-alloc_skbs_failed:
-       spider_net_free_chain(card, &card->rx_chain);
-alloc_rx_failed:
-       spider_net_free_chain(card, &card->tx_chain);
-alloc_tx_failed:
-       del_timer_sync(&card->aneg_timer);
-init_firmware_failed:
-       return result;
-}
-
-/**
- * spider_net_link_phy
- * @data: used for pointer to card structure
- *
- */
-static void spider_net_link_phy(unsigned long data)
-{
-       struct spider_net_card *card = (struct spider_net_card *)data;
-       struct mii_phy *phy = &card->phy;
-
-       /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */
-       if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) {
-
-               pr_debug("%s: link is down trying to bring it up\n",
-                        card->netdev->name);
-
-               switch (card->medium) {
-               case BCM54XX_COPPER:
-                       /* enable fiber with autonegotiation first */
-                       if (phy->def->ops->enable_fiber)
-                               phy->def->ops->enable_fiber(phy, 1);
-                       card->medium = BCM54XX_FIBER;
-                       break;
-
-               case BCM54XX_FIBER:
-                       /* fiber didn't come up, try to disable fiber autoneg */
-                       if (phy->def->ops->enable_fiber)
-                               phy->def->ops->enable_fiber(phy, 0);
-                       card->medium = BCM54XX_UNKNOWN;
-                       break;
-
-               case BCM54XX_UNKNOWN:
-                       /* copper, fiber with and without failed,
-                        * retry from beginning */
-                       spider_net_setup_aneg(card);
-                       card->medium = BCM54XX_COPPER;
-                       break;
-               }
-
-               card->aneg_count = 0;
-               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
-               return;
-       }
-
-       /* link still not up, try again later */
-       if (!(phy->def->ops->poll_link(phy))) {
-               card->aneg_count++;
-               mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
-               return;
-       }
-
-       /* link came up, get abilities */
-       phy->def->ops->read_link(phy);
-
-       spider_net_write_reg(card, SPIDER_NET_GMACST,
-                            spider_net_read_reg(card, SPIDER_NET_GMACST));
-       spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4);
-
-       if (phy->speed == 1000)
-               spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001);
-       else
-               spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0);
-
-       card->aneg_count = 0;
-
-       pr_info("%s: link up, %i Mbps, %s-duplex %sautoneg.\n",
-               card->netdev->name, phy->speed,
-               phy->duplex == 1 ? "Full" : "Half",
-               phy->autoneg == 1 ? "" : "no ");
-}
-
-/**
- * spider_net_setup_phy - setup PHY
- * @card: card structure
- *
- * returns 0 on success, <0 on failure
- *
- * spider_net_setup_phy is used as part of spider_net_probe.
- **/
-static int
-spider_net_setup_phy(struct spider_net_card *card)
-{
-       struct mii_phy *phy = &card->phy;
-
-       spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
-                            SPIDER_NET_DMASEL_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
-                            SPIDER_NET_PHY_CTRL_VALUE);
-
-       phy->dev = card->netdev;
-       phy->mdio_read = spider_net_read_phy;
-       phy->mdio_write = spider_net_write_phy;
-
-       for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) {
-               unsigned short id;
-               id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
-               if (id != 0x0000 && id != 0xffff) {
-                       if (!mii_phy_probe(phy, phy->mii_id)) {
-                               pr_info("Found %s.\n", phy->def->name);
-                               break;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/**
- * spider_net_workaround_rxramfull - work around firmware bug
- * @card: card structure
- *
- * no return value
- **/
-static void
-spider_net_workaround_rxramfull(struct spider_net_card *card)
-{
-       int i, sequencer = 0;
-
-       /* cancel reset */
-       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
-                            SPIDER_NET_CKRCTRL_RUN_VALUE);
-
-       /* empty sequencer data */
-       for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
-            sequencer++) {
-               spider_net_write_reg(card, SPIDER_NET_GSnPRGADR +
-                                    sequencer * 8, 0x0);
-               for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
-                       spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
-                                            sequencer * 8, 0x0);
-               }
-       }
-
-       /* set sequencer operation */
-       spider_net_write_reg(card, SPIDER_NET_GSINIT, 0x000000fe);
-
-       /* reset */
-       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
-                            SPIDER_NET_CKRCTRL_STOP_VALUE);
-}
-
-/**
- * spider_net_stop - called upon ifconfig down
- * @netdev: interface device structure
- *
- * always returns 0
- */
-int
-spider_net_stop(struct net_device *netdev)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-
-       napi_disable(&card->napi);
-       netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
-       del_timer_sync(&card->tx_timer);
-       del_timer_sync(&card->aneg_timer);
-
-       spider_net_disable_interrupts(card);
-
-       free_irq(netdev->irq, netdev);
-
-       spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
-                            SPIDER_NET_DMA_TX_FEND_VALUE);
-
-       /* turn off DMA, force end */
-       spider_net_disable_rxdmac(card);
-
-       /* release chains */
-       spider_net_release_tx_chain(card, 1);
-       spider_net_free_rx_chain_contents(card);
-
-       spider_net_free_chain(card, &card->tx_chain);
-       spider_net_free_chain(card, &card->rx_chain);
-
-       return 0;
-}
-
-/**
- * spider_net_tx_timeout_task - task scheduled by the watchdog timeout
- * function (to be called not under interrupt status)
- * @data: data, is interface device structure
- *
- * called as task when tx hangs, resets interface (if interface is up)
- */
-static void
-spider_net_tx_timeout_task(struct work_struct *work)
-{
-       struct spider_net_card *card =
-               container_of(work, struct spider_net_card, tx_timeout_task);
-       struct net_device *netdev = card->netdev;
-
-       if (!(netdev->flags & IFF_UP))
-               goto out;
-
-       netif_device_detach(netdev);
-       spider_net_stop(netdev);
-
-       spider_net_workaround_rxramfull(card);
-       spider_net_init_card(card);
-
-       if (spider_net_setup_phy(card))
-               goto out;
-
-       spider_net_open(netdev);
-       spider_net_kick_tx_dma(card);
-       netif_device_attach(netdev);
-
-out:
-       atomic_dec(&card->tx_timeout_task_counter);
-}
-
-/**
- * spider_net_tx_timeout - called when the tx timeout watchdog kicks in.
- * @netdev: interface device structure
- *
- * called, if tx hangs. Schedules a task that resets the interface
- */
-static void
-spider_net_tx_timeout(struct net_device *netdev)
-{
-       struct spider_net_card *card;
-
-       card = netdev_priv(netdev);
-       atomic_inc(&card->tx_timeout_task_counter);
-       if (netdev->flags & IFF_UP)
-               schedule_work(&card->tx_timeout_task);
-       else
-               atomic_dec(&card->tx_timeout_task_counter);
-       card->spider_stats.tx_timeouts++;
-}
-
-static const struct net_device_ops spider_net_ops = {
-       .ndo_open               = spider_net_open,
-       .ndo_stop               = spider_net_stop,
-       .ndo_start_xmit         = spider_net_xmit,
-       .ndo_set_multicast_list = spider_net_set_multi,
-       .ndo_set_mac_address    = spider_net_set_mac,
-       .ndo_change_mtu         = spider_net_change_mtu,
-       .ndo_do_ioctl           = spider_net_do_ioctl,
-       .ndo_tx_timeout         = spider_net_tx_timeout,
-       .ndo_validate_addr      = eth_validate_addr,
-       /* HW VLAN */
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       /* poll controller */
-       .ndo_poll_controller    = spider_net_poll_controller,
-#endif /* CONFIG_NET_POLL_CONTROLLER */
-};
-
-/**
- * spider_net_setup_netdev_ops - initialization of net_device operations
- * @netdev: net_device structure
- *
- * fills out function pointers in the net_device structure
- */
-static void
-spider_net_setup_netdev_ops(struct net_device *netdev)
-{
-       netdev->netdev_ops = &spider_net_ops;
-       netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
-       /* ethtool ops */
-       netdev->ethtool_ops = &spider_net_ethtool_ops;
-}
-
-/**
- * spider_net_setup_netdev - initialization of net_device
- * @card: card structure
- *
- * Returns 0 on success or <0 on failure
- *
- * spider_net_setup_netdev initializes the net_device structure
- **/
-static int
-spider_net_setup_netdev(struct spider_net_card *card)
-{
-       int result;
-       struct net_device *netdev = card->netdev;
-       struct device_node *dn;
-       struct sockaddr addr;
-       const u8 *mac;
-
-       SET_NETDEV_DEV(netdev, &card->pdev->dev);
-
-       pci_set_drvdata(card->pdev, netdev);
-
-       init_timer(&card->tx_timer);
-       card->tx_timer.function =
-               (void (*)(unsigned long)) spider_net_cleanup_tx_ring;
-       card->tx_timer.data = (unsigned long) card;
-       netdev->irq = card->pdev->irq;
-
-       card->aneg_count = 0;
-       init_timer(&card->aneg_timer);
-       card->aneg_timer.function = spider_net_link_phy;
-       card->aneg_timer.data = (unsigned long) card;
-
-       netif_napi_add(netdev, &card->napi,
-                      spider_net_poll, SPIDER_NET_NAPI_WEIGHT);
-
-       spider_net_setup_netdev_ops(netdev);
-
-       netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
-       if (SPIDER_NET_RX_CSUM_DEFAULT)
-               netdev->features |= NETIF_F_RXCSUM;
-       netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX;
-       /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
-        *              NETIF_F_HW_VLAN_FILTER */
-
-       netdev->irq = card->pdev->irq;
-       card->num_rx_ints = 0;
-       card->ignore_rx_ramfull = 0;
-
-       dn = pci_device_to_OF_node(card->pdev);
-       if (!dn)
-               return -EIO;
-
-       mac = of_get_property(dn, "local-mac-address", NULL);
-       if (!mac)
-               return -EIO;
-       memcpy(addr.sa_data, mac, ETH_ALEN);
-
-       result = spider_net_set_mac(netdev, &addr);
-       if ((result) && (netif_msg_probe(card)))
-               dev_err(&card->netdev->dev,
-                       "Failed to set MAC address: %i\n", result);
-
-       result = register_netdev(netdev);
-       if (result) {
-               if (netif_msg_probe(card))
-                       dev_err(&card->netdev->dev,
-                               "Couldn't register net_device: %i\n", result);
-               return result;
-       }
-
-       if (netif_msg_probe(card))
-               pr_info("Initialized device %s.\n", netdev->name);
-
-       return 0;
-}
-
-/**
- * spider_net_alloc_card - allocates net_device and card structure
- *
- * returns the card structure or NULL in case of errors
- *
- * the card and net_device structures are linked to each other
- */
-static struct spider_net_card *
-spider_net_alloc_card(void)
-{
-       struct net_device *netdev;
-       struct spider_net_card *card;
-       size_t alloc_size;
-
-       alloc_size = sizeof(struct spider_net_card) +
-          (tx_descriptors + rx_descriptors) * sizeof(struct spider_net_descr);
-       netdev = alloc_etherdev(alloc_size);
-       if (!netdev)
-               return NULL;
-
-       card = netdev_priv(netdev);
-       card->netdev = netdev;
-       card->msg_enable = SPIDER_NET_DEFAULT_MSG;
-       INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task);
-       init_waitqueue_head(&card->waitq);
-       atomic_set(&card->tx_timeout_task_counter, 0);
-
-       card->rx_chain.num_desc = rx_descriptors;
-       card->rx_chain.ring = card->darray;
-       card->tx_chain.num_desc = tx_descriptors;
-       card->tx_chain.ring = card->darray + rx_descriptors;
-
-       return card;
-}
-
-/**
- * spider_net_undo_pci_setup - releases PCI ressources
- * @card: card structure
- *
- * spider_net_undo_pci_setup releases the mapped regions
- */
-static void
-spider_net_undo_pci_setup(struct spider_net_card *card)
-{
-       iounmap(card->regs);
-       pci_release_regions(card->pdev);
-}
-
-/**
- * spider_net_setup_pci_dev - sets up the device in terms of PCI operations
- * @pdev: PCI device
- *
- * Returns the card structure or NULL if any errors occur
- *
- * spider_net_setup_pci_dev initializes pdev and together with the
- * functions called in spider_net_open configures the device so that
- * data can be transferred over it
- * The net_device structure is attached to the card structure, if the
- * function returns without error.
- **/
-static struct spider_net_card *
-spider_net_setup_pci_dev(struct pci_dev *pdev)
-{
-       struct spider_net_card *card;
-       unsigned long mmio_start, mmio_len;
-
-       if (pci_enable_device(pdev)) {
-               dev_err(&pdev->dev, "Couldn't enable PCI device\n");
-               return NULL;
-       }
-
-       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               dev_err(&pdev->dev,
-                       "Couldn't find proper PCI device base address.\n");
-               goto out_disable_dev;
-       }
-
-       if (pci_request_regions(pdev, spider_net_driver_name)) {
-               dev_err(&pdev->dev,
-                       "Couldn't obtain PCI resources, aborting.\n");
-               goto out_disable_dev;
-       }
-
-       pci_set_master(pdev);
-
-       card = spider_net_alloc_card();
-       if (!card) {
-               dev_err(&pdev->dev,
-                       "Couldn't allocate net_device structure, aborting.\n");
-               goto out_release_regions;
-       }
-       card->pdev = pdev;
-
-       /* fetch base address and length of first resource */
-       mmio_start = pci_resource_start(pdev, 0);
-       mmio_len = pci_resource_len(pdev, 0);
-
-       card->netdev->mem_start = mmio_start;
-       card->netdev->mem_end = mmio_start + mmio_len;
-       card->regs = ioremap(mmio_start, mmio_len);
-
-       if (!card->regs) {
-               dev_err(&pdev->dev,
-                       "Couldn't obtain PCI resources, aborting.\n");
-               goto out_release_regions;
-       }
-
-       return card;
-
-out_release_regions:
-       pci_release_regions(pdev);
-out_disable_dev:
-       pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
-       return NULL;
-}
-
-/**
- * spider_net_probe - initialization of a device
- * @pdev: PCI device
- * @ent: entry in the device id list
- *
- * Returns 0 on success, <0 on failure
- *
- * spider_net_probe initializes pdev and registers a net_device
- * structure for it. After that, the device can be ifconfig'ed up
- **/
-static int __devinit
-spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       int err = -EIO;
-       struct spider_net_card *card;
-
-       card = spider_net_setup_pci_dev(pdev);
-       if (!card)
-               goto out;
-
-       spider_net_workaround_rxramfull(card);
-       spider_net_init_card(card);
-
-       err = spider_net_setup_phy(card);
-       if (err)
-               goto out_undo_pci;
-
-       err = spider_net_setup_netdev(card);
-       if (err)
-               goto out_undo_pci;
-
-       return 0;
-
-out_undo_pci:
-       spider_net_undo_pci_setup(card);
-       free_netdev(card->netdev);
-out:
-       return err;
-}
-
-/**
- * spider_net_remove - removal of a device
- * @pdev: PCI device
- *
- * Returns 0 on success, <0 on failure
- *
- * spider_net_remove is called to remove the device and unregisters the
- * net_device
- **/
-static void __devexit
-spider_net_remove(struct pci_dev *pdev)
-{
-       struct net_device *netdev;
-       struct spider_net_card *card;
-
-       netdev = pci_get_drvdata(pdev);
-       card = netdev_priv(netdev);
-
-       wait_event(card->waitq,
-                  atomic_read(&card->tx_timeout_task_counter) == 0);
-
-       unregister_netdev(netdev);
-
-       /* switch off card */
-       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
-                            SPIDER_NET_CKRCTRL_STOP_VALUE);
-       spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
-                            SPIDER_NET_CKRCTRL_RUN_VALUE);
-
-       spider_net_undo_pci_setup(card);
-       free_netdev(netdev);
-}
-
-static struct pci_driver spider_net_driver = {
-       .name           = spider_net_driver_name,
-       .id_table       = spider_net_pci_tbl,
-       .probe          = spider_net_probe,
-       .remove         = __devexit_p(spider_net_remove)
-};
-
-/**
- * spider_net_init - init function when the driver is loaded
- *
- * spider_net_init registers the device driver
- */
-static int __init spider_net_init(void)
-{
-       printk(KERN_INFO "Spidernet version %s.\n", VERSION);
-
-       if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) {
-               rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN;
-               pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
-       }
-       if (rx_descriptors > SPIDER_NET_RX_DESCRIPTORS_MAX) {
-               rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MAX;
-               pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
-       }
-       if (tx_descriptors < SPIDER_NET_TX_DESCRIPTORS_MIN) {
-               tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MIN;
-               pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
-       }
-       if (tx_descriptors > SPIDER_NET_TX_DESCRIPTORS_MAX) {
-               tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MAX;
-               pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
-       }
-
-       return pci_register_driver(&spider_net_driver);
-}
-
-/**
- * spider_net_cleanup - exit function when driver is unloaded
- *
- * spider_net_cleanup unregisters the device driver
- */
-static void __exit spider_net_cleanup(void)
-{
-       pci_unregister_driver(&spider_net_driver);
-}
-
-module_init(spider_net_init);
-module_exit(spider_net_cleanup);
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
deleted file mode 100644 (file)
index a891ad0..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Network device driver for Cell Processor-Based Blade and Celleb platform
- *
- * (C) Copyright IBM Corp. 2005
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * Authors : Utz Bacher <utz.bacher@de.ibm.com>
- *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _SPIDER_NET_H
-#define _SPIDER_NET_H
-
-#define VERSION "2.0 B"
-
-#include "./ethernet/sun/sungem_phy.h"
-
-extern int spider_net_stop(struct net_device *netdev);
-extern int spider_net_open(struct net_device *netdev);
-
-extern const struct ethtool_ops spider_net_ethtool_ops;
-
-extern char spider_net_driver_name[];
-
-#define SPIDER_NET_MAX_FRAME                   2312
-#define SPIDER_NET_MAX_MTU                     2294
-#define SPIDER_NET_MIN_MTU                     64
-
-#define SPIDER_NET_RXBUF_ALIGN                 128
-
-#define SPIDER_NET_RX_DESCRIPTORS_DEFAULT      256
-#define SPIDER_NET_RX_DESCRIPTORS_MIN          16
-#define SPIDER_NET_RX_DESCRIPTORS_MAX          512
-
-#define SPIDER_NET_TX_DESCRIPTORS_DEFAULT      256
-#define SPIDER_NET_TX_DESCRIPTORS_MIN          16
-#define SPIDER_NET_TX_DESCRIPTORS_MAX          512
-
-#define SPIDER_NET_TX_TIMER                    (HZ/5)
-#define SPIDER_NET_ANEG_TIMER                  (HZ)
-#define SPIDER_NET_ANEG_TIMEOUT                        5
-
-#define SPIDER_NET_RX_CSUM_DEFAULT             1
-
-#define SPIDER_NET_WATCHDOG_TIMEOUT            50*HZ
-#define SPIDER_NET_NAPI_WEIGHT                 64
-
-#define SPIDER_NET_FIRMWARE_SEQS       6
-#define SPIDER_NET_FIRMWARE_SEQWORDS   1024
-#define SPIDER_NET_FIRMWARE_LEN                (SPIDER_NET_FIRMWARE_SEQS * \
-                                        SPIDER_NET_FIRMWARE_SEQWORDS * \
-                                        sizeof(u32))
-#define SPIDER_NET_FIRMWARE_NAME       "spider_fw.bin"
-
-/** spider_net SMMIO registers */
-#define SPIDER_NET_GHIINT0STS          0x00000000
-#define SPIDER_NET_GHIINT1STS          0x00000004
-#define SPIDER_NET_GHIINT2STS          0x00000008
-#define SPIDER_NET_GHIINT0MSK          0x00000010
-#define SPIDER_NET_GHIINT1MSK          0x00000014
-#define SPIDER_NET_GHIINT2MSK          0x00000018
-
-#define SPIDER_NET_GRESUMINTNUM                0x00000020
-#define SPIDER_NET_GREINTNUM           0x00000024
-
-#define SPIDER_NET_GFFRMNUM            0x00000028
-#define SPIDER_NET_GFAFRMNUM           0x0000002c
-#define SPIDER_NET_GFBFRMNUM           0x00000030
-#define SPIDER_NET_GFCFRMNUM           0x00000034
-#define SPIDER_NET_GFDFRMNUM           0x00000038
-
-/* clear them (don't use it) */
-#define SPIDER_NET_GFREECNNUM          0x0000003c
-#define SPIDER_NET_GONETIMENUM         0x00000040
-
-#define SPIDER_NET_GTOUTFRMNUM         0x00000044
-
-#define SPIDER_NET_GTXMDSET            0x00000050
-#define SPIDER_NET_GPCCTRL             0x00000054
-#define SPIDER_NET_GRXMDSET            0x00000058
-#define SPIDER_NET_GIPSECINIT          0x0000005c
-#define SPIDER_NET_GFTRESTRT           0x00000060
-#define SPIDER_NET_GRXDMAEN            0x00000064
-#define SPIDER_NET_GMRWOLCTRL          0x00000068
-#define SPIDER_NET_GPCWOPCMD           0x0000006c
-#define SPIDER_NET_GPCROPCMD           0x00000070
-#define SPIDER_NET_GTTFRMCNT           0x00000078
-#define SPIDER_NET_GTESTMD             0x0000007c
-
-#define SPIDER_NET_GSINIT              0x00000080
-#define SPIDER_NET_GSnPRGADR           0x00000084
-#define SPIDER_NET_GSnPRGDAT           0x00000088
-
-#define SPIDER_NET_GMACOPEMD           0x00000100
-#define SPIDER_NET_GMACLENLMT          0x00000108
-#define SPIDER_NET_GMACST              0x00000110
-#define SPIDER_NET_GMACINTEN           0x00000118
-#define SPIDER_NET_GMACPHYCTRL         0x00000120
-
-#define SPIDER_NET_GMACAPAUSE          0x00000154
-#define SPIDER_NET_GMACTXPAUSE         0x00000164
-
-#define SPIDER_NET_GMACMODE            0x000001b0
-#define SPIDER_NET_GMACBSTLMT          0x000001b4
-
-#define SPIDER_NET_GMACUNIMACU         0x000001c0
-#define SPIDER_NET_GMACUNIMACL         0x000001c8
-
-#define SPIDER_NET_GMRMHFILnR          0x00000400
-#define SPIDER_NET_MULTICAST_HASHES    256
-
-#define SPIDER_NET_GMRUAFILnR          0x00000500
-#define SPIDER_NET_GMRUA0FIL15R                0x00000578
-
-#define SPIDER_NET_GTTQMSK             0x00000934
-
-/* RX DMA controller registers, all 0x00000a.. are for DMA controller A,
- * 0x00000b.. for DMA controller B, etc. */
-#define SPIDER_NET_GDADCHA             0x00000a00
-#define SPIDER_NET_GDADMACCNTR         0x00000a04
-#define SPIDER_NET_GDACTDPA            0x00000a08
-#define SPIDER_NET_GDACTDCNT           0x00000a0c
-#define SPIDER_NET_GDACDBADDR          0x00000a20
-#define SPIDER_NET_GDACDBSIZE          0x00000a24
-#define SPIDER_NET_GDACNEXTDA          0x00000a28
-#define SPIDER_NET_GDACCOMST           0x00000a2c
-#define SPIDER_NET_GDAWBCOMST          0x00000a30
-#define SPIDER_NET_GDAWBRSIZE          0x00000a34
-#define SPIDER_NET_GDAWBVSIZE          0x00000a38
-#define SPIDER_NET_GDAWBTRST           0x00000a3c
-#define SPIDER_NET_GDAWBTRERR          0x00000a40
-
-/* TX DMA controller registers */
-#define SPIDER_NET_GDTDCHA             0x00000e00
-#define SPIDER_NET_GDTDMACCNTR         0x00000e04
-#define SPIDER_NET_GDTCDPA             0x00000e08
-#define SPIDER_NET_GDTDMASEL           0x00000e14
-
-#define SPIDER_NET_ECMODE              0x00000f00
-/* clock and reset control register */
-#define SPIDER_NET_CKRCTRL             0x00000ff0
-
-/** SCONFIG registers */
-#define SPIDER_NET_SCONFIG_IOACTE      0x00002810
-
-/** interrupt mask registers */
-#define SPIDER_NET_INT0_MASK_VALUE     0x3f7fe2c7
-#define SPIDER_NET_INT1_MASK_VALUE     0x0000fff2
-#define SPIDER_NET_INT2_MASK_VALUE     0x000003f1
-
-/* we rely on flagged descriptor interrupts */
-#define SPIDER_NET_FRAMENUM_VALUE      0x00000000
-/* set this first, then the FRAMENUM_VALUE */
-#define SPIDER_NET_GFXFRAMES_VALUE     0x00000000
-
-#define SPIDER_NET_STOP_SEQ_VALUE      0x00000000
-#define SPIDER_NET_RUN_SEQ_VALUE       0x0000007e
-
-#define SPIDER_NET_PHY_CTRL_VALUE      0x00040040
-/* #define SPIDER_NET_PHY_CTRL_VALUE   0x01070080*/
-#define SPIDER_NET_RXMODE_VALUE                0x00000011
-/* auto retransmission in case of MAC aborts */
-#define SPIDER_NET_TXMODE_VALUE                0x00010000
-#define SPIDER_NET_RESTART_VALUE       0x00000000
-#define SPIDER_NET_WOL_VALUE           0x00001111
-#if 0
-#define SPIDER_NET_WOL_VALUE           0x00000000
-#endif
-#define SPIDER_NET_IPSECINIT_VALUE     0x6f716f71
-
-/* pause frames: automatic, no upper retransmission count */
-/* outside loopback mode: ETOMOD signal dont matter, not connected */
-/* ETOMOD signal is brought to PHY reset. bit 2 must be 1 in Celleb */
-#define SPIDER_NET_OPMODE_VALUE                0x00000067
-/*#define SPIDER_NET_OPMODE_VALUE              0x001b0062*/
-#define SPIDER_NET_LENLMT_VALUE                0x00000908
-
-#define SPIDER_NET_MACAPAUSE_VALUE     0x00000800 /* about 1 ms */
-#define SPIDER_NET_TXPAUSE_VALUE       0x00000000
-
-#define SPIDER_NET_MACMODE_VALUE       0x00000001
-#define SPIDER_NET_BURSTLMT_VALUE      0x00000200 /* about 16 us */
-
-/* DMAC control register GDMACCNTR
- *
- * 1(0)                                enable r/tx dma
- *  0000000                            fixed to 0
- *
- *         000000                      fixed to 0
- *               0(1)                  en/disable descr writeback on force end
- *                0(1)                 force end
- *
- *                 000000              fixed to 0
- *                       00            burst alignment: 128 bytes
- *                       11            burst alignment: 1024 bytes
- *
- *                         00000       fixed to 0
- *                              0      descr writeback size 32 bytes
- *                               0(1)  descr chain end interrupt enable
- *                                0(1) descr status writeback enable */
-
-/* to set RX_DMA_EN */
-#define SPIDER_NET_DMA_RX_VALUE                0x80000000
-#define SPIDER_NET_DMA_RX_FEND_VALUE   0x00030003
-/* to set TX_DMA_EN */
-#define SPIDER_NET_TX_DMA_EN           0x80000000
-#define SPIDER_NET_GDTBSTA             0x00000300
-#define SPIDER_NET_GDTDCEIDIS          0x00000002
-#define SPIDER_NET_DMA_TX_VALUE        SPIDER_NET_TX_DMA_EN | \
-                                       SPIDER_NET_GDTDCEIDIS | \
-                                       SPIDER_NET_GDTBSTA
-
-#define SPIDER_NET_DMA_TX_FEND_VALUE   0x00030003
-
-/* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
-#define SPIDER_NET_UA_DESCR_VALUE      0x00080000
-#define SPIDER_NET_PROMISC_VALUE       0x00080000
-#define SPIDER_NET_NONPROMISC_VALUE    0x00000000
-
-#define SPIDER_NET_DMASEL_VALUE                0x00000001
-
-#define SPIDER_NET_ECMODE_VALUE                0x00000000
-
-#define SPIDER_NET_CKRCTRL_RUN_VALUE   0x1fff010f
-#define SPIDER_NET_CKRCTRL_STOP_VALUE  0x0000010f
-
-#define SPIDER_NET_SBIMSTATE_VALUE     0x00000000
-#define SPIDER_NET_SBTMSTATE_VALUE     0x00000000
-
-/* SPIDER_NET_GHIINT0STS bits, in reverse order so that they can be used
- * with 1 << SPIDER_NET_... */
-enum spider_net_int0_status {
-       SPIDER_NET_GPHYINT = 0,
-       SPIDER_NET_GMAC2INT,
-       SPIDER_NET_GMAC1INT,
-       SPIDER_NET_GIPSINT,
-       SPIDER_NET_GFIFOINT,
-       SPIDER_NET_GDMACINT,
-       SPIDER_NET_GSYSINT,
-       SPIDER_NET_GPWOPCMPINT,
-       SPIDER_NET_GPROPCMPINT,
-       SPIDER_NET_GPWFFINT,
-       SPIDER_NET_GRMDADRINT,
-       SPIDER_NET_GRMARPINT,
-       SPIDER_NET_GRMMPINT,
-       SPIDER_NET_GDTDEN0INT,
-       SPIDER_NET_GDDDEN0INT,
-       SPIDER_NET_GDCDEN0INT,
-       SPIDER_NET_GDBDEN0INT,
-       SPIDER_NET_GDADEN0INT,
-       SPIDER_NET_GDTFDCINT,
-       SPIDER_NET_GDDFDCINT,
-       SPIDER_NET_GDCFDCINT,
-       SPIDER_NET_GDBFDCINT,
-       SPIDER_NET_GDAFDCINT,
-       SPIDER_NET_GTTEDINT,
-       SPIDER_NET_GDTDCEINT,
-       SPIDER_NET_GRFDNMINT,
-       SPIDER_NET_GRFCNMINT,
-       SPIDER_NET_GRFBNMINT,
-       SPIDER_NET_GRFANMINT,
-       SPIDER_NET_GRFNMINT,
-       SPIDER_NET_G1TMCNTINT,
-       SPIDER_NET_GFREECNTINT
-};
-/* GHIINT1STS bits */
-enum spider_net_int1_status {
-       SPIDER_NET_GTMFLLINT = 0,
-       SPIDER_NET_GRMFLLINT,
-       SPIDER_NET_GTMSHTINT,
-       SPIDER_NET_GDTINVDINT,
-       SPIDER_NET_GRFDFLLINT,
-       SPIDER_NET_GDDDCEINT,
-       SPIDER_NET_GDDINVDINT,
-       SPIDER_NET_GRFCFLLINT,
-       SPIDER_NET_GDCDCEINT,
-       SPIDER_NET_GDCINVDINT,
-       SPIDER_NET_GRFBFLLINT,
-       SPIDER_NET_GDBDCEINT,
-       SPIDER_NET_GDBINVDINT,
-       SPIDER_NET_GRFAFLLINT,
-       SPIDER_NET_GDADCEINT,
-       SPIDER_NET_GDAINVDINT,
-       SPIDER_NET_GDTRSERINT,
-       SPIDER_NET_GDDRSERINT,
-       SPIDER_NET_GDCRSERINT,
-       SPIDER_NET_GDBRSERINT,
-       SPIDER_NET_GDARSERINT,
-       SPIDER_NET_GDSERINT,
-       SPIDER_NET_GDTPTERINT,
-       SPIDER_NET_GDDPTERINT,
-       SPIDER_NET_GDCPTERINT,
-       SPIDER_NET_GDBPTERINT,
-       SPIDER_NET_GDAPTERINT
-};
-/* GHIINT2STS bits */
-enum spider_net_int2_status {
-       SPIDER_NET_GPROPERINT = 0,
-       SPIDER_NET_GMCTCRSNGINT,
-       SPIDER_NET_GMCTLCOLINT,
-       SPIDER_NET_GMCTTMOTINT,
-       SPIDER_NET_GMCRCAERINT,
-       SPIDER_NET_GMCRCALERINT,
-       SPIDER_NET_GMCRALNERINT,
-       SPIDER_NET_GMCROVRINT,
-       SPIDER_NET_GMCRRNTINT,
-       SPIDER_NET_GMCRRXERINT,
-       SPIDER_NET_GTITCSERINT,
-       SPIDER_NET_GTIFMTERINT,
-       SPIDER_NET_GTIPKTRVKINT,
-       SPIDER_NET_GTISPINGINT,
-       SPIDER_NET_GTISADNGINT,
-       SPIDER_NET_GTISPDNGINT,
-       SPIDER_NET_GRIFMTERINT,
-       SPIDER_NET_GRIPKTRVKINT,
-       SPIDER_NET_GRISPINGINT,
-       SPIDER_NET_GRISADNGINT,
-       SPIDER_NET_GRISPDNGINT
-};
-
-#define SPIDER_NET_TXINT       (1 << SPIDER_NET_GDTFDCINT)
-
-/* We rely on flagged descriptor interrupts */
-#define SPIDER_NET_RXINT       ( (1 << SPIDER_NET_GDAFDCINT) )
-
-#define SPIDER_NET_LINKINT     ( 1 << SPIDER_NET_GMAC2INT )
-
-#define SPIDER_NET_ERRINT      ( 0xffffffff & \
-                                 (~SPIDER_NET_TXINT) & \
-                                 (~SPIDER_NET_RXINT) & \
-                                 (~SPIDER_NET_LINKINT) )
-
-#define SPIDER_NET_GPREXEC                     0x80000000
-#define SPIDER_NET_GPRDAT_MASK                 0x0000ffff
-
-#define SPIDER_NET_DMAC_NOINTR_COMPLETE                0x00800000
-#define SPIDER_NET_DMAC_TXFRMTL                0x00040000
-#define SPIDER_NET_DMAC_TCP                    0x00020000
-#define SPIDER_NET_DMAC_UDP                    0x00030000
-#define SPIDER_NET_TXDCEST                     0x08000000
-
-#define SPIDER_NET_DESCR_RXFDIS        0x00000001
-#define SPIDER_NET_DESCR_RXDCEIS       0x00000002
-#define SPIDER_NET_DESCR_RXDEN0IS      0x00000004
-#define SPIDER_NET_DESCR_RXINVDIS      0x00000008
-#define SPIDER_NET_DESCR_RXRERRIS      0x00000010
-#define SPIDER_NET_DESCR_RXFDCIMS      0x00000100
-#define SPIDER_NET_DESCR_RXDCEIMS      0x00000200
-#define SPIDER_NET_DESCR_RXDEN0IMS     0x00000400
-#define SPIDER_NET_DESCR_RXINVDIMS     0x00000800
-#define SPIDER_NET_DESCR_RXRERRMIS     0x00001000
-#define SPIDER_NET_DESCR_UNUSED        0x077fe0e0
-
-#define SPIDER_NET_DESCR_IND_PROC_MASK         0xF0000000
-#define SPIDER_NET_DESCR_COMPLETE              0x00000000 /* used in rx and tx */
-#define SPIDER_NET_DESCR_RESPONSE_ERROR                0x10000000 /* used in rx and tx */
-#define SPIDER_NET_DESCR_PROTECTION_ERROR      0x20000000 /* used in rx and tx */
-#define SPIDER_NET_DESCR_FRAME_END             0x40000000 /* used in rx */
-#define SPIDER_NET_DESCR_FORCE_END             0x50000000 /* used in rx and tx */
-#define SPIDER_NET_DESCR_CARDOWNED             0xA0000000 /* used in rx and tx */
-#define SPIDER_NET_DESCR_NOT_IN_USE            0xF0000000
-#define SPIDER_NET_DESCR_TXDESFLG              0x00800000
-
-#define SPIDER_NET_DESCR_BAD_STATUS   (SPIDER_NET_DESCR_RXDEN0IS | \
-                                       SPIDER_NET_DESCR_RXRERRIS | \
-                                       SPIDER_NET_DESCR_RXDEN0IMS | \
-                                       SPIDER_NET_DESCR_RXINVDIMS | \
-                                       SPIDER_NET_DESCR_RXRERRMIS | \
-                                       SPIDER_NET_DESCR_UNUSED)
-
-/* Descriptor, as defined by the hardware */
-struct spider_net_hw_descr {
-       u32 buf_addr;
-       u32 buf_size;
-       u32 next_descr_addr;
-       u32 dmac_cmd_status;
-       u32 result_size;
-       u32 valid_size; /* all zeroes for tx */
-       u32 data_status;
-       u32 data_error; /* all zeroes for tx */
-} __attribute__((aligned(32)));
-
-struct spider_net_descr {
-       struct spider_net_hw_descr *hwdescr;
-       struct sk_buff *skb;
-       u32 bus_addr;
-       struct spider_net_descr *next;
-       struct spider_net_descr *prev;
-};
-
-struct spider_net_descr_chain {
-       spinlock_t lock;
-       struct spider_net_descr *head;
-       struct spider_net_descr *tail;
-       struct spider_net_descr *ring;
-       int num_desc;
-       struct spider_net_hw_descr *hwring;
-       dma_addr_t dma_addr;
-};
-
-/* descriptor data_status bits */
-#define SPIDER_NET_RX_IPCHK            29
-#define SPIDER_NET_RX_TCPCHK           28
-#define SPIDER_NET_VLAN_PACKET         21
-#define SPIDER_NET_DATA_STATUS_CKSUM_MASK ( (1 << SPIDER_NET_RX_IPCHK) | \
-                                         (1 << SPIDER_NET_RX_TCPCHK) )
-
-/* descriptor data_error bits */
-#define SPIDER_NET_RX_IPCHKERR         27
-#define SPIDER_NET_RX_RXTCPCHKERR      28
-
-#define SPIDER_NET_DATA_ERR_CKSUM_MASK (1 << SPIDER_NET_RX_IPCHKERR)
-
-/* the cases we don't pass the packet to the stack.
- * 701b8000 would be correct, but every packets gets that flag */
-#define SPIDER_NET_DESTROY_RX_FLAGS    0x700b8000
-
-#define SPIDER_NET_DEFAULT_MSG         ( NETIF_MSG_DRV | \
-                                         NETIF_MSG_PROBE | \
-                                         NETIF_MSG_LINK | \
-                                         NETIF_MSG_TIMER | \
-                                         NETIF_MSG_IFDOWN | \
-                                         NETIF_MSG_IFUP | \
-                                         NETIF_MSG_RX_ERR | \
-                                         NETIF_MSG_TX_ERR | \
-                                         NETIF_MSG_TX_QUEUED | \
-                                         NETIF_MSG_INTR | \
-                                         NETIF_MSG_TX_DONE | \
-                                         NETIF_MSG_RX_STATUS | \
-                                         NETIF_MSG_PKTDATA | \
-                                         NETIF_MSG_HW | \
-                                         NETIF_MSG_WOL )
-
-struct spider_net_extra_stats {
-       unsigned long rx_desc_error;
-       unsigned long tx_timeouts;
-       unsigned long alloc_rx_skb_error;
-       unsigned long rx_iommu_map_error;
-       unsigned long tx_iommu_map_error;
-       unsigned long rx_desc_unk_state;
-};
-
-struct spider_net_card {
-       struct net_device *netdev;
-       struct pci_dev *pdev;
-       struct mii_phy phy;
-
-       struct napi_struct napi;
-
-       int medium;
-
-       void __iomem *regs;
-
-       struct spider_net_descr_chain tx_chain;
-       struct spider_net_descr_chain rx_chain;
-       struct spider_net_descr *low_watermark;
-
-       int aneg_count;
-       struct timer_list aneg_timer;
-       struct timer_list tx_timer;
-       struct work_struct tx_timeout_task;
-       atomic_t tx_timeout_task_counter;
-       wait_queue_head_t waitq;
-       int num_rx_ints;
-       int ignore_rx_ramfull;
-
-       /* for ethtool */
-       int msg_enable;
-       struct spider_net_extra_stats spider_stats;
-
-       /* Must be last item in struct */
-       struct spider_net_descr darray[0];
-};
-
-#endif
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
deleted file mode 100644 (file)
index 9c288cd..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Network device driver for Cell Processor-Based Blade
- *
- * (C) Copyright IBM Corp. 2005
- *
- * Authors : Utz Bacher <utz.bacher@de.ibm.com>
- *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/pci.h>
-
-#include "spider_net.h"
-
-
-static struct {
-       const char str[ETH_GSTRING_LEN];
-} ethtool_stats_keys[] = {
-       { "tx_packets" },
-       { "tx_bytes" },
-       { "rx_packets" },
-       { "rx_bytes" },
-       { "tx_errors" },
-       { "tx_dropped" },
-       { "rx_dropped" },
-       { "rx_descriptor_error" },
-       { "tx_timeouts" },
-       { "alloc_rx_skb_error" },
-       { "rx_iommu_map_error" },
-       { "tx_iommu_map_error" },
-       { "rx_desc_unk_state" },
-};
-
-static int
-spider_net_ethtool_get_settings(struct net_device *netdev,
-                              struct ethtool_cmd *cmd)
-{
-       struct spider_net_card *card;
-       card = netdev_priv(netdev);
-
-       cmd->supported   = (SUPPORTED_1000baseT_Full |
-                            SUPPORTED_FIBRE);
-       cmd->advertising = (ADVERTISED_1000baseT_Full |
-                            ADVERTISED_FIBRE);
-       cmd->port = PORT_FIBRE;
-       ethtool_cmd_speed_set(cmd, card->phy.speed);
-       cmd->duplex = DUPLEX_FULL;
-
-       return 0;
-}
-
-static void
-spider_net_ethtool_get_drvinfo(struct net_device *netdev,
-                              struct ethtool_drvinfo *drvinfo)
-{
-       struct spider_net_card *card;
-       card = netdev_priv(netdev);
-
-       /* clear and fill out info */
-       memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
-       strncpy(drvinfo->driver, spider_net_driver_name, 32);
-       strncpy(drvinfo->version, VERSION, 32);
-       strcpy(drvinfo->fw_version, "no information");
-       strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
-}
-
-static void
-spider_net_ethtool_get_wol(struct net_device *netdev,
-                          struct ethtool_wolinfo *wolinfo)
-{
-       /* no support for wol */
-       wolinfo->supported = 0;
-       wolinfo->wolopts = 0;
-}
-
-static u32
-spider_net_ethtool_get_msglevel(struct net_device *netdev)
-{
-       struct spider_net_card *card;
-       card = netdev_priv(netdev);
-       return card->msg_enable;
-}
-
-static void
-spider_net_ethtool_set_msglevel(struct net_device *netdev,
-                               u32 level)
-{
-       struct spider_net_card *card;
-       card = netdev_priv(netdev);
-       card->msg_enable = level;
-}
-
-static int
-spider_net_ethtool_nway_reset(struct net_device *netdev)
-{
-       if (netif_running(netdev)) {
-               spider_net_stop(netdev);
-               spider_net_open(netdev);
-       }
-       return 0;
-}
-
-static void
-spider_net_ethtool_get_ringparam(struct net_device *netdev,
-                                struct ethtool_ringparam *ering)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-
-       ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
-       ering->tx_pending = card->tx_chain.num_desc;
-       ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
-       ering->rx_pending = card->rx_chain.num_desc;
-}
-
-static int spider_net_get_sset_count(struct net_device *netdev, int sset)
-{
-       switch (sset) {
-       case ETH_SS_STATS:
-               return ARRAY_SIZE(ethtool_stats_keys);
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-static void spider_net_get_ethtool_stats(struct net_device *netdev,
-               struct ethtool_stats *stats, u64 *data)
-{
-       struct spider_net_card *card = netdev_priv(netdev);
-
-       data[0] = netdev->stats.tx_packets;
-       data[1] = netdev->stats.tx_bytes;
-       data[2] = netdev->stats.rx_packets;
-       data[3] = netdev->stats.rx_bytes;
-       data[4] = netdev->stats.tx_errors;
-       data[5] = netdev->stats.tx_dropped;
-       data[6] = netdev->stats.rx_dropped;
-       data[7] = card->spider_stats.rx_desc_error;
-       data[8] = card->spider_stats.tx_timeouts;
-       data[9] = card->spider_stats.alloc_rx_skb_error;
-       data[10] = card->spider_stats.rx_iommu_map_error;
-       data[11] = card->spider_stats.tx_iommu_map_error;
-       data[12] = card->spider_stats.rx_desc_unk_state;
-}
-
-static void spider_net_get_strings(struct net_device *netdev, u32 stringset,
-                                  u8 *data)
-{
-       memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
-}
-
-const struct ethtool_ops spider_net_ethtool_ops = {
-       .get_settings           = spider_net_ethtool_get_settings,
-       .get_drvinfo            = spider_net_ethtool_get_drvinfo,
-       .get_wol                = spider_net_ethtool_get_wol,
-       .get_msglevel           = spider_net_ethtool_get_msglevel,
-       .set_msglevel           = spider_net_ethtool_set_msglevel,
-       .get_link               = ethtool_op_get_link,
-       .nway_reset             = spider_net_ethtool_nway_reset,
-       .get_ringparam          = spider_net_ethtool_get_ringparam,
-       .get_strings            = spider_net_get_strings,
-       .get_sset_count         = spider_net_get_sset_count,
-       .get_ethtool_stats      = spider_net_get_ethtool_stats,
-};
-
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
deleted file mode 100644 (file)
index 4a55a16..0000000
+++ /dev/null
@@ -1,2228 +0,0 @@
-/*
- * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
- *
- * Based on skelton.c by Donald Becker.
- *
- * This driver is a replacement of older and less maintained version.
- * This is a header of the older version:
- *     -----<snip>-----
- *     Copyright 2001 MontaVista Software Inc.
- *     Author: MontaVista Software, Inc.
- *             ahennessy@mvista.com
- *     Copyright (C) 2000-2001 Toshiba Corporation
- *     static const char *version =
- *             "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
- *     -----<snip>-----
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * (C) Copyright TOSHIBA CORPORATION 2004-2005
- * All Rights Reserved.
- */
-
-#define DRV_VERSION    "1.39"
-static const char *version = "tc35815.c:v" DRV_VERSION "\n";
-#define MODNAME                        "tc35815"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/if_vlan.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/phy.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/prefetch.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
-enum tc35815_chiptype {
-       TC35815CF = 0,
-       TC35815_NWU,
-       TC35815_TX4939,
-};
-
-/* indexed by tc35815_chiptype, above */
-static const struct {
-       const char *name;
-} chip_info[] __devinitdata = {
-       { "TOSHIBA TC35815CF 10/100BaseTX" },
-       { "TOSHIBA TC35815 with Wake on LAN" },
-       { "TOSHIBA TC35815/TX4939" },
-};
-
-static DEFINE_PCI_DEVICE_TABLE(tc35815_pci_tbl) = {
-       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
-       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
-       {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
-       {0,}
-};
-MODULE_DEVICE_TABLE(pci, tc35815_pci_tbl);
-
-/* see MODULE_PARM_DESC */
-static struct tc35815_options {
-       int speed;
-       int duplex;
-} options;
-
-/*
- * Registers
- */
-struct tc35815_regs {
-       __u32 DMA_Ctl;          /* 0x00 */
-       __u32 TxFrmPtr;
-       __u32 TxThrsh;
-       __u32 TxPollCtr;
-       __u32 BLFrmPtr;
-       __u32 RxFragSize;
-       __u32 Int_En;
-       __u32 FDA_Bas;
-       __u32 FDA_Lim;          /* 0x20 */
-       __u32 Int_Src;
-       __u32 unused0[2];
-       __u32 PauseCnt;
-       __u32 RemPauCnt;
-       __u32 TxCtlFrmStat;
-       __u32 unused1;
-       __u32 MAC_Ctl;          /* 0x40 */
-       __u32 CAM_Ctl;
-       __u32 Tx_Ctl;
-       __u32 Tx_Stat;
-       __u32 Rx_Ctl;
-       __u32 Rx_Stat;
-       __u32 MD_Data;
-       __u32 MD_CA;
-       __u32 CAM_Adr;          /* 0x60 */
-       __u32 CAM_Data;
-       __u32 CAM_Ena;
-       __u32 PROM_Ctl;
-       __u32 PROM_Data;
-       __u32 Algn_Cnt;
-       __u32 CRC_Cnt;
-       __u32 Miss_Cnt;
-};
-
-/*
- * Bit assignments
- */
-/* DMA_Ctl bit assign ------------------------------------------------------- */
-#define DMA_RxAlign           0x00c00000 /* 1:Reception Alignment           */
-#define DMA_RxAlign_1         0x00400000
-#define DMA_RxAlign_2         0x00800000
-#define DMA_RxAlign_3         0x00c00000
-#define DMA_M66EnStat         0x00080000 /* 1:66MHz Enable State            */
-#define DMA_IntMask           0x00040000 /* 1:Interrupt mask                */
-#define DMA_SWIntReq          0x00020000 /* 1:Software Interrupt request    */
-#define DMA_TxWakeUp          0x00010000 /* 1:Transmit Wake Up              */
-#define DMA_RxBigE            0x00008000 /* 1:Receive Big Endian            */
-#define DMA_TxBigE            0x00004000 /* 1:Transmit Big Endian           */
-#define DMA_TestMode          0x00002000 /* 1:Test Mode                     */
-#define DMA_PowrMgmnt         0x00001000 /* 1:Power Management              */
-#define DMA_DmBurst_Mask       0x000001fc /* DMA Burst size                 */
-
-/* RxFragSize bit assign ---------------------------------------------------- */
-#define RxFrag_EnPack         0x00008000 /* 1:Enable Packing                */
-#define RxFrag_MinFragMask     0x00000ffc /* Minimum Fragment               */
-
-/* MAC_Ctl bit assign ------------------------------------------------------- */
-#define MAC_Link10            0x00008000 /* 1:Link Status 10Mbits           */
-#define MAC_EnMissRoll        0x00002000 /* 1:Enable Missed Roll            */
-#define MAC_MissRoll          0x00000400 /* 1:Missed Roll                   */
-#define MAC_Loop10            0x00000080 /* 1:Loop 10 Mbps                  */
-#define MAC_Conn_Auto         0x00000000 /*00:Connection mode (Automatic)   */
-#define MAC_Conn_10M          0x00000020 /*01:                (10Mbps endec)*/
-#define MAC_Conn_Mll          0x00000040 /*10:                (Mll clock)   */
-#define MAC_MacLoop           0x00000010 /* 1:MAC Loopback                  */
-#define MAC_FullDup           0x00000008 /* 1:Full Duplex 0:Half Duplex     */
-#define MAC_Reset             0x00000004 /* 1:Software Reset                */
-#define MAC_HaltImm           0x00000002 /* 1:Halt Immediate                */
-#define MAC_HaltReq           0x00000001 /* 1:Halt request                  */
-
-/* PROM_Ctl bit assign ------------------------------------------------------ */
-#define PROM_Busy             0x00008000 /* 1:Busy (Start Operation)        */
-#define PROM_Read             0x00004000 /*10:Read operation                */
-#define PROM_Write            0x00002000 /*01:Write operation               */
-#define PROM_Erase            0x00006000 /*11:Erase operation               */
-                                         /*00:Enable or Disable Writting,   */
-                                         /*      as specified in PROM_Addr. */
-#define PROM_Addr_Ena         0x00000030 /*11xxxx:PROM Write enable         */
-                                         /*00xxxx:           disable        */
-
-/* CAM_Ctl bit assign ------------------------------------------------------- */
-#define CAM_CompEn            0x00000010 /* 1:CAM Compare Enable            */
-#define CAM_NegCAM            0x00000008 /* 1:Reject packets CAM recognizes,*/
-                                         /*                    accept other */
-#define CAM_BroadAcc          0x00000004 /* 1:Broadcast assept              */
-#define CAM_GroupAcc          0x00000002 /* 1:Multicast assept              */
-#define CAM_StationAcc        0x00000001 /* 1:unicast accept                */
-
-/* CAM_Ena bit assign ------------------------------------------------------- */
-#define CAM_ENTRY_MAX                 21   /* CAM Data entry max count      */
-#define CAM_Ena_Mask ((1<<CAM_ENTRY_MAX)-1) /* CAM Enable bits (Max 21bits)  */
-#define CAM_Ena_Bit(index)     (1 << (index))
-#define CAM_ENTRY_DESTINATION  0
-#define CAM_ENTRY_SOURCE       1
-#define CAM_ENTRY_MACCTL       20
-
-/* Tx_Ctl bit assign -------------------------------------------------------- */
-#define Tx_En                 0x00000001 /* 1:Transmit enable               */
-#define Tx_TxHalt             0x00000002 /* 1:Transmit Halt Request         */
-#define Tx_NoPad              0x00000004 /* 1:Suppress Padding              */
-#define Tx_NoCRC              0x00000008 /* 1:Suppress Padding              */
-#define Tx_FBack              0x00000010 /* 1:Fast Back-off                 */
-#define Tx_EnUnder            0x00000100 /* 1:Enable Underrun               */
-#define Tx_EnExDefer          0x00000200 /* 1:Enable Excessive Deferral     */
-#define Tx_EnLCarr            0x00000400 /* 1:Enable Lost Carrier           */
-#define Tx_EnExColl           0x00000800 /* 1:Enable Excessive Collision    */
-#define Tx_EnLateColl         0x00001000 /* 1:Enable Late Collision         */
-#define Tx_EnTxPar            0x00002000 /* 1:Enable Transmit Parity        */
-#define Tx_EnComp             0x00004000 /* 1:Enable Completion             */
-
-/* Tx_Stat bit assign ------------------------------------------------------- */
-#define Tx_TxColl_MASK        0x0000000F /* Tx Collision Count              */
-#define Tx_ExColl             0x00000010 /* Excessive Collision             */
-#define Tx_TXDefer            0x00000020 /* Transmit Defered                */
-#define Tx_Paused             0x00000040 /* Transmit Paused                 */
-#define Tx_IntTx              0x00000080 /* Interrupt on Tx                 */
-#define Tx_Under              0x00000100 /* Underrun                        */
-#define Tx_Defer              0x00000200 /* Deferral                        */
-#define Tx_NCarr              0x00000400 /* No Carrier                      */
-#define Tx_10Stat             0x00000800 /* 10Mbps Status                   */
-#define Tx_LateColl           0x00001000 /* Late Collision                  */
-#define Tx_TxPar              0x00002000 /* Tx Parity Error                 */
-#define Tx_Comp                       0x00004000 /* Completion                      */
-#define Tx_Halted             0x00008000 /* Tx Halted                       */
-#define Tx_SQErr              0x00010000 /* Signal Quality Error(SQE)       */
-
-/* Rx_Ctl bit assign -------------------------------------------------------- */
-#define Rx_EnGood             0x00004000 /* 1:Enable Good                   */
-#define Rx_EnRxPar            0x00002000 /* 1:Enable Receive Parity         */
-#define Rx_EnLongErr          0x00000800 /* 1:Enable Long Error             */
-#define Rx_EnOver             0x00000400 /* 1:Enable OverFlow               */
-#define Rx_EnCRCErr           0x00000200 /* 1:Enable CRC Error              */
-#define Rx_EnAlign            0x00000100 /* 1:Enable Alignment              */
-#define Rx_IgnoreCRC          0x00000040 /* 1:Ignore CRC Value              */
-#define Rx_StripCRC           0x00000010 /* 1:Strip CRC Value               */
-#define Rx_ShortEn            0x00000008 /* 1:Short Enable                  */
-#define Rx_LongEn             0x00000004 /* 1:Long Enable                   */
-#define Rx_RxHalt             0x00000002 /* 1:Receive Halt Request          */
-#define Rx_RxEn                       0x00000001 /* 1:Receive Intrrupt Enable       */
-
-/* Rx_Stat bit assign ------------------------------------------------------- */
-#define Rx_Halted             0x00008000 /* Rx Halted                       */
-#define Rx_Good                       0x00004000 /* Rx Good                         */
-#define Rx_RxPar              0x00002000 /* Rx Parity Error                 */
-#define Rx_TypePkt            0x00001000 /* Rx Type Packet                  */
-#define Rx_LongErr            0x00000800 /* Rx Long Error                   */
-#define Rx_Over                       0x00000400 /* Rx Overflow                     */
-#define Rx_CRCErr             0x00000200 /* Rx CRC Error                    */
-#define Rx_Align              0x00000100 /* Rx Alignment Error              */
-#define Rx_10Stat             0x00000080 /* Rx 10Mbps Status                */
-#define Rx_IntRx              0x00000040 /* Rx Interrupt                    */
-#define Rx_CtlRecd            0x00000020 /* Rx Control Receive              */
-#define Rx_InLenErr           0x00000010 /* Rx In Range Frame Length Error  */
-
-#define Rx_Stat_Mask          0x0000FFF0 /* Rx All Status Mask              */
-
-/* Int_En bit assign -------------------------------------------------------- */
-#define Int_NRAbtEn           0x00000800 /* 1:Non-recoverable Abort Enable  */
-#define Int_TxCtlCmpEn        0x00000400 /* 1:Transmit Ctl Complete Enable  */
-#define Int_DmParErrEn        0x00000200 /* 1:DMA Parity Error Enable       */
-#define Int_DParDEn           0x00000100 /* 1:Data Parity Error Enable      */
-#define Int_EarNotEn          0x00000080 /* 1:Early Notify Enable           */
-#define Int_DParErrEn         0x00000040 /* 1:Detected Parity Error Enable  */
-#define Int_SSysErrEn         0x00000020 /* 1:Signalled System Error Enable */
-#define Int_RMasAbtEn         0x00000010 /* 1:Received Master Abort Enable  */
-#define Int_RTargAbtEn        0x00000008 /* 1:Received Target Abort Enable  */
-#define Int_STargAbtEn        0x00000004 /* 1:Signalled Target Abort Enable */
-#define Int_BLExEn            0x00000002 /* 1:Buffer List Exhausted Enable  */
-#define Int_FDAExEn           0x00000001 /* 1:Free Descriptor Area          */
-                                         /*               Exhausted Enable  */
-
-/* Int_Src bit assign ------------------------------------------------------- */
-#define Int_NRabt             0x00004000 /* 1:Non Recoverable error         */
-#define Int_DmParErrStat       0x00002000 /* 1:DMA Parity Error & Clear             */
-#define Int_BLEx              0x00001000 /* 1:Buffer List Empty & Clear     */
-#define Int_FDAEx             0x00000800 /* 1:FDA Empty & Clear             */
-#define Int_IntNRAbt          0x00000400 /* 1:Non Recoverable Abort         */
-#define Int_IntCmp            0x00000200 /* 1:MAC control packet complete   */
-#define Int_IntExBD           0x00000100 /* 1:Interrupt Extra BD & Clear    */
-#define Int_DmParErr          0x00000080 /* 1:DMA Parity Error & Clear      */
-#define Int_IntEarNot         0x00000040 /* 1:Receive Data write & Clear    */
-#define Int_SWInt             0x00000020 /* 1:Software request & Clear      */
-#define Int_IntBLEx           0x00000010 /* 1:Buffer List Empty & Clear     */
-#define Int_IntFDAEx          0x00000008 /* 1:FDA Empty & Clear             */
-#define Int_IntPCI            0x00000004 /* 1:PCI controller & Clear        */
-#define Int_IntMacRx          0x00000002 /* 1:Rx controller & Clear         */
-#define Int_IntMacTx          0x00000001 /* 1:Tx controller & Clear         */
-
-/* MD_CA bit assign --------------------------------------------------------- */
-#define MD_CA_PreSup          0x00001000 /* 1:Preamble Suppress                     */
-#define MD_CA_Busy            0x00000800 /* 1:Busy (Start Operation)        */
-#define MD_CA_Wr              0x00000400 /* 1:Write 0:Read                  */
-
-
-/*
- * Descriptors
- */
-
-/* Frame descripter */
-struct FDesc {
-       volatile __u32 FDNext;
-       volatile __u32 FDSystem;
-       volatile __u32 FDStat;
-       volatile __u32 FDCtl;
-};
-
-/* Buffer descripter */
-struct BDesc {
-       volatile __u32 BuffData;
-       volatile __u32 BDCtl;
-};
-
-#define FD_ALIGN       16
-
-/* Frame Descripter bit assign ---------------------------------------------- */
-#define FD_FDLength_MASK       0x0000FFFF /* Length MASK                    */
-#define FD_BDCnt_MASK         0x001F0000 /* BD count MASK in FD             */
-#define FD_FrmOpt_MASK        0x7C000000 /* Frame option MASK               */
-#define FD_FrmOpt_BigEndian    0x40000000 /* Tx/Rx */
-#define FD_FrmOpt_IntTx               0x20000000 /* Tx only */
-#define FD_FrmOpt_NoCRC               0x10000000 /* Tx only */
-#define FD_FrmOpt_NoPadding    0x08000000 /* Tx only */
-#define FD_FrmOpt_Packing      0x04000000 /* Rx only */
-#define FD_CownsFD            0x80000000 /* FD Controller owner bit         */
-#define FD_Next_EOL           0x00000001 /* FD EOL indicator                */
-#define FD_BDCnt_SHIFT        16
-
-/* Buffer Descripter bit assign --------------------------------------------- */
-#define BD_BuffLength_MASK     0x0000FFFF /* Receive Data Size              */
-#define BD_RxBDID_MASK        0x00FF0000 /* BD ID Number MASK               */
-#define BD_RxBDSeqN_MASK       0x7F000000 /* Rx BD Sequence Number          */
-#define BD_CownsBD            0x80000000 /* BD Controller owner bit         */
-#define BD_RxBDID_SHIFT               16
-#define BD_RxBDSeqN_SHIFT      24
-
-
-/* Some useful constants. */
-
-#define TX_CTL_CMD     (Tx_EnTxPar | Tx_EnLateColl | \
-       Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
-       Tx_En)  /* maybe  0x7b01 */
-/* Do not use Rx_StripCRC -- it causes trouble on BLEx/FDAEx condition */
-#define RX_CTL_CMD     (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
-       | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */
-#define INT_EN_CMD  (Int_NRAbtEn | \
-       Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
-       Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
-       Int_STargAbtEn | \
-       Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
-#define DMA_CTL_CMD    DMA_BURST_SIZE
-#define HAVE_DMA_RXALIGN(lp)   likely((lp)->chiptype != TC35815CF)
-
-/* Tuning parameters */
-#define DMA_BURST_SIZE 32
-#define TX_THRESHOLD   1024
-/* used threshold with packet max byte for low pci transfer ability.*/
-#define TX_THRESHOLD_MAX 1536
-/* setting threshold max value when overrun error occurred this count. */
-#define TX_THRESHOLD_KEEP_LIMIT 10
-
-/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
-#define FD_PAGE_NUM 4
-#define RX_BUF_NUM     128     /* < 256 */
-#define RX_FD_NUM      256     /* >= 32 */
-#define TX_FD_NUM      128
-#if RX_CTL_CMD & Rx_LongEn
-#define RX_BUF_SIZE    PAGE_SIZE
-#elif RX_CTL_CMD & Rx_StripCRC
-#define RX_BUF_SIZE    \
-       L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + NET_IP_ALIGN)
-#else
-#define RX_BUF_SIZE    \
-       L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN + NET_IP_ALIGN)
-#endif
-#define RX_FD_RESERVE  (2 / 2) /* max 2 BD per RxFD */
-#define NAPI_WEIGHT    16
-
-struct TxFD {
-       struct FDesc fd;
-       struct BDesc bd;
-       struct BDesc unused;
-};
-
-struct RxFD {
-       struct FDesc fd;
-       struct BDesc bd[0];     /* variable length */
-};
-
-struct FrFD {
-       struct FDesc fd;
-       struct BDesc bd[RX_BUF_NUM];
-};
-
-
-#define tc_readl(addr) ioread32(addr)
-#define tc_writel(d, addr)     iowrite32(d, addr)
-
-#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)
-
-/* Information that need to be kept for each controller. */
-struct tc35815_local {
-       struct pci_dev *pci_dev;
-
-       struct net_device *dev;
-       struct napi_struct napi;
-
-       /* statistics */
-       struct {
-               int max_tx_qlen;
-               int tx_ints;
-               int rx_ints;
-               int tx_underrun;
-       } lstats;
-
-       /* Tx control lock.  This protects the transmit buffer ring
-        * state along with the "tx full" state of the driver.  This
-        * means all netif_queue flow control actions are protected
-        * by this lock as well.
-        */
-       spinlock_t lock;
-       spinlock_t rx_lock;
-
-       struct mii_bus *mii_bus;
-       struct phy_device *phy_dev;
-       int duplex;
-       int speed;
-       int link;
-       struct work_struct restart_work;
-
-       /*
-        * Transmitting: Batch Mode.
-        *      1 BD in 1 TxFD.
-        * Receiving: Non-Packing Mode.
-        *      1 circular FD for Free Buffer List.
-        *      RX_BUF_NUM BD in Free Buffer FD.
-        *      One Free Buffer BD has ETH_FRAME_LEN data buffer.
-        */
-       void *fd_buf;   /* for TxFD, RxFD, FrFD */
-       dma_addr_t fd_buf_dma;
-       struct TxFD *tfd_base;
-       unsigned int tfd_start;
-       unsigned int tfd_end;
-       struct RxFD *rfd_base;
-       struct RxFD *rfd_limit;
-       struct RxFD *rfd_cur;
-       struct FrFD *fbl_ptr;
-       unsigned int fbl_count;
-       struct {
-               struct sk_buff *skb;
-               dma_addr_t skb_dma;
-       } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
-       u32 msg_enable;
-       enum tc35815_chiptype chiptype;
-};
-
-static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
-{
-       return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
-}
-#ifdef DEBUG
-static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
-{
-       return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
-}
-#endif
-static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
-                                      struct pci_dev *hwdev,
-                                      dma_addr_t *dma_handle)
-{
-       struct sk_buff *skb;
-       skb = dev_alloc_skb(RX_BUF_SIZE);
-       if (!skb)
-               return NULL;
-       *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
-                                    PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(hwdev, *dma_handle)) {
-               dev_kfree_skb_any(skb);
-               return NULL;
-       }
-       skb_reserve(skb, 2);    /* make IP header 4byte aligned */
-       return skb;
-}
-
-static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
-{
-       pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
-                        PCI_DMA_FROMDEVICE);
-       dev_kfree_skb_any(skb);
-}
-
-/* Index to functions, as function prototypes. */
-
-static int     tc35815_open(struct net_device *dev);
-static int     tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t     tc35815_interrupt(int irq, void *dev_id);
-static int     tc35815_rx(struct net_device *dev, int limit);
-static int     tc35815_poll(struct napi_struct *napi, int budget);
-static void    tc35815_txdone(struct net_device *dev);
-static int     tc35815_close(struct net_device *dev);
-static struct  net_device_stats *tc35815_get_stats(struct net_device *dev);
-static void    tc35815_set_multicast_list(struct net_device *dev);
-static void    tc35815_tx_timeout(struct net_device *dev);
-static int     tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void    tc35815_poll_controller(struct net_device *dev);
-#endif
-static const struct ethtool_ops tc35815_ethtool_ops;
-
-/* Example routines you must write ;->. */
-static void    tc35815_chip_reset(struct net_device *dev);
-static void    tc35815_chip_init(struct net_device *dev);
-
-#ifdef DEBUG
-static void    panic_queues(struct net_device *dev);
-#endif
-
-static void tc35815_restart_work(struct work_struct *work);
-
-static int tc_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-       struct net_device *dev = bus->priv;
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       unsigned long timeout = jiffies + HZ;
-
-       tc_writel(MD_CA_Busy | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA);
-       udelay(12); /* it takes 32 x 400ns at least */
-       while (tc_readl(&tr->MD_CA) & MD_CA_Busy) {
-               if (time_after(jiffies, timeout))
-                       return -EIO;
-               cpu_relax();
-       }
-       return tc_readl(&tr->MD_Data) & 0xffff;
-}
-
-static int tc_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val)
-{
-       struct net_device *dev = bus->priv;
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       unsigned long timeout = jiffies + HZ;
-
-       tc_writel(val, &tr->MD_Data);
-       tc_writel(MD_CA_Busy | MD_CA_Wr | (mii_id << 5) | (regnum & 0x1f),
-                 &tr->MD_CA);
-       udelay(12); /* it takes 32 x 400ns at least */
-       while (tc_readl(&tr->MD_CA) & MD_CA_Busy) {
-               if (time_after(jiffies, timeout))
-                       return -EIO;
-               cpu_relax();
-       }
-       return 0;
-}
-
-static void tc_handle_link_change(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct phy_device *phydev = lp->phy_dev;
-       unsigned long flags;
-       int status_change = 0;
-
-       spin_lock_irqsave(&lp->lock, flags);
-       if (phydev->link &&
-           (lp->speed != phydev->speed || lp->duplex != phydev->duplex)) {
-               struct tc35815_regs __iomem *tr =
-                       (struct tc35815_regs __iomem *)dev->base_addr;
-               u32 reg;
-
-               reg = tc_readl(&tr->MAC_Ctl);
-               reg |= MAC_HaltReq;
-               tc_writel(reg, &tr->MAC_Ctl);
-               if (phydev->duplex == DUPLEX_FULL)
-                       reg |= MAC_FullDup;
-               else
-                       reg &= ~MAC_FullDup;
-               tc_writel(reg, &tr->MAC_Ctl);
-               reg &= ~MAC_HaltReq;
-               tc_writel(reg, &tr->MAC_Ctl);
-
-               /*
-                * TX4939 PCFG.SPEEDn bit will be changed on
-                * NETDEV_CHANGE event.
-                */
-               /*
-                * WORKAROUND: enable LostCrS only if half duplex
-                * operation.
-                * (TX4939 does not have EnLCarr)
-                */
-               if (phydev->duplex == DUPLEX_HALF &&
-                   lp->chiptype != TC35815_TX4939)
-                       tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr,
-                                 &tr->Tx_Ctl);
-
-               lp->speed = phydev->speed;
-               lp->duplex = phydev->duplex;
-               status_change = 1;
-       }
-
-       if (phydev->link != lp->link) {
-               if (phydev->link) {
-                       /* delayed promiscuous enabling */
-                       if (dev->flags & IFF_PROMISC)
-                               tc35815_set_multicast_list(dev);
-               } else {
-                       lp->speed = 0;
-                       lp->duplex = -1;
-               }
-               lp->link = phydev->link;
-
-               status_change = 1;
-       }
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       if (status_change && netif_msg_link(lp)) {
-               phy_print_status(phydev);
-               pr_debug("%s: MII BMCR %04x BMSR %04x LPA %04x\n",
-                        dev->name,
-                        phy_read(phydev, MII_BMCR),
-                        phy_read(phydev, MII_BMSR),
-                        phy_read(phydev, MII_LPA));
-       }
-}
-
-static int tc_mii_probe(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct phy_device *phydev = NULL;
-       int phy_addr;
-       u32 dropmask;
-
-       /* find the first phy */
-       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-               if (lp->mii_bus->phy_map[phy_addr]) {
-                       if (phydev) {
-                               printk(KERN_ERR "%s: multiple PHYs found\n",
-                                      dev->name);
-                               return -EINVAL;
-                       }
-                       phydev = lp->mii_bus->phy_map[phy_addr];
-                       break;
-               }
-       }
-
-       if (!phydev) {
-               printk(KERN_ERR "%s: no PHY found\n", dev->name);
-               return -ENODEV;
-       }
-
-       /* attach the mac to the phy */
-       phydev = phy_connect(dev, dev_name(&phydev->dev),
-                            &tc_handle_link_change, 0,
-                            lp->chiptype == TC35815_TX4939 ?
-                            PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
-       if (IS_ERR(phydev)) {
-               printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
-               return PTR_ERR(phydev);
-       }
-       printk(KERN_INFO "%s: attached PHY driver [%s] "
-               "(mii_bus:phy_addr=%s, id=%x)\n",
-               dev->name, phydev->drv->name, dev_name(&phydev->dev),
-               phydev->phy_id);
-
-       /* mask with MAC supported features */
-       phydev->supported &= PHY_BASIC_FEATURES;
-       dropmask = 0;
-       if (options.speed == 10)
-               dropmask |= SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
-       else if (options.speed == 100)
-               dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full;
-       if (options.duplex == 1)
-               dropmask |= SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full;
-       else if (options.duplex == 2)
-               dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_100baseT_Half;
-       phydev->supported &= ~dropmask;
-       phydev->advertising = phydev->supported;
-
-       lp->link = 0;
-       lp->speed = 0;
-       lp->duplex = -1;
-       lp->phy_dev = phydev;
-
-       return 0;
-}
-
-static int tc_mii_init(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       int err;
-       int i;
-
-       lp->mii_bus = mdiobus_alloc();
-       if (lp->mii_bus == NULL) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-       lp->mii_bus->name = "tc35815_mii_bus";
-       lp->mii_bus->read = tc_mdio_read;
-       lp->mii_bus->write = tc_mdio_write;
-       snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x",
-                (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn);
-       lp->mii_bus->priv = dev;
-       lp->mii_bus->parent = &lp->pci_dev->dev;
-       lp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-       if (!lp->mii_bus->irq) {
-               err = -ENOMEM;
-               goto err_out_free_mii_bus;
-       }
-
-       for (i = 0; i < PHY_MAX_ADDR; i++)
-               lp->mii_bus->irq[i] = PHY_POLL;
-
-       err = mdiobus_register(lp->mii_bus);
-       if (err)
-               goto err_out_free_mdio_irq;
-       err = tc_mii_probe(dev);
-       if (err)
-               goto err_out_unregister_bus;
-       return 0;
-
-err_out_unregister_bus:
-       mdiobus_unregister(lp->mii_bus);
-err_out_free_mdio_irq:
-       kfree(lp->mii_bus->irq);
-err_out_free_mii_bus:
-       mdiobus_free(lp->mii_bus);
-err_out:
-       return err;
-}
-
-#ifdef CONFIG_CPU_TX49XX
-/*
- * Find a platform_device providing a MAC address.  The platform code
- * should provide a "tc35815-mac" device with a MAC address in its
- * platform_data.
- */
-static int __devinit tc35815_mac_match(struct device *dev, void *data)
-{
-       struct platform_device *plat_dev = to_platform_device(dev);
-       struct pci_dev *pci_dev = data;
-       unsigned int id = pci_dev->irq;
-       return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;
-}
-
-static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct device *pd = bus_find_device(&platform_bus_type, NULL,
-                                           lp->pci_dev, tc35815_mac_match);
-       if (pd) {
-               if (pd->platform_data)
-                       memcpy(dev->dev_addr, pd->platform_data, ETH_ALEN);
-               put_device(pd);
-               return is_valid_ether_addr(dev->dev_addr) ? 0 : -ENODEV;
-       }
-       return -ENODEV;
-}
-#else
-static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
-{
-       return -ENODEV;
-}
-#endif
-
-static int __devinit tc35815_init_dev_addr(struct net_device *dev)
-{
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       int i;
-
-       while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-               ;
-       for (i = 0; i < 6; i += 2) {
-               unsigned short data;
-               tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
-               while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-                       ;
-               data = tc_readl(&tr->PROM_Data);
-               dev->dev_addr[i] = data & 0xff;
-               dev->dev_addr[i+1] = data >> 8;
-       }
-       if (!is_valid_ether_addr(dev->dev_addr))
-               return tc35815_read_plat_dev_addr(dev);
-       return 0;
-}
-
-static const struct net_device_ops tc35815_netdev_ops = {
-       .ndo_open               = tc35815_open,
-       .ndo_stop               = tc35815_close,
-       .ndo_start_xmit         = tc35815_send_packet,
-       .ndo_get_stats          = tc35815_get_stats,
-       .ndo_set_multicast_list = tc35815_set_multicast_list,
-       .ndo_tx_timeout         = tc35815_tx_timeout,
-       .ndo_do_ioctl           = tc35815_ioctl,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = tc35815_poll_controller,
-#endif
-};
-
-static int __devinit tc35815_init_one(struct pci_dev *pdev,
-                                     const struct pci_device_id *ent)
-{
-       void __iomem *ioaddr = NULL;
-       struct net_device *dev;
-       struct tc35815_local *lp;
-       int rc;
-
-       static int printed_version;
-       if (!printed_version++) {
-               printk(version);
-               dev_printk(KERN_DEBUG, &pdev->dev,
-                          "speed:%d duplex:%d\n",
-                          options.speed, options.duplex);
-       }
-
-       if (!pdev->irq) {
-               dev_warn(&pdev->dev, "no IRQ assigned.\n");
-               return -ENODEV;
-       }
-
-       /* dev zeroed in alloc_etherdev */
-       dev = alloc_etherdev(sizeof(*lp));
-       if (dev == NULL) {
-               dev_err(&pdev->dev, "unable to alloc new ethernet\n");
-               return -ENOMEM;
-       }
-       SET_NETDEV_DEV(dev, &pdev->dev);
-       lp = netdev_priv(dev);
-       lp->dev = dev;
-
-       /* enable device (incl. PCI PM wakeup), and bus-mastering */
-       rc = pcim_enable_device(pdev);
-       if (rc)
-               goto err_out;
-       rc = pcim_iomap_regions(pdev, 1 << 1, MODNAME);
-       if (rc)
-               goto err_out;
-       pci_set_master(pdev);
-       ioaddr = pcim_iomap_table(pdev)[1];
-
-       /* Initialize the device structure. */
-       dev->netdev_ops = &tc35815_netdev_ops;
-       dev->ethtool_ops = &tc35815_ethtool_ops;
-       dev->watchdog_timeo = TC35815_TX_TIMEOUT;
-       netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT);
-
-       dev->irq = pdev->irq;
-       dev->base_addr = (unsigned long)ioaddr;
-
-       INIT_WORK(&lp->restart_work, tc35815_restart_work);
-       spin_lock_init(&lp->lock);
-       spin_lock_init(&lp->rx_lock);
-       lp->pci_dev = pdev;
-       lp->chiptype = ent->driver_data;
-
-       lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
-       pci_set_drvdata(pdev, dev);
-
-       /* Soft reset the chip. */
-       tc35815_chip_reset(dev);
-
-       /* Retrieve the ethernet address. */
-       if (tc35815_init_dev_addr(dev)) {
-               dev_warn(&pdev->dev, "not valid ether addr\n");
-               random_ether_addr(dev->dev_addr);
-       }
-
-       rc = register_netdev(dev);
-       if (rc)
-               goto err_out;
-
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-       printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
-               dev->name,
-               chip_info[ent->driver_data].name,
-               dev->base_addr,
-               dev->dev_addr,
-               dev->irq);
-
-       rc = tc_mii_init(dev);
-       if (rc)
-               goto err_out_unregister;
-
-       return 0;
-
-err_out_unregister:
-       unregister_netdev(dev);
-err_out:
-       free_netdev(dev);
-       return rc;
-}
-
-
-static void __devexit tc35815_remove_one(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       phy_disconnect(lp->phy_dev);
-       mdiobus_unregister(lp->mii_bus);
-       kfree(lp->mii_bus->irq);
-       mdiobus_free(lp->mii_bus);
-       unregister_netdev(dev);
-       free_netdev(dev);
-       pci_set_drvdata(pdev, NULL);
-}
-
-static int
-tc35815_init_queues(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       int i;
-       unsigned long fd_addr;
-
-       if (!lp->fd_buf) {
-               BUG_ON(sizeof(struct FDesc) +
-                      sizeof(struct BDesc) * RX_BUF_NUM +
-                      sizeof(struct FDesc) * RX_FD_NUM +
-                      sizeof(struct TxFD) * TX_FD_NUM >
-                      PAGE_SIZE * FD_PAGE_NUM);
-
-               lp->fd_buf = pci_alloc_consistent(lp->pci_dev,
-                                                 PAGE_SIZE * FD_PAGE_NUM,
-                                                 &lp->fd_buf_dma);
-               if (!lp->fd_buf)
-                       return -ENOMEM;
-               for (i = 0; i < RX_BUF_NUM; i++) {
-                       lp->rx_skbs[i].skb =
-                               alloc_rxbuf_skb(dev, lp->pci_dev,
-                                               &lp->rx_skbs[i].skb_dma);
-                       if (!lp->rx_skbs[i].skb) {
-                               while (--i >= 0) {
-                                       free_rxbuf_skb(lp->pci_dev,
-                                                      lp->rx_skbs[i].skb,
-                                                      lp->rx_skbs[i].skb_dma);
-                                       lp->rx_skbs[i].skb = NULL;
-                               }
-                               pci_free_consistent(lp->pci_dev,
-                                                   PAGE_SIZE * FD_PAGE_NUM,
-                                                   lp->fd_buf,
-                                                   lp->fd_buf_dma);
-                               lp->fd_buf = NULL;
-                               return -ENOMEM;
-                       }
-               }
-               printk(KERN_DEBUG "%s: FD buf %p DataBuf",
-                      dev->name, lp->fd_buf);
-               printk("\n");
-       } else {
-               for (i = 0; i < FD_PAGE_NUM; i++)
-                       clear_page((void *)((unsigned long)lp->fd_buf +
-                                           i * PAGE_SIZE));
-       }
-       fd_addr = (unsigned long)lp->fd_buf;
-
-       /* Free Descriptors (for Receive) */
-       lp->rfd_base = (struct RxFD *)fd_addr;
-       fd_addr += sizeof(struct RxFD) * RX_FD_NUM;
-       for (i = 0; i < RX_FD_NUM; i++)
-               lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
-       lp->rfd_cur = lp->rfd_base;
-       lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
-
-       /* Transmit Descriptors */
-       lp->tfd_base = (struct TxFD *)fd_addr;
-       fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
-       for (i = 0; i < TX_FD_NUM; i++) {
-               lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
-               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
-               lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
-       }
-       lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
-       lp->tfd_start = 0;
-       lp->tfd_end = 0;
-
-       /* Buffer List (for Receive) */
-       lp->fbl_ptr = (struct FrFD *)fd_addr;
-       lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
-       lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
-       /*
-        * move all allocated skbs to head of rx_skbs[] array.
-        * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
-        * tc35815_rx() had failed.
-        */
-       lp->fbl_count = 0;
-       for (i = 0; i < RX_BUF_NUM; i++) {
-               if (lp->rx_skbs[i].skb) {
-                       if (i != lp->fbl_count) {
-                               lp->rx_skbs[lp->fbl_count].skb =
-                                       lp->rx_skbs[i].skb;
-                               lp->rx_skbs[lp->fbl_count].skb_dma =
-                                       lp->rx_skbs[i].skb_dma;
-                       }
-                       lp->fbl_count++;
-               }
-       }
-       for (i = 0; i < RX_BUF_NUM; i++) {
-               if (i >= lp->fbl_count) {
-                       lp->fbl_ptr->bd[i].BuffData = 0;
-                       lp->fbl_ptr->bd[i].BDCtl = 0;
-                       continue;
-               }
-               lp->fbl_ptr->bd[i].BuffData =
-                       cpu_to_le32(lp->rx_skbs[i].skb_dma);
-               /* BDID is index of FrFD.bd[] */
-               lp->fbl_ptr->bd[i].BDCtl =
-                       cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
-                                   RX_BUF_SIZE);
-       }
-
-       printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
-              dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
-       return 0;
-}
-
-static void
-tc35815_clear_queues(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       int i;
-
-       for (i = 0; i < TX_FD_NUM; i++) {
-               u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-               struct sk_buff *skb =
-                       fdsystem != 0xffffffff ?
-                       lp->tx_skbs[fdsystem].skb : NULL;
-#ifdef DEBUG
-               if (lp->tx_skbs[i].skb != skb) {
-                       printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
-                       panic_queues(dev);
-               }
-#else
-               BUG_ON(lp->tx_skbs[i].skb != skb);
-#endif
-               if (skb) {
-                       pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
-                       lp->tx_skbs[i].skb = NULL;
-                       lp->tx_skbs[i].skb_dma = 0;
-                       dev_kfree_skb_any(skb);
-               }
-               lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
-       }
-
-       tc35815_init_queues(dev);
-}
-
-static void
-tc35815_free_queues(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       int i;
-
-       if (lp->tfd_base) {
-               for (i = 0; i < TX_FD_NUM; i++) {
-                       u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-                       struct sk_buff *skb =
-                               fdsystem != 0xffffffff ?
-                               lp->tx_skbs[fdsystem].skb : NULL;
-#ifdef DEBUG
-                       if (lp->tx_skbs[i].skb != skb) {
-                               printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
-                               panic_queues(dev);
-                       }
-#else
-                       BUG_ON(lp->tx_skbs[i].skb != skb);
-#endif
-                       if (skb) {
-                               dev_kfree_skb(skb);
-                               pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
-                               lp->tx_skbs[i].skb = NULL;
-                               lp->tx_skbs[i].skb_dma = 0;
-                       }
-                       lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
-               }
-       }
-
-       lp->rfd_base = NULL;
-       lp->rfd_limit = NULL;
-       lp->rfd_cur = NULL;
-       lp->fbl_ptr = NULL;
-
-       for (i = 0; i < RX_BUF_NUM; i++) {
-               if (lp->rx_skbs[i].skb) {
-                       free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
-                                      lp->rx_skbs[i].skb_dma);
-                       lp->rx_skbs[i].skb = NULL;
-               }
-       }
-       if (lp->fd_buf) {
-               pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
-                                   lp->fd_buf, lp->fd_buf_dma);
-               lp->fd_buf = NULL;
-       }
-}
-
-static void
-dump_txfd(struct TxFD *fd)
-{
-       printk("TxFD(%p): %08x %08x %08x %08x\n", fd,
-              le32_to_cpu(fd->fd.FDNext),
-              le32_to_cpu(fd->fd.FDSystem),
-              le32_to_cpu(fd->fd.FDStat),
-              le32_to_cpu(fd->fd.FDCtl));
-       printk("BD: ");
-       printk(" %08x %08x",
-              le32_to_cpu(fd->bd.BuffData),
-              le32_to_cpu(fd->bd.BDCtl));
-       printk("\n");
-}
-
-static int
-dump_rxfd(struct RxFD *fd)
-{
-       int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
-       if (bd_count > 8)
-               bd_count = 8;
-       printk("RxFD(%p): %08x %08x %08x %08x\n", fd,
-              le32_to_cpu(fd->fd.FDNext),
-              le32_to_cpu(fd->fd.FDSystem),
-              le32_to_cpu(fd->fd.FDStat),
-              le32_to_cpu(fd->fd.FDCtl));
-       if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD)
-               return 0;
-       printk("BD: ");
-       for (i = 0; i < bd_count; i++)
-               printk(" %08x %08x",
-                      le32_to_cpu(fd->bd[i].BuffData),
-                      le32_to_cpu(fd->bd[i].BDCtl));
-       printk("\n");
-       return bd_count;
-}
-
-#ifdef DEBUG
-static void
-dump_frfd(struct FrFD *fd)
-{
-       int i;
-       printk("FrFD(%p): %08x %08x %08x %08x\n", fd,
-              le32_to_cpu(fd->fd.FDNext),
-              le32_to_cpu(fd->fd.FDSystem),
-              le32_to_cpu(fd->fd.FDStat),
-              le32_to_cpu(fd->fd.FDCtl));
-       printk("BD: ");
-       for (i = 0; i < RX_BUF_NUM; i++)
-               printk(" %08x %08x",
-                      le32_to_cpu(fd->bd[i].BuffData),
-                      le32_to_cpu(fd->bd[i].BDCtl));
-       printk("\n");
-}
-
-static void
-panic_queues(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       int i;
-
-       printk("TxFD base %p, start %u, end %u\n",
-              lp->tfd_base, lp->tfd_start, lp->tfd_end);
-       printk("RxFD base %p limit %p cur %p\n",
-              lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
-       printk("FrFD %p\n", lp->fbl_ptr);
-       for (i = 0; i < TX_FD_NUM; i++)
-               dump_txfd(&lp->tfd_base[i]);
-       for (i = 0; i < RX_FD_NUM; i++) {
-               int bd_count = dump_rxfd(&lp->rfd_base[i]);
-               i += (bd_count + 1) / 2;        /* skip BDs */
-       }
-       dump_frfd(lp->fbl_ptr);
-       panic("%s: Illegal queue state.", dev->name);
-}
-#endif
-
-static void print_eth(const u8 *add)
-{
-       printk(KERN_DEBUG "print_eth(%p)\n", add);
-       printk(KERN_DEBUG " %pM => %pM : %02x%02x\n",
-               add + 6, add, add[12], add[13]);
-}
-
-static int tc35815_tx_full(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       return (lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end;
-}
-
-static void tc35815_restart(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       if (lp->phy_dev) {
-               int timeout;
-
-               phy_write(lp->phy_dev, MII_BMCR, BMCR_RESET);
-               timeout = 100;
-               while (--timeout) {
-                       if (!(phy_read(lp->phy_dev, MII_BMCR) & BMCR_RESET))
-                               break;
-                       udelay(1);
-               }
-               if (!timeout)
-                       printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
-       }
-
-       spin_lock_bh(&lp->rx_lock);
-       spin_lock_irq(&lp->lock);
-       tc35815_chip_reset(dev);
-       tc35815_clear_queues(dev);
-       tc35815_chip_init(dev);
-       /* Reconfigure CAM again since tc35815_chip_init() initialize it. */
-       tc35815_set_multicast_list(dev);
-       spin_unlock_irq(&lp->lock);
-       spin_unlock_bh(&lp->rx_lock);
-
-       netif_wake_queue(dev);
-}
-
-static void tc35815_restart_work(struct work_struct *work)
-{
-       struct tc35815_local *lp =
-               container_of(work, struct tc35815_local, restart_work);
-       struct net_device *dev = lp->dev;
-
-       tc35815_restart(dev);
-}
-
-static void tc35815_schedule_restart(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       unsigned long flags;
-
-       /* disable interrupts */
-       spin_lock_irqsave(&lp->lock, flags);
-       tc_writel(0, &tr->Int_En);
-       tc_writel(tc_readl(&tr->DMA_Ctl) | DMA_IntMask, &tr->DMA_Ctl);
-       schedule_work(&lp->restart_work);
-       spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-static void tc35815_tx_timeout(struct net_device *dev)
-{
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-
-       printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
-              dev->name, tc_readl(&tr->Tx_Stat));
-
-       /* Try to restart the adaptor. */
-       tc35815_schedule_restart(dev);
-       dev->stats.tx_errors++;
-}
-
-/*
- * Open/initialize the controller. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-static int
-tc35815_open(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       /*
-        * This is used if the interrupt line can turned off (shared).
-        * See 3c503.c for an example of selecting the IRQ at config-time.
-        */
-       if (request_irq(dev->irq, tc35815_interrupt, IRQF_SHARED,
-                       dev->name, dev))
-               return -EAGAIN;
-
-       tc35815_chip_reset(dev);
-
-       if (tc35815_init_queues(dev) != 0) {
-               free_irq(dev->irq, dev);
-               return -EAGAIN;
-       }
-
-       napi_enable(&lp->napi);
-
-       /* Reset the hardware here. Don't forget to set the station address. */
-       spin_lock_irq(&lp->lock);
-       tc35815_chip_init(dev);
-       spin_unlock_irq(&lp->lock);
-
-       netif_carrier_off(dev);
-       /* schedule a link state check */
-       phy_start(lp->phy_dev);
-
-       /* We are now ready to accept transmit requeusts from
-        * the queueing layer of the networking.
-        */
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-/* This will only be invoked if your driver is _not_ in XOFF state.
- * What this means is that you need not check it, and that this
- * invariant will hold if you make sure that the netif_*_queue()
- * calls are done at the proper times.
- */
-static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct TxFD *txfd;
-       unsigned long flags;
-
-       /* If some error occurs while trying to transmit this
-        * packet, you should return '1' from this function.
-        * In such a case you _may not_ do anything to the
-        * SKB, it is still owned by the network queueing
-        * layer when an error is returned.  This means you
-        * may not modify any SKB fields, you may not free
-        * the SKB, etc.
-        */
-
-       /* This is the most common case for modern hardware.
-        * The spinlock protects this code from the TX complete
-        * hardware interrupt handler.  Queue flow control is
-        * thus managed under this lock as well.
-        */
-       spin_lock_irqsave(&lp->lock, flags);
-
-       /* failsafe... (handle txdone now if half of FDs are used) */
-       if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
-           TX_FD_NUM / 2)
-               tc35815_txdone(dev);
-
-       if (netif_msg_pktdata(lp))
-               print_eth(skb->data);
-#ifdef DEBUG
-       if (lp->tx_skbs[lp->tfd_start].skb) {
-               printk("%s: tx_skbs conflict.\n", dev->name);
-               panic_queues(dev);
-       }
-#else
-       BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
-#endif
-       lp->tx_skbs[lp->tfd_start].skb = skb;
-       lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
-
-       /*add to ring */
-       txfd = &lp->tfd_base[lp->tfd_start];
-       txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
-       txfd->bd.BDCtl = cpu_to_le32(skb->len);
-       txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
-       txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
-
-       if (lp->tfd_start == lp->tfd_end) {
-               struct tc35815_regs __iomem *tr =
-                       (struct tc35815_regs __iomem *)dev->base_addr;
-               /* Start DMA Transmitter. */
-               txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
-               txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
-               if (netif_msg_tx_queued(lp)) {
-                       printk("%s: starting TxFD.\n", dev->name);
-                       dump_txfd(txfd);
-               }
-               tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
-       } else {
-               txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
-               if (netif_msg_tx_queued(lp)) {
-                       printk("%s: queueing TxFD.\n", dev->name);
-                       dump_txfd(txfd);
-               }
-       }
-       lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
-
-       /* If we just used up the very last entry in the
-        * TX ring on this device, tell the queueing
-        * layer to send no more.
-        */
-       if (tc35815_tx_full(dev)) {
-               if (netif_msg_tx_queued(lp))
-                       printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
-               netif_stop_queue(dev);
-       }
-
-       /* When the TX completion hw interrupt arrives, this
-        * is when the transmit statistics are updated.
-        */
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-       return NETDEV_TX_OK;
-}
-
-#define FATAL_ERROR_INT \
-       (Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
-static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
-{
-       static int count;
-       printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
-              dev->name, status);
-       if (status & Int_IntPCI)
-               printk(" IntPCI");
-       if (status & Int_DmParErr)
-               printk(" DmParErr");
-       if (status & Int_IntNRAbt)
-               printk(" IntNRAbt");
-       printk("\n");
-       if (count++ > 100)
-               panic("%s: Too many fatal errors.", dev->name);
-       printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
-       /* Try to restart the adaptor. */
-       tc35815_schedule_restart(dev);
-}
-
-static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       int ret = -1;
-
-       /* Fatal errors... */
-       if (status & FATAL_ERROR_INT) {
-               tc35815_fatal_error_interrupt(dev, status);
-               return 0;
-       }
-       /* recoverable errors */
-       if (status & Int_IntFDAEx) {
-               if (netif_msg_rx_err(lp))
-                       dev_warn(&dev->dev,
-                                "Free Descriptor Area Exhausted (%#x).\n",
-                                status);
-               dev->stats.rx_dropped++;
-               ret = 0;
-       }
-       if (status & Int_IntBLEx) {
-               if (netif_msg_rx_err(lp))
-                       dev_warn(&dev->dev,
-                                "Buffer List Exhausted (%#x).\n",
-                                status);
-               dev->stats.rx_dropped++;
-               ret = 0;
-       }
-       if (status & Int_IntExBD) {
-               if (netif_msg_rx_err(lp))
-                       dev_warn(&dev->dev,
-                                "Excessive Buffer Descriptiors (%#x).\n",
-                                status);
-               dev->stats.rx_length_errors++;
-               ret = 0;
-       }
-
-       /* normal notification */
-       if (status & Int_IntMacRx) {
-               /* Got a packet(s). */
-               ret = tc35815_rx(dev, limit);
-               lp->lstats.rx_ints++;
-       }
-       if (status & Int_IntMacTx) {
-               /* Transmit complete. */
-               lp->lstats.tx_ints++;
-               spin_lock_irq(&lp->lock);
-               tc35815_txdone(dev);
-               spin_unlock_irq(&lp->lock);
-               if (ret < 0)
-                       ret = 0;
-       }
-       return ret;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       u32 dmactl = tc_readl(&tr->DMA_Ctl);
-
-       if (!(dmactl & DMA_IntMask)) {
-               /* disable interrupts */
-               tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
-               if (napi_schedule_prep(&lp->napi))
-                       __napi_schedule(&lp->napi);
-               else {
-                       printk(KERN_ERR "%s: interrupt taken in poll\n",
-                              dev->name);
-                       BUG();
-               }
-               (void)tc_readl(&tr->Int_Src);   /* flush */
-               return IRQ_HANDLED;
-       }
-       return IRQ_NONE;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void tc35815_poll_controller(struct net_device *dev)
-{
-       disable_irq(dev->irq);
-       tc35815_interrupt(dev->irq, dev);
-       enable_irq(dev->irq);
-}
-#endif
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static int
-tc35815_rx(struct net_device *dev, int limit)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       unsigned int fdctl;
-       int i;
-       int received = 0;
-
-       while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
-               int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
-               int pkt_len = fdctl & FD_FDLength_MASK;
-               int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
-#ifdef DEBUG
-               struct RxFD *next_rfd;
-#endif
-#if (RX_CTL_CMD & Rx_StripCRC) == 0
-               pkt_len -= ETH_FCS_LEN;
-#endif
-
-               if (netif_msg_rx_status(lp))
-                       dump_rxfd(lp->rfd_cur);
-               if (status & Rx_Good) {
-                       struct sk_buff *skb;
-                       unsigned char *data;
-                       int cur_bd;
-
-                       if (--limit < 0)
-                               break;
-                       BUG_ON(bd_count > 1);
-                       cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
-                                 & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
-#ifdef DEBUG
-                       if (cur_bd >= RX_BUF_NUM) {
-                               printk("%s: invalid BDID.\n", dev->name);
-                               panic_queues(dev);
-                       }
-                       BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
-                              (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
-                       if (!lp->rx_skbs[cur_bd].skb) {
-                               printk("%s: NULL skb.\n", dev->name);
-                               panic_queues(dev);
-                       }
-#else
-                       BUG_ON(cur_bd >= RX_BUF_NUM);
-#endif
-                       skb = lp->rx_skbs[cur_bd].skb;
-                       prefetch(skb->data);
-                       lp->rx_skbs[cur_bd].skb = NULL;
-                       pci_unmap_single(lp->pci_dev,
-                                        lp->rx_skbs[cur_bd].skb_dma,
-                                        RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-                       if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN)
-                               memmove(skb->data, skb->data - NET_IP_ALIGN,
-                                       pkt_len);
-                       data = skb_put(skb, pkt_len);
-                       if (netif_msg_pktdata(lp))
-                               print_eth(data);
-                       skb->protocol = eth_type_trans(skb, dev);
-                       netif_receive_skb(skb);
-                       received++;
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-               } else {
-                       dev->stats.rx_errors++;
-                       if (netif_msg_rx_err(lp))
-                               dev_info(&dev->dev, "Rx error (status %x)\n",
-                                        status & Rx_Stat_Mask);
-                       /* WORKAROUND: LongErr and CRCErr means Overflow. */
-                       if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
-                               status &= ~(Rx_LongErr|Rx_CRCErr);
-                               status |= Rx_Over;
-                       }
-                       if (status & Rx_LongErr)
-                               dev->stats.rx_length_errors++;
-                       if (status & Rx_Over)
-                               dev->stats.rx_fifo_errors++;
-                       if (status & Rx_CRCErr)
-                               dev->stats.rx_crc_errors++;
-                       if (status & Rx_Align)
-                               dev->stats.rx_frame_errors++;
-               }
-
-               if (bd_count > 0) {
-                       /* put Free Buffer back to controller */
-                       int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
-                       unsigned char id =
-                               (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
-#ifdef DEBUG
-                       if (id >= RX_BUF_NUM) {
-                               printk("%s: invalid BDID.\n", dev->name);
-                               panic_queues(dev);
-                       }
-#else
-                       BUG_ON(id >= RX_BUF_NUM);
-#endif
-                       /* free old buffers */
-                       lp->fbl_count--;
-                       while (lp->fbl_count < RX_BUF_NUM)
-                       {
-                               unsigned char curid =
-                                       (id + 1 + lp->fbl_count) % RX_BUF_NUM;
-                               struct BDesc *bd = &lp->fbl_ptr->bd[curid];
-#ifdef DEBUG
-                               bdctl = le32_to_cpu(bd->BDCtl);
-                               if (bdctl & BD_CownsBD) {
-                                       printk("%s: Freeing invalid BD.\n",
-                                              dev->name);
-                                       panic_queues(dev);
-                               }
-#endif
-                               /* pass BD to controller */
-                               if (!lp->rx_skbs[curid].skb) {
-                                       lp->rx_skbs[curid].skb =
-                                               alloc_rxbuf_skb(dev,
-                                                               lp->pci_dev,
-                                                               &lp->rx_skbs[curid].skb_dma);
-                                       if (!lp->rx_skbs[curid].skb)
-                                               break; /* try on next reception */
-                                       bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
-                               }
-                               /* Note: BDLength was modified by chip. */
-                               bd->BDCtl = cpu_to_le32(BD_CownsBD |
-                                                       (curid << BD_RxBDID_SHIFT) |
-                                                       RX_BUF_SIZE);
-                               lp->fbl_count++;
-                       }
-               }
-
-               /* put RxFD back to controller */
-#ifdef DEBUG
-               next_rfd = fd_bus_to_virt(lp,
-                                         le32_to_cpu(lp->rfd_cur->fd.FDNext));
-               if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
-                       printk("%s: RxFD FDNext invalid.\n", dev->name);
-                       panic_queues(dev);
-               }
-#endif
-               for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
-                       /* pass FD to controller */
-#ifdef DEBUG
-                       lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
-#else
-                       lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
-#endif
-                       lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
-                       lp->rfd_cur++;
-               }
-               if (lp->rfd_cur > lp->rfd_limit)
-                       lp->rfd_cur = lp->rfd_base;
-#ifdef DEBUG
-               if (lp->rfd_cur != next_rfd)
-                       printk("rfd_cur = %p, next_rfd %p\n",
-                              lp->rfd_cur, next_rfd);
-#endif
-       }
-
-       return received;
-}
-
-static int tc35815_poll(struct napi_struct *napi, int budget)
-{
-       struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi);
-       struct net_device *dev = lp->dev;
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       int received = 0, handled;
-       u32 status;
-
-       spin_lock(&lp->rx_lock);
-       status = tc_readl(&tr->Int_Src);
-       do {
-               /* BLEx, FDAEx will be cleared later */
-               tc_writel(status & ~(Int_BLEx | Int_FDAEx),
-                         &tr->Int_Src);        /* write to clear */
-
-               handled = tc35815_do_interrupt(dev, status, budget - received);
-               if (status & (Int_BLEx | Int_FDAEx))
-                       tc_writel(status & (Int_BLEx | Int_FDAEx),
-                                 &tr->Int_Src);
-               if (handled >= 0) {
-                       received += handled;
-                       if (received >= budget)
-                               break;
-               }
-               status = tc_readl(&tr->Int_Src);
-       } while (status);
-       spin_unlock(&lp->rx_lock);
-
-       if (received < budget) {
-               napi_complete(napi);
-               /* enable interrupts */
-               tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
-       }
-       return received;
-}
-
-#define TX_STA_ERR     (Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)
-
-static void
-tc35815_check_tx_stat(struct net_device *dev, int status)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       const char *msg = NULL;
-
-       /* count collisions */
-       if (status & Tx_ExColl)
-               dev->stats.collisions += 16;
-       if (status & Tx_TxColl_MASK)
-               dev->stats.collisions += status & Tx_TxColl_MASK;
-
-       /* TX4939 does not have NCarr */
-       if (lp->chiptype == TC35815_TX4939)
-               status &= ~Tx_NCarr;
-       /* WORKAROUND: ignore LostCrS in full duplex operation */
-       if (!lp->link || lp->duplex == DUPLEX_FULL)
-               status &= ~Tx_NCarr;
-
-       if (!(status & TX_STA_ERR)) {
-               /* no error. */
-               dev->stats.tx_packets++;
-               return;
-       }
-
-       dev->stats.tx_errors++;
-       if (status & Tx_ExColl) {
-               dev->stats.tx_aborted_errors++;
-               msg = "Excessive Collision.";
-       }
-       if (status & Tx_Under) {
-               dev->stats.tx_fifo_errors++;
-               msg = "Tx FIFO Underrun.";
-               if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
-                       lp->lstats.tx_underrun++;
-                       if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
-                               struct tc35815_regs __iomem *tr =
-                                       (struct tc35815_regs __iomem *)dev->base_addr;
-                               tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
-                               msg = "Tx FIFO Underrun.Change Tx threshold to max.";
-                       }
-               }
-       }
-       if (status & Tx_Defer) {
-               dev->stats.tx_fifo_errors++;
-               msg = "Excessive Deferral.";
-       }
-       if (status & Tx_NCarr) {
-               dev->stats.tx_carrier_errors++;
-               msg = "Lost Carrier Sense.";
-       }
-       if (status & Tx_LateColl) {
-               dev->stats.tx_aborted_errors++;
-               msg = "Late Collision.";
-       }
-       if (status & Tx_TxPar) {
-               dev->stats.tx_fifo_errors++;
-               msg = "Transmit Parity Error.";
-       }
-       if (status & Tx_SQErr) {
-               dev->stats.tx_heartbeat_errors++;
-               msg = "Signal Quality Error.";
-       }
-       if (msg && netif_msg_tx_err(lp))
-               printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
-}
-
-/* This handles TX complete events posted by the device
- * via interrupts.
- */
-static void
-tc35815_txdone(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct TxFD *txfd;
-       unsigned int fdctl;
-
-       txfd = &lp->tfd_base[lp->tfd_end];
-       while (lp->tfd_start != lp->tfd_end &&
-              !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {
-               int status = le32_to_cpu(txfd->fd.FDStat);
-               struct sk_buff *skb;
-               unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
-               u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
-
-               if (netif_msg_tx_done(lp)) {
-                       printk("%s: complete TxFD.\n", dev->name);
-                       dump_txfd(txfd);
-               }
-               tc35815_check_tx_stat(dev, status);
-
-               skb = fdsystem != 0xffffffff ?
-                       lp->tx_skbs[fdsystem].skb : NULL;
-#ifdef DEBUG
-               if (lp->tx_skbs[lp->tfd_end].skb != skb) {
-                       printk("%s: tx_skbs mismatch.\n", dev->name);
-                       panic_queues(dev);
-               }
-#else
-               BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
-#endif
-               if (skb) {
-                       dev->stats.tx_bytes += skb->len;
-                       pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
-                       lp->tx_skbs[lp->tfd_end].skb = NULL;
-                       lp->tx_skbs[lp->tfd_end].skb_dma = 0;
-                       dev_kfree_skb_any(skb);
-               }
-               txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
-
-               lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
-               txfd = &lp->tfd_base[lp->tfd_end];
-#ifdef DEBUG
-               if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
-                       printk("%s: TxFD FDNext invalid.\n", dev->name);
-                       panic_queues(dev);
-               }
-#endif
-               if (fdnext & FD_Next_EOL) {
-                       /* DMA Transmitter has been stopping... */
-                       if (lp->tfd_end != lp->tfd_start) {
-                               struct tc35815_regs __iomem *tr =
-                                       (struct tc35815_regs __iomem *)dev->base_addr;
-                               int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
-                               struct TxFD *txhead = &lp->tfd_base[head];
-                               int qlen = (lp->tfd_start + TX_FD_NUM
-                                           - lp->tfd_end) % TX_FD_NUM;
-
-#ifdef DEBUG
-                               if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
-                                       printk("%s: TxFD FDCtl invalid.\n", dev->name);
-                                       panic_queues(dev);
-                               }
-#endif
-                               /* log max queue length */
-                               if (lp->lstats.max_tx_qlen < qlen)
-                                       lp->lstats.max_tx_qlen = qlen;
-
-
-                               /* start DMA Transmitter again */
-                               txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
-                               txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
-                               if (netif_msg_tx_queued(lp)) {
-                                       printk("%s: start TxFD on queue.\n",
-                                              dev->name);
-                                       dump_txfd(txfd);
-                               }
-                               tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
-                       }
-                       break;
-               }
-       }
-
-       /* If we had stopped the queue due to a "tx full"
-        * condition, and space has now been made available,
-        * wake up the queue.
-        */
-       if (netif_queue_stopped(dev) && !tc35815_tx_full(dev))
-               netif_wake_queue(dev);
-}
-
-/* The inverse routine to tc35815_open(). */
-static int
-tc35815_close(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       netif_stop_queue(dev);
-       napi_disable(&lp->napi);
-       if (lp->phy_dev)
-               phy_stop(lp->phy_dev);
-       cancel_work_sync(&lp->restart_work);
-
-       /* Flush the Tx and disable Rx here. */
-       tc35815_chip_reset(dev);
-       free_irq(dev->irq, dev);
-
-       tc35815_free_queues(dev);
-
-       return 0;
-
-}
-
-/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
-{
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       if (netif_running(dev))
-               /* Update the statistics from the device registers. */
-               dev->stats.rx_missed_errors += tc_readl(&tr->Miss_Cnt);
-
-       return &dev->stats;
-}
-
-static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       int cam_index = index * 6;
-       u32 cam_data;
-       u32 saved_addr;
-
-       saved_addr = tc_readl(&tr->CAM_Adr);
-
-       if (netif_msg_hw(lp))
-               printk(KERN_DEBUG "%s: CAM %d: %pM\n",
-                       dev->name, index, addr);
-       if (index & 1) {
-               /* read modify write */
-               tc_writel(cam_index - 2, &tr->CAM_Adr);
-               cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;
-               cam_data |= addr[0] << 8 | addr[1];
-               tc_writel(cam_data, &tr->CAM_Data);
-               /* write whole word */
-               tc_writel(cam_index + 2, &tr->CAM_Adr);
-               cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
-               tc_writel(cam_data, &tr->CAM_Data);
-       } else {
-               /* write whole word */
-               tc_writel(cam_index, &tr->CAM_Adr);
-               cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
-               tc_writel(cam_data, &tr->CAM_Data);
-               /* read modify write */
-               tc_writel(cam_index + 4, &tr->CAM_Adr);
-               cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;
-               cam_data |= addr[4] << 24 | (addr[5] << 16);
-               tc_writel(cam_data, &tr->CAM_Data);
-       }
-
-       tc_writel(saved_addr, &tr->CAM_Adr);
-}
-
-
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1     Promiscuous mode, receive all packets
- * num_addrs == 0      Normal mode, clear multicast list
- * num_addrs > 0       Multicast mode, receive normal and MC packets,
- *                     and do best-effort filtering.
- */
-static void
-tc35815_set_multicast_list(struct net_device *dev)
-{
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-
-       if (dev->flags & IFF_PROMISC) {
-               /* With some (all?) 100MHalf HUB, controller will hang
-                * if we enabled promiscuous mode before linkup... */
-               struct tc35815_local *lp = netdev_priv(dev);
-
-               if (!lp->link)
-                       return;
-               /* Enable promiscuous mode */
-               tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
-       } else if ((dev->flags & IFF_ALLMULTI) ||
-                 netdev_mc_count(dev) > CAM_ENTRY_MAX - 3) {
-               /* CAM 0, 1, 20 are reserved. */
-               /* Disable promiscuous mode, use normal mode. */
-               tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
-       } else if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               int i;
-               int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
-
-               tc_writel(0, &tr->CAM_Ctl);
-               /* Walk the address list, and load the filter */
-               i = 0;
-               netdev_for_each_mc_addr(ha, dev) {
-                       /* entry 0,1 is reserved. */
-                       tc35815_set_cam_entry(dev, i + 2, ha->addr);
-                       ena_bits |= CAM_Ena_Bit(i + 2);
-                       i++;
-               }
-               tc_writel(ena_bits, &tr->CAM_Ena);
-               tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
-       } else {
-               tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
-               tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
-       }
-}
-
-static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       strcpy(info->driver, MODNAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(lp->pci_dev));
-}
-
-static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       if (!lp->phy_dev)
-               return -ENODEV;
-       return phy_ethtool_gset(lp->phy_dev, cmd);
-}
-
-static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       if (!lp->phy_dev)
-               return -ENODEV;
-       return phy_ethtool_sset(lp->phy_dev, cmd);
-}
-
-static u32 tc35815_get_msglevel(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       return lp->msg_enable;
-}
-
-static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       lp->msg_enable = datum;
-}
-
-static int tc35815_get_sset_count(struct net_device *dev, int sset)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       switch (sset) {
-       case ETH_SS_STATS:
-               return sizeof(lp->lstats) / sizeof(int);
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       data[0] = lp->lstats.max_tx_qlen;
-       data[1] = lp->lstats.tx_ints;
-       data[2] = lp->lstats.rx_ints;
-       data[3] = lp->lstats.tx_underrun;
-}
-
-static struct {
-       const char str[ETH_GSTRING_LEN];
-} ethtool_stats_keys[] = {
-       { "max_tx_qlen" },
-       { "tx_ints" },
-       { "rx_ints" },
-       { "tx_underrun" },
-};
-
-static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
-{
-       memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
-}
-
-static const struct ethtool_ops tc35815_ethtool_ops = {
-       .get_drvinfo            = tc35815_get_drvinfo,
-       .get_settings           = tc35815_get_settings,
-       .set_settings           = tc35815_set_settings,
-       .get_link               = ethtool_op_get_link,
-       .get_msglevel           = tc35815_get_msglevel,
-       .set_msglevel           = tc35815_set_msglevel,
-       .get_strings            = tc35815_get_strings,
-       .get_sset_count         = tc35815_get_sset_count,
-       .get_ethtool_stats      = tc35815_get_ethtool_stats,
-};
-
-static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       if (!netif_running(dev))
-               return -EINVAL;
-       if (!lp->phy_dev)
-               return -ENODEV;
-       return phy_mii_ioctl(lp->phy_dev, rq, cmd);
-}
-
-static void tc35815_chip_reset(struct net_device *dev)
-{
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       int i;
-       /* reset the controller */
-       tc_writel(MAC_Reset, &tr->MAC_Ctl);
-       udelay(4); /* 3200ns */
-       i = 0;
-       while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
-               if (i++ > 100) {
-                       printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
-                       break;
-               }
-               mdelay(1);
-       }
-       tc_writel(0, &tr->MAC_Ctl);
-
-       /* initialize registers to default value */
-       tc_writel(0, &tr->DMA_Ctl);
-       tc_writel(0, &tr->TxThrsh);
-       tc_writel(0, &tr->TxPollCtr);
-       tc_writel(0, &tr->RxFragSize);
-       tc_writel(0, &tr->Int_En);
-       tc_writel(0, &tr->FDA_Bas);
-       tc_writel(0, &tr->FDA_Lim);
-       tc_writel(0xffffffff, &tr->Int_Src);    /* Write 1 to clear */
-       tc_writel(0, &tr->CAM_Ctl);
-       tc_writel(0, &tr->Tx_Ctl);
-       tc_writel(0, &tr->Rx_Ctl);
-       tc_writel(0, &tr->CAM_Ena);
-       (void)tc_readl(&tr->Miss_Cnt);  /* Read to clear */
-
-       /* initialize internal SRAM */
-       tc_writel(DMA_TestMode, &tr->DMA_Ctl);
-       for (i = 0; i < 0x1000; i += 4) {
-               tc_writel(i, &tr->CAM_Adr);
-               tc_writel(0, &tr->CAM_Data);
-       }
-       tc_writel(0, &tr->DMA_Ctl);
-}
-
-static void tc35815_chip_init(struct net_device *dev)
-{
-       struct tc35815_local *lp = netdev_priv(dev);
-       struct tc35815_regs __iomem *tr =
-               (struct tc35815_regs __iomem *)dev->base_addr;
-       unsigned long txctl = TX_CTL_CMD;
-
-       /* load station address to CAM */
-       tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
-
-       /* Enable CAM (broadcast and unicast) */
-       tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
-       tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
-
-       /* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
-       if (HAVE_DMA_RXALIGN(lp))
-               tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
-       else
-               tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
-       tc_writel(0, &tr->TxPollCtr);   /* Batch mode */
-       tc_writel(TX_THRESHOLD, &tr->TxThrsh);
-       tc_writel(INT_EN_CMD, &tr->Int_En);
-
-       /* set queues */
-       tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
-       tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
-                 &tr->FDA_Lim);
-       /*
-        * Activation method:
-        * First, enable the MAC Transmitter and the DMA Receive circuits.
-        * Then enable the DMA Transmitter and the MAC Receive circuits.
-        */
-       tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);      /* start DMA receiver */
-       tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);     /* start MAC receiver */
-
-       /* start MAC transmitter */
-       /* TX4939 does not have EnLCarr */
-       if (lp->chiptype == TC35815_TX4939)
-               txctl &= ~Tx_EnLCarr;
-       /* WORKAROUND: ignore LostCrS in full duplex operation */
-       if (!lp->phy_dev || !lp->link || lp->duplex == DUPLEX_FULL)
-               txctl &= ~Tx_EnLCarr;
-       tc_writel(txctl, &tr->Tx_Ctl);
-}
-
-#ifdef CONFIG_PM
-static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct tc35815_local *lp = netdev_priv(dev);
-       unsigned long flags;
-
-       pci_save_state(pdev);
-       if (!netif_running(dev))
-               return 0;
-       netif_device_detach(dev);
-       if (lp->phy_dev)
-               phy_stop(lp->phy_dev);
-       spin_lock_irqsave(&lp->lock, flags);
-       tc35815_chip_reset(dev);
-       spin_unlock_irqrestore(&lp->lock, flags);
-       pci_set_power_state(pdev, PCI_D3hot);
-       return 0;
-}
-
-static int tc35815_resume(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct tc35815_local *lp = netdev_priv(dev);
-
-       pci_restore_state(pdev);
-       if (!netif_running(dev))
-               return 0;
-       pci_set_power_state(pdev, PCI_D0);
-       tc35815_restart(dev);
-       netif_carrier_off(dev);
-       if (lp->phy_dev)
-               phy_start(lp->phy_dev);
-       netif_device_attach(dev);
-       return 0;
-}
-#endif /* CONFIG_PM */
-
-static struct pci_driver tc35815_pci_driver = {
-       .name           = MODNAME,
-       .id_table       = tc35815_pci_tbl,
-       .probe          = tc35815_init_one,
-       .remove         = __devexit_p(tc35815_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = tc35815_suspend,
-       .resume         = tc35815_resume,
-#endif
-};
-
-module_param_named(speed, options.speed, int, 0);
-MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
-module_param_named(duplex, options.duplex, int, 0);
-MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
-
-static int __init tc35815_init_module(void)
-{
-       return pci_register_driver(&tc35815_pci_driver);
-}
-
-static void __exit tc35815_cleanup_module(void)
-{
-       pci_unregister_driver(&tc35815_pci_driver);
-}
-
-module_init(tc35815_init_module);
-module_exit(tc35815_cleanup_module);
-
-MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
-MODULE_LICENSE("GPL");