ipg.c

来自「linux 内核源代码」· C语言 代码 · 共 2,341 行 · 第 1/5 页

C
2,341
字号
		(void) ipg_r16(INT_STATUS_ACK);		ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);		synchronize_irq(pdev->irq);	} while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK);	ipg_rx_clear(sp);	ipg_tx_clear(sp);	pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);	pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);	free_irq(pdev->irq, dev);	return 0;}static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct ipg_nic_private *sp = netdev_priv(dev);	void __iomem *ioaddr = sp->ioaddr;	unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH;	unsigned long flags;	struct ipg_tx *txfd;	IPG_DDEBUG_MSG("_nic_hard_start_xmit\n");	/* If in 10Mbps mode, stop the transmit queue so	 * no more transmit frames are accepted.	 */	if (sp->tenmbpsmode)		netif_stop_queue(dev);	if (sp->ResetCurrentTFD) {		sp->ResetCurrentTFD = 0;		entry = 0;	}	txfd = sp->txd + entry;	sp->TxBuff[entry] = skb;	/* Clear all TFC fields, except TFDDONE. */	txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);	/* Specify the TFC field within the TFD. */	txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED |		(IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) |		(IPG_TFC_FRAGCOUNT & (1 << 24)));	/* Request TxComplete interrupts at an interval defined	 * by the constant IPG_FRAMESBETWEENTXCOMPLETES.	 * Request TxComplete interrupt for every frame	 * if in 10Mbps mode to accomodate problem with 10Mbps	 * processing.	 */	if (sp->tenmbpsmode)		txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);	txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);	/* Based on compilation option, determine if FCS is to be	 * appended to transmit frame by IPG.	 */	if (!(IPG_APPEND_FCS_ON_TX))		txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE);	/* Based on compilation option, determine if IP, TCP and/or	 * UDP checksums are to be added to transmit frame by IPG.	 */	if (IPG_ADD_IPCHECKSUM_ON_TX)		txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE);	if (IPG_ADD_TCPCHECKSUM_ON_TX)		txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE);	if (IPG_ADD_UDPCHECKSUM_ON_TX)		txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE);	/* Based on compilation option, determine if VLAN tag info is to be	 * inserted into transmit frame by IPG.	 */	if (IPG_INSERT_MANUAL_VLAN_TAG) {		txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT |			((u64) IPG_MANUAL_VLAN_VID << 32) |			((u64) IPG_MANUAL_VLAN_CFI << 44) |			((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45));	}	/* The fragment start location within system memory is defined	 * by the sk_buff structure's data field. The physical address	 * of this location within the system's virtual memory space	 * is determined using the IPG_HOST2BUS_MAP function.	 */	txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,		skb->len, PCI_DMA_TODEVICE));	/* The length of the fragment within system memory is defined by	 * the sk_buff structure's len field.	 */	txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN &		((u64) (skb->len & 0xffff) << 48));	/* Clear the TFDDone bit last to indicate the TFD is ready	 * for transfer to the IPG.	 */	txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE);	spin_lock_irqsave(&sp->lock, flags);	sp->tx_current++;	mmiowb();	ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);	if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))		netif_stop_queue(dev);	spin_unlock_irqrestore(&sp->lock, flags);	return NETDEV_TX_OK;}static void ipg_set_phy_default_param(unsigned char rev,				      struct net_device *dev, int phy_address){	unsigned short length;	unsigned char revision;	unsigned short *phy_param;	unsigned short address, value;	phy_param = &DefaultPhyParam[0];	length = *phy_param & 0x00FF;	revision = (unsigned char)((*phy_param) >> 8);	phy_param++;	while (length != 0) {		if (rev == revision) {			while (length > 1) {				address = *phy_param;				value = *(phy_param + 1);				phy_param += 2;				mdio_write(dev, phy_address, address, value);				length -= 4;			}			break;		} else {			phy_param += length / 2;			length = *phy_param & 0x00FF;			revision = (unsigned char)((*phy_param) >> 8);			phy_param++;		}	}}/* JES20040127EEPROM */static int read_eeprom(struct net_device *dev, int eep_addr){	void __iomem *ioaddr = ipg_ioaddr(dev);	unsigned int i;	int ret = 0;	u16 value;	value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff);	ipg_w16(value, EEPROM_CTRL);	for (i = 0; i < 1000; i++) {		u16 data;		mdelay(10);		data = ipg_r16(EEPROM_CTRL);		if (!(data & IPG_EC_EEPROM_BUSY)) {			ret = ipg_r16(EEPROM_DATA);			break;		}	}	return ret;}static void ipg_init_mii(struct net_device *dev){	struct ipg_nic_private *sp = netdev_priv(dev);	struct mii_if_info *mii_if = &sp->mii_if;	int phyaddr;	mii_if->dev          = dev;	mii_if->mdio_read    = mdio_read;	mii_if->mdio_write   = mdio_write;	mii_if->phy_id_mask  = 0x1f;	mii_if->reg_num_mask = 0x1f;	mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev);	if (phyaddr != 0x1f) {		u16 mii_phyctrl, mii_1000cr;		u8 revisionid = 0;		mii_1000cr  = mdio_read(dev, phyaddr, MII_CTRL1000);		mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF |			GMII_PHY_1000BASETCONTROL_PreferMaster;		mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr);		mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR);		/* Set default phyparam */		pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid);		ipg_set_phy_default_param(revisionid, dev, phyaddr);		/* Reset PHY */		mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART;		mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl);	}}static int ipg_hw_init(struct net_device *dev){	struct ipg_nic_private *sp = netdev_priv(dev);	void __iomem *ioaddr = sp->ioaddr;	unsigned int i;	int rc;	/* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */	/* Read LED Mode Configuration from EEPROM */	sp->LED_Mode = read_eeprom(dev, 6);	/* Reset all functions within the IPG. Do not assert	 * RST_OUT as not compatible with some PHYs.	 */	rc = ipg_reset(dev, IPG_RESET_MASK);	if (rc < 0)		goto out;	ipg_init_mii(dev);	/* Read MAC Address from EEPROM */	for (i = 0; i < 3; i++)		sp->station_addr[i] = read_eeprom(dev, 16 + i);	for (i = 0; i < 3; i++)		ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i);	/* Set station address in ethernet_device structure. */	dev->dev_addr[0] =  ipg_r16(STATION_ADDRESS_0) & 0x00ff;	dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8;	dev->dev_addr[2] =  ipg_r16(STATION_ADDRESS_1) & 0x00ff;	dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8;	dev->dev_addr[4] =  ipg_r16(STATION_ADDRESS_2) & 0x00ff;	dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8;out:	return rc;}static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	struct ipg_nic_private *sp = netdev_priv(dev);	int rc;	mutex_lock(&sp->mii_mutex);	rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL);	mutex_unlock(&sp->mii_mutex);	return rc;}static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu){	/* Function to accomodate changes to Maximum Transfer Unit	 * (or MTU) of IPG NIC. Cannot use default function since	 * the default will not allow for MTU > 1500 bytes.	 */	IPG_DEBUG_MSG("_nic_change_mtu\n");	/* Check that the new MTU value is between 68 (14 byte header, 46	 * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which	 * corresponds to the MAXFRAMESIZE register in the IPG.	 */	if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE))		return -EINVAL;	dev->mtu = new_mtu;	return 0;}static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct ipg_nic_private *sp = netdev_priv(dev);	int rc;	mutex_lock(&sp->mii_mutex);	rc = mii_ethtool_gset(&sp->mii_if, cmd);	mutex_unlock(&sp->mii_mutex);	return rc;}static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct ipg_nic_private *sp = netdev_priv(dev);	int rc;	mutex_lock(&sp->mii_mutex);	rc = mii_ethtool_sset(&sp->mii_if, cmd);	mutex_unlock(&sp->mii_mutex);	return rc;}static int ipg_nway_reset(struct net_device *dev){	struct ipg_nic_private *sp = netdev_priv(dev);	int rc;	mutex_lock(&sp->mii_mutex);	rc = mii_nway_restart(&sp->mii_if);	mutex_unlock(&sp->mii_mutex);	return rc;}static struct ethtool_ops ipg_ethtool_ops = {	.get_settings = ipg_get_settings,	.set_settings = ipg_set_settings,	.nway_reset   = ipg_nway_reset,};static void ipg_remove(struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	struct ipg_nic_private *sp = netdev_priv(dev);	IPG_DEBUG_MSG("_remove\n");	/* Un-register Ethernet device. */	unregister_netdev(dev);	pci_iounmap(pdev, sp->ioaddr);	pci_release_regions(pdev);	free_netdev(dev);	pci_disable_device(pdev);	pci_set_drvdata(pdev, NULL);}static int __devinit ipg_probe(struct pci_dev *pdev,			       const struct pci_device_id *id){	unsigned int i = id->driver_data;	struct ipg_nic_private *sp;	struct net_device *dev;	void __iomem *ioaddr;	int rc;	rc = pci_enable_device(pdev);	if (rc < 0)		goto out;	printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]);	pci_set_master(pdev);	rc = pci_set_dma_mask(pdev, DMA_40BIT_MASK);	if (rc < 0) {		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);		if (rc < 0) {			printk(KERN_ERR "%s: DMA config failed.\n",			       pci_name(pdev));			goto err_disable_0;		}	}	/*	 * Initialize net device.	 */	dev = alloc_etherdev(sizeof(struct ipg_nic_private));	if (!dev) {		printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev));		rc = -ENOMEM;		goto err_disable_0;	}	sp = netdev_priv(dev);	spin_lock_init(&sp->lock);	mutex_init(&sp->mii_mutex);	/* Declare IPG NIC functions for Ethernet device methods.	 */	dev->open = &ipg_nic_open;	dev->stop = &ipg_nic_stop;	dev->hard_start_xmit = &ipg_nic_hard_start_xmit;	dev->get_stats = &ipg_nic_get_stats;	dev->set_multicast_list = &ipg_nic_set_multicast_list;	dev->do_ioctl = ipg_ioctl;	dev->tx_timeout = ipg_tx_timeout;	dev->change_mtu = &ipg_nic_change_mtu;	SET_NETDEV_DEV(dev, &pdev->dev);	SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops);	rc = pci_request_regions(pdev, DRV_NAME);	if (rc)		goto err_free_dev_1;	ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));	if (!ioaddr) {		printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev));		rc = -EIO;		goto err_release_regions_2;	}	/* Save the pointer to the PCI device information. */	sp->ioaddr = ioaddr;	sp->pdev = pdev;	sp->dev = dev;	INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error);	pci_set_drvdata(pdev, dev);	rc = ipg_hw_init(dev);	if (rc < 0)		goto err_unmap_3;	rc = register_netdev(dev);	if (rc < 0)		goto err_unmap_3;	printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name);out:	return rc;err_unmap_3:	pci_iounmap(pdev, ioaddr);err_release_regions_2:	pci_release_regions(pdev);err_free_dev_1:	free_netdev(dev);err_disable_0:	pci_disable_device(pdev);	goto out;}static struct pci_driver ipg_pci_driver = {	.name		= IPG_DRIVER_NAME,	.id_table	= ipg_pci_tbl,	.probe		= ipg_probe,	.remove		= __devexit_p(ipg_remove),};static int __init ipg_init_module(void){	return pci_register_driver(&ipg_pci_driver);}static void __exit ipg_exit_module(void){	pci_unregister_driver(&ipg_pci_driver);}module_init(ipg_init_module);module_exit(ipg_exit_module);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?