Exemple #1
0
static int __devinit enic_probe(struct pci_dev *pdev,
	const struct pci_device_id *ent)
{
	struct net_device *netdev;
	struct enic *enic;
	int using_dac = 0;
	unsigned int i;
	int err;

	const u8 rss_default_cpu = 0;
	const u8 rss_hash_type = 0;
	const u8 rss_hash_bits = 0;
	const u8 rss_base_cpu = 0;
	const u8 rss_enable = 0;
	const u8 tso_ipid_split_en = 0;
	const u8 ig_vlan_strip_en = 1;

	/* Allocate net device structure and initialize.  Private
	 * instance data is initialized to zero.
	 */

	netdev = alloc_etherdev(sizeof(struct enic));
	if (!netdev) {
		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
		return -ENOMEM;
	}

	pci_set_drvdata(pdev, netdev);

	SET_NETDEV_DEV(netdev, &pdev->dev);

	enic = netdev_priv(netdev);
	enic->netdev = netdev;
	enic->pdev = pdev;

	/* Setup PCI resources
	 */

	err = pci_enable_device(pdev);
	if (err) {
		printk(KERN_ERR PFX
			"Cannot enable PCI device, aborting.\n");
		goto err_out_free_netdev;
	}

	err = pci_request_regions(pdev, DRV_NAME);
	if (err) {
		printk(KERN_ERR PFX
			"Cannot request PCI regions, aborting.\n");
		goto err_out_disable_device;
	}

	pci_set_master(pdev);

	/* Query PCI controller on system for DMA addressing
	 * limitation for the device.  Try 40-bit first, and
	 * fail to 32-bit.
	 */

	err = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
	if (err) {
		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
		if (err) {
			printk(KERN_ERR PFX
				"No usable DMA configuration, aborting.\n");
			goto err_out_release_regions;
		}
		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
		if (err) {
			printk(KERN_ERR PFX
				"Unable to obtain 32-bit DMA "
				"for consistent allocations, aborting.\n");
			goto err_out_release_regions;
		}
	} else {
		err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK);
		if (err) {
			printk(KERN_ERR PFX
				"Unable to obtain 40-bit DMA "
				"for consistent allocations, aborting.\n");
			goto err_out_release_regions;
		}
		using_dac = 1;
	}

	/* Map vNIC resources from BAR0
	 */

	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
		printk(KERN_ERR PFX
			"BAR0 not memory-map'able, aborting.\n");
		err = -ENODEV;
		goto err_out_release_regions;
	}

	enic->bar0.vaddr = pci_iomap(pdev, 0, enic->bar0.len);
	enic->bar0.bus_addr = pci_resource_start(pdev, 0);
	enic->bar0.len = pci_resource_len(pdev, 0);

	if (!enic->bar0.vaddr) {
		printk(KERN_ERR PFX
			"Cannot memory-map BAR0 res hdr, aborting.\n");
		err = -ENODEV;
		goto err_out_release_regions;
	}

	/* Register vNIC device
	 */

	enic->vdev = vnic_dev_register(NULL, enic, pdev, &enic->bar0);
	if (!enic->vdev) {
		printk(KERN_ERR PFX
			"vNIC registration failed, aborting.\n");
		err = -ENODEV;
		goto err_out_iounmap;
	}

	/* Issue device open to get device in known state
	 */

	err = enic_dev_open(enic);
	if (err) {
		printk(KERN_ERR PFX
			"vNIC dev open failed, aborting.\n");
		goto err_out_vnic_unregister;
	}

	/* Issue device init to initialize the vnic-to-switch link.
	 * We'll start with carrier off and wait for link UP
	 * notification later to turn on carrier.  We don't need
	 * to wait here for the vnic-to-switch link initialization
	 * to complete; link UP notification is the indication that
	 * the process is complete.
	 */

	netif_carrier_off(netdev);

	err = vnic_dev_init(enic->vdev, 0);
	if (err) {
		printk(KERN_ERR PFX
			"vNIC dev init failed, aborting.\n");
		goto err_out_dev_close;
	}

	/* Get vNIC configuration
	 */

	err = enic_get_vnic_config(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Get vNIC configuration failed, aborting.\n");
		goto err_out_dev_close;
	}

	/* Get available resource counts
	 */

	enic_get_res_counts(enic);

	/* Set interrupt mode based on resource counts and system
	 * capabilities
	 */

	err = enic_set_intr_mode(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Failed to set intr mode, aborting.\n");
		goto err_out_dev_close;
	}

	/* Allocate and configure vNIC resources
	 */

	err = enic_alloc_vnic_resources(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Failed to alloc vNIC resources, aborting.\n");
		goto err_out_free_vnic_resources;
	}

	enic_init_vnic_resources(enic);

	/* Enable VLAN tag stripping.  RSS not enabled (yet).
	 */

	err = enic_set_nic_cfg(enic,
		rss_default_cpu, rss_hash_type,
		rss_hash_bits, rss_base_cpu,
		rss_enable, tso_ipid_split_en,
		ig_vlan_strip_en);
	if (err) {
		printk(KERN_ERR PFX
			"Failed to config nic, aborting.\n");
		goto err_out_free_vnic_resources;
	}

	/* Setup notification timer, HW reset task, and locks
	 */

	init_timer(&enic->notify_timer);
	enic->notify_timer.function = enic_notify_timer;
	enic->notify_timer.data = (unsigned long)enic;

	INIT_WORK(&enic->reset, enic_reset);

	for (i = 0; i < enic->wq_count; i++)
		spin_lock_init(&enic->wq_lock[i]);

	spin_lock_init(&enic->devcmd_lock);

	/* Register net device
	 */

	enic->port_mtu = enic->config.mtu;
	(void)enic_change_mtu(netdev, enic->port_mtu);

	err = enic_set_mac_addr(netdev, enic->mac_addr);
	if (err) {
		printk(KERN_ERR PFX
			"Invalid MAC address, aborting.\n");
		goto err_out_free_vnic_resources;
	}

	netdev->netdev_ops = &enic_netdev_ops;
	netdev->watchdog_timeo = 2 * HZ;
	netdev->ethtool_ops = &enic_ethtool_ops;

	switch (vnic_dev_get_intr_mode(enic->vdev)) {
	default:
		netif_napi_add(netdev, &enic->napi, enic_poll, 64);
		break;
	case VNIC_DEV_INTR_MODE_MSIX:
		netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64);
		break;
	}

	netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
	if (ENIC_SETTING(enic, TXCSUM))
		netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
	if (ENIC_SETTING(enic, TSO))
		netdev->features |= NETIF_F_TSO |
			NETIF_F_TSO6 | NETIF_F_TSO_ECN;
	if (ENIC_SETTING(enic, LRO))
		netdev->features |= NETIF_F_LRO;
	if (using_dac)
		netdev->features |= NETIF_F_HIGHDMA;


	enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM);

	enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR;
	enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC;
	enic->lro_mgr.lro_arr = enic->lro_desc;
	enic->lro_mgr.get_skb_header = enic_get_skb_header;
	enic->lro_mgr.features	= LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
	enic->lro_mgr.dev = netdev;
	enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE;
	enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;


	err = register_netdev(netdev);
	if (err) {
		printk(KERN_ERR PFX
			"Cannot register net device, aborting.\n");
		goto err_out_free_vnic_resources;
	}

	return 0;

