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