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