err_out_free_vnic_resources:
	enic_free_vnic_resources(enic);
err_out_dev_close:
	vnic_dev_close(enic->vdev);
err_out_vnic_unregister:
	enic_clear_intr_mode(enic);
	vnic_dev_unregister(enic->vdev);
err_out_iounmap:
	enic_iounmap(enic);
err_out_release_regions:
	pci_release_regions(pdev);
err_out_disable_device:
	pci_disable_device(pdev);
err_out_free_netdev:
	pci_set_drvdata(pdev, NULL);
	free_netdev(netdev);

	return err;
}
Exemple #2
0
int enic_dev_init(struct enic *enic)
{
	struct net_device *netdev = enic->netdev;
	int err;

	

	err = enic_get_vnic_config(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Get vNIC configuration failed, aborting.\n");
		return err;
	}

	

	enic_get_res_counts(enic);

	

	err = enic_set_intr_mode(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Failed to set intr mode, aborting.\n");
		return err;
	}

	

	err = enic_alloc_vnic_resources(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Failed to alloc vNIC resources, aborting.\n");
		goto err_out_free_vnic_resources;
	}

	enic_init_vnic_resources(enic);

	err = enic_set_rq_alloc_buf(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Failed to set RQ buffer allocator, aborting.\n");
		goto err_out_free_vnic_resources;
	}

	err = enic_set_niccfg(enic);
	if (err) {
		printk(KERN_ERR PFX
			"Failed to config nic, aborting.\n");
		goto err_out_free_vnic_resources;
	}

	switch (vnic_dev_get_intr_mode(enic->vdev)) {
	default:
		netif_napi_add(netdev, &enic->napi, enic_poll, 64);
		break;
	case VNIC_DEV_INTR_MODE_MSIX:
		netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64);
		break;
	}

	return 0;

