drivers/net/ethernet/meta/fbnic/fbnic_irq.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/meta/fbnic/fbnic_irq.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/meta/fbnic/fbnic_irq.c
Extension
.c
Size
11822 bytes
Lines
470
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

struct fbnic_msix_test_data {
	struct fbnic_dev *fbd;
	unsigned long test_msix_status[BITS_TO_LONGS(FBNIC_MAX_MSIX_VECS)];
	int irq_vector[FBNIC_MAX_MSIX_VECS];
};

static irqreturn_t fbnic_irq_test(int irq, void *data)
{
	struct fbnic_msix_test_data *test_data = data;
	struct fbnic_dev *fbd = test_data->fbd;
	int i;

	for (i = fbd->num_irqs; i--;) {
		if (test_data->irq_vector[i] == irq) {
			set_bit(i, test_data->test_msix_status);
			break;
		}
	}

	return IRQ_HANDLED;
}

/**
 * fbnic_msix_test - Verify behavior of NIC interrupts
 * @fbd: device to test
 *
 * This function is meant to test the global interrupt registers and the
 * PCIe IP MSI-X functionality. It essentially goes through and tests
 * various combinations of the set, clear, and mask bits in order to
 * verify the behavior is as we expect it to be from the driver.
 *
 * Return: See enum fbnic_msix_self_test_codes
 **/
enum fbnic_msix_self_test_codes fbnic_msix_test(struct fbnic_dev *fbd)
{
	enum fbnic_msix_self_test_codes result = FBNIC_TEST_MSIX_SUCCESS;
	struct pci_dev *pdev = to_pci_dev(fbd->dev);
	struct fbnic_msix_test_data *test_data;
	u32 mask = 0;
	int i;

	/* Allocate bitmap and IRQ vector table */
	test_data = kzalloc_obj(*test_data, GFP_KERNEL);

	/* memory allocation failure */
	if (!test_data)
		return FBNIC_TEST_MSIX_NOMEM;

	/* Initialize test data */
	test_data->fbd = fbd;

	for (i = FBNIC_NON_NAPI_VECTORS; i < fbd->num_irqs; i++) {
		/* Add IRQ to vector table so it can be found */
		test_data->irq_vector[i] = pci_irq_vector(pdev, i);

		/* Enable the interrupt */
		if (!fbnic_request_irq(fbd, i, fbnic_irq_test, 0,
				       fbd->netdev->name, test_data))
			continue;

		while (i-- > FBNIC_NON_NAPI_VECTORS)
			fbnic_free_irq(fbd, i, test_data);
		kfree(test_data);

		/* IRQ request failure */
		return FBNIC_TEST_MSIX_IRQ_REQ_FAIL;
	}

	/* Test each bit individually */
	for (i = FBNIC_NON_NAPI_VECTORS; i < fbd->num_irqs; i++) {
		mask = 1U << (i % 32);

		/* Start with mask set and interrupt cleared */
		fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(i / 32), mask);
		fbnic_wrfl(fbd);
		fbnic_wr32(fbd, FBNIC_INTR_CLEAR(i / 32), mask);
		fbnic_wrfl(fbd);

		/* masking failure to prevent interrupt */
		result = FBNIC_TEST_MSIX_MASK;

		fbnic_wr32(fbd, FBNIC_INTR_SET(i / 32), mask);
		fbnic_wrfl(fbd);
		usleep_range(10000, 11000);

		if (test_bit(i, test_data->test_msix_status))
			break;

		/* unmasking failure w/ sw status set */
		result = FBNIC_TEST_MSIX_UNMASK;

Annotation

Implementation Notes