drivers/net/ethernet/sfc/efx_channels.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/sfc/efx_channels.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sfc/efx_channels.c
Extension
.c
Size
35154 bytes
Lines
1352
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (rc >= 0) {
			n_channels = rc;
			for (i = 0; i < n_channels; i++)
				xentries[i].entry = i;
			rc = pci_enable_msix_range(efx->pci_dev, xentries, 1,
						   n_channels);
		}
		if (rc < 0) {
			/* Fall back to single channel MSI */
			netif_err(efx, drv, efx->net_dev,
				  "could not enable MSI-X\n");
			if (efx->type->min_interrupt_mode >= EFX_INT_MODE_MSI)
				efx->interrupt_mode = EFX_INT_MODE_MSI;
			else
				return rc;
		} else if (rc < n_channels) {
			netif_err(efx, drv, efx->net_dev,
				  "WARNING: Insufficient MSI-X vectors"
				  " available (%d < %u).\n", rc, n_channels);
			netif_err(efx, drv, efx->net_dev,
				  "WARNING: Performance may be reduced.\n");
			n_channels = rc;
		}

		if (rc > 0) {
			for (i = 0; i < efx->n_channels; i++)
				efx_get_channel(efx, i)->irq =
					xentries[i].vector;
		}
	}

	/* Try single interrupt MSI */
	if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
		efx->n_channels = 1;
		efx->n_rx_channels = 1;
		efx->n_tx_channels = 1;
		efx->tx_channel_offset = 0;
		efx->n_xdp_channels = 0;
		efx->xdp_channel_offset = efx->n_channels;
		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
		rc = pci_enable_msi(efx->pci_dev);
		if (rc == 0) {
			efx_get_channel(efx, 0)->irq = efx->pci_dev->irq;
		} else {
			netif_err(efx, drv, efx->net_dev,
				  "could not enable MSI\n");
			if (efx->type->min_interrupt_mode >= EFX_INT_MODE_LEGACY)
				efx->interrupt_mode = EFX_INT_MODE_LEGACY;
			else
				return rc;
		}
	}

	/* Assume legacy interrupts */
	if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
		efx->n_channels = 1 + (efx_separate_tx_channels ? 1 : 0);
		efx->n_rx_channels = 1;
		efx->n_tx_channels = 1;
		efx->tx_channel_offset = efx_separate_tx_channels ? 1 : 0;
		efx->n_xdp_channels = 0;
		efx->xdp_channel_offset = efx->n_channels;
		efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
		efx->legacy_irq = efx->pci_dev->irq;
	}

	/* Assign extra channels if possible, before XDP channels */
	efx->n_extra_tx_channels = 0;
	j = efx->xdp_channel_offset;
	for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) {
		if (!efx->extra_channel_type[i])
			continue;
		if (j <= efx->tx_channel_offset + efx->n_tx_channels) {
			efx->extra_channel_type[i]->handle_no_channel(efx);
		} else {
			--j;
			efx_get_channel(efx, j)->type =
				efx->extra_channel_type[i];
			if (efx_channel_has_tx_queues(efx_get_channel(efx, j)))
				efx->n_extra_tx_channels++;
		}
	}

	rss_spread = efx->n_rx_channels;
	/* RSS might be usable on VFs even if it is disabled on the PF */
#ifdef CONFIG_SFC_SRIOV
	if (efx->type->sriov_wanted) {
		efx->rss_spread = ((rss_spread > 1 ||
				    !efx->type->sriov_wanted(efx)) ?
				   rss_spread : efx_vf_size(efx));
		return 0;

Annotation

Implementation Notes