err_out_free_vnic_resources:
	enic_clear_intr_mode(enic);
	enic_free_vnic_resources(enic);

	return err;
}
static int enic_set_ringparam(struct net_device *netdev,
			      struct ethtool_ringparam *ring)
{
	struct enic *enic = netdev_priv(netdev);
	struct vnic_enet_config *c = &enic->config;
	int running = netif_running(netdev);
	unsigned int rx_pending;
	unsigned int tx_pending;
	int err = 0;

	if (ring->rx_mini_max_pending || ring->rx_mini_pending) {
		netdev_info(netdev,
			    "modifying mini ring params is not supported");
		return -EINVAL;
	}
	if (ring->rx_jumbo_max_pending || ring->rx_jumbo_pending) {
		netdev_info(netdev,
			    "modifying jumbo ring params is not supported");
		return -EINVAL;
	}
	rx_pending = c->rq_desc_count;
	tx_pending = c->wq_desc_count;
	if (ring->rx_pending > ENIC_MAX_RQ_DESCS ||
	    ring->rx_pending < ENIC_MIN_RQ_DESCS) {
		netdev_info(netdev, "rx pending (%u) not in range [%u,%u]",
			    ring->rx_pending, ENIC_MIN_RQ_DESCS,
			    ENIC_MAX_RQ_DESCS);
		return -EINVAL;
	}
	if (ring->tx_pending > ENIC_MAX_WQ_DESCS ||
	    ring->tx_pending < ENIC_MIN_WQ_DESCS) {
		netdev_info(netdev, "tx pending (%u) not in range [%u,%u]",
			    ring->tx_pending, ENIC_MIN_WQ_DESCS,
			    ENIC_MAX_WQ_DESCS);
		return -EINVAL;
	}
	if (running)
		dev_close(netdev);
	c->rq_desc_count =
		ring->rx_pending & 0xffffffe0; /* must be aligned to groups of 32 */
	c->wq_desc_count =
		ring->tx_pending & 0xffffffe0; /* must be aligned to groups of 32 */
	enic_free_vnic_resources(enic);
	err = enic_alloc_vnic_resources(enic);
	if (err) {
		netdev_err(netdev,
			   "Failed to alloc vNIC resources, aborting\n");
		enic_free_vnic_resources(enic);
		goto err_out;
	}
	enic_init_vnic_resources(enic);
	if (running) {
		err = dev_open(netdev);
		if (err)
			goto err_out;
	}
	return 0;
err_out:
	c->rq_desc_count = rx_pending;
	c->wq_desc_count = tx_pending;
	return err;
}