📄 via-velocity.c
字号:
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--;}/** * velocity_set_int_opt - parser for integer options * @opt: pointer to option value * @val: value the user requested (or -1 for default) * @min: lowest value allowed * @max: highest value allowed * @def: default value * @name: property name * @dev: device name * * Set an integer property in the module options. This function does * all the verification and checking as well as reporting so that * we don't duplicate code for each option. */static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, char *devname){ if (val == -1) *opt = def; else if (val < min || val > max) { VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n", devname, name, min, max); *opt = def; } else { VELOCITY_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n", devname, name, val); *opt = val; }}/** * velocity_set_bool_opt - parser for boolean options * @opt: pointer to option value * @val: value the user requested (or -1 for default) * @def: default value (yes/no) * @flag: numeric value to set for true. * @name: property name * @dev: device name * * Set a boolean property in the module options. This function does * all the verification and checking as well as reporting so that * we don't duplicate code for each option. */static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, char *devname){ (*opt) &= (~flag); 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", devname, name); *opt |= (def ? flag : 0); } else { printk(KERN_INFO "%s: set parameter %s to %s\n", devname, name, val ? "TRUE" : "FALSE"); *opt |= (val ? flag : 0); }}/** * velocity_get_options - set options on device * @opts: option structure for the device * @index: index of option to use in module options array * @devname: device name * * Turn the module and command options into a single structure * for the current device */static void __devinit velocity_get_options(struct velocity_opt *opts, int index, char *devname){ velocity_set_int_opt(&opts->rx_thresh, rx_thresh[index], RX_THRESH_MIN, RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh", devname); velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname); velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname); velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname); velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname); velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname); velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname); velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname); velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname); velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname); velocity_set_int_opt((int *) &opts->int_works, int_works[index], INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, "Interrupt service works", devname); opts->numrx = (opts->numrx & ~3);}/** * velocity_init_cam_filter - initialise CAM * @vptr: velocity to program * * Initialize the content addressable memory used for filters. Load * appropriately according to the presence of VLAN */static void velocity_init_cam_filter(struct velocity_info *vptr){ struct mac_regs __iomem * regs = vptr->mac_regs; unsigned short vid; /* 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); /* Disable all CAMs */ memset(vptr->vCAMmask, 0, sizeof(u8) * 8); memset(vptr->mCAMmask, 0, sizeof(u8) * 8); mac_set_vlan_cam_mask(regs, vptr->vCAMmask); mac_set_cam_mask(regs, vptr->mCAMmask); /* Enable first VCAM */ if (vptr->vlgrp) { for (vid = 0; vid < VLAN_VID_MASK; vid++) { if (vlan_group_get_device(vptr->vlgrp, vid)) { /* If Tagging option is enabled and VLAN ID is not zero, then turn on MCFG_RTGOPT also */ if (vid != 0) WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); mac_set_vlan_cam(regs, 0, (u8 *) &vid); } } vptr->vCAMmask[0] |= 1; mac_set_vlan_cam_mask(regs, vptr->vCAMmask); } else { u16 temp = 0; mac_set_vlan_cam(regs, 0, (u8 *) &temp); temp = 1; mac_set_vlan_cam_mask(regs, (u8 *) &temp); }}static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid){ struct velocity_info *vptr = netdev_priv(dev); spin_lock_irq(&vptr->lock); velocity_init_cam_filter(vptr); spin_unlock_irq(&vptr->lock);}static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid){ struct velocity_info *vptr = netdev_priv(dev); spin_lock_irq(&vptr->lock); vlan_group_set_device(vptr->vlgrp, vid, NULL); velocity_init_cam_filter(vptr); spin_unlock_irq(&vptr->lock);}/** * velocity_rx_reset - handle a receive reset * @vptr: velocity we are resetting * * Reset the ownership and status for the receive ring side. * Hand all the receive queue to the NIC. */static void velocity_rx_reset(struct velocity_info *vptr){ struct mac_regs __iomem * regs = vptr->mac_regs; int i; 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 = OWNED_BY_NIC; writew(vptr->options.numrx, ®s->RBRDU); writel(vptr->rd_pool_dma, ®s->RDBaseLo); writew(0, ®s->RDIdx); writew(vptr->options.numrx - 1, ®s->RDCSize);}/** * velocity_init_registers - initialise MAC registers * @vptr: velocity to init * @type: type of initialisation (hot or cold) * * Initialise the MAC on a reset or on first set up on the * hardware. */static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type){ struct mac_regs __iomem * regs = vptr->mac_regs; int i, mii_status; mac_wol_reset(regs); switch (type) { case VELOCITY_INIT_RESET: case VELOCITY_INIT_WOL: netif_stop_queue(vptr->dev); /* * Reset RX to prevent RX pointer not on the 4X location */ velocity_rx_reset(vptr); mac_rx_queue_run(regs); mac_rx_queue_wake(regs); mii_status = velocity_get_opt_media_mode(vptr); if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { velocity_print_link_status(vptr); if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) netif_wake_queue(vptr->dev); } enable_flow_control_ability(vptr); mac_clear_isr(regs); writel(CR0_STOP, ®s->CR0Clr); writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); break; case VELOCITY_INIT_COLD: default: /* * Do reset */ velocity_soft_reset(vptr); mdelay(5); mac_eeprom_reload(regs); for (i = 0; i < 6; i++) { writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); } /* * clear Pre_ACPI bit. */ BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA)); mac_set_rx_thresh(regs, vptr->options.rx_thresh); mac_set_dma_length(regs, vptr->options.DMA_length); writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); /* * 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 */ velocity_set_multi(vptr->dev); /* * Enable MII auto-polling */ enable_mii_autopoll(regs); vptr->int_mask = INT_MASK_DEF; writel(cpu_to_le32(vptr->rd_pool_dma), ®s->RDBaseLo); writew(vptr->options.numrx - 1, ®s->RDCSize); mac_rx_queue_run(regs); mac_rx_queue_wake(regs); writew(vptr->options.numtx - 1, ®s->TDCSize); for (i = 0; i < vptr->num_txq; i++) { writel(cpu_to_le32(vptr->td_pool_dma[i]), &(regs->TDBaseLo[i])); mac_tx_queue_run(regs, i); } init_flow_control_register(vptr); writel(CR0_STOP, ®s->CR0Clr); writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); mii_status = velocity_get_opt_media_mode(vptr); netif_stop_queue(vptr->dev); mii_init(vptr, mii_status); if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { velocity_print_link_status(vptr); if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) netif_wake_queue(vptr->dev); } enable_flow_control_ability(vptr); mac_hw_mibs_init(regs); mac_write_int_mask(vptr->int_mask, regs); mac_clear_isr(regs); }}/** * velocity_soft_reset - soft reset * @vptr: velocity to reset * * Kick off a soft reset of the velocity adapter and then poll * until the reset sequence has completed before returning. */static int velocity_soft_reset(struct velocity_info *vptr){ struct mac_regs __iomem * regs = vptr->mac_regs; int i = 0; writel(CR0_SFRST, ®s->CR0Set); for (i = 0; i < W_MAX_TIMEOUT; i++) { udelay(5); if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, ®s->CR0Set)) break; } if (i == W_MAX_TIMEOUT) { writel(CR0_FORSRST, ®s->CR0Set); /* FIXME: PCI POSTING */ /* delay 2ms */ mdelay(2); } return 0;}/** * velocity_found1 - set up discovered velocity card * @pdev: PCI device * @ent: PCI device table entry that matched * * Configure a discovered adapter from scratch. Return a negative * errno error code on failure paths. */static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent){ static int first = 1; struct net_device *dev; int i; const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; struct velocity_info *vptr; struct mac_regs __iomem * regs; int ret = -ENOMEM; /* 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) { dev_err(&pdev->dev, "allocate net device failed.\n"); goto out; } /* Chain it all together */ SET_NETDEV_DEV(dev, &pdev->dev); vptr = netdev_priv(dev); if (first) { 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"); first = 0; } velocity_init_info(pdev, vptr, info); vptr->dev = dev; dev->irq = pdev->irq; ret = pci_enable_device(pdev); if (ret < 0) goto err_free_dev; ret = velocity_get_pci_info(vptr, pdev); if (ret < 0) { /* error message already printed */ goto err_disable; } ret = pci_request_regions(pdev, VELOCITY_NAME); if (ret < 0) { dev_err(&pdev->dev, "No PCI resources.\n"); goto err_disable; } regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE); if (regs == NULL) { ret = -EIO; goto err_release_res; } vptr->mac_regs = regs; mac_wol_reset(regs); dev->base_addr = vptr->ioaddr; for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(®s->PAR[i]); 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; vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); dev->irq = pdev->irq; dev->open = velocity_open; dev->hard_start_xmit = velocity_xmit; dev->stop = velocity_close; dev->get_stats = velocity_get_stats; dev->set_multicast_list = velocity_set_multi; dev->do_ioctl = velocity_ioctl; dev->ethtool_ops = &velocity_ethtool_ops; dev->change_mtu = velocity_change_mtu; dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid; dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid;#ifdef VELOCITY_ZERO_COPY_SUPPORT dev->features |= NETIF_F_SG;#endif dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER; if (vptr->flags & VELOCITY_FLAGS_TX_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, 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -