X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fvia-velocity.c;h=8e5d82051bd4f94f42c91b711793b23a1f9825c3;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=f053d2a9e4f2cc2066168769cd758480549f29b2;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index f053d2a9e..8e5d82051 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include @@ -61,12 +60,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -78,6 +75,8 @@ #include #include #include +#include +#include #include "via-velocity.h" @@ -87,7 +86,7 @@ static int msglevel = MSG_LEVEL_INFO; static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static struct ethtool_ops velocity_ethtool_ops; +static const struct ethtool_ops velocity_ethtool_ops; /* Define module options @@ -98,8 +97,8 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"); #define VELOCITY_PARAM(N,D) \ - static const int N[MAX_UNITS]=OPTION_DEFAULT;\ - MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\ + static int N[MAX_UNITS]=OPTION_DEFAULT;\ + module_param_array(N, int, NULL, 0); \ MODULE_PARM_DESC(N, D); #define RX_DESC_MIN 64 @@ -226,61 +225,83 @@ VELOCITY_PARAM(wol_opts, "Wake On Lan options"); VELOCITY_PARAM(int_works, "Number of packets per interrupt services"); -static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent); -static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info); +static int rx_copybreak = 200; +module_param(rx_copybreak, int, 0644); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); + +static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, + const struct velocity_info_tbl *info); static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev); static void velocity_print_info(struct velocity_info *vptr); static int velocity_open(struct net_device *dev); static int velocity_change_mtu(struct net_device *dev, int mtu); static int velocity_xmit(struct sk_buff *skb, struct net_device *dev); -static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs); +static int velocity_intr(int irq, void *dev_instance); static void velocity_set_multi(struct net_device *dev); static struct net_device_stats *velocity_get_stats(struct net_device *dev); static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int velocity_close(struct net_device *dev); -static int velocity_rx_srv(struct velocity_info *vptr, int status); static int velocity_receive_frame(struct velocity_info *, int idx); static int velocity_alloc_rx_buf(struct velocity_info *, int idx); -static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type); static void velocity_free_rd_ring(struct velocity_info *vptr); static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); static int velocity_soft_reset(struct velocity_info *vptr); static void mii_init(struct velocity_info *vptr, u32 mii_status); +static u32 velocity_get_link(struct net_device *dev); static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); static void velocity_print_link_status(struct velocity_info *vptr); -static void safe_disable_mii_autopoll(struct mac_regs * regs); +static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs); static void velocity_shutdown(struct velocity_info *vptr); static void enable_flow_control_ability(struct velocity_info *vptr); -static void enable_mii_autopoll(struct mac_regs * regs); -static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata); -static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data); -static int velocity_set_wol(struct velocity_info *vptr); -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context); -static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context); -static u32 mii_check_media_mode(struct mac_regs * regs); -static u32 check_connection_type(struct mac_regs * regs); -static void velocity_init_cam_filter(struct velocity_info *vptr); +static void enable_mii_autopoll(struct mac_regs __iomem * regs); +static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata); +static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data); +static u32 mii_check_media_mode(struct mac_regs __iomem * regs); +static u32 check_connection_type(struct mac_regs __iomem * regs); static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); #ifdef CONFIG_PM -static int velocity_suspend(struct pci_dev *pdev, u32 state); + +static int velocity_suspend(struct pci_dev *pdev, pm_message_t state); static int velocity_resume(struct pci_dev *pdev); +static DEFINE_SPINLOCK(velocity_dev_list_lock); +static LIST_HEAD(velocity_dev_list); + +#endif + +#if defined(CONFIG_PM) && defined(CONFIG_INET) + static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); static struct notifier_block velocity_inetaddr_notifier = { - notifier_call:velocity_netdev_event, + .notifier_call = velocity_netdev_event, }; -#endif /* CONFIG_PM */ +static void velocity_register_notifier(void) +{ + register_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +static void velocity_unregister_notifier(void) +{ + unregister_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +#else + +#define velocity_register_notifier() do {} while (0) +#define velocity_unregister_notifier() do {} while (0) + +#endif /* * Internal board variants. At the moment we have only one */ -static struct velocity_info_tbl chip_info_table[] = { - {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL}, - {0, NULL} +static const struct velocity_info_tbl chip_info_table[] __devinitdata = { + {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL}, + { } }; /* @@ -288,9 +309,9 @@ static struct velocity_info_tbl chip_info_table[] = { * device driver. Used for hotplug autoloading. */ -static struct pci_device_id velocity_id_table[] __devinitdata = { - {0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]}, - {0,} +static const struct pci_device_id velocity_id_table[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) }, + { } }; MODULE_DEVICE_TABLE(pci, velocity_id_table); @@ -324,14 +345,24 @@ static char __devinit *get_chip_name(enum chip_type chip_id) static void __devexit velocity_remove1(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); +#ifdef CONFIG_PM + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + if (!list_empty(&velocity_dev_list)) + list_del(&vptr->list); + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); +#endif unregister_netdev(dev); iounmap(vptr->mac_regs); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_netdev(dev); + + velocity_nics--; } /** @@ -384,11 +415,11 @@ static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 fla if (val == -1) *opt |= (def ? flag : 0); else if (val < 0 || val > 1) { - printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n", + printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n", devname, name); *opt |= (def ? flag : 0); } else { - printk(KERN_INFO "%s: set parameter %s to %s\n", + printk(KERN_INFO "%s: set parameter %s to %s\n", devname, name, val ? "TRUE" : "FALSE"); *opt |= (val ? flag : 0); } @@ -433,9 +464,9 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, static void velocity_init_cam_filter(struct velocity_info *vptr) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; - /* T urn on MCFG_PQEN, turn off MCFG_RTGOPT */ + /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); WORD_REG_BITS_ON(MCFG_VIDFR, ®s->MCFG); @@ -474,16 +505,16 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) static void velocity_rx_reset(struct velocity_info *vptr) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; int i; - vptr->rd_used = vptr->rd_curr = 0; + vptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0; /* * Init state, all RD entries belong to the NIC */ for (i = 0; i < vptr->options.numrx; ++i) - vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC); + vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC; writew(vptr->options.numrx, ®s->RBRDU); writel(vptr->rd_pool_dma, ®s->RDBaseLo); @@ -500,10 +531,10 @@ static void velocity_rx_reset(struct velocity_info *vptr) * hardware. */ -static void velocity_init_registers(struct velocity_info *vptr, +static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; int i, mii_status; mac_wol_reset(regs); @@ -532,7 +563,7 @@ static void velocity_init_registers(struct velocity_info *vptr, mac_clear_isr(regs); writel(CR0_STOP, ®s->CR0Clr); - writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), + writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); break; @@ -558,10 +589,15 @@ static void velocity_init_registers(struct velocity_info *vptr, writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); /* - * Bback off algorithm use original IEEE standard + * Back off algorithm use original IEEE standard */ BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); + /* + * Init CAM filter + */ + velocity_init_cam_filter(vptr); + /* * Set packet filter: Receive directed and broadcast address */ @@ -586,8 +622,6 @@ static void velocity_init_registers(struct velocity_info *vptr, mac_tx_queue_run(regs, i); } - velocity_init_cam_filter(vptr); - init_flow_control_register(vptr); writel(CR0_STOP, ®s->CR0Clr); @@ -595,7 +629,6 @@ static void velocity_init_registers(struct velocity_info *vptr, mii_status = velocity_get_opt_media_mode(vptr); netif_stop_queue(vptr->dev); - mac_clear_isr(regs); mii_init(vptr, mii_status); @@ -623,7 +656,7 @@ static void velocity_init_registers(struct velocity_info *vptr, static int velocity_soft_reset(struct velocity_info *vptr) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; int i = 0; writel(CR0_SFRST, ®s->CR0Set); @@ -657,33 +690,35 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi static int first = 1; struct net_device *dev; int i; - struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data; + const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; struct velocity_info *vptr; - struct mac_regs * regs; + struct mac_regs __iomem * regs; int ret = -ENOMEM; - if (velocity_nics++ >= MAX_UNITS) { - printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n", - velocity_nics); + /* FIXME: this driver, like almost all other ethernet drivers, + * can support more than MAX_UNITS. + */ + if (velocity_nics >= MAX_UNITS) { + dev_notice(&pdev->dev, "already found %d NICs.\n", + velocity_nics); return -ENODEV; } dev = alloc_etherdev(sizeof(struct velocity_info)); - - if (dev == NULL) { - printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n"); + if (!dev) { + dev_err(&pdev->dev, "allocate net device failed.\n"); goto out; } - + /* Chain it all together */ - + SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - vptr = dev->priv; + vptr = netdev_priv(dev); if (first) { - printk(KERN_INFO "%s Ver. %s\n", + printk(KERN_INFO "%s Ver. %s\n", VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION); printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n"); printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n"); @@ -694,26 +729,25 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi vptr->dev = dev; - dev->priv = vptr; dev->irq = pdev->irq; ret = pci_enable_device(pdev); - if (ret < 0) + if (ret < 0) goto err_free_dev; ret = velocity_get_pci_info(vptr, pdev); if (ret < 0) { - printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n"); + /* error message already printed */ goto err_disable; } ret = pci_request_regions(pdev, VELOCITY_NAME); if (ret < 0) { - printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n"); + dev_err(&pdev->dev, "No PCI resources.\n"); goto err_disable; } - regs = ioremap(vptr->memaddr, vptr->io_size); + regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE); if (regs == NULL) { ret = -EIO; goto err_release_res; @@ -729,18 +763,18 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->dev_addr[i] = readb(®s->PAR[i]); - velocity_get_options(&vptr->options, velocity_nics - 1, dev->name); + velocity_get_options(&vptr->options, velocity_nics, dev->name); - /* + /* * Mask out the options cannot be set to the chip */ - + vptr->options.flags &= info->flags; /* * Enable the chip specified capbilities */ - + vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL); vptr->wol_opts = vptr->options.wol_opts; @@ -762,19 +796,32 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi #endif if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) { - dev->features |= NETIF_F_HW_CSUM; + dev->features |= NETIF_F_IP_CSUM; } ret = register_netdev(dev); if (ret < 0) goto err_iounmap; + if (velocity_get_link(dev)) + netif_carrier_off(dev); + velocity_print_info(vptr); pci_set_drvdata(pdev, dev); - + /* and leave the chip powered down */ - - pci_set_power_state(pdev, 3); + + pci_set_power_state(pdev, PCI_D3hot); +#ifdef CONFIG_PM + { + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + list_add(&vptr->list, &velocity_dev_list); + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + } +#endif + velocity_nics++; out: return ret; @@ -802,9 +849,9 @@ static void __devinit velocity_print_info(struct velocity_info *vptr) struct net_device *dev = vptr->dev; printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id)); - printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); } @@ -818,18 +865,18 @@ static void __devinit velocity_print_info(struct velocity_info *vptr) * discovered. */ -static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info) +static void __devinit velocity_init_info(struct pci_dev *pdev, + struct velocity_info *vptr, + const struct velocity_info_tbl *info) { memset(vptr, 0, sizeof(struct velocity_info)); vptr->pdev = pdev; vptr->chip_id = info->chip_id; - vptr->io_size = info->io_size; vptr->num_txq = info->txqueue; vptr->multicast_limit = MCAM_SIZE; - spin_lock_init(&vptr->lock); - spin_lock_init(&vptr->xmit_lock); + INIT_LIST_HEAD(&vptr->list); } /** @@ -843,33 +890,28 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev) { - - if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0) + if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0) return -EIO; - + pci_set_master(pdev); vptr->ioaddr = pci_resource_start(pdev, 0); vptr->memaddr = pci_resource_start(pdev, 1); - - if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) - { - printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n", - pci_name(pdev)); + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { + dev_err(&pdev->dev, + "region #0 is not an I/O resource, aborting.\n"); return -EINVAL; } - if((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) - { - printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n", - pci_name(pdev)); + if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) { + dev_err(&pdev->dev, + "region #1 is an I/O resource, aborting.\n"); return -EINVAL; } - if(pci_resource_len(pdev, 1) < 256) - { - printk(KERN_ERR "%s: region #1 is too small.\n", - pci_name(pdev)); + if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) { + dev_err(&pdev->dev, "region #1 is too small.\n"); return -EINVAL; } vptr->pdev = pdev; @@ -894,10 +936,10 @@ static int velocity_init_rings(struct velocity_info *vptr) u8 *pool; /* - * Allocate all RD/TD rings a single pool + * Allocate all RD/TD rings a single pool */ - - psize = vptr->options.numrx * sizeof(struct rx_desc) + + + psize = vptr->options.numrx * sizeof(struct rx_desc) + vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq; /* @@ -907,7 +949,7 @@ static int velocity_init_rings(struct velocity_info *vptr) pool = pci_alloc_consistent(vptr->pdev, psize, &pool_dma); if (pool == NULL) { - printk(KERN_ERR "%s : DMA memory allocation failed.\n", + printk(KERN_ERR "%s : DMA memory allocation failed.\n", vptr->dev->name); return -ENOMEM; } @@ -919,11 +961,11 @@ static int velocity_init_rings(struct velocity_info *vptr) vptr->rd_pool_dma = pool_dma; tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq; - vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize, + vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize, &vptr->tx_bufs_dma); if (vptr->tx_bufs == NULL) { - printk(KERN_ERR "%s: DMA memory allocation failed.\n", + printk(KERN_ERR "%s: DMA memory allocation failed.\n", vptr->dev->name); pci_free_consistent(vptr->pdev, psize, pool, pool_dma); return -ENOMEM; @@ -956,7 +998,7 @@ static void velocity_free_rings(struct velocity_info *vptr) { int size; - size = vptr->options.numrx * sizeof(struct rx_desc) + + size = vptr->options.numrx * sizeof(struct rx_desc) + vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq; pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma); @@ -966,6 +1008,60 @@ static void velocity_free_rings(struct velocity_info *vptr) pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma); } +static inline void velocity_give_many_rx_descs(struct velocity_info *vptr) +{ + struct mac_regs __iomem *regs = vptr->mac_regs; + int avail, dirty, unusable; + + /* + * RD number must be equal to 4X per hardware spec + * (programming guide rev 1.20, p.13) + */ + if (vptr->rd_filled < 4) + return; + + wmb(); + + unusable = vptr->rd_filled & 0x0003; + dirty = vptr->rd_dirty - unusable; + for (avail = vptr->rd_filled & 0xfffc; avail; avail--) { + dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; + vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC; + } + + writew(vptr->rd_filled & 0xfffc, ®s->RBRDU); + vptr->rd_filled = unusable; +} + +static int velocity_rx_refill(struct velocity_info *vptr) +{ + int dirty = vptr->rd_dirty, done = 0, ret = 0; + + do { + struct rx_desc *rd = vptr->rd_ring + dirty; + + /* Fine for an all zero Rx desc at init time as well */ + if (rd->rdesc0.owner == OWNED_BY_NIC) + break; + + if (!vptr->rd_info[dirty].skb) { + ret = velocity_alloc_rx_buf(vptr, dirty); + if (ret < 0) + break; + } + done++; + dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; + } while (dirty != vptr->rd_curr); + + if (done) { + vptr->rd_dirty = dirty; + vptr->rd_filled += done; + velocity_give_many_rx_descs(vptr); + } + + return ret; +} + /** * velocity_init_rd_ring - set up receive ring * @vptr: velocity to configure @@ -976,10 +1072,8 @@ static void velocity_free_rings(struct velocity_info *vptr) static int velocity_init_rd_ring(struct velocity_info *vptr) { - int i, ret = -ENOMEM; - struct rx_desc *rd; - struct velocity_rd_info *rd_info; - unsigned int rsize = sizeof(struct velocity_rd_info) * + int ret = -ENOMEM; + unsigned int rsize = sizeof(struct velocity_rd_info) * vptr->options.numrx; vptr->rd_info = kmalloc(rsize, GFP_KERNEL); @@ -987,28 +1081,20 @@ static int velocity_init_rd_ring(struct velocity_info *vptr) goto out; memset(vptr->rd_info, 0, rsize); - /* Init the RD ring entries */ - for (i = 0; i < vptr->options.numrx; i++) { - rd = &(vptr->rd_ring[i]); - rd_info = &(vptr->rd_info[i]); + vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0; - ret = velocity_alloc_rx_buf(vptr, i); - if (ret < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR - "%s: failed to allocate RX buffer.\n", - vptr->dev->name); - velocity_free_rd_ring(vptr); - goto out; - } - rd->rdesc0.owner = OWNED_BY_NIC; + ret = velocity_rx_refill(vptr); + if (ret < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: failed to allocate RX buffer.\n", vptr->dev->name); + velocity_free_rd_ring(vptr); } - vptr->rd_used = vptr->rd_curr = 0; out: return ret; } /** - * velocity_free_rd_ring - set up receive ring + * velocity_free_rd_ring - free receive ring * @vptr: velocity to clean up * * Free the receive buffers for each ring slot and any @@ -1024,8 +1110,11 @@ static void velocity_free_rd_ring(struct velocity_info *vptr) for (i = 0; i < vptr->options.numrx; i++) { struct velocity_rd_info *rd_info = &(vptr->rd_info[i]); + struct rx_desc *rd = vptr->rd_ring + i; - if (!rd_info->skb_dma) + memset(rd, 0, sizeof(*rd)); + + if (!rd_info->skb) continue; pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); @@ -1047,14 +1136,14 @@ static void velocity_free_rd_ring(struct velocity_info *vptr) * Returns zero on success or a negative posix errno code for * failure. */ - + static int velocity_init_td_ring(struct velocity_info *vptr) { int i, j; dma_addr_t curr; struct tx_desc *td; struct velocity_td_info *td_info; - unsigned int tsize = sizeof(struct velocity_td_info) * + unsigned int tsize = sizeof(struct velocity_td_info) * vptr->options.numtx; /* Init the TD ring entries */ @@ -1073,8 +1162,10 @@ static int velocity_init_td_ring(struct velocity_info *vptr) for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) { td = &(vptr->td_rings[j][i]); td_info = &(vptr->td_infos[j][i]); - td_info->buf = vptr->tx_bufs + (i + j) * PKT_BUF_SZ; - td_info->buf_dma = vptr->tx_bufs_dma + (i + j) * PKT_BUF_SZ; + td_info->buf = vptr->tx_bufs + + (j * vptr->options.numtx + i) * PKT_BUF_SZ; + td_info->buf_dma = vptr->tx_bufs_dma + + (j * vptr->options.numtx + i) * PKT_BUF_SZ; } vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0; } @@ -1090,15 +1181,15 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, { struct velocity_td_info * td_info = &(vptr->td_infos[q][n]); int i; - + if (td_info == NULL) return; - + if (td_info->skb) { for (i = 0; i < td_info->nskb_dma; i++) { if (td_info->skb_dma[i]) { - pci_unmap_single(vptr->pdev, td_info->skb_dma[i], + pci_unmap_single(vptr->pdev, td_info->skb_dma[i], td_info->skb->len, PCI_DMA_TODEVICE); td_info->skb_dma[i] = (dma_addr_t) NULL; } @@ -1115,7 +1206,7 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr, * Free up the transmit ring for this particular velocity adapter. * We free the ring contents but not the ring itself. */ - + static void velocity_free_td_ring(struct velocity_info *vptr) { int i, j; @@ -1127,10 +1218,8 @@ static void velocity_free_td_ring(struct velocity_info *vptr) velocity_free_td_ring_entry(vptr, j, i); } - if (vptr->td_infos[j]) { - kfree(vptr->td_infos[j]); - vptr->td_infos[j] = NULL; - } + kfree(vptr->td_infos[j]); + vptr->td_infos[j] = NULL; } } @@ -1143,43 +1232,30 @@ static void velocity_free_td_ring(struct velocity_info *vptr) * any received packets from the receive queue. Hand the ring * slots back to the adapter for reuse. */ - + static int velocity_rx_srv(struct velocity_info *vptr, int status) { - struct rx_desc *rd; struct net_device_stats *stats = &vptr->stats; - struct mac_regs * regs = vptr->mac_regs; int rd_curr = vptr->rd_curr; int works = 0; - while (1) { - - rd = &(vptr->rd_ring[rd_curr]); - - if ((vptr->rd_info[rd_curr]).skb == NULL) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) - break; - } + do { + struct rx_desc *rd = vptr->rd_ring + rd_curr; - if (works++ > 15) + if (!vptr->rd_info[rd_curr].skb) break; if (rd->rdesc0.owner == OWNED_BY_NIC) break; + rmb(); + /* * Don't drop CE or RL error frame although RXOK is off - * FIXME: need to handle copybreak */ if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) { - if (velocity_receive_frame(vptr, rd_curr) == 0) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name); - break; - } - } else { + if (velocity_receive_frame(vptr, rd_curr) < 0) stats->rx_dropped++; - } } else { if (rd->rdesc0.RSR & RSR_CRC) stats->rx_crc_errors++; @@ -1191,26 +1267,20 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) rd->inten = 1; - if (++vptr->rd_used >= 4) { - int i, rd_prev = rd_curr; - for (i = 0; i < 4; i++) { - if (--rd_prev < 0) - rd_prev = vptr->options.numrx - 1; - - rd = &(vptr->rd_ring[rd_prev]); - rd->rdesc0.owner = OWNED_BY_NIC; - } - writew(4, &(regs->RBRDU)); - vptr->rd_used -= 4; - } - vptr->dev->last_rx = jiffies; rd_curr++; if (rd_curr >= vptr->options.numrx) rd_curr = 0; - } + } while (++works <= 15); + vptr->rd_curr = rd_curr; + + if (works > 0 && velocity_rx_refill(vptr) < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: rx buf allocation failure\n", vptr->dev->name); + } + VAR_USED(stats); return works; } @@ -1223,14 +1293,14 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) * Process the status bits for the received packet and determine * if the checksum was computed and verified by the hardware */ - + static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) { skb->ip_summed = CHECKSUM_NONE; if (rd->rdesc1.CSM & CSM_IPKT) { if (rd->rdesc1.CSM & CSM_IPOK) { - if ((rd->rdesc1.CSM & CSM_TCPKT) || + if ((rd->rdesc1.CSM & CSM_TCPKT) || (rd->rdesc1.CSM & CSM_UDPKT)) { if (!(rd->rdesc1.CSM & CSM_TUPOK)) { return; @@ -1241,20 +1311,81 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) } } +/** + * velocity_rx_copy - in place Rx copy for small packets + * @rx_skb: network layer packet buffer candidate + * @pkt_size: received data size + * @rd: receive packet descriptor + * @dev: network device + * + * Replace the current skb that is scheduled for Rx processing by a + * shorter, immediatly allocated skb, if the received packet is small + * enough. This function returns a negative value if the received + * packet is too big or if memory is exhausted. + */ +static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *new_skb; + + new_skb = dev_alloc_skb(pkt_size + 2); + if (new_skb) { + new_skb->dev = vptr->dev; + new_skb->ip_summed = rx_skb[0]->ip_summed; + + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) + skb_reserve(new_skb, 2); + + memcpy(new_skb->data, rx_skb[0]->data, pkt_size); + *rx_skb = new_skb; + ret = 0; + } + + } + return ret; +} + +/** + * velocity_iph_realign - IP header alignment + * @vptr: velocity we are handling + * @skb: network layer packet buffer + * @pkt_size: received data size + * + * Align IP header on a 2 bytes boundary. This behavior can be + * configured by the user. + */ +static inline void velocity_iph_realign(struct velocity_info *vptr, + struct sk_buff *skb, int pkt_size) +{ + /* FIXME - memmove ? */ + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { + int i; + + for (i = pkt_size; i >= 0; i--) + *(skb->data + i + 2) = *(skb->data + i); + skb_reserve(skb, 2); + } +} + /** * velocity_receive_frame - received packet processor * @vptr: velocity we are handling * @idx: ring index - * + * * A packet has arrived. We process the packet and if appropriate * pass the frame up the network stack */ - + static int velocity_receive_frame(struct velocity_info *vptr, int idx) { + void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); struct net_device_stats *stats = &vptr->stats; struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); struct rx_desc *rd = &(vptr->rd_ring[idx]); + int pkt_len = rd->rdesc0.len; struct sk_buff *skb; if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { @@ -1269,27 +1400,13 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) skb = rd_info->skb; skb->dev = vptr->dev; - pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, - PCI_DMA_FROMDEVICE); - rd_info->skb_dma = (dma_addr_t) NULL; - rd_info->skb = NULL; - - /* FIXME - memmove ? */ - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - int i; - for (i = rd->rdesc0.len + 4; i >= 0; i--) - *(skb->data + i + 2) = *(skb->data + i); - skb->data += 2; - skb->tail += 2; - } - - skb_put(skb, (rd->rdesc0.len - 4)); - skb->protocol = eth_type_trans(skb, skb->dev); + pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, + vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* * Drop frame not meeting IEEE 802.3 */ - + if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { if (rd->rdesc0.RSR & RSR_RL) { stats->rx_length_errors++; @@ -1297,13 +1414,23 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) } } + pci_action = pci_dma_sync_single_for_device; + velocity_rx_csum(rd, skb); - - /* - * FIXME: need rx_copybreak handling - */ - stats->rx_bytes += skb->len; + if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { + velocity_iph_realign(vptr, skb, pkt_len); + pci_action = pci_unmap_single; + rd_info->skb = NULL; + } + + pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + skb_put(skb, pkt_len - 4); + skb->protocol = eth_type_trans(skb, skb->dev); + + stats->rx_bytes += pkt_len; netif_rx(skb); return 0; @@ -1319,7 +1446,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) * requires *64* byte alignment of the buffer which makes life * less fun than would be ideal. */ - + static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) { struct rx_desc *rd = &(vptr->rd_ring[idx]); @@ -1333,14 +1460,14 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) * Do the gymnastics to get the buffer head for data at * 64byte alignment. */ - skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63); + skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63); rd_info->skb->dev = vptr->dev; - rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); - + rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); + /* * Fill in the descriptor to match - */ - + */ + *((u32 *) & (rd->rdesc0)) = 0; rd->len = cpu_to_le32(vptr->rx_buf_sz); rd->inten = 1; @@ -1358,7 +1485,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) * we can complete and clean up. Update any statistics as * neccessary/ */ - + static int velocity_tx_srv(struct velocity_info *vptr, u32 status) { struct tx_desc *td; @@ -1370,7 +1497,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) struct net_device_stats *stats = &vptr->stats; for (qnum = 0; qnum < vptr->num_txq; qnum++) { - for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0; + for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0; idx = (idx + 1) % vptr->options.numtx) { /* @@ -1475,36 +1602,36 @@ static void velocity_print_link_status(struct velocity_info *vptr) * @status: card status * * Process an error report from the hardware and attempt to recover - * the card itself. At the moment we cannot recover from some + * the card itself. At the moment we cannot recover from some * theoretically impossible errors but this could be fixed using * the pci_device_failed logic to bounce the hardware * */ - + static void velocity_error(struct velocity_info *vptr, int status) { if (status & ISR_TXSTLI) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(®s->TDIdx[0])); BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); writew(TRDCSR_RUN, ®s->TDCSRClr); netif_stop_queue(vptr->dev); - + /* FIXME: port over the pci_device_failed code and use it here */ } if (status & ISR_SRCI) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; int linked; if (vptr->options.spd_dpx == SPD_DPX_AUTO) { vptr->mii_status = check_connection_type(regs); /* - * If it is a 3119, disable frame bursting in + * If it is a 3119, disable frame bursting in * halfduplex mode and enable it in fullduplex * mode */ @@ -1530,18 +1657,20 @@ static void velocity_error(struct velocity_info *vptr, int status) if (linked) { vptr->mii_status &= ~VELOCITY_LINK_FAIL; + netif_carrier_on(vptr->dev); } else { vptr->mii_status |= VELOCITY_LINK_FAIL; + netif_carrier_off(vptr->dev); } velocity_print_link_status(vptr); enable_flow_control_ability(vptr); /* - * Re-enable auto-polling because SRCI will disable + * Re-enable auto-polling because SRCI will disable * auto-polling */ - + enable_mii_autopoll(regs); if (vptr->mii_status & VELOCITY_LINK_FAIL) @@ -1564,7 +1693,7 @@ static void velocity_error(struct velocity_info *vptr, int status) * Release an transmit buffer. If the buffer was preallocated then * recycle it, if not then unmap the buffer. */ - + static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) { struct sk_buff *skb = tdinfo->skb; @@ -1598,10 +1727,10 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_ * All the ring allocation and set up is done on open for this * adapter to minimise memory usage when inactive */ - + static int velocity_open(struct net_device *dev) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); int ret; vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32); @@ -1617,17 +1746,17 @@ static int velocity_open(struct net_device *dev) ret = velocity_init_td_ring(vptr); if (ret < 0) goto err_free_rd_ring; - - /* Ensure chip is running */ - pci_set_power_state(vptr->pdev, 0); - + + /* Ensure chip is running */ + pci_set_power_state(vptr->pdev, PCI_D0); + velocity_init_registers(vptr, VELOCITY_INIT_COLD); - ret = request_irq(vptr->pdev->irq, &velocity_intr, SA_SHIRQ, + ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED, dev->name, dev); if (ret < 0) { /* Power down the chip */ - pci_set_power_state(vptr->pdev, 3); + pci_set_power_state(vptr->pdev, PCI_D3hot); goto err_free_td_ring; } @@ -1646,7 +1775,7 @@ err_free_desc_rings: goto out; } -/** +/** * velocity_change_mtu - MTU change callback * @dev: network device * @new_mtu: desired MTU @@ -1655,16 +1784,16 @@ err_free_desc_rings: * this interface. It gets called on a change by the network layer. * Return zero for success or negative posix error code. */ - + static int velocity_change_mtu(struct net_device *dev, int new_mtu) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); unsigned long flags; int oldmtu = dev->mtu; int ret = 0; if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", vptr->dev->name); return -EINVAL; } @@ -1712,10 +1841,10 @@ out_unlock: * Shuts down the internal operations of the velocity and * disables interrupts, autopolling, transmit and receive */ - + static void velocity_shutdown(struct velocity_info *vptr) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; mac_disable_int(regs); writel(CR0_STOP, ®s->CR0Set); writew(0xFFFF, ®s->TDCSRClr); @@ -1734,7 +1863,7 @@ static void velocity_shutdown(struct velocity_info *vptr) static int velocity_close(struct net_device *dev) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); netif_stop_queue(dev); velocity_shutdown(vptr); @@ -1743,10 +1872,10 @@ static int velocity_close(struct net_device *dev) velocity_get_ip(vptr); if (dev->irq != 0) free_irq(dev->irq, dev); - + /* Power down the chip */ - pci_set_power_state(vptr->pdev, 3); - + pci_set_power_state(vptr->pdev, PCI_D3hot); + /* Free the resources */ velocity_free_td_ring(vptr); velocity_free_rd_ring(vptr); @@ -1764,10 +1893,10 @@ static int velocity_close(struct net_device *dev) * Called by the networ layer to request a packet is queued to * the velocity. Returns zero on success. */ - + static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); int qnum = 0; struct tx_desc *td_ptr; struct velocity_td_info *tdinfo; @@ -1776,6 +1905,13 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) int pktlen = skb->len; +#ifdef VELOCITY_ZERO_COPY_SUPPORT + if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { + kfree_skb(skb); + return 0; + } +#endif + spin_lock_irqsave(&vptr->lock, flags); index = vptr->td_curr[qnum]; @@ -1787,12 +1923,10 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) td_ptr->td_buf[0].queue = 0; /* - * Pad short frames. + * Pad short frames. */ if (pktlen < ETH_ZLEN) { /* Cannot occur until ZC support */ - if(skb_linearize(skb, GFP_ATOMIC)) - return 0; pktlen = ETH_ZLEN; memcpy(tdinfo->buf, skb->data, skb->len); memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len); @@ -1810,10 +1944,9 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) int nfrags = skb_shinfo(skb)->nr_frags; tdinfo->skb = skb; if (nfrags > 6) { - skb_linearize(skb, GFP_ATOMIC); memcpy(tdinfo->buf, skb->data, skb->len); tdinfo->skb_dma[0] = tdinfo->buf_dma; - td_ptr->tdesc0.pktsize = + td_ptr->tdesc0.pktsize = td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); td_ptr->td_buf[0].pa_high = 0; td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize; @@ -1873,7 +2006,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) * Handle hardware checksum */ if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) - && (skb->ip_summed == CHECKSUM_HW)) { + && (skb->ip_summed == CHECKSUM_PARTIAL)) { struct iphdr *ip = skb->nh.iph; if (ip->protocol == IPPROTO_TCP) td_ptr->tdesc1.TCR |= TCR0_TCPCK; @@ -1907,18 +2040,17 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) * velocity_intr - interrupt callback * @irq: interrupt number * @dev_instance: interrupting device - * @pt_regs: CPU register state at interrupt * * Called whenever an interrupt is generated by the velocity * adapter IRQ line. We may not be the source of the interrupt * and need to identify initially if we are, and if not exit as * efficiently as possible. */ - -static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs) + +static int velocity_intr(int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); u32 isr_status; int max_count = 0; @@ -1938,7 +2070,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs) * Keep processing the ISR until we have completed * processing and the isr_status becomes zero */ - + while (isr_status != 0) { mac_write_isr(vptr->mac_regs, isr_status); if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) @@ -1950,7 +2082,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs) isr_status = mac_read_isr(vptr->mac_regs); if (max_count > vptr->options.int_works) { - printk(KERN_WARNING "%s: excessive work at interrupt.\n", + printk(KERN_WARNING "%s: excessive work at interrupt.\n", dev->name); max_count = 0; } @@ -1962,32 +2094,6 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs) } -/** - * ether_crc - ethernet CRC function - * - * Compute an ethernet CRC hash of the data block provided. This - * is not performance optimised but is not needed in performance - * critical code paths. - * - * FIXME: could we use shared code here ? - */ - -static inline u32 ether_crc(int length, unsigned char *data) -{ - static unsigned const ethernet_polynomial = 0x04c11db7U; - - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - return crc; -} - /** * velocity_set_multi - filter list change callback * @dev: network device @@ -1996,18 +2102,16 @@ static inline u32 ether_crc(int length, unsigned char *data) * for a velocity adapter. Reload the CAMs with the new address * filter ruleset. */ - + static void velocity_set_multi(struct net_device *dev) { - struct velocity_info *vptr = dev->priv; - struct mac_regs * regs = vptr->mac_regs; + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem * regs = vptr->mac_regs; u8 rx_mode; int i; struct dev_mc_list *mclist; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); writel(0xffffffff, ®s->MARCAM[0]); writel(0xffffffff, ®s->MARCAM[4]); rx_mode = (RCR_AM | RCR_AB | RCR_PROM); @@ -2045,11 +2149,11 @@ static void velocity_set_multi(struct net_device *dev) * the hardware into the counters before letting the network * layer display them. */ - + static struct net_device_stats *velocity_get_stats(struct net_device *dev) { - struct velocity_info *vptr = dev->priv; - + struct velocity_info *vptr = netdev_priv(dev); + /* If the hardware is down, don't touch MII */ if(!netif_running(dev)) return &vptr->stats; @@ -2088,18 +2192,18 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) * Called when the user issues an ioctl request to the network * device in question. The velocity interface supports MII. */ - + static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); int ret; /* If we are asked for information and the device is power saving then we need to bring the device back up to talk to it */ - - if(!netif_running(dev)) - pci_set_power_state(vptr->pdev, 0); - + + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D0); + switch (cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCGMIIREG: /* Read MII PHY register. */ @@ -2110,10 +2214,10 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) default: ret = -EOPNOTSUPP; } - if(!netif_running(dev)) - pci_set_power_state(vptr->pdev, 3); - - + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D3hot); + + return ret; } @@ -2121,15 +2225,15 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) * Definition for our device driver. The PCI layer interface * uses this to handle all our card discover and plugging */ - + static struct pci_driver velocity_driver = { - name:VELOCITY_NAME, - id_table:velocity_id_table, - probe:velocity_found1, - remove:velocity_remove1, + .name = VELOCITY_NAME, + .id_table = velocity_id_table, + .probe = velocity_found1, + .remove = __devexit_p(velocity_remove1), #ifdef CONFIG_PM - suspend:velocity_suspend, - resume:velocity_resume, + .suspend = velocity_suspend, + .resume = velocity_resume, #endif }; @@ -2141,15 +2245,15 @@ static struct pci_driver velocity_driver = { * the probe functions for each velocity adapter installed * in the system. */ - + static int __init velocity_init_module(void) { int ret; - ret = pci_module_init(&velocity_driver); -#ifdef CONFIG_PM - register_inetaddr_notifier(&velocity_inetaddr_notifier); -#endif + velocity_register_notifier(); + ret = pci_register_driver(&velocity_driver); + if (ret < 0) + velocity_unregister_notifier(); return ret; } @@ -2157,16 +2261,14 @@ static int __init velocity_init_module(void) * velocity_cleanup - module unload * * When the velocity hardware is unloaded this function is called. - * It will clean up the notifiers and the unregister the PCI + * It will clean up the notifiers and the unregister the PCI * driver interface for this hardware. This in turn cleans up * all discovered interfaces before returning from the function */ - + static void __exit velocity_cleanup_module(void) { -#ifdef CONFIG_PM - unregister_inetaddr_notifier(&velocity_inetaddr_notifier); -#endif + velocity_unregister_notifier(); pci_unregister_driver(&velocity_driver); } @@ -2177,8 +2279,8 @@ module_exit(velocity_cleanup_module); /* * MII access , media link mode setting functions */ - - + + /** * mii_init - set up MII * @vptr: velocity adapter @@ -2186,7 +2288,7 @@ module_exit(velocity_cleanup_module); * * Set up the PHY for the current link state. */ - + static void mii_init(struct velocity_info *vptr, u32 mii_status) { u16 BMCR; @@ -2199,7 +2301,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); /* * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. + * off it in NWay-forced half mode for NWay-forced v.s. * legacy-forced issue. */ if (vptr->mii_status & VELOCITY_DUPLEX_FULL) @@ -2219,7 +2321,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); /* * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. + * off it in NWay-forced half mode for NWay-forced v.s. * legacy-forced issue */ if (vptr->mii_status & VELOCITY_DUPLEX_FULL) @@ -2231,11 +2333,11 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) case PHYID_MARVELL_1000: case PHYID_MARVELL_1000S: /* - * Assert CRS on Transmit + * Assert CRS on Transmit */ MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs); /* - * Reset to hardware default + * Reset to hardware default */ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); break; @@ -2255,8 +2357,8 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) * * Turn off the autopoll and wait for it to disable on the chip */ - -static void safe_disable_mii_autopoll(struct mac_regs * regs) + +static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs) { u16 ww; @@ -2277,7 +2379,7 @@ static void safe_disable_mii_autopoll(struct mac_regs * regs) * hardware. Wait for it to enable. */ -static void enable_mii_autopoll(struct mac_regs * regs) +static void enable_mii_autopoll(struct mac_regs __iomem * regs) { int ii; @@ -2309,8 +2411,8 @@ static void enable_mii_autopoll(struct mac_regs * regs) * Perform a single read of an MII 16bit register. Returns zero * on success or -ETIMEDOUT if the PHY did not respond. */ - -static int velocity_mii_read(struct mac_regs * regs, u8 index, u16 *data) + +static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data) { u16 ww; @@ -2345,8 +2447,8 @@ static int velocity_mii_read(struct mac_regs * regs, u8 index, u16 *data) * Perform a single write to an MII 16bit register. Returns zero * on success or -ETIMEDOUT if the PHY did not respond. */ - -static int velocity_mii_write(struct mac_regs * regs, u8 mii_addr, u16 data) + +static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data) { u16 ww; @@ -2384,7 +2486,7 @@ static int velocity_mii_write(struct mac_regs * regs, u8 mii_addr, u16 data) * mii_status accordingly. The requested link state information * is also returned. */ - + static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) { u32 status = 0; @@ -2416,7 +2518,7 @@ static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) * * Enable autonegotation on this interface */ - + static void mii_set_auto_on(struct velocity_info *vptr) { if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs)) @@ -2440,7 +2542,7 @@ static void mii_set_auto_off(struct velocity_info * vptr) * Set up the flow control on this interface according to * the supplied user/eeprom options. */ - + static void set_mii_flow_control(struct velocity_info *vptr) { /*Enable or Disable PAUSE in ANAR */ @@ -2477,11 +2579,11 @@ static void set_mii_flow_control(struct velocity_info *vptr) * PHY and also velocity hardware setup accordingly. In particular * we need to set up CD polling and frame bursting. */ - + static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) { u32 curr_status; - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; vptr->mii_status = mii_check_media_mode(vptr->mac_regs); curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); @@ -2587,8 +2689,8 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) * Check the current MII status and determine the link status * accordingly */ - -static u32 mii_check_media_mode(struct mac_regs * regs) + +static u32 mii_check_media_mode(struct mac_regs __iomem * regs) { u32 status = 0; u16 ANAR; @@ -2624,7 +2726,7 @@ static u32 mii_check_media_mode(struct mac_regs * regs) return status; } -static u32 check_connection_type(struct mac_regs * regs) +static u32 check_connection_type(struct mac_regs __iomem * regs) { u32 status = 0; u8 PHYSR0; @@ -2641,7 +2743,7 @@ static u32 check_connection_type(struct mac_regs * regs) if (PHYSR0 & PHYSR0_SPDG) status |= VELOCITY_SPEED_1000; - if (PHYSR0 & PHYSR0_SPD10) + else if (PHYSR0 & PHYSR0_SPD10) status |= VELOCITY_SPEED_10; else status |= VELOCITY_SPEED_100; @@ -2669,7 +2771,7 @@ static u32 check_connection_type(struct mac_regs * regs) static void enable_flow_control_ability(struct velocity_info *vptr) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; switch (vptr->options.flow_cntl) { @@ -2719,14 +2821,14 @@ static void enable_flow_control_ability(struct velocity_info *vptr) * Called before an ethtool operation. We need to make sure the * chip is out of D3 state before we poke at it. */ - + static int velocity_ethtool_up(struct net_device *dev) { - struct velocity_info *vptr = dev->priv; - if(!netif_running(dev)) - pci_set_power_state(vptr->pdev, 0); + struct velocity_info *vptr = netdev_priv(dev); + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D0); return 0; -} +} /** * velocity_ethtool_down - post hook for ethtool @@ -2735,23 +2837,32 @@ static int velocity_ethtool_up(struct net_device *dev) * Called after an ethtool operation. Restore the chip back to D3 * state if it isn't running. */ - + static void velocity_ethtool_down(struct net_device *dev) { - struct velocity_info *vptr = dev->priv; - if(!netif_running(dev)) - pci_set_power_state(vptr->pdev, 3); + struct velocity_info *vptr = netdev_priv(dev); + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D3hot); } static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct velocity_info *vptr = dev->priv; - struct mac_regs * regs = vptr->mac_regs; + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem * regs = vptr->mac_regs; u32 status; status = check_connection_type(vptr->mac_regs); - cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; - if (status & VELOCITY_SPEED_100) + cmd->supported = SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; + if (status & VELOCITY_SPEED_1000) + cmd->speed = SPEED_1000; + else if (status & VELOCITY_SPEED_100) cmd->speed = SPEED_100; else cmd->speed = SPEED_10; @@ -2764,17 +2875,17 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd cmd->duplex = DUPLEX_FULL; else cmd->duplex = DUPLEX_HALF; - + return 0; } static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); u32 curr_status; u32 new_status = 0; int ret = 0; - + curr_status = check_connection_type(vptr->mac_regs); curr_status &= (~VELOCITY_LINK_FAIL); @@ -2793,22 +2904,22 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd static u32 velocity_get_link(struct net_device *dev) { - struct velocity_info *vptr = dev->priv; - struct mac_regs * regs = vptr->mac_regs; - return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 0 : 1; + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem * regs = vptr->mac_regs; + return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 1 : 0; } static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); strcpy(info->driver, VELOCITY_NAME); strcpy(info->version, VELOCITY_VERSION); - strcpy(info->bus_info, vptr->pdev->slot_name); + strcpy(info->bus_info, pci_name(vptr->pdev)); } static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP; wol->wolopts |= WAKE_MAGIC; /* @@ -2824,7 +2935,7 @@ static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_woli static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct velocity_info *vptr = dev->priv; + struct velocity_info *vptr = netdev_priv(dev); if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP))) return -EFAULT; @@ -2863,7 +2974,7 @@ static void velocity_set_msglevel(struct net_device *dev, u32 value) msglevel = value; } -static struct ethtool_ops velocity_ethtool_ops = { +static const struct ethtool_ops velocity_ethtool_ops = { .get_settings = velocity_get_settings, .set_settings = velocity_set_settings, .get_drvinfo = velocity_get_drvinfo, @@ -2886,15 +2997,15 @@ static struct ethtool_ops velocity_ethtool_ops = { * are used by tools like kudzu to interrogate the link state of the * hardware */ - + static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct velocity_info *vptr = dev->priv; - struct mac_regs * regs = vptr->mac_regs; + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem * regs = vptr->mac_regs; unsigned long flags; struct mii_ioctl_data *miidata = if_mii(ifr); int err; - + switch (cmd) { case SIOCGMIIPHY: miidata->phy_id = readb(®s->MIIADR) & 0x1f; @@ -2925,7 +3036,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd /** * velocity_save_context - save registers - * @vptr: velocity + * @vptr: velocity * @context: buffer for stored context * * Retrieve the current configuration from the velocity hardware @@ -2933,12 +3044,12 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd * restore functions. This allows us to save things we need across * power down states */ - + static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; u16 i; - u8 *ptr = (u8 *)regs; + u8 __iomem *ptr = (u8 __iomem *)regs; for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4) *((u32 *) (context->mac_reg + i)) = readl(ptr + i); @@ -2953,18 +3064,18 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co /** * velocity_restore_context - restore registers - * @vptr: velocity + * @vptr: velocity * @context: buffer for stored context * - * Reload the register configuration from the velocity context + * Reload the register configuration from the velocity context * created by velocity_save_context. */ - + static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; int i; - u8 *ptr = (u8 *)regs; + u8 __iomem *ptr = (u8 __iomem *)regs; for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) { writel(*((u32 *) (context->mac_reg + i)), ptr + i); @@ -2992,172 +3103,6 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity } -static int velocity_suspend(struct pci_dev *pdev, u32 state) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - - if(!netif_running(vptr->dev)) - return 0; - - netif_device_detach(vptr->dev); - - spin_lock_irqsave(&vptr->lock, flags); - pci_save_state(pdev, vptr->pci_state); -#ifdef ETHTOOL_GWOL - if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { - velocity_get_ip(vptr); - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - velocity_set_wol(vptr); - pci_enable_wake(pdev, 3, 1); - pci_set_power_state(pdev, 3); - } else { - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - pci_disable_device(pdev); - pci_set_power_state(pdev, state); - } -#else - pci_set_power_state(pdev, state); -#endif - spin_unlock_irqrestore(&vptr->lock, flags); - return 0; -} - -static int velocity_resume(struct pci_dev *pdev) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - int i; - - if(!netif_running(vptr->dev)) - return 0; - - pci_set_power_state(pdev, 0); - pci_enable_wake(pdev, 0, 0); - pci_restore_state(pdev, vptr->pci_state); - - mac_wol_reset(vptr->mac_regs); - - spin_lock_irqsave(&vptr->lock, flags); - velocity_restore_context(vptr, &vptr->context); - velocity_init_registers(vptr, VELOCITY_INIT_WOL); - mac_disable_int(vptr->mac_regs); - - velocity_tx_srv(vptr, 0); - - for (i = 0; i < vptr->num_txq; i++) { - if (vptr->td_used[i]) { - mac_tx_queue_wake(vptr->mac_regs, i); - } - } - - mac_enable_int(vptr->mac_regs); - spin_unlock_irqrestore(&vptr->lock, flags); - netif_device_attach(vptr->dev); - - return 0; -} - -static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; - struct net_device *dev; - struct velocity_info *vptr; - - if (ifa) { - dev = ifa->ifa_dev->dev; - vptr = dev->priv; - velocity_get_ip(vptr); - } - return NOTIFY_DONE; -} -#endif - -/* - * Purpose: Functions to set WOL. - */ - -const static unsigned short crc16_tab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - - -static u32 mask_pattern[2][4] = { - {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ - {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ -}; - -/** - * ether_crc16 - compute ethernet CRC - * @len: buffer length - * @cp: buffer - * @crc16: initial CRC - * - * Compute a CRC value for a block of data. - * FIXME: can we use generic functions ? - */ - -static u16 ether_crc16(int len, u8 * cp, u16 crc16) -{ - while (len--) - crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff]; - return (crc16); -} - -/** - * bit_reverse - 16bit reverse - * @data: 16bit data t reverse - * - * Reverse the order of a 16bit value and return the reversed bits - */ - -static u16 bit_reverse(u16 data) -{ - u32 new = 0x00000000; - int ii; - - - for (ii = 0; ii < 16; ii++) { - new |= ((u32) (data & 1) << (31 - ii)); - data >>= 1; - } - - return (u16) (new >> 16); -} - /** * wol_calc_crc - WOL CRC * @pattern: data pattern @@ -3166,8 +3111,8 @@ static u16 bit_reverse(u16 data) * Compute the wake on lan crc hashes for the packet header * we are interested in. */ - -u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) + +static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; u8 mask; @@ -3186,12 +3131,12 @@ u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) continue; } mask >>= 1; - crc = ether_crc16(1, &(pattern[i * 8 + j]), crc); + crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1); } } /* Finally, invert the result once to get the correct data */ crc = ~crc; - return bit_reverse(crc); + return bitrev32(crc) >> 16; } /** @@ -3203,13 +3148,18 @@ u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) * * FIXME: check static buffer is safe here */ - + static int velocity_set_wol(struct velocity_info *vptr) { - struct mac_regs * regs = vptr->mac_regs; + struct mac_regs __iomem * regs = vptr->mac_regs; static u8 buf[256]; int i; + static u32 mask_pattern[2][4] = { + {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ + {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ + }; + writew(0xFFFF, ®s->WOLCRClr); writeb(WOLCFG_SAB | WOLCFG_SAM, ®s->WOLCFGSet); writew(WOLCR_MAGIC_EN, ®s->WOLCRSet); @@ -3236,7 +3186,8 @@ static int velocity_set_wol(struct velocity_info *vptr) memcpy(arp->ar_tip, vptr->ip_addr, 4); - crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]); + crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, + (u8 *) & mask_pattern[0][0]); writew(crc, ®s->PatternCRC[0]); writew(WOLCR_ARP_EN, ®s->WOLCRSet); @@ -3275,3 +3226,98 @@ static int velocity_set_wol(struct velocity_info *vptr) return 0; } +static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct velocity_info *vptr = netdev_priv(dev); + unsigned long flags; + + if(!netif_running(vptr->dev)) + return 0; + + netif_device_detach(vptr->dev); + + spin_lock_irqsave(&vptr->lock, flags); + pci_save_state(pdev); +#ifdef ETHTOOL_GWOL + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { + velocity_get_ip(vptr); + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + velocity_set_wol(vptr); + pci_enable_wake(pdev, 3, 1); + pci_set_power_state(pdev, PCI_D3hot); + } else { + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + } +#else + pci_set_power_state(pdev, pci_choose_state(pdev, state)); +#endif + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +static int velocity_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct velocity_info *vptr = netdev_priv(dev); + unsigned long flags; + int i; + + if(!netif_running(vptr->dev)) + return 0; + + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, 0, 0); + pci_restore_state(pdev); + + mac_wol_reset(vptr->mac_regs); + + spin_lock_irqsave(&vptr->lock, flags); + velocity_restore_context(vptr, &vptr->context); + velocity_init_registers(vptr, VELOCITY_INIT_WOL); + mac_disable_int(vptr->mac_regs); + + velocity_tx_srv(vptr, 0); + + for (i = 0; i < vptr->num_txq; i++) { + if (vptr->td_used[i]) { + mac_tx_queue_wake(vptr->mac_regs, i); + } + } + + mac_enable_int(vptr->mac_regs); + spin_unlock_irqrestore(&vptr->lock, flags); + netif_device_attach(vptr->dev); + + return 0; +} + +#ifdef CONFIG_INET + +static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; + + if (ifa) { + struct net_device *dev = ifa->ifa_dev->dev; + struct velocity_info *vptr; + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + list_for_each_entry(vptr, &velocity_dev_list, list) { + if (vptr->dev == dev) { + velocity_get_ip(vptr); + break; + } + } + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + } + return NOTIFY_DONE; +} + +#endif +#endif