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; }
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; }