xref: /kernel/linux/linux-6.6/drivers/pci/msi/msi.h (revision 62306a36)
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