amd8111e.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,175 行 · 第 1/4 页
C
2,175 行
return -EFAULT; regbuf = amd8111e_read_regs(lp); if (!regbuf) return -ENOMEM; useraddr += offsetof(struct ethtool_regs, data); ret = 0; if (copy_to_user(useraddr, regbuf, regs.len)) ret = -EFAULT; kfree(regbuf); return ret; } /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { return mii_nway_restart(&lp->mii_if); } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value val = {ETHTOOL_GLINK}; val.data = mii_link_ok(&lp->mii_if); if (copy_to_user(useraddr, &val, sizeof(val))) return -EFAULT; return 0; } case ETHTOOL_GWOL: { struct ethtool_wolinfo wol_info = { ETHTOOL_GWOL }; wol_info.supported = WAKE_MAGIC|WAKE_PHY; wol_info.wolopts = 0; if (lp->options & OPTION_WOL_ENABLE) wol_info.wolopts = WAKE_MAGIC; memset(&wol_info.sopass, 0, sizeof(wol_info.sopass)); if (copy_to_user(useraddr, &wol_info, sizeof(wol_info))) return -EFAULT; return 0; } case ETHTOOL_SWOL: { struct ethtool_wolinfo wol_info; if (copy_from_user(&wol_info, useraddr, sizeof(wol_info))) return -EFAULT; if (wol_info.wolopts & ~(WAKE_MAGIC |WAKE_PHY)) return -EINVAL; spin_lock_irq(&lp->lock); if(wol_info.wolopts & WAKE_MAGIC) lp->options |= (OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE); else if(wol_info.wolopts & WAKE_PHY) lp->options |= (OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE); else lp->options &= ~OPTION_WOL_ENABLE; spin_unlock_irq(&lp->lock); return 0; } default: break; } return -EOPNOTSUPP;}static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd){ struct mii_ioctl_data *data = if_mii(ifr); struct amd8111e_priv *lp = netdev_priv(dev); int err; u32 mii_regval; if (!capable(CAP_NET_ADMIN)) return -EPERM; switch(cmd) { case SIOCETHTOOL: return amd8111e_ethtool_ioctl(dev, ifr->ifr_data); case SIOCGMIIPHY: data->phy_id = PHY_ID; /* fallthru */ case SIOCGMIIREG: spin_lock_irq(&lp->lock); err = amd8111e_read_phy(lp, data->phy_id, data->reg_num & PHY_REG_ADDR_MASK, &mii_regval); spin_unlock_irq(&lp->lock); data->val_out = mii_regval; return err; case SIOCSMIIREG: spin_lock_irq(&lp->lock); err = amd8111e_write_phy(lp, data->phy_id, data->reg_num & PHY_REG_ADDR_MASK, data->val_in); spin_unlock_irq(&lp->lock); return err; default: /* do nothing */ break; } return -EOPNOTSUPP;}static int amd8111e_set_mac_address(struct net_device *dev, void *p){ struct amd8111e_priv *lp = dev->priv; int i; struct sockaddr *addr = p; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); spin_lock_irq(&lp->lock); /* Setting the MAC address to the device */ for(i = 0; i < ETH_ADDR_LEN; i++) writeb( dev->dev_addr[i], lp->mmio + PADR + i ); spin_unlock_irq(&lp->lock); return 0;}/* This function changes the mtu of the device. It restarts the device to initialize the descriptor with new receive buffers.*/ int amd8111e_change_mtu(struct net_device *dev, int new_mtu){ struct amd8111e_priv *lp = netdev_priv(dev); int err; if ((new_mtu < AMD8111E_MIN_MTU) || (new_mtu > AMD8111E_MAX_MTU)) return -EINVAL; if (!netif_running(dev)) { /* new_mtu will be used when device starts netxt time */ dev->mtu = new_mtu; return 0; } spin_lock_irq(&lp->lock); /* stop the chip */ writel(RUN, lp->mmio + CMD0); dev->mtu = new_mtu; err = amd8111e_restart(dev); spin_unlock_irq(&lp->lock); if(!err) netif_start_queue(dev); return err;}#if AMD8111E_VLAN_TAG_USEDstatic void amd8111e_vlan_rx_register(struct net_device *dev, struct vlan_group *grp){ struct amd8111e_priv *lp = netdev_priv(dev); spin_lock_irq(&lp->lock); lp->vlgrp = grp; spin_unlock_irq(&lp->lock);} static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid){ struct amd8111e_priv *lp = netdev_priv(dev); spin_lock_irq(&lp->lock); if (lp->vlgrp) lp->vlgrp->vlan_devices[vid] = NULL; spin_unlock_irq(&lp->lock);}#endifstatic int amd8111e_enable_magicpkt(struct amd8111e_priv* lp){ writel( VAL1|MPPLBA, lp->mmio + CMD3); writel( VAL0|MPEN_SW, lp->mmio + CMD7); /* To eliminate PCI posting bug */ readl(lp->mmio + CMD7); return 0;}static int amd8111e_enable_link_change(struct amd8111e_priv* lp){ /* Adapter is already stoped/suspended/interrupt-disabled */ writel(VAL0|LCMODE_SW,lp->mmio + CMD7); /* To eliminate PCI posting bug */ readl(lp->mmio + CMD7); return 0;} /* This function is called when a packet transmission fails to complete within a resonable period, on the assumption that an interrupts have been failed or the interface is locked up. This function will reinitialize the hardware */static void amd8111e_tx_timeout(struct net_device *dev){ struct amd8111e_priv* lp = netdev_priv(dev); int err; printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); spin_lock_irq(&lp->lock); err = amd8111e_restart(dev); spin_unlock_irq(&lp->lock); if(!err) netif_wake_queue(dev);}static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state){ struct net_device *dev = pci_get_drvdata(pci_dev); struct amd8111e_priv *lp = netdev_priv(dev); if (!netif_running(dev)) return 0; /* disable the interrupt */ spin_lock_irq(&lp->lock); amd8111e_disable_interrupt(lp); spin_unlock_irq(&lp->lock); netif_device_detach(dev); /* stop chip */ spin_lock_irq(&lp->lock); if(lp->options & OPTION_DYN_IPG_ENABLE) del_timer_sync(&lp->ipg_data.ipg_timer); amd8111e_stop_chip(lp); spin_unlock_irq(&lp->lock); if(lp->options & OPTION_WOL_ENABLE){ /* enable wol */ if(lp->options & OPTION_WAKE_MAGIC_ENABLE) amd8111e_enable_magicpkt(lp); if(lp->options & OPTION_WAKE_PHY_ENABLE) amd8111e_enable_link_change(lp); pci_enable_wake(pci_dev, 3, 1); pci_enable_wake(pci_dev, 4, 1); /* D3 cold */ } else{ pci_enable_wake(pci_dev, 3, 0); pci_enable_wake(pci_dev, 4, 0); /* 4 == D3 cold */ } pci_save_state(pci_dev, lp->pm_state); pci_set_power_state(pci_dev, 3); return 0;}static int amd8111e_resume(struct pci_dev *pci_dev){ struct net_device *dev = pci_get_drvdata(pci_dev); struct amd8111e_priv *lp = netdev_priv(dev); if (!netif_running(dev)) return 0; pci_set_power_state(pci_dev, 0); pci_restore_state(pci_dev, lp->pm_state); pci_enable_wake(pci_dev, 3, 0); pci_enable_wake(pci_dev, 4, 0); /* D3 cold */ netif_device_attach(dev); spin_lock_irq(&lp->lock); amd8111e_restart(dev); /* Restart ipg timer */ if(lp->options & OPTION_DYN_IPG_ENABLE) mod_timer(&lp->ipg_data.ipg_timer, jiffies + IPG_CONVERGE_JIFFIES); spin_unlock_irq(&lp->lock); return 0;}static void __devexit amd8111e_remove_one(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); if (dev) { unregister_netdev(dev); iounmap((void *) ((struct amd8111e_priv *)(dev->priv))->mmio); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); }}static void amd8111e_config_ipg(struct net_device* dev){ struct amd8111e_priv *lp = netdev_priv(dev); struct ipg_info* ipg_data = &lp->ipg_data; void * mmio = lp->mmio; unsigned int prev_col_cnt = ipg_data->col_cnt; unsigned int total_col_cnt; unsigned int tmp_ipg; if(lp->link_config.duplex == DUPLEX_FULL){ ipg_data->ipg = DEFAULT_IPG; return; } if(ipg_data->ipg_state == SSTATE){ if(ipg_data->timer_tick == IPG_STABLE_TIME){ ipg_data->timer_tick = 0; ipg_data->ipg = MIN_IPG - IPG_STEP; ipg_data->current_ipg = MIN_IPG; ipg_data->diff_col_cnt = 0xFFFFFFFF; ipg_data->ipg_state = CSTATE; } else ipg_data->timer_tick++; } if(ipg_data->ipg_state == CSTATE){ /* Get the current collision count */ total_col_cnt = ipg_data->col_cnt = amd8111e_read_mib(mmio, xmt_collisions); if ((total_col_cnt - prev_col_cnt) < (ipg_data->diff_col_cnt)){ ipg_data->diff_col_cnt = total_col_cnt - prev_col_cnt ; ipg_data->ipg = ipg_data->current_ipg; } ipg_data->current_ipg += IPG_STEP; if (ipg_data->current_ipg <= MAX_IPG) tmp_ipg = ipg_data->current_ipg; else{ tmp_ipg = ipg_data->ipg; ipg_data->ipg_state = SSTATE; } writew((u32)tmp_ipg, mmio + IPG); writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1); } mod_timer(&lp->ipg_data.ipg_timer, jiffies + IPG_CONVERGE_JIFFIES); return;}static int __devinit amd8111e_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent){ int err,i,pm_cap; unsigned long reg_addr,reg_len; struct amd8111e_priv* lp; struct net_device* dev; err = pci_enable_device(pdev); if(err){ printk(KERN_ERR "amd8111e: Cannot enable new PCI device," "exiting.\n"); return err; } if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)){ printk(KERN_ERR "amd8111e: Cannot find PCI base address" "exiting.\n"); err = -ENODEV; goto err_disable_pdev; } err = pci_request_regions(pdev, MODULE_NAME); if(err){ printk(KERN_ERR "amd8111e: Cannot obtain PCI resources, " "exiting.\n"); goto err_disable_pdev; } pci_set_master(pdev); /* Find power-management capability. */ if((pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM))==0){ printk(KERN_ERR "amd8111e: No Power Management capability, " "exiting.\n"); goto err_free_reg; } /* Initialize DMA */ if(!pci_dma_supported(pdev, 0xffffffff)){ printk(KERN_ERR "amd8111e: DMA not supported," "exiting.\n"); goto err_free_reg; } else pdev->dma_mask = 0xffffffff; reg_addr = pci_resource_start(pdev, 0); reg_len = pci_resource_len(pdev, 0); dev = alloc_etherdev(sizeof(struct amd8111e_priv)); if (!dev) { printk(KERN_ERR "amd8111e: Etherdev alloc failed, exiting.\n"); err = -ENOMEM; goto err_free_reg; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev);#if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ; dev->vlan_rx_register =amd8111e_vlan_rx_register; dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;#endif lp = netdev_priv(dev); lp->pci_dev = pdev; lp->amd8111e_net_dev = dev; lp->pm_cap = pm_cap; /* setting mii default values */ lp->mii_if.dev = dev; lp->mii_if.mdio_read = amd8111e_mdio_read; lp->mii_if.mdio_write = amd8111e_mdio_write; lp->mii_if.phy_id = PHY_ID; spin_lock_init(&lp->lock); lp->mmio = ioremap(reg_addr, reg_len); if (lp->mmio == 0) { printk(KERN_ERR "amd8111e: Cannot map device registers, " "exiting\n"); err = -ENOMEM; goto err_free_dev; } /* Initializing MAC address */ for(i = 0; i < ETH_ADDR_LEN; i++) dev->dev_addr[i] =readb(lp->mmio + PADR + i); /* Setting user defined parametrs */ lp->ext_phy_option = speed_duplex[card_idx]; if(coalesce[card_idx]) lp->options |= OPTION_INTR_COAL_ENABLE; if(dynamic_ipg[card_idx++]) lp->options |= OPTION_DYN_IPG_ENABLE; /* Initialize driver entry points */ dev->open = amd8111e_open; dev->hard_start_xmit = amd8111e_start_xmit; dev->stop = amd8111e_close; dev->get_stats = amd8111e_get_stats; dev->set_multicast_list = amd8111e_set_multicast_list; dev->set_mac_address = amd8111e_set_mac_address; dev->do_ioctl = amd8111e_ioctl; dev->change_mtu = amd8111e_change_mtu; dev->irq =pdev->irq; dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; #ifdef CONFIG_AMD8111E_NAPI dev->poll = amd8111e_rx_poll; dev->weight = 32;#endif#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = amd8111e_poll; #endif#if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->vlan_rx_register =amd8111e_vlan_rx_register; dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;#endif /* Set receive buffer length and set jumbo option*/ amd8111e_set_rx_buff_len(dev); err = register_netdev(dev); if (err) { printk(KERN_ERR "amd8111e: Cannot register net device, " "exiting.\n"); goto err_iounmap; } pci_set_drvdata(pdev, dev); /* Initialize software ipg timer */ if(lp->options & OPTION_DYN_IPG_ENABLE){ init_timer(&lp->ipg_data.ipg_timer); lp->ipg_data.ipg_timer.data = (unsigned long) dev; lp->ipg_data.ipg_timer.function = (void *)&amd8111e_config_ipg; lp->ipg_data.ipg_timer.expires = jiffies + IPG_CONVERGE_JIFFIES; lp->ipg_data.ipg = DEFAULT_IPG; lp->ipg_data.ipg_state = CSTATE; }; /* display driver and device information */ chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERS); printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version); for (i = 0; i < 6; i++) printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':'); printk( "\n"); return 0;err_iounmap: iounmap((void *) lp->mmio);err_free_dev: free_netdev(dev);err_free_reg: pci_release_regions(pdev);err_disable_pdev: pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); return err;}static struct pci_driver amd8111e_driver = { .name = MODULE_NAME, .id_table = amd8111e_pci_tbl, .probe = amd8111e_probe_one, .remove = __devexit_p(amd8111e_remove_one), .suspend = amd8111e_suspend, .resume = amd8111e_resume};static int __init amd8111e_init(void){ return pci_module_init(&amd8111e_driver);}static void __exit amd8111e_cleanup(void){ pci_unregister_driver(&amd8111e_driver);}module_init(amd8111e_init);module_exit(amd8111e_cleanup);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?