| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 |  | 
|---|
| 3 | #include <linux/pci.h> | 
|---|
| 4 | #include <linux/msi.h> | 
|---|
| 5 |  | 
|---|
| 6 | #define msix_table_size(flags)	((flags & PCI_MSIX_FLAGS_QSIZE) + 1) | 
|---|
| 7 |  | 
|---|
| 8 | int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); | 
|---|
| 9 | void pci_msi_teardown_msi_irqs(struct pci_dev *dev); | 
|---|
| 10 |  | 
|---|
| 11 | /* Mask/unmask helpers */ | 
|---|
| 12 | void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set); | 
|---|
| 13 |  | 
|---|
| 14 | static inline void pci_msi_mask(struct msi_desc *desc, u32 mask) | 
|---|
| 15 | { | 
|---|
| 16 | pci_msi_update_mask(desc, clear: 0, set: mask); | 
|---|
| 17 | } | 
|---|
| 18 |  | 
|---|
| 19 | static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask) | 
|---|
| 20 | { | 
|---|
| 21 | pci_msi_update_mask(desc, clear: mask, set: 0); | 
|---|
| 22 | } | 
|---|
| 23 |  | 
|---|
| 24 | static inline void __iomem *pci_msix_desc_addr(struct msi_desc *desc) | 
|---|
| 25 | { | 
|---|
| 26 | return desc->pci.mask_base + desc->msi_index * PCI_MSIX_ENTRY_SIZE; | 
|---|
| 27 | } | 
|---|
| 28 |  | 
|---|
| 29 | /* | 
|---|
| 30 | * This internal function does not flush PCI writes to the device.  All | 
|---|
| 31 | * users must ensure that they read from the device before either assuming | 
|---|
| 32 | * that the device state is up to date, or returning out of this file. | 
|---|
| 33 | * It does not affect the msi_desc::msix_ctrl cache either. Use with care! | 
|---|
| 34 | */ | 
|---|
| 35 | static inline void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl) | 
|---|
| 36 | { | 
|---|
| 37 | void __iomem *desc_addr = pci_msix_desc_addr(desc); | 
|---|
| 38 |  | 
|---|
| 39 | if (desc->pci.msi_attrib.can_mask) | 
|---|
| 40 | writel(val: ctrl, addr: desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL); | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | static inline void pci_msix_mask(struct msi_desc *desc) | 
|---|
| 44 | { | 
|---|
| 45 | desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT; | 
|---|
| 46 | pci_msix_write_vector_ctrl(desc, ctrl: desc->pci.msix_ctrl); | 
|---|
| 47 | /* Flush write to device */ | 
|---|
| 48 | readl(addr: desc->pci.mask_base); | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|
| 51 | static inline void pci_msix_unmask(struct msi_desc *desc) | 
|---|
| 52 | { | 
|---|
| 53 | desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; | 
|---|
| 54 | pci_msix_write_vector_ctrl(desc, ctrl: desc->pci.msix_ctrl); | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | static inline void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask) | 
|---|
| 58 | { | 
|---|
| 59 | if (desc->pci.msi_attrib.is_msix) | 
|---|
| 60 | pci_msix_mask(desc); | 
|---|
| 61 | else | 
|---|
| 62 | pci_msi_mask(desc, mask); | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | static inline void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask) | 
|---|
| 66 | { | 
|---|
| 67 | if (desc->pci.msi_attrib.is_msix) | 
|---|
| 68 | pci_msix_unmask(desc); | 
|---|
| 69 | else | 
|---|
| 70 | pci_msi_unmask(desc, mask); | 
|---|
| 71 | } | 
|---|
| 72 |  | 
|---|
| 73 | /* | 
|---|
| 74 | * PCI 2.3 does not specify mask bits for each MSI interrupt.  Attempting to | 
|---|
| 75 | * mask all MSI interrupts by clearing the MSI enable bit does not work | 
|---|
| 76 | * reliably as devices without an INTx disable bit will then generate a | 
|---|
| 77 | * level IRQ which will never be cleared. | 
|---|
| 78 | */ | 
|---|
| 79 | static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc) | 
|---|
| 80 | { | 
|---|
| 81 | /* Don't shift by >= width of type */ | 
|---|
| 82 | if (desc->pci.msi_attrib.multi_cap >= 5) | 
|---|
| 83 | return 0xffffffff; | 
|---|
| 84 | return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1; | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc); | 
|---|
| 88 |  | 
|---|
| 89 | /* Subsystem variables */ | 
|---|
| 90 | extern bool pci_msi_enable; | 
|---|
| 91 |  | 
|---|
| 92 | /* MSI internal functions invoked from the public APIs */ | 
|---|
| 93 | void pci_msi_shutdown(struct pci_dev *dev); | 
|---|
| 94 | void pci_msix_shutdown(struct pci_dev *dev); | 
|---|
| 95 | void pci_free_msi_irqs(struct pci_dev *dev); | 
|---|
| 96 | int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, struct irq_affinity *affd); | 
|---|
| 97 | int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, | 
|---|
| 98 | int maxvec,  struct irq_affinity *affd, int flags); | 
|---|
| 99 | void __pci_restore_msi_state(struct pci_dev *dev); | 
|---|
| 100 | void __pci_restore_msix_state(struct pci_dev *dev); | 
|---|
| 101 |  | 
|---|
| 102 | /* irq_domain related functionality */ | 
|---|
| 103 |  | 
|---|
| 104 | enum support_mode { | 
|---|
| 105 | ALLOW_LEGACY, | 
|---|
| 106 | DENY_LEGACY, | 
|---|
| 107 | }; | 
|---|
| 108 |  | 
|---|
| 109 | bool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode); | 
|---|
| 110 | bool pci_setup_msi_device_domain(struct pci_dev *pdev, unsigned int hwsize); | 
|---|
| 111 | bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize); | 
|---|
| 112 |  | 
|---|
| 113 | /* Legacy (!IRQDOMAIN) fallbacks */ | 
|---|
| 114 |  | 
|---|
| 115 | #ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS | 
|---|
| 116 | int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); | 
|---|
| 117 | void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev); | 
|---|
| 118 | #else | 
|---|
| 119 | static inline int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 
|---|
| 120 | { | 
|---|
| 121 | WARN_ON_ONCE(1); | 
|---|
| 122 | return -ENODEV; | 
|---|
| 123 | } | 
|---|
| 124 |  | 
|---|
| 125 | static inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev) | 
|---|
| 126 | { | 
|---|
| 127 | WARN_ON_ONCE(1); | 
|---|
| 128 | } | 
|---|
| 129 | #endif | 
|---|
| 130 |  | 
|---|