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 + -
显示快捷键?