Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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
  8int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
  9void pci_msi_teardown_msi_irqs(struct pci_dev *dev);
 10
 11/* Mask/unmask helpers */
 12void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set);
 13
 14static inline void pci_msi_mask(struct msi_desc *desc, u32 mask)
 15{
 16	pci_msi_update_mask(desc, 0, mask);
 17}
 18
 19static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask)
 20{
 21	pci_msi_update_mask(desc, mask, 0);
 22}
 23
 24static 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 */
 35static 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(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
 41}
 42
 43static 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, desc->pci.msix_ctrl);
 47	/* Flush write to device */
 48	readl(desc->pci.mask_base);
 49}
 50
 51static 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, desc->pci.msix_ctrl);
 55}
 56
 57static 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
 65static 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 */
 79static 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
 87void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc);
 88
 89/* Subsystem variables */
 90extern int pci_msi_enable;
 91
 92/* MSI internal functions invoked from the public APIs */
 93void pci_msi_shutdown(struct pci_dev *dev);
 94void pci_msix_shutdown(struct pci_dev *dev);
 95void pci_free_msi_irqs(struct pci_dev *dev);
 96int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, struct irq_affinity *affd);
 97int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec,
 98			    int maxvec,  struct irq_affinity *affd, int flags);
 99void __pci_restore_msi_state(struct pci_dev *dev);
100void __pci_restore_msix_state(struct pci_dev *dev);
101
102/* irq_domain related functionality */
103
104enum support_mode {
105	ALLOW_LEGACY,
106	DENY_LEGACY,
107};
108
109bool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode);
110bool pci_setup_msi_device_domain(struct pci_dev *pdev);
111bool 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
116int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
117void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev);
118#else
119static 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
125static inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
126{
127	WARN_ON_ONCE(1);
128}
129#endif