162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/pci.h> 462306a36Sopenharmony_ci#include <linux/msi.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) 762306a36Sopenharmony_ci 862306a36Sopenharmony_ciint pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); 962306a36Sopenharmony_civoid pci_msi_teardown_msi_irqs(struct pci_dev *dev); 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* Mask/unmask helpers */ 1262306a36Sopenharmony_civoid pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set); 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic inline void pci_msi_mask(struct msi_desc *desc, u32 mask) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci pci_msi_update_mask(desc, 0, mask); 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic inline void pci_msi_unmask(struct msi_desc *desc, u32 mask) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci pci_msi_update_mask(desc, mask, 0); 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic inline void __iomem *pci_msix_desc_addr(struct msi_desc *desc) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci return desc->pci.mask_base + desc->msi_index * PCI_MSIX_ENTRY_SIZE; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * This internal function does not flush PCI writes to the device. All 3162306a36Sopenharmony_ci * users must ensure that they read from the device before either assuming 3262306a36Sopenharmony_ci * that the device state is up to date, or returning out of this file. 3362306a36Sopenharmony_ci * It does not affect the msi_desc::msix_ctrl cache either. Use with care! 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistatic inline void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci void __iomem *desc_addr = pci_msix_desc_addr(desc); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (desc->pci.msi_attrib.can_mask) 4062306a36Sopenharmony_ci writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic inline void pci_msix_mask(struct msi_desc *desc) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT; 4662306a36Sopenharmony_ci pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl); 4762306a36Sopenharmony_ci /* Flush write to device */ 4862306a36Sopenharmony_ci readl(desc->pci.mask_base); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic inline void pci_msix_unmask(struct msi_desc *desc) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; 5462306a36Sopenharmony_ci pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic inline void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci if (desc->pci.msi_attrib.is_msix) 6062306a36Sopenharmony_ci pci_msix_mask(desc); 6162306a36Sopenharmony_ci else 6262306a36Sopenharmony_ci pci_msi_mask(desc, mask); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic inline void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci if (desc->pci.msi_attrib.is_msix) 6862306a36Sopenharmony_ci pci_msix_unmask(desc); 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci pci_msi_unmask(desc, mask); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to 7562306a36Sopenharmony_ci * mask all MSI interrupts by clearing the MSI enable bit does not work 7662306a36Sopenharmony_ci * reliably as devices without an INTx disable bit will then generate a 7762306a36Sopenharmony_ci * level IRQ which will never be cleared. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_cistatic inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci /* Don't shift by >= width of type */ 8262306a36Sopenharmony_ci if (desc->pci.msi_attrib.multi_cap >= 5) 8362306a36Sopenharmony_ci return 0xffffffff; 8462306a36Sopenharmony_ci return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_civoid msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* Subsystem variables */ 9062306a36Sopenharmony_ciextern int pci_msi_enable; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* MSI internal functions invoked from the public APIs */ 9362306a36Sopenharmony_civoid pci_msi_shutdown(struct pci_dev *dev); 9462306a36Sopenharmony_civoid pci_msix_shutdown(struct pci_dev *dev); 9562306a36Sopenharmony_civoid pci_free_msi_irqs(struct pci_dev *dev); 9662306a36Sopenharmony_ciint __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, struct irq_affinity *affd); 9762306a36Sopenharmony_ciint __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, 9862306a36Sopenharmony_ci int maxvec, struct irq_affinity *affd, int flags); 9962306a36Sopenharmony_civoid __pci_restore_msi_state(struct pci_dev *dev); 10062306a36Sopenharmony_civoid __pci_restore_msix_state(struct pci_dev *dev); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* irq_domain related functionality */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cienum support_mode { 10562306a36Sopenharmony_ci ALLOW_LEGACY, 10662306a36Sopenharmony_ci DENY_LEGACY, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cibool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode); 11062306a36Sopenharmony_cibool pci_setup_msi_device_domain(struct pci_dev *pdev); 11162306a36Sopenharmony_cibool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* Legacy (!IRQDOMAIN) fallbacks */ 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS 11662306a36Sopenharmony_ciint pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); 11762306a36Sopenharmony_civoid pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev); 11862306a36Sopenharmony_ci#else 11962306a36Sopenharmony_cistatic inline int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci WARN_ON_ONCE(1); 12262306a36Sopenharmony_ci return -ENODEV; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci WARN_ON_ONCE(1); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci#endif 130