diff options
38 files changed, 5357 insertions, 2306 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ae9e7a579b94..6bb9232514b4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2058,6 +2058,13 @@ config BNX2 To compile this driver as a module, choose M here: the module will be called bnx2. This is recommended. +config SPIDER_NET + tristate "Spider Gigabit Ethernet driver" + depends on PCI && PPC_BPA + help + This driver supports the Gigabit Ethernet chips present on the + Cell Processor-Based Blades from IBM. + config GIANFAR tristate "Gianfar Ethernet" depends on 85xx || 83xx diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5baafcd55610..8645c843cf4d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -54,6 +54,8 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o +spidernet-y += spider_net.o spider_net_ethtool.o sungem_phy.o +obj-$(CONFIG_SPIDER_NET) += spidernet.o obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SK98LIN) += sk98lin/ diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 91791ba37769..8a0af5453e21 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -275,7 +275,7 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) return 0; out2: if (ei_status.reg0) - iounmap((void *)dev->mem_start); + iounmap(ei_status.mem); out1: free_irq(dev->irq, dev); out: diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index ad011214c7f2..e01b6a78ec63 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -235,7 +235,7 @@ struct lance_private { #define MEM lp->mem #define DREG IO->data #define AREG IO->addr -#define REGA(a) ( AREG = (a), DREG ) +#define REGA(a) (*( AREG = (a), &DREG )) /* Definitions for packet buffer access: */ #define PKT_BUF_SZ 1544 diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 6440a892bb81..e54fc10f6846 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1140,7 +1140,7 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) } static int -dm9000_drv_suspend(struct device *dev, u32 state, u32 level) +dm9000_drv_suspend(struct device *dev, pm_message_t state, u32 level) { struct net_device *ndev = dev_get_drvdata(dev); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 7d93948aec83..d6eefdb71c17 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -1372,7 +1372,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) /* synchronized against open : rtnl_lock() held by caller */ if (netif_running(dev)) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); /* * It seems that the nic preloads valid ring entries into an * internal buffer. The procedure for flushing everything is @@ -1423,7 +1423,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) static void nv_copy_mac_to_hw(struct net_device *dev) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); u32 mac[2]; mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index dc5d089bf184..3d56cf5a4e23 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -4,6 +4,7 @@ * Copyright (C) 2001 Kyle A. Lucke (klucke@us.ibm.com), IBM Corp. * Substantially cleaned up by: * Copyright (C) 2003 David Gibson <dwg@au1.ibm.com>, IBM Corporation. + * Copyright (C) 2004-2005 Michael Ellerman, IBM Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 2234a8f05eb2..7cefe5507b9e 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -1,5 +1,5 @@ /************************************************************************ - * regs.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC + * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC * Copyright(c) 2002-2005 Neterion Inc. * This software may be used and distributed according to the terms of @@ -713,13 +713,16 @@ typedef struct _XENA_dev_config { u64 mc_err_reg; #define MC_ERR_REG_ECC_DB_ERR_L BIT(14) #define MC_ERR_REG_ECC_DB_ERR_U BIT(15) +#define MC_ERR_REG_MIRI_ECC_DB_ERR_0 BIT(18) +#define MC_ERR_REG_MIRI_ECC_DB_ERR_1 BIT(20) #define MC_ERR_REG_MIRI_CRI_ERR_0 BIT(22) #define MC_ERR_REG_MIRI_CRI_ERR_1 BIT(23) #define MC_ERR_REG_SM_ERR BIT(31) -#define MC_ERR_REG_ECC_ALL_SNG (BIT(6) | \ - BIT(7) | BIT(17) | BIT(19)) -#define MC_ERR_REG_ECC_ALL_DBL (BIT(14) | \ - BIT(15) | BIT(18) | BIT(20)) +#define MC_ERR_REG_ECC_ALL_SNG (BIT(2) | BIT(3) | BIT(4) | BIT(5) |\ + BIT(6) | BIT(7) | BIT(17) | BIT(19)) +#define MC_ERR_REG_ECC_ALL_DBL (BIT(10) | BIT(11) | BIT(12) |\ + BIT(13) | BIT(14) | BIT(15) |\ + BIT(18) | BIT(20)) u64 mc_err_mask; u64 mc_err_alarm; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 7f9a11fc3a18..c829e6a2e8a6 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1,5 +1,5 @@ /************************************************************************ - * s2io.c: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC + * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC * Copyright(c) 2002-2005 Neterion Inc. * This software may be used and distributed according to the terms of @@ -28,7 +28,7 @@ * explaination of all the variables. * rx_ring_num : This can be used to program the number of receive rings used * in the driver. - * rx_ring_len: This defines the number of descriptors each ring can have. This + * rx_ring_sz: This defines the number of descriptors each ring can have. This * is also an array of size 8. * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver. * tx_fifo_len: This too is an array of 8. Each element defines the number of @@ -67,7 +67,7 @@ /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; -static char s2io_driver_version[] = "Version 2.0.3.1"; +static char s2io_driver_version[] = "Version 2.0.8.1"; static inline int RXD_IS_UP2DT(RxD_t *rxdp) { @@ -404,7 +404,7 @@ static int init_shared_mem(struct s2io_nic *nic) config->tx_cfg[i].fifo_len - 1; mac_control->fifos[i].fifo_no = i; mac_control->fifos[i].nic = nic; - mac_control->fifos[i].max_txds = MAX_SKB_FRAGS; + mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 1; for (j = 0; j < page_num; j++) { int k = 0; @@ -418,6 +418,26 @@ static int init_shared_mem(struct s2io_nic *nic) DBG_PRINT(ERR_DBG, "failed for TxDL\n"); return -ENOMEM; } + /* If we got a zero DMA address(can happen on + * certain platforms like PPC), reallocate. + * Store virtual address of page we don't want, + * to be freed later. + */ + if (!tmp_p) { + mac_control->zerodma_virt_addr = tmp_v; + DBG_PRINT(INIT_DBG, + "%s: Zero DMA address for TxDL. ", dev->name); + DBG_PRINT(INIT_DBG, + "Virtual address %llx\n", (u64)tmp_v); + tmp_v = pci_alloc_consistent(nic->pdev, + PAGE_SIZE, &tmp_p); + if (!tmp_v) { + DBG_PRINT(ERR_DBG, + "pci_alloc_consistent "); + DBG_PRINT(ERR_DBG, "failed for TxDL\n"); + return -ENOMEM; + } + } while (k < lst_per_page) { int l = (j * lst_per_page) + k; if (l == config->tx_cfg[i].fifo_len) @@ -600,7 +620,7 @@ static void free_shared_mem(struct s2io_nic *nic) mac_info_t *mac_control; struct config_param *config; int lst_size, lst_per_page; - + struct net_device *dev = nic->dev; if (!nic) return; @@ -616,9 +636,10 @@ static void free_shared_mem(struct s2io_nic *nic) lst_per_page); for (j = 0; j < page_num; j++) { int mem_blks = (j * lst_per_page); - if ((!mac_control->fifos[i].list_info) || - (!mac_control->fifos[i].list_info[mem_blks]. - list_virt_addr)) + if (!mac_control->fifos[i].list_info) + return; + if (!mac_control->fifos[i].list_info[mem_blks]. + list_virt_addr) break; pci_free_consistent(nic->pdev, PAGE_SIZE, mac_control->fifos[i]. @@ -628,6 +649,18 @@ static void free_shared_mem(struct s2io_nic *nic) list_info[mem_blks]. list_phy_addr); } + /* If we got a zero DMA address during allocation, + * free the page now + */ + if (mac_control->zerodma_virt_addr) { + pci_free_consistent(nic->pdev, PAGE_SIZE, + mac_control->zerodma_virt_addr, + (dma_addr_t)0); + DBG_PRINT(INIT_DBG, + "%s: Freeing TxDL with zero DMA addr. ", dev->name); + DBG_PRINT(INIT_DBG, "Virtual address %llx\n", + (u64)(mac_control->zerodma_virt_addr)); + } kfree(mac_control->fifos[i].list_info); } @@ -2479,9 +2512,10 @@ static void rx_intr_handler(ring_info_t *ring_data) #endif spin_lock(&nic->rx_lock); if (atomic_read(&nic->card_state) == CARD_DOWN) { - DBG_PRINT(ERR_DBG, "%s: %s going down for reset\n", + DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n", __FUNCTION__, dev->name); spin_unlock(&nic->rx_lock); + return; } get_info = ring_data->rx_curr_get_info; @@ -2596,8 +2630,14 @@ static void tx_intr_handler(fifo_info_t *fifo_data) if (txdlp->Control_1 & TXD_T_CODE) { unsigned long long err; err = txdlp->Control_1 & TXD_T_CODE; - DBG_PRINT(ERR_DBG, "***TxD error %llx\n", - err); + if ((err >> 48) == 0xA) { + DBG_PRINT(TX_DBG, "TxD returned due \ + to loss of link\n"); + } + else { + DBG_PRINT(ERR_DBG, "***TxD error \ + %llx\n", err); + } } skb = (struct sk_buff *) ((unsigned long) @@ -2689,12 +2729,16 @@ static void alarm_intr_handler(struct s2io_nic *nic) if (val64 & MC_ERR_REG_ECC_ALL_DBL) { nic->mac_control.stats_info->sw_stat. double_ecc_errs++; - DBG_PRINT(ERR_DBG, "%s: Device indicates ", + DBG_PRINT(INIT_DBG, "%s: Device indicates ", dev->name); - DBG_PRINT(ERR_DBG, "double ECC error!!\n"); + DBG_PRINT(INIT_DBG, "double ECC error!!\n"); if (nic->device_type != XFRAME_II_DEVICE) { - netif_stop_queue(dev); - schedule_work(&nic->rst_timer_task); + /* Reset XframeI only if critical error */ + if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | + MC_ERR_REG_MIRI_ECC_DB_ERR_1)) { + netif_stop_queue(dev); + schedule_work(&nic->rst_timer_task); + } } } else { nic->mac_control.stats_info->sw_stat. @@ -2706,7 +2750,8 @@ static void alarm_intr_handler(struct s2io_nic *nic) val64 = readq(&bar0->serr_source); if (val64 & SERR_SOURCE_ANY) { DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name); - DBG_PRINT(ERR_DBG, "serious error!!\n"); + DBG_PRINT(ERR_DBG, "serious error %llx!!\n", + (unsigned long long)val64); netif_stop_queue(dev); schedule_work(&nic->rst_timer_task); } @@ -3130,7 +3175,7 @@ int s2io_xmit(struct sk_buff *skb, struct net_device *dev) queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; /* Avoid "put" pointer going beyond "get" pointer */ if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) { - DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n"); + DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n"); netif_stop_queue(dev); dev_kfree_skb(skb); spin_unlock_irqrestore(&sp->tx_lock, flags); @@ -3528,7 +3573,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = readq(&bar0->mac_cfg); sp->promisc_flg = 1; - DBG_PRINT(ERR_DBG, "%s: entered promiscuous mode\n", + DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n", dev->name); } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) { /* Remove the NIC from promiscuous mode */ @@ -3543,7 +3588,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = readq(&bar0->mac_cfg); sp->promisc_flg = 0; - DBG_PRINT(ERR_DBG, "%s: left promiscuous mode\n", + DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n", dev->name); } @@ -5325,7 +5370,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) break; } } - config->max_txds = MAX_SKB_FRAGS; + config->max_txds = MAX_SKB_FRAGS + 1; /* Rx side parameters. */ if (rx_ring_sz[0] == 0) @@ -5525,9 +5570,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (sp->device_type & XFRAME_II_DEVICE) { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n", + DBG_PRINT(ERR_DBG, "(rev %d), %s", get_xena_rev_id(sp->pdev), s2io_driver_version); +#ifdef CONFIG_2BUFF_MODE + DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); +#endif + + DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", sp->def_mac_addr[0].mac_addr[0], sp->def_mac_addr[0].mac_addr[1], @@ -5544,9 +5594,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } else { DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ", dev->name); - DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n", + DBG_PRINT(ERR_DBG, "(rev %d), %s", get_xena_rev_id(sp->pdev), s2io_driver_version); +#ifdef CONFIG_2BUFF_MODE + DBG_PRINT(ERR_DBG, ", Buffer mode %d",2); +#endif + DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", sp->def_mac_addr[0].mac_addr[0], sp->def_mac_addr[0].mac_addr[1], diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index bc64d967f080..89151cb52181 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1,5 +1,5 @@ /************************************************************************ - * s2io.h: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC + * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC * Copyright(c) 2002-2005 Neterion Inc. * This software may be used and distributed according to the terms of @@ -622,6 +622,9 @@ typedef struct mac_info { /* Fifo specific structure */ fifo_info_t fifos[MAX_TX_FIFOS]; + /* Save virtual address of TxD page with zero DMA addr(if any) */ + void *zerodma_virt_addr; + /* rx side stuff */ /* Ring specific structure */ ring_info_t rings[MAX_RX_RINGS]; diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c new file mode 100644 index 000000000000..4e19220473d0 --- /dev/null +++ b/drivers/net/spider_net.c @@ -0,0 +1,2334 @@ +/* + * 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/config.h> + +#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/init.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/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <asm/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"); + +static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT; +static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT; + +module_param(rx_descriptors, int, 0644); +module_param(tx_descriptors, int, 0644); + +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 struct pci_device_id 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 u32 +spider_net_read_reg(struct spider_net_card *card, u32 reg) +{ + u32 value; + + value = readl(card->regs + reg); + value = le32_to_cpu(value); + + return value; +} + +/** + * 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 void +spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value) +{ + value = cpu_to_le32(value); + writel(value, card->regs + reg); +} + +/** + * spider_net_write_reg_sync - 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 + * + * Unlike spider_net_write_reg, this will also make sure the + * data arrives on the card by reading the reg again. + */ +static void +spider_net_write_reg_sync(struct spider_net_card *card, u32 reg, u32 value) +{ + value = cpu_to_le32(value); + writel(value, card->regs + reg); + (void)readl(card->regs + reg); +} + +/** + * 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; + unsigned long flags; + + spin_lock_irqsave(&card->intmask_lock, flags); + regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); + regvalue &= ~SPIDER_NET_RXINT; + spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); + spin_unlock_irqrestore(&card->intmask_lock, flags); +} + +/** 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_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; + unsigned long flags; + + spin_lock_irqsave(&card->intmask_lock, flags); + regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); + regvalue |= SPIDER_NET_RXINT; + spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); + spin_unlock_irqrestore(&card->intmask_lock, flags); +} + +/** + * spider_net_tx_irq_off - switch off tx irq on this spider card + * @card: device structure + * + * switches off tx irq by masking them out in the GHIINTnMSK register + */ +static void +spider_net_tx_irq_off(struct spider_net_card *card) +{ + u32 regvalue; + unsigned long flags; + + spin_lock_irqsave(&card->intmask_lock, flags); + regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); + regvalue &= ~SPIDER_NET_TXINT; + spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); + spin_unlock_irqrestore(&card->intmask_lock, flags); +} + +/** + * spider_net_tx_irq_on - switch on tx irq on this spider card + * @card: device structure + * + * switches on tx irq by enabling them in the GHIINTnMSK register + */ +static void +spider_net_tx_irq_on(struct spider_net_card *card) +{ + u32 regvalue; + unsigned long flags; + + spin_lock_irqsave(&card->intmask_lock, flags); + regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); + regvalue |= SPIDER_NET_TXINT; + spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); + spin_unlock_irqrestore(&card->intmask_lock, flags); +} + +/** + * 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 enum spider_net_descr_status +spider_net_get_descr_status(struct spider_net_descr *descr) +{ + u32 cmd_status; + rmb(); + cmd_status = descr->dmac_cmd_status; + rmb(); + cmd_status >>= SPIDER_NET_DESCR_IND_PROC_SHIFT; + /* no need to mask out any bits, as cmd_status is 32 bits wide only + * (and unsigned) */ + return cmd_status; +} + +/** + * spider_net_set_descr_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 +spider_net_set_descr_status(struct spider_net_descr *descr, + enum spider_net_descr_status status) +{ + u32 cmd_status; + /* read the status */ + mb(); + cmd_status = descr->dmac_cmd_status; + /* clean the upper 4 bits */ + cmd_status &= SPIDER_NET_DESCR_IND_PROC_MASKO; + /* add the status to it */ + cmd_status |= ((u32)status)<<SPIDER_NET_DESCR_IND_PROC_SHIFT; + /* and write it back */ + descr->dmac_cmd_status = cmd_status; + wmb(); +} + +/** + * 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; + + for (descr = chain->tail; !descr->bus_addr; descr = descr->next) { + pci_unmap_single(card->pdev, descr->bus_addr, + SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL); + descr->bus_addr = 0; + } +} + +/** + * spider_net_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 |