drivers/pci/msi/irqdomain.c

Source file repositories/reference/linux-study-clean/drivers/pci/msi/irqdomain.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/msi/irqdomain.c
Extension
.c
Size
12516 bytes
Lines
432
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * PCI Message Signaled Interrupt (MSI) - irqdomain support
 */
#include <linux/acpi_iort.h>
#include <linux/irqdomain.h>
#include <linux/of_irq.h>

#include "msi.h"

int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
	struct irq_domain *domain;

	domain = dev_get_msi_domain(&dev->dev);
	if (domain && irq_domain_is_hierarchy(domain))
		return msi_domain_alloc_irqs_all_locked(&dev->dev, MSI_DEFAULT_DOMAIN, nvec);

	return pci_msi_legacy_setup_msi_irqs(dev, nvec, type);
}

void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
{
	struct irq_domain *domain;

	domain = dev_get_msi_domain(&dev->dev);
	if (domain && irq_domain_is_hierarchy(domain)) {
		msi_domain_free_irqs_all_locked(&dev->dev, MSI_DEFAULT_DOMAIN);
	} else {
		pci_msi_legacy_teardown_msi_irqs(dev);
		msi_free_msi_descs(&dev->dev);
	}
}

/**
 * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
 * @irq_data:	Pointer to interrupt data of the MSI interrupt
 * @msg:	Pointer to the message
 */
static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
{
	struct msi_desc *desc = irq_data_get_msi_desc(irq_data);

	/*
	 * For MSI-X desc->irq is always equal to irq_data->irq. For
	 * MSI only the first interrupt of MULTI MSI passes the test.
	 */
	if (desc->irq == irq_data->irq)
		__pci_write_msi_msg(desc, msg);
}

/*
 * Per device MSI[-X] domain functionality
 */
static void pci_device_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
{
	arg->desc = desc;
	arg->hwirq = desc->msi_index;
}

static void cond_shutdown_parent(struct irq_data *data)
{
	struct msi_domain_info *info = data->domain->host_data;

	if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT))
		irq_chip_shutdown_parent(data);
	else if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT))
		irq_chip_mask_parent(data);
}

static unsigned int cond_startup_parent(struct irq_data *data)
{
	struct msi_domain_info *info = data->domain->host_data;

	if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT))
		return irq_chip_startup_parent(data);
	else if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT))
		irq_chip_unmask_parent(data);

	return 0;
}

static void pci_irq_shutdown_msi(struct irq_data *data)
{
	struct msi_desc *desc = irq_data_get_msi_desc(data);

	pci_msi_mask(desc, BIT(data->irq - desc->irq));
	cond_shutdown_parent(data);
}

Annotation

Implementation Notes