tehuti.c
来自「linux 内核源代码」· C语言 代码 · 共 2,340 行 · 第 1/5 页
C
2,340 行
/** * bdx_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in bdx_pci_tbl * * Returns 0 on success, negative on failure * * bdx_probe initializes an adapter identified by a pci_dev structure. * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. * * functions and their order used as explained in * /usr/src/linux/Documentation/DMA-{API,mapping}.txt * *//* TBD: netif_msg should be checked and implemented. I disable it for now */static int __devinitbdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *ndev; struct bdx_priv *priv; int err, pci_using_dac, port; unsigned long pciaddr; u32 regionSize; struct pci_nic *nic; ENTER; nic = vmalloc(sizeof(*nic)); if (!nic) RET(-ENOMEM); /************** pci *****************/ if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */ goto err_pci; /* it's not a problem though */ if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { pci_using_dac = 1; } else { if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { printk(KERN_ERR "tehuti: No usable DMA configuration" ", aborting\n"); goto err_dma; } pci_using_dac = 0; } if ((err = pci_request_regions(pdev, BDX_DRV_NAME))) goto err_dma; pci_set_master(pdev); pciaddr = pci_resource_start(pdev, 0); if (!pciaddr) { err = -EIO; ERR("tehuti: no MMIO resource\n"); goto err_out_res; } if ((regionSize = pci_resource_len(pdev, 0)) < BDX_REGS_SIZE) { err = -EIO; ERR("tehuti: MMIO resource (%x) too small\n", regionSize); goto err_out_res; } nic->regs = ioremap(pciaddr, regionSize); if (!nic->regs) { err = -EIO; ERR("tehuti: ioremap failed\n"); goto err_out_res; } if (pdev->irq < 2) { err = -EIO; ERR("tehuti: invalid irq (%d)\n", pdev->irq); goto err_out_iomap; } pci_set_drvdata(pdev, nic); if (pdev->device == 0x3014) nic->port_num = 2; else nic->port_num = 1; print_hw_id(pdev); bdx_hw_reset_direct(nic->regs); nic->irq_type = IRQ_INTX;#ifdef BDX_MSI if ((readl(nic->regs + FPGA_VER) & 0xFFF) >= 378) { if ((err = pci_enable_msi(pdev))) ERR("Tehuti: Can't eneble msi. error is %d\n", err); else nic->irq_type = IRQ_MSI; } else DBG("HW does not support MSI\n");#endif /************** netdev **************/ for (port = 0; port < nic->port_num; port++) { if (!(ndev = alloc_etherdev(sizeof(struct bdx_priv)))) { err = -ENOMEM; printk(KERN_ERR "tehuti: alloc_etherdev failed\n"); goto err_out_iomap; } ndev->open = bdx_open; ndev->stop = bdx_close; ndev->hard_start_xmit = bdx_tx_transmit; ndev->do_ioctl = bdx_ioctl; ndev->set_multicast_list = bdx_setmulti; ndev->get_stats = bdx_get_stats; ndev->change_mtu = bdx_change_mtu; ndev->set_mac_address = bdx_set_mac; ndev->tx_queue_len = BDX_NDEV_TXQ_LEN; ndev->vlan_rx_register = bdx_vlan_rx_register; ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid; ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid; bdx_ethtool_ops(ndev); /* ethtool interface */ /* these fields are used for info purposes only * so we can have them same for all ports of the board */ ndev->if_port = port; ndev->base_addr = pciaddr; ndev->mem_start = pciaddr; ndev->mem_end = pciaddr + regionSize; ndev->irq = pdev->irq; ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER /*| NETIF_F_FRAGLIST */ ; if (pci_using_dac) ndev->features |= NETIF_F_HIGHDMA; /************** priv ****************/ priv = nic->priv[port] = ndev->priv; memset(priv, 0, sizeof(struct bdx_priv)); priv->pBdxRegs = nic->regs + port * 0x8000; priv->port = port; priv->pdev = pdev; priv->ndev = ndev; priv->nic = nic; priv->msg_enable = BDX_DEF_MSG_ENABLE; netif_napi_add(ndev, &priv->napi, bdx_poll, 64); if ((readl(nic->regs + FPGA_VER) & 0xFFF) == 308) { DBG("HW statistics not supported\n"); priv->stats_flag = 0; } else { priv->stats_flag = 1; } /* Initialize fifo sizes. */ priv->txd_size = 2; priv->txf_size = 2; priv->rxd_size = 2; priv->rxf_size = 3; /* Initialize the initial coalescing registers. */ priv->rdintcm = INT_REG_VAL(0x20, 1, 4, 12); priv->tdintcm = INT_REG_VAL(0x20, 1, 0, 12); /* ndev->xmit_lock spinlock is not used. * Private priv->tx_lock is used for synchronization * between transmit and TX irq cleanup. In addition * set multicast list callback has to use priv->tx_lock. */#ifdef BDX_LLTX ndev->features |= NETIF_F_LLTX;#endif spin_lock_init(&priv->tx_lock); /*bdx_hw_reset(priv); */ if (bdx_read_mac(priv)) { printk(KERN_ERR "tehuti: load MAC address failed\n"); goto err_out_iomap; } SET_NETDEV_DEV(ndev, &pdev->dev); if ((err = register_netdev(ndev))) { printk(KERN_ERR "tehuti: register_netdev failed\n"); goto err_out_free; } netif_carrier_off(ndev); netif_stop_queue(ndev); print_eth_id(ndev); } RET(0);err_out_free: free_netdev(ndev);err_out_iomap: iounmap(nic->regs);err_out_res: pci_release_regions(pdev);err_dma: pci_disable_device(pdev);err_pci: vfree(nic); RET(err);}/****************** Ethtool interface *********************//* get strings for tests */static const char bdx_test_names[][ETH_GSTRING_LEN] = { "No tests defined"};/* get strings for statistics counters */static const char bdx_stat_names[][ETH_GSTRING_LEN] = { "InUCast", /* 0x7200 */ "InMCast", /* 0x7210 */ "InBCast", /* 0x7220 */ "InPkts", /* 0x7230 */ "InErrors", /* 0x7240 */ "InDropped", /* 0x7250 */ "FrameTooLong", /* 0x7260 */ "FrameSequenceErrors", /* 0x7270 */ "InVLAN", /* 0x7280 */ "InDroppedDFE", /* 0x7290 */ "InDroppedIntFull", /* 0x72A0 */ "InFrameAlignErrors", /* 0x72B0 */ /* 0x72C0-0x72E0 RSRV */ "OutUCast", /* 0x72F0 */ "OutMCast", /* 0x7300 */ "OutBCast", /* 0x7310 */ "OutPkts", /* 0x7320 */ /* 0x7330-0x7360 RSRV */ "OutVLAN", /* 0x7370 */ "InUCastOctects", /* 0x7380 */ "OutUCastOctects", /* 0x7390 */ /* 0x73A0-0x73B0 RSRV */ "InBCastOctects", /* 0x73C0 */ "OutBCastOctects", /* 0x73D0 */ "InOctects", /* 0x73E0 */ "OutOctects", /* 0x73F0 */};/* * bdx_get_settings - get device-specific settings * @netdev * @ecmd */static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd){ u32 rdintcm; u32 tdintcm; struct bdx_priv *priv = netdev->priv; rdintcm = priv->rdintcm; tdintcm = priv->tdintcm; ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); ecmd->speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; ecmd->port = PORT_FIBRE; ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */ ecmd->autoneg = AUTONEG_DISABLE; /* PCK_TH measures in multiples of FIFO bytes We translate to packets */ ecmd->maxtxpkt = ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ); ecmd->maxrxpkt = ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc)); return 0;}/* * bdx_get_drvinfo - report driver information * @netdev * @drvinfo */static voidbdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo){ struct bdx_priv *priv = netdev->priv; strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver)); strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version)); strlcat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); strlcat(drvinfo->bus_info, pci_name(priv->pdev), sizeof(drvinfo->bus_info)); drvinfo->n_stats = ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0); drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; drvinfo->eedump_len = 0;}/* * bdx_get_rx_csum - report whether receive checksums are turned on or off * @netdev */static u32 bdx_get_rx_csum(struct net_device *netdev){ return 1; /* always on */}/* * bdx_get_tx_csum - report whether transmit checksums are turned on or off * @netdev */static u32 bdx_get_tx_csum(struct net_device *netdev){ return (netdev->features & NETIF_F_IP_CSUM) != 0;}/* * bdx_get_coalesce - get interrupt coalescing parameters * @netdev * @ecoal */static intbdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal){ u32 rdintcm; u32 tdintcm; struct bdx_priv *priv = netdev->priv; rdintcm = priv->rdintcm; tdintcm = priv->tdintcm; /* PCK_TH measures in multiples of FIFO bytes We translate to packets */ ecoal->rx_coalesce_usecs = GET_INT_COAL(rdintcm) * INT_COAL_MULT; ecoal->rx_max_coalesced_frames = ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc)); ecoal->tx_coalesce_usecs = GET_INT_COAL(tdintcm) * INT_COAL_MULT; ecoal->tx_max_coalesced_frames = ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ); /* adaptive parameters ignored */ return 0;}/* * bdx_set_coalesce - set interrupt coalescing parameters * @netdev * @ecoal */static intbdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal){ u32 rdintcm; u32 tdintcm; struct bdx_priv *priv = netdev->priv; int rx_coal; int tx_coal; int rx_max_coal; int tx_max_coal; /* Check for valid input */ rx_coal = ecoal->rx_coalesce_usecs / INT_COAL_MULT; tx_coal = ecoal->tx_coalesce_usecs / INT_COAL_MULT; rx_max_coal = ecoal->rx_max_coalesced_frames; tx_max_coal = ecoal->tx_max_coalesced_frames; /* Translate from packets to multiples of FIFO bytes */ rx_max_coal = (((rx_max_coal * sizeof(struct rxf_desc)) + PCK_TH_MULT - 1) / PCK_TH_MULT); tx_max_coal = (((tx_max_coal * BDX_TXF_DESC_SZ) + PCK_TH_MULT - 1) / PCK_TH_MULT); if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF) || (rx_max_coal > 0xF) || (tx_max_coal > 0xF)) return -EINVAL; rdintcm = INT_REG_VAL(rx_coal, GET_INT_COAL_RC(priv->rdintcm), GET_RXF_TH(priv->rdintcm), rx_max_coal); tdintcm = INT_REG_VAL(tx_coal, GET_INT_COAL_RC(priv->tdintcm), 0, tx_max_coal); priv->rdintcm = rdintcm; priv->tdintcm = tdintcm; WRITE_REG(priv, regRDINTCM0, rdintcm); WRITE_REG(priv, regTDINTCM0, tdintcm); return 0;}/* Convert RX fifo size to number of pending packets */static inline int bdx_rx_fifo_size_to_packets(int rx_size){ return ((FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc));}/* Convert TX fifo size to number of pending packets */static inline int bdx_tx_fifo_size_to_packets(int tx_size){ return ((FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ);}/* * bdx_get_ringparam - report ring sizes * @netdev * @ring */static voidbdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring){ struct bdx_priv *priv = netdev->priv; /*max_pending - the maximum-sized FIFO we allow */ ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3); ring->tx_max_pending = bdx_tx_fifo_size_to_packets(3); ring->rx_pending = bdx_rx_fifo_size_to_packets(priv->rxf_size); ring->tx_pending = bdx_tx_fifo_size_to_packets(priv->txd_size);}/* * bdx_set_ringparam - set ring sizes * @netdev * @ring */static intbdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring){ struct bdx_priv *priv = netdev->priv; int rx_size = 0; int tx_size = 0; for (; rx_size < 4; rx_size++) { if (bdx_rx_fifo_size_to_packets(rx_size) >= ring->rx_pending) break; } if (rx_size == 4) rx_size = 3; for (; tx_size < 4; tx_size++) { if (bdx_tx_fifo_size_to_packets(tx_size) >= ring->tx_pending) break; } if (tx_size == 4) tx_size = 3; /*Is there anything to do? */ if ((rx_size == priv->rxf_size) && (tx_size == priv->txd_size)) return 0; priv->rxf_size = rx_size; i
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?