struct net_device * nfp_repr_alloc_mqs(struct nfp_app *app, unsigned int txqs, unsigned int rxqs) { struct net_device *netdev; struct nfp_repr *repr; netdev = alloc_etherdev_mqs(sizeof(*repr), txqs, rxqs); if (!netdev) return NULL; netif_carrier_off(netdev); repr = netdev_priv(netdev); repr->netdev = netdev; repr->app = app; repr->stats = netdev_alloc_pcpu_stats(struct nfp_repr_pcpu_stats); if (!repr->stats) goto err_free_netdev; return netdev; err_free_netdev: free_netdev(netdev); return NULL; }
struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv, unsigned int txqs, unsigned int rxqs) { struct net_device **dr; struct net_device *netdev; dr = devres_alloc(devm_free_netdev, sizeof(*dr), GFP_KERNEL); if (!dr) return NULL; netdev = alloc_etherdev_mqs(sizeof_priv, txqs, rxqs); if (!netdev) { devres_free(dr); return NULL; } *dr = netdev; devres_add(dev, dr); return netdev; }
/* bar must be a virtual address (whether it's host or guest), * where the kernel can directly access to */ int sn_create_netdev(void *bar, struct sn_device **dev_ret) { struct sn_conf_space *conf = bar; struct sn_device *dev; struct net_device *netdev; char *name; int ret; *dev_ret = NULL; if (conf->bar_size < sizeof(struct sn_conf_space)) { log_err("invalid BAR size %llu\n", conf->bar_size); return -EINVAL; } if (conf->num_txq < 1 || conf->num_rxq < 1 || conf->num_txq > MAX_QUEUES || conf->num_rxq > MAX_QUEUES) { log_err("invalid ioctl arguments: num_txq=%d, num_rxq=%d\n", conf->num_txq, conf->num_rxq); return -EINVAL; } netdev = alloc_etherdev_mqs(sizeof(struct sn_device), conf->num_txq, conf->num_rxq); if (!netdev) { log_err("alloc_netdev_mqs() failed\n"); return -ENOMEM; } if (strcmp(conf->ifname, "") == 0) name = "sn%d"; else name = conf->ifname; ret = dev_alloc_name(netdev, name); if (ret < 0) { log_err("failed to alloc name %s\n", name); free_netdev(netdev); return ret; } dev = netdev_priv(netdev); dev->netdev = netdev; dev->num_txq = conf->num_txq; dev->num_rxq = conf->num_rxq; sn_set_default_queue_mapping(dev); /* This will disable the default qdisc (mq or pfifo_fast) on the * interface. We don't need qdisc since BESS already has its own. * Also see attach_default_qdiscs() in sch_generic.c */ netdev->tx_queue_len = 0; netdev->destructor = sn_netdev_destructor; sn_set_offloads(netdev); netdev->netdev_ops = &sn_netdev_ops; netdev->ethtool_ops = &sn_ethtool_ops; memcpy(netdev->dev_addr, conf->mac_addr, ETH_ALEN); ret = sn_alloc_queues(dev, conf + 1, conf->bar_size - sizeof(struct sn_conf_space), &conf->txq_opts, &conf->rxq_opts); if (ret) { log_err("sn_alloc_queues() failed\n"); free_netdev(netdev); return ret; } *dev_ret = dev; return 0; }