in build/gve_main.c [506:677]
static int gve_alloc_notify_blocks(struct gve_priv *priv)
{
int num_vecs_requested = priv->num_ntfy_blks + 1;
unsigned int active_cpus;
int vecs_enabled;
int i, j;
int err;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
priv->msix_vectors = kvcalloc(num_vecs_requested,
sizeof(*priv->msix_vectors), GFP_KERNEL);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
priv->msix_vectors = kcalloc(num_vecs_requested,
sizeof(*priv->msix_vectors), GFP_KERNEL);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
if (!priv->msix_vectors)
return -ENOMEM;
for (i = 0; i < num_vecs_requested; i++)
priv->msix_vectors[i].entry = i;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
vecs_enabled = pci_enable_msix_range(priv->pdev, priv->msix_vectors,
GVE_MIN_MSIX, num_vecs_requested);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) */
vecs_enabled = pci_enable_msix(priv->pdev, priv->msix_vectors,
num_vecs_requested);
if (!vecs_enabled) {
vecs_enabled = num_vecs_requested;
}
else
if (vecs_enabled > 0) {
if (vecs_enabled >= GVE_MIN_MSIX) {
vecs_enabled = pci_enable_msix(priv->pdev,
priv->msix_vectors,
GVE_MIN_MSIX);
if (vecs_enabled) {
dev_err(&priv->pdev->dev,
"Could not enable min msix %d error %d\n",
GVE_MIN_MSIX, vecs_enabled);
err = vecs_enabled;
goto abort_with_msix_vectors;
}
else {
vecs_enabled = GVE_MIN_MSIX;
}
}
else {
dev_err(&priv->pdev->dev,
"Could not enable msix error %d\n",
vecs_enabled);
err = vecs_enabled;
goto abort_with_msix_vectors;
}
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) */
if (vecs_enabled < 0) {
dev_err(&priv->pdev->dev, "Could not enable min msix %d/%d\n",
GVE_MIN_MSIX, vecs_enabled);
err = vecs_enabled;
goto abort_with_msix_vectors;
}
if (vecs_enabled != num_vecs_requested) {
int new_num_ntfy_blks = (vecs_enabled - 1) & ~0x1;
int vecs_per_type = new_num_ntfy_blks / 2;
int vecs_left = new_num_ntfy_blks % 2;
priv->num_ntfy_blks = new_num_ntfy_blks;
priv->mgmt_msix_idx = priv->num_ntfy_blks;
priv->tx_cfg.max_queues = min_t(int, priv->tx_cfg.max_queues,
vecs_per_type);
priv->rx_cfg.max_queues = min_t(int, priv->rx_cfg.max_queues,
vecs_per_type + vecs_left);
dev_err(&priv->pdev->dev,
"Could not enable desired msix, only enabled %d, adjusting tx max queues to %d, and rx max queues to %d\n",
vecs_enabled, priv->tx_cfg.max_queues,
priv->rx_cfg.max_queues);
if (priv->tx_cfg.num_queues > priv->tx_cfg.max_queues)
priv->tx_cfg.num_queues = priv->tx_cfg.max_queues;
if (priv->rx_cfg.num_queues > priv->rx_cfg.max_queues)
priv->rx_cfg.num_queues = priv->rx_cfg.max_queues;
}
/* Half the notification blocks go to TX and half to RX */
active_cpus = min_t(int, priv->num_ntfy_blks / 2, num_online_cpus());
/* Setup Management Vector - the last vector */
snprintf(priv->mgmt_msix_name, sizeof(priv->mgmt_msix_name), "gve-mgmnt@pci:%s",
pci_name(priv->pdev));
err = request_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector,
gve_mgmnt_intr, 0, priv->mgmt_msix_name, priv);
if (err) {
dev_err(&priv->pdev->dev, "Did not receive management vector.\n");
goto abort_with_msix_enabled;
}
priv->irq_db_indices =
dma_alloc_coherent(&priv->pdev->dev,
priv->num_ntfy_blks *
sizeof(*priv->irq_db_indices),
&priv->irq_db_indices_bus, GFP_KERNEL);
if (!priv->irq_db_indices) {
err = -ENOMEM;
goto abort_with_mgmt_vector;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
priv->ntfy_blocks = kvzalloc(priv->num_ntfy_blks *
sizeof(*priv->ntfy_blocks), GFP_KERNEL);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
priv->ntfy_blocks = kcalloc(1,
priv->num_ntfy_blks * sizeof(*priv->ntfy_blocks),
GFP_KERNEL);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
if (!priv->ntfy_blocks) {
err = -ENOMEM;
goto abort_with_irq_db_indices;
}
/* Setup the other blocks - the first n-1 vectors */
for (i = 0; i < priv->num_ntfy_blks; i++) {
struct gve_notify_block *block = &priv->ntfy_blocks[i];
int msix_idx = i;
snprintf(block->name, sizeof(block->name), "gve-ntfy-blk%d@pci:%s",
i, pci_name(priv->pdev));
block->priv = priv;
err = request_irq(priv->msix_vectors[msix_idx].vector,
gve_is_gqi(priv) ? gve_intr : gve_intr_dqo,
0, block->name, block);
if (err) {
dev_err(&priv->pdev->dev,
"Failed to receive msix vector %d\n", i);
goto abort_with_some_ntfy_blocks;
}
block->irq = priv->msix_vectors[msix_idx].vector;
irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
get_cpu_mask(i % active_cpus));
block->irq_db_index = &priv->irq_db_indices[i].index;
}
return 0;
abort_with_some_ntfy_blocks:
for (j = 0; j < i; j++) {
struct gve_notify_block *block = &priv->ntfy_blocks[j];
int msix_idx = j;
irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
NULL);
free_irq(priv->msix_vectors[msix_idx].vector, block);
block->irq = 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
kvfree(priv->ntfy_blocks);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
kfree(priv->ntfy_blocks);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
priv->ntfy_blocks = NULL;
abort_with_irq_db_indices:
dma_free_coherent(&priv->pdev->dev, priv->num_ntfy_blks *
sizeof(*priv->irq_db_indices),
priv->irq_db_indices, priv->irq_db_indices_bus);
priv->irq_db_indices = NULL;
abort_with_mgmt_vector:
free_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector, priv);
abort_with_msix_enabled:
pci_disable_msix(priv->pdev);
abort_with_msix_vectors:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
kvfree(priv->msix_vectors);
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
kfree(priv->msix_vectors);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) */
priv->msix_vectors = NULL;
return err;
}