// SPDX-License-Identifier: GPL-2.0 /* * PCI Message Signaled Interrupt (MSI) * * Copyright (C) 2003-2004 Intel * Copyright (C) Tom Long Nguyen ([email protected]) * Copyright (C) 2016 Christoph Hellwig. */ #include <linux/bitfield.h> #include <linux/err.h> #include <linux/export.h> #include <linux/irq.h> #include "../pci.h" #include "msi.h" int pci_msi_enable = …; int pci_msi_ignore_mask; /** * pci_msi_supported - check whether MSI may be enabled on a device * @dev: pointer to the pci_dev data structure of MSI device function * @nvec: how many MSIs have been requested? * * Look at global flags, the device itself, and its parent buses * to determine if MSI/-X are supported for the device. If MSI/-X is * supported return 1, else return 0. **/ static int pci_msi_supported(struct pci_dev *dev, int nvec) { … } static void pcim_msi_release(void *pcidev) { … } /* * Needs to be separate from pcim_release to prevent an ordering problem * vs. msi_device_data_release() in the MSI core code. */ static int pcim_setup_msi_release(struct pci_dev *dev) { … } /* * Ordering vs. devres: msi device data has to be installed first so that * pcim_msi_release() is invoked before it on device release. */ static int pci_setup_msi_context(struct pci_dev *dev) { … } /* * Helper functions for mask/unmask and MSI message handling */ void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set) { … } /** * pci_msi_mask_irq - Generic IRQ chip callback to mask PCI/MSI interrupts * @data: pointer to irqdata associated to that interrupt */ void pci_msi_mask_irq(struct irq_data *data) { … } EXPORT_SYMBOL_GPL(…); /** * pci_msi_unmask_irq - Generic IRQ chip callback to unmask PCI/MSI interrupts * @data: pointer to irqdata associated to that interrupt */ void pci_msi_unmask_irq(struct irq_data *data) { … } EXPORT_SYMBOL_GPL(…); void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { … } static inline void pci_write_msg_msi(struct pci_dev *dev, struct msi_desc *desc, struct msi_msg *msg) { … } static inline void pci_write_msg_msix(struct msi_desc *desc, struct msi_msg *msg) { … } void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { … } void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg) { … } EXPORT_SYMBOL_GPL(…); /* PCI/MSI specific functionality */ static void pci_intx_for_msi(struct pci_dev *dev, int enable) { … } static void pci_msi_set_enable(struct pci_dev *dev, int enable) { … } static int msi_setup_msi_desc(struct pci_dev *dev, int nvec, struct irq_affinity_desc *masks) { … } static int msi_verify_entries(struct pci_dev *dev) { … } /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function * @nvec: number of interrupts to allocate * @affd: description of automatic IRQ affinity assignments (may be %NULL) * * Setup the MSI capability structure of the device with the requested * number of interrupts. A return value of zero indicates the successful * setup of an entry with the new MSI IRQ. A negative return value indicates * an error, and a positive return value indicates the number of interrupts * which could have been allocated. */ static int msi_capability_init(struct pci_dev *dev, int nvec, struct irq_affinity *affd) { … } int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, struct irq_affinity *affd) { … } /** * pci_msi_vec_count - Return the number of MSI vectors a device can send * @dev: device to report about * * This function returns the number of MSI vectors a device requested via * Multiple Message Capable register. It returns a negative errno if the * device is not capable sending MSI interrupts. Otherwise, the call succeeds * and returns a power of two, up to a maximum of 2^5 (32), according to the * MSI specification. **/ int pci_msi_vec_count(struct pci_dev *dev) { … } EXPORT_SYMBOL(…); /* * Architecture override returns true when the PCI MSI message should be * written by the generic restore function. */ bool __weak arch_restore_msi_irqs(struct pci_dev *dev) { … } void __pci_restore_msi_state(struct pci_dev *dev) { … } void pci_msi_shutdown(struct pci_dev *dev) { … } /* PCI/MSI-X specific functionality */ static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set) { … } static void __iomem *msix_map_region(struct pci_dev *dev, unsigned int nr_entries) { … } /** * msix_prepare_msi_desc - Prepare a half initialized MSI descriptor for operation * @dev: The PCI device for which the descriptor is prepared * @desc: The MSI descriptor for preparation * * This is separate from msix_setup_msi_descs() below to handle dynamic * allocations for MSI-X after initial enablement. * * Ideally the whole MSI-X setup would work that way, but there is no way to * support this for the legacy arch_setup_msi_irqs() mechanism and for the * fake irq domains like the x86 XEN one. Sigh... * * The descriptor is zeroed and only @desc::msi_index and @desc::affinity * are set. When called from msix_setup_msi_descs() then the is_virtual * attribute is initialized as well. * * Fill in the rest. */ void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc) { … } static int msix_setup_msi_descs(struct pci_dev *dev, struct msix_entry *entries, int nvec, struct irq_affinity_desc *masks) { … } static void msix_update_entries(struct pci_dev *dev, struct msix_entry *entries) { … } static void msix_mask_all(void __iomem *base, int tsize) { … } static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries, int nvec, struct irq_affinity *affd) { … } /** * msix_capability_init - configure device's MSI-X capability * @dev: pointer to the pci_dev data structure of MSI-X device function * @entries: pointer to an array of struct msix_entry entries * @nvec: number of @entries * @affd: Optional pointer to enable automatic affinity assignment * * Setup the MSI-X capability structure of device function with a * single MSI-X IRQ. A return of zero indicates the successful setup of * requested MSI-X entries with allocated IRQs or non-zero for otherwise. **/ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec, struct irq_affinity *affd) { … } static bool pci_msix_validate_entries(struct pci_dev *dev, struct msix_entry *entries, int nvec) { … } int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, int maxvec, struct irq_affinity *affd, int flags) { … } void __pci_restore_msix_state(struct pci_dev *dev) { … } void pci_msix_shutdown(struct pci_dev *dev) { … } /* Common interfaces */ void pci_free_msi_irqs(struct pci_dev *dev) { … } /* Misc. infrastructure */ struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) { … } EXPORT_SYMBOL(…); void pci_no_msi(void) { … }