// 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) { … } void pci_msi_teardown_msi_irqs(struct pci_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) { … } /** * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source * @desc: Pointer to the MSI descriptor * * The ID number is only used within the irqdomain. */ static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc) { … } static void pci_msi_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) { … } static struct msi_domain_ops pci_msi_domain_ops_default = …; static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info) { … } static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info) { … } /** * pci_msi_create_irq_domain - Create a MSI interrupt domain * @fwnode: Optional fwnode of the interrupt controller * @info: MSI domain info * @parent: Parent irq domain * * Updates the domain and chip ops and creates a MSI interrupt domain. * * Returns: * A domain pointer or NULL in case of failure. */ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, struct msi_domain_info *info, struct irq_domain *parent) { … } EXPORT_SYMBOL_GPL(…); /* * Per device MSI[-X] domain functionality */ static void pci_device_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) { … } static __always_inline void cond_mask_parent(struct irq_data *data) { … } static __always_inline void cond_unmask_parent(struct irq_data *data) { … } static void pci_irq_mask_msi(struct irq_data *data) { … } static void pci_irq_unmask_msi(struct irq_data *data) { … } #ifdef CONFIG_GENERIC_IRQ_RESERVATION_MODE #define MSI_REACTIVATE … #else #define MSI_REACTIVATE … #endif #define MSI_COMMON_FLAGS … static const struct msi_domain_template pci_msi_template = …; static void pci_irq_mask_msix(struct irq_data *data) { … } static void pci_irq_unmask_msix(struct irq_data *data) { … } static void pci_msix_prepare_desc(struct irq_domain *domain, msi_alloc_info_t *arg, struct msi_desc *desc) { … } static const struct msi_domain_template pci_msix_template = …; static bool pci_match_device_domain(struct pci_dev *pdev, enum irq_domain_bus_token bus_token) { … } static bool pci_create_device_domain(struct pci_dev *pdev, const struct msi_domain_template *tmpl, unsigned int hwsize) { … } /** * pci_setup_msi_device_domain - Setup a device MSI interrupt domain * @pdev: The PCI device to create the domain on * * Return: * True when: * - The device does not have a MSI parent irq domain associated, * which keeps the legacy architecture specific and the global * PCI/MSI domain models working * - The MSI domain exists already * - The MSI domain was successfully allocated * False when: * - MSI-X is enabled * - The domain creation fails. * * The created MSI domain is preserved until: * - The device is removed * - MSI is disabled and a MSI-X domain is created */ bool pci_setup_msi_device_domain(struct pci_dev *pdev) { … } /** * pci_setup_msix_device_domain - Setup a device MSI-X interrupt domain * @pdev: The PCI device to create the domain on * @hwsize: The size of the MSI-X vector table * * Return: * True when: * - The device does not have a MSI parent irq domain associated, * which keeps the legacy architecture specific and the global * PCI/MSI domain models working * - The MSI-X domain exists already * - The MSI-X domain was successfully allocated * False when: * - MSI is enabled * - The domain creation fails. * * The created MSI-X domain is preserved until: * - The device is removed * - MSI-X is disabled and a MSI domain is created */ bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize) { … } /** * pci_msi_domain_supports - Check for support of a particular feature flag * @pdev: The PCI device to operate on * @feature_mask: The feature mask to check for (full match) * @mode: If ALLOW_LEGACY this grants the feature when there is no irq domain * associated to the device. If DENY_LEGACY the lack of an irq domain * makes the feature unsupported */ bool pci_msi_domain_supports(struct pci_dev *pdev, unsigned int feature_mask, enum support_mode mode) { … } /* * Users of the generic MSI infrastructure expect a device to have a single ID, * so with DMA aliases we have to pick the least-worst compromise. Devices with * DMA phantom functions tend to still emit MSIs from the real function number, * so we ignore those and only consider topological aliases where either the * alias device or RID appears on a different bus number. We also make the * reasonable assumption that bridges are walked in an upstream direction (so * the last one seen wins), and the much braver assumption that the most likely * case is that of PCI->PCIe so we should always use the alias RID. This echoes * the logic from intel_irq_remapping's set_msi_sid(), which presumably works * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions * for taking ownership all we can really do is close our eyes and hope... */ static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data) { … } /** * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID) * @domain: The interrupt domain * @pdev: The PCI device. * * The RID for a device is formed from the alias, with a firmware * supplied mapping applied * * Returns: The RID. */ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev) { … } /** * pci_msi_get_device_domain - Get the MSI domain for a given PCI device * @pdev: The PCI device * * Use the firmware data to find a device-specific MSI domain * (i.e. not one that is set as a default). * * Returns: The corresponding MSI domain or NULL if none has been found. */ struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev) { … }