From 6b2fd7efeb888fa781c1f767de6c36497ac1596b Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Sun, 7 Sep 2014 20:57:53 +0200 Subject: [PATCH 01/12] PCI/MSI/PPC: Remove arch_msi_check_device() Move MSI checks from arch_msi_check_device() to arch_setup_msi_irqs(). This makes the code more compact and allows removing arch_msi_check_device() from generic MSI code. Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas Acked-by: Michael Ellerman --- arch/powerpc/include/asm/machdep.h | 2 -- arch/powerpc/kernel/msi.c | 12 +------- arch/powerpc/platforms/cell/axon_msi.c | 9 ------ arch/powerpc/platforms/powernv/pci.c | 19 +++--------- arch/powerpc/platforms/pseries/msi.c | 42 ++++++++++---------------- arch/powerpc/sysdev/fsl_msi.c | 12 ++------ arch/powerpc/sysdev/mpic_pasemi_msi.c | 11 ++----- arch/powerpc/sysdev/mpic_u3msi.c | 28 +++++++---------- arch/powerpc/sysdev/ppc4xx_hsta_msi.c | 18 ++++------- arch/powerpc/sysdev/ppc4xx_msi.c | 19 ++++-------- 10 files changed, 50 insertions(+), 122 deletions(-) diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index b125ceab149c..3af721633618 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -136,8 +136,6 @@ struct machdep_calls { int (*pci_setup_phb)(struct pci_controller *host); #ifdef CONFIG_PCI_MSI - int (*msi_check_device)(struct pci_dev* dev, - int nvec, int type); int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); void (*teardown_msi_irqs)(struct pci_dev *dev); diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c index 8bbc12d20f5c..71bd161640cf 100644 --- a/arch/powerpc/kernel/msi.c +++ b/arch/powerpc/kernel/msi.c @@ -13,7 +13,7 @@ #include -int arch_msi_check_device(struct pci_dev* dev, int nvec, int type) +int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) { pr_debug("msi: Platform doesn't provide MSI callbacks.\n"); @@ -24,16 +24,6 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type) if (type == PCI_CAP_ID_MSI && nvec > 1) return 1; - if (ppc_md.msi_check_device) { - pr_debug("msi: Using platform check routine.\n"); - return ppc_md.msi_check_device(dev, nvec, type); - } - - return 0; -} - -int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -{ return ppc_md.setup_msi_irqs(dev, nvec, type); } diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 85825b5401e5..862b32702d29 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -199,14 +199,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) return msic; } -static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type) -{ - if (!find_msi_translator(dev)) - return -ENODEV; - - return 0; -} - static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) { struct device_node *dn; @@ -416,7 +408,6 @@ static int axon_msi_probe(struct platform_device *device) ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; - ppc_md.msi_check_device = axon_msi_check_device; axon_msi_debug_setup(dn, msic); diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index b854b57ed5e1..b45c49249a5d 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -46,29 +46,21 @@ //#define cfg_dbg(fmt...) printk(fmt) #ifdef CONFIG_PCI_MSI -static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type) -{ - struct pci_controller *hose = pci_bus_to_host(pdev->bus); - struct pnv_phb *phb = hose->private_data; - struct pci_dn *pdn = pci_get_pdn(pdev); - - if (pdn && pdn->force_32bit_msi && !phb->msi32_support) - return -ENODEV; - - return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV; -} - static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { struct pci_controller *hose = pci_bus_to_host(pdev->bus); struct pnv_phb *phb = hose->private_data; + struct pci_dn *pdn = pci_get_pdn(pdev); struct msi_desc *entry; struct msi_msg msg; int hwirq; unsigned int virq; int rc; - if (WARN_ON(!phb)) + if (WARN_ON(!phb) || !phb->msi_bmp.bitmap) + return -ENODEV; + + if (pdn && pdn->force_32bit_msi && !phb->msi32_support) return -ENODEV; list_for_each_entry(entry, &pdev->msi_list, list) { @@ -860,7 +852,6 @@ void __init pnv_pci_init(void) /* Configure MSIs */ #ifdef CONFIG_PCI_MSI - ppc_md.msi_check_device = pnv_msi_check_device; ppc_md.setup_msi_irqs = pnv_setup_msi_irqs; ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs; #endif diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 18ff4626d74e..e68c196def1a 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -336,26 +336,6 @@ static int msi_quota_for_device(struct pci_dev *dev, int request) return request; } -static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - int quota, rc; - - if (type == PCI_CAP_ID_MSIX) - rc = check_req_msix(pdev, nvec); - else - rc = check_req_msi(pdev, nvec); - - if (rc) - return rc; - - quota = msi_quota_for_device(pdev, nvec); - - if (quota && quota < nvec) - return quota; - - return 0; -} - static int check_msix_entries(struct pci_dev *pdev) { struct msi_desc *entry; @@ -397,15 +377,24 @@ static void rtas_hack_32bit_msi_gen2(struct pci_dev *pdev) static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) { struct pci_dn *pdn; - int hwirq, virq, i, rc; + int hwirq, virq, i, quota, rc; struct msi_desc *entry; struct msi_msg msg; int nvec = nvec_in; int use_32bit_msi_hack = 0; - pdn = pci_get_pdn(pdev); - if (!pdn) - return -ENODEV; + if (type == PCI_CAP_ID_MSIX) + rc = check_req_msix(pdev, nvec); + else + rc = check_req_msi(pdev, nvec); + + if (rc) + return rc; + + quota = msi_quota_for_device(pdev, nvec); + + if (quota && quota < nvec) + return quota; if (type == PCI_CAP_ID_MSIX && check_msix_entries(pdev)) return -EINVAL; @@ -416,12 +405,14 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) */ if (type == PCI_CAP_ID_MSIX) { int m = roundup_pow_of_two(nvec); - int quota = msi_quota_for_device(pdev, m); + quota = msi_quota_for_device(pdev, m); if (quota >= m) nvec = m; } + pdn = pci_get_pdn(pdev); + /* * Try the new more explicit firmware interface, if that fails fall * back to the old interface. The old interface is known to never @@ -526,7 +517,6 @@ static int rtas_msi_init(void) WARN_ON(ppc_md.setup_msi_irqs); ppc_md.setup_msi_irqs = rtas_setup_msi_irqs; ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs; - ppc_md.msi_check_device = rtas_msi_check_device; WARN_ON(ppc_md.pci_irq_fixup); ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 77efbaec7b9c..b32e79dbef4f 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -109,14 +109,6 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data) return 0; } -static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - if (type == PCI_CAP_ID_MSIX) - pr_debug("fslmsi: MSI-X untested, trying anyway.\n"); - - return 0; -} - static void fsl_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; @@ -173,6 +165,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) struct msi_msg msg; struct fsl_msi *msi_data; + if (type == PCI_CAP_ID_MSIX) + pr_debug("fslmsi: MSI-X untested, trying anyway.\n"); + /* * If the PCI node has an fsl,msi property, then we need to use it * to find the specific MSI. @@ -527,7 +522,6 @@ static int fsl_of_msi_probe(struct platform_device *dev) if (!ppc_md.setup_msi_irqs) { ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; - ppc_md.msi_check_device = fsl_msi_check_device; } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) { dev_err(&dev->dev, "Different MSI driver already installed!\n"); err = -ENODEV; diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c index 38e62382070c..15dccd35fa11 100644 --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c @@ -63,14 +63,6 @@ static struct irq_chip mpic_pasemi_msi_chip = { .name = "PASEMI-MSI", }; -static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - if (type == PCI_CAP_ID_MSIX) - pr_debug("pasemi_msi: MSI-X untested, trying anyway\n"); - - return 0; -} - static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; @@ -97,6 +89,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) struct msi_msg msg; int hwirq; + if (type == PCI_CAP_ID_MSIX) + pr_debug("pasemi_msi: MSI-X untested, trying anyway\n"); pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n", pdev, nvec, type); @@ -169,7 +163,6 @@ int mpic_pasemi_msi_init(struct mpic *mpic) WARN_ON(ppc_md.setup_msi_irqs); ppc_md.setup_msi_irqs = pasemi_msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs; - ppc_md.msi_check_device = pasemi_msi_check_device; return 0; } diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 9a7aa0ed9c1c..623d7fba15b4 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -105,22 +105,6 @@ static u64 find_u4_magic_addr(struct pci_dev *pdev, unsigned int hwirq) return 0; } -static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - if (type == PCI_CAP_ID_MSIX) - pr_debug("u3msi: MSI-X untested, trying anyway.\n"); - - /* If we can't find a magic address then MSI ain't gonna work */ - if (find_ht_magic_addr(pdev, 0) == 0 && - find_u4_magic_addr(pdev, 0) == 0) { - pr_debug("u3msi: no magic address found for %s\n", - pci_name(pdev)); - return -ENXIO; - } - - return 0; -} - static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; @@ -146,6 +130,17 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) u64 addr; int hwirq; + if (type == PCI_CAP_ID_MSIX) + pr_debug("u3msi: MSI-X untested, trying anyway.\n"); + + /* If we can't find a magic address then MSI ain't gonna work */ + if (find_ht_magic_addr(pdev, 0) == 0 && + find_u4_magic_addr(pdev, 0) == 0) { + pr_debug("u3msi: no magic address found for %s\n", + pci_name(pdev)); + return -ENXIO; + } + list_for_each_entry(entry, &pdev->msi_list, list) { hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1); if (hwirq < 0) { @@ -202,7 +197,6 @@ int mpic_u3msi_init(struct mpic *mpic) WARN_ON(ppc_md.setup_msi_irqs); ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs; ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs; - ppc_md.msi_check_device = u3msi_msi_check_device; return 0; } diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c index 11c888416f0a..a6a4dbda9078 100644 --- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c @@ -44,6 +44,12 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) int irq, hwirq; u64 addr; + /* We don't support MSI-X */ + if (type == PCI_CAP_ID_MSIX) { + pr_debug("%s: MSI-X not supported.\n", __func__); + return -EINVAL; + } + list_for_each_entry(entry, &dev->msi_list, list) { irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1); if (irq < 0) { @@ -117,17 +123,6 @@ static void hsta_teardown_msi_irqs(struct pci_dev *dev) } } -static int hsta_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - /* We don't support MSI-X */ - if (type == PCI_CAP_ID_MSIX) { - pr_debug("%s: MSI-X not supported.\n", __func__); - return -EINVAL; - } - - return 0; -} - static int hsta_msi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -178,7 +173,6 @@ static int hsta_msi_probe(struct platform_device *pdev) ppc_md.setup_msi_irqs = hsta_setup_msi_irqs; ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs; - ppc_md.msi_check_device = hsta_msi_check_device; return 0; out2: diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c index 43948da837a7..22b5200636e7 100644 --- a/arch/powerpc/sysdev/ppc4xx_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_msi.c @@ -85,8 +85,12 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) struct msi_desc *entry; struct ppc4xx_msi *msi_data = &ppc4xx_msi; - msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int), - GFP_KERNEL); + dev_dbg(&dev->dev, "PCIE-MSI:%s called. vec %x type %d\n", + __func__, nvec, type); + if (type == PCI_CAP_ID_MSIX) + pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n"); + + msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int), GFP_KERNEL); if (!msi_data->msi_virqs) return -ENOMEM; @@ -134,16 +138,6 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev) } } -static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type) -{ - dev_dbg(&pdev->dev, "PCIE-MSI:%s called. vec %x type %d\n", - __func__, nvec, type); - if (type == PCI_CAP_ID_MSIX) - pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n"); - - return 0; -} - static int ppc4xx_setup_pcieh_hw(struct platform_device *dev, struct resource res, struct ppc4xx_msi *msi) { @@ -259,7 +253,6 @@ static int ppc4xx_msi_probe(struct platform_device *dev) ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs; ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs; - ppc_md.msi_check_device = ppc4xx_msi_check_device; return err; error_out: From 3930115e0dd67f61b3b1882c7a34d0baeff1bb4c Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Sun, 7 Sep 2014 20:57:54 +0200 Subject: [PATCH 02/12] irqchip: armada-370-xp: Remove arch_msi_check_device() Move MSI checks from arch_msi_check_device() to arch_setup_msi_irqs(). This makes the code more compact and allows removing arch_msi_check_device() from generic MSI code. Tested-by: Thomas Petazzoni Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas Acked-by: Jason Cooper CC: Thomas Gleixner --- drivers/irqchip/irq-armada-370-xp.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 574aba0eba4e..df60eabaf49e 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -136,6 +136,10 @@ static int armada_370_xp_setup_msi_irq(struct msi_chip *chip, struct msi_msg msg; int virq, hwirq; + /* We support MSI, but not MSI-X */ + if (desc->msi_attrib.is_msix) + return -EINVAL; + hwirq = armada_370_xp_alloc_msi(); if (hwirq < 0) return hwirq; @@ -166,15 +170,6 @@ static void armada_370_xp_teardown_msi_irq(struct msi_chip *chip, armada_370_xp_free_msi(hwirq); } -static int armada_370_xp_check_msi_device(struct msi_chip *chip, struct pci_dev *dev, - int nvec, int type) -{ - /* We support MSI, but not MSI-X */ - if (type == PCI_CAP_ID_MSI) - return 0; - return -EINVAL; -} - static struct irq_chip armada_370_xp_msi_irq_chip = { .name = "armada_370_xp_msi_irq", .irq_enable = unmask_msi_irq, @@ -213,7 +208,6 @@ static int armada_370_xp_msi_init(struct device_node *node, msi_chip->setup_irq = armada_370_xp_setup_msi_irq; msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq; - msi_chip->check_device = armada_370_xp_check_msi_device; msi_chip->of_node = node; armada_370_xp_msi_domain = From ad975ebad4c3ce8dcc7d0bb4db26ea5aca4cfc99 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 23 Sep 2014 12:39:54 -0600 Subject: [PATCH 03/12] PCI/MSI: Remove arch_msi_check_device() No architectures implement arch_msi_check_device() or the struct msi_chip .check_device() method, so remove them. Remove the "type" parameter to pci_msi_check_device() because it was only used to call arch_msi_check_device() and is no longer needed. [bhelgaas: changelog, split to separate patch] Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 21 +++------------------ include/linux/msi.h | 3 --- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 5a40516444f3..db21b77a03a5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -56,16 +56,6 @@ void __weak arch_teardown_msi_irq(unsigned int irq) chip->teardown_irq(chip, irq); } -int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type) -{ - struct msi_chip *chip = dev->bus->msi; - - if (!chip || !chip->check_device) - return 0; - - return chip->check_device(chip, dev, nvec, type); -} - int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { struct msi_desc *entry; @@ -815,10 +805,9 @@ static int msix_capability_init(struct pci_dev *dev, * to determine if MSI/-X are supported for the device. If MSI/-X is * supported return 0, else return an error code. **/ -static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type) +static int pci_msi_check_device(struct pci_dev *dev, int nvec) { struct pci_bus *bus; - int ret; /* MSI must be globally enabled and supported by the device */ if (!pci_msi_enable || !dev || dev->no_msi) @@ -843,10 +832,6 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) return -EINVAL; - ret = arch_msi_check_device(dev, nvec, type); - if (ret) - return ret; - return 0; } @@ -952,7 +937,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) if (!entries || !dev->msix_cap || dev->current_state != PCI_D0) return -EINVAL; - status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); + status = pci_msi_check_device(dev, nvec); if (status) return status; @@ -1086,7 +1071,7 @@ int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) nvec = maxvec; do { - rc = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI); + rc = pci_msi_check_device(dev, nvec); if (rc < 0) { return rc; } else if (rc > 0) { diff --git a/include/linux/msi.h b/include/linux/msi.h index 8103f32f6d87..dbf7cc932444 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -60,7 +60,6 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); void arch_teardown_msi_irq(unsigned int irq); int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); void arch_teardown_msi_irqs(struct pci_dev *dev); -int arch_msi_check_device(struct pci_dev* dev, int nvec, int type); void arch_restore_msi_irqs(struct pci_dev *dev); void default_teardown_msi_irqs(struct pci_dev *dev); @@ -77,8 +76,6 @@ struct msi_chip { int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev, struct msi_desc *desc); void (*teardown_irq)(struct msi_chip *chip, unsigned int irq); - int (*check_device)(struct msi_chip *chip, struct pci_dev *dev, - int nvec, int type); }; #endif /* LINUX_MSI_H */ From 27e20603c54ba633ed259284d006275f13c9f95b Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 23 Sep 2014 14:25:11 -0600 Subject: [PATCH 04/12] PCI/MSI: Move D0 check into pci_msi_check_device() Both callers of pci_msi_check_device() check that the device is in D0 state, so move the check from the callers into pci_msi_check_device() itself. In pci_enable_msi_range(), note that pci_msi_check_device() never returns a positive value any more, so the loop that called it until it returns zero or negative is no longer necessary. [bhelgaas: changelog, split to separate patch] Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index db21b77a03a5..338b027ea65f 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -810,7 +810,10 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec) struct pci_bus *bus; /* MSI must be globally enabled and supported by the device */ - if (!pci_msi_enable || !dev || dev->no_msi) + if (!pci_msi_enable) + return -EINVAL; + + if (!dev || dev->no_msi || dev->current_state != PCI_D0) return -EINVAL; /* @@ -934,13 +937,13 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) int status, nr_entries; int i, j; - if (!entries || !dev->msix_cap || dev->current_state != PCI_D0) - return -EINVAL; - status = pci_msi_check_device(dev, nvec); if (status) return status; + if (!entries) + return -EINVAL; + nr_entries = pci_msix_vec_count(dev); if (nr_entries < 0) return nr_entries; @@ -1047,8 +1050,9 @@ int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) int nvec; int rc; - if (dev->current_state != PCI_D0) - return -EINVAL; + rc = pci_msi_check_device(dev, minvec); + if (rc) + return rc; WARN_ON(!!dev->msi_enabled); @@ -1070,17 +1074,6 @@ int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) else if (nvec > maxvec) nvec = maxvec; - do { - rc = pci_msi_check_device(dev, nvec); - if (rc < 0) { - return rc; - } else if (rc > 0) { - if (rc < minvec) - return -ENOSPC; - nvec = rc; - } - } while (rc); - do { rc = msi_capability_init(dev, nvec); if (rc < 0) { From a06cd74cefe754341f747ddc4cf7b0058fa9bff8 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 23 Sep 2014 12:45:58 -0600 Subject: [PATCH 05/12] PCI/MSI: Rename pci_msi_check_device() to pci_msi_supported() Rename pci_msi_check_device() to pci_msi_supported() for clarity. Note that pci_msi_supported() returns true if MSI/MSI-X is supported, so code like: if (pci_msi_supported(...)) reads naturally. [bhelgaas: changelog, split to separate patch, reverse sense] Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 338b027ea65f..5f1e5dc994cf 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -796,25 +796,24 @@ static int msix_capability_init(struct pci_dev *dev, } /** - * pci_msi_check_device - check whether MSI may be enabled on a device + * 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 ? - * @type: are we checking for MSI or MSI-X ? * * 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 0, else return an error code. + * supported return 1, else return 0. **/ -static int pci_msi_check_device(struct pci_dev *dev, int nvec) +static int pci_msi_supported(struct pci_dev *dev, int nvec) { struct pci_bus *bus; /* MSI must be globally enabled and supported by the device */ if (!pci_msi_enable) - return -EINVAL; + return 0; if (!dev || dev->no_msi || dev->current_state != PCI_D0) - return -EINVAL; + return 0; /* * You can't ask to have 0 or less MSIs configured. @@ -822,7 +821,7 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec) * b) the list manipulation code assumes nvec >= 1. */ if (nvec < 1) - return -ERANGE; + return 0; /* * Any bridge which does NOT route MSI transactions from its @@ -833,9 +832,9 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec) */ for (bus = dev->bus; bus; bus = bus->parent) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) - return -EINVAL; + return 0; - return 0; + return 1; } /** @@ -937,9 +936,8 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) int status, nr_entries; int i, j; - status = pci_msi_check_device(dev, nvec); - if (status) - return status; + if (!pci_msi_supported(dev, nvec)) + return -EINVAL; if (!entries) return -EINVAL; @@ -1050,9 +1048,8 @@ int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) int nvec; int rc; - rc = pci_msi_check_device(dev, minvec); - if (rc) - return rc; + if (!pci_msi_supported(dev, minvec)) + return -EINVAL; WARN_ON(!!dev->msi_enabled); From 81052769e48609525c452d8f078a5786b673e178 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 13:27:22 +0800 Subject: [PATCH 06/12] PCI/MSI: Remove unused kobject from struct msi_desc After commit 1c51b50c2995 ("PCI/MSI: Export MSI mode using attributes, not kobjects"), the kobject in struct msi_desc is unused. Remove the unused struct kobject from struct msi_desc. [bhelgaas: changelog] Fixes: 1c51b50c2995 ("PCI/MSI: Export MSI mode using attributes, not kobjects") Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 11 ----------- include/linux/msi.h | 2 -- 2 files changed, 13 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 5f1e5dc994cf..97d6ef67a3c8 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -374,17 +374,6 @@ static void free_msi_irqs(struct pci_dev *dev) iounmap(entry->mask_base); } - /* - * Its possible that we get into this path - * When populate_msi_sysfs fails, which means the entries - * were not registered with sysfs. In that case don't - * unregister them. - */ - if (entry->kobj.parent) { - kobject_del(&entry->kobj); - kobject_put(&entry->kobj); - } - list_del(&entry->list); kfree(entry); } diff --git a/include/linux/msi.h b/include/linux/msi.h index dbf7cc932444..5a91c2d58ffd 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -47,8 +47,6 @@ struct msi_desc { /* Last set MSI message */ struct msi_msg msg; - - struct kobject kobj; }; /* From 48c3c38f003c25d50a09d3da558667c5ecd530aa Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 11:02:42 -0600 Subject: [PATCH 07/12] PCI/MSI: Remove "pos" from the struct msi_desc msi_attrib "msi_attrib.pos" is only used for MSI (not MSI-X), and we already cache the MSI capability offset in "dev->msi_cap". Remove "pos" from the struct msi_attrib and use "dev->msi_cap" directly. [bhelgaas: changelog, fix whitespace] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- arch/mips/pci/msi-octeon.c | 6 ++---- drivers/pci/host/pcie-designware.c | 5 ++--- drivers/pci/msi.c | 2 -- include/linux/msi.h | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index ab0c5d14c6f7..63bbe07a1ccd 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -73,8 +73,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) * wants. Most devices only want 1, which will give * configured_private_bits and request_private_bits equal 0. */ - pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, - &control); + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); /* * If the number of private bits has been configured then use @@ -176,8 +175,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) /* Update the number of IRQs the device has available to it */ control &= ~PCI_MSI_FLAGS_QSIZE; control |= request_private_bits << 4; - pci_write_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, - control); + pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); irq_set_msi_desc(irq, desc); write_msi_msg(irq, &msg); diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 52bd3a143563..fa2fa459ed90 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -355,9 +355,8 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, return -EINVAL; } - pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS, - &msg_ctr); - msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4; + pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &msg_ctr); + msgvec = (msg_ctr & PCI_MSI_FLAGS_QSIZE) >> 4; if (msgvec == 0) msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1; if (msgvec > 5) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 97d6ef67a3c8..40699a2041b5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -574,7 +574,6 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev) entry->msi_attrib.entry_nr = 0; entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT); entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ - entry->msi_attrib.pos = dev->msi_cap; entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1; if (control & PCI_MSI_FLAGS_64BIT) @@ -678,7 +677,6 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, entry->msi_attrib.is_64 = 1; entry->msi_attrib.entry_nr = entries[i].entry; entry->msi_attrib.default_irq = dev->irq; - entry->msi_attrib.pos = dev->msix_cap; entry->mask_base = base; list_add_tail(&entry->list, &dev->msi_list); diff --git a/include/linux/msi.h b/include/linux/msi.h index 5a91c2d58ffd..44f4746d033b 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -29,7 +29,6 @@ struct msi_desc { __u8 multi_cap : 3; /* log2 num of messages supported */ __u8 maskbit : 1; /* mask-pending bit supported ? */ __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ - __u8 pos; /* Location of the msi capability */ __u16 entry_nr; /* specific enabled entry */ unsigned default_irq; /* default pre-assigned irq */ } msi_attrib; From 468ff15a3ab98ed7153c29c68229ffb97f15a251 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 13:27:24 +0800 Subject: [PATCH 08/12] PCI/MSI: Add "msi_bus" sysfs MSI/MSI-X control for endpoints The "msi_bus" sysfs file for bridges sets a bus flag to allow or disallow future driver requests for MSI or MSI-X. Previously, the sysfs file existed for endpoints but did nothing. Add "msi_bus" support for endpoints, so an administrator can prevent the use of MSI and MSI-X for individual devices. Note that as for bridges, these changes only affect future driver requests for MSI or MSI-X, so drivers may need to be reloaded. Add documentation for the "msi_bus" sysfs file. [bhelgaas: changelog, comments, add "subordinate", add endpoint printk, rework bus_flags setting, make bus_flags printk unconditional] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- Documentation/ABI/testing/sysfs-bus-pci | 10 +++++++ drivers/pci/pci-sysfs.c | 39 ++++++++++++------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 6615fda0abfb..ee6c04036492 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -65,6 +65,16 @@ Description: force a rescan of all PCI buses in the system, and re-discover previously removed devices. +What: /sys/bus/pci/devices/.../msi_bus +Date: September 2014 +Contact: Linux PCI developers +Description: + Writing a zero value to this attribute disallows MSI and + MSI-X for any future drivers of the device. If the device + is a bridge, MSI and MSI-X will be disallowed for future + drivers of all child devices under the bridge. Drivers + must be reloaded for the new setting to take effect. + What: /sys/bus/pci/devices/.../msi_irqs/ Date: September, 2011 Contact: Neil Horman diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 9ff0a901ecf7..dbf63e23988d 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -250,46 +250,45 @@ static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); + struct pci_bus *subordinate = pdev->subordinate; - if (!pdev->subordinate) - return 0; - - return sprintf(buf, "%u\n", - !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)); + return sprintf(buf, "%u\n", subordinate ? + !(subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) + : !pdev->no_msi); } static ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); + struct pci_bus *subordinate = pdev->subordinate; unsigned long val; if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; - /* - * Bad things may happen if the no_msi flag is changed - * while drivers are loaded. - */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; /* - * Maybe devices without subordinate buses shouldn't have this - * attribute in the first place? + * "no_msi" and "bus_flags" only affect what happens when a driver + * requests MSI or MSI-X. They don't affect any drivers that have + * already requested MSI or MSI-X. */ - if (!pdev->subordinate) + if (!subordinate) { + pdev->no_msi = !val; + dev_info(&pdev->dev, "MSI/MSI-X %s for future drivers\n", + val ? "allowed" : "disallowed"); return count; - - /* Is the flag going to change, or keep the value it already had? */ - if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^ - !!val) { - pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI; - - dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI, bad things could happen\n", - val ? "" : " not"); } + if (val) + subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI; + else + subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; + + dev_info(&subordinate->dev, "MSI/MSI-X %s for future drivers of devices on this bus\n", + val ? "allowed" : "disallowed"); return count; } static DEVICE_ATTR_RW(msi_bus); From 2b260085e466c345e78f23b1c9ad1d123d509ef8 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 13:27:25 +0800 Subject: [PATCH 09/12] PCI/MSI: Use __get_cached_msi_msg() instead of get_cached_msi_msg() Both callers of get_cached_msi_msg() start with a struct irq_data pointer, look up the corresponding IRQ number, and pass it to get_cached_msi_msg(), which then uses irq_get_irq_data() to look up the struct irq_data again to call __get_cached_msi_msg(). Since we already have the struct irq_data, call __get_cached_msi_msg() directly and skip the lookup work done by get_cached_msi_msg(). No functional change. [bhelgaas: changelog] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas CC: Tony Luck CC: linux-ia64@vger.kernel.org --- arch/ia64/kernel/msi_ia64.c | 2 +- arch/ia64/sn/kernel/msi_sn.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index c430f9198d1b..8c3730c3c63d 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c @@ -23,7 +23,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata, if (irq_prepare_move(irq, cpu)) return -1; - get_cached_msi_msg(irq, &msg); + __get_cached_msi_msg(idata->msi_desc, &msg); addr = msg.address_lo; addr &= MSI_ADDR_DEST_ID_MASK; diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index afc58d2799ad..446e7799928c 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c @@ -175,8 +175,8 @@ static int sn_set_msi_irq_affinity(struct irq_data *data, * Release XIO resources for the old MSI PCI address */ - get_cached_msi_msg(irq, &msg); - sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; + __get_cached_msi_msg(data->msi_desc, &msg); + sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; pdev = sn_pdev->pdi_linux_pcidev; provider = SN_PCIDEV_BUSPROVIDER(pdev); From 1e8f4cc82eded0c3c97ef6e2f119782e42deda35 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Wed, 24 Sep 2014 11:09:45 +0800 Subject: [PATCH 10/12] MSI/powerpc: Use __read_msi_msg() instead of read_msi_msg() rtas_setup_msi_irqs() already has the struct msi_desc pointer required by __read_msi_msg(), so call it directly instead of having read_msi_msg() look it up from the IRQ. No functional change. [bhelgaas: changelog] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Acked-by: Michael Ellerman CC: Benjamin Herrenschmidt CC: linuxppc-dev@lists.ozlabs.org --- arch/powerpc/platforms/pseries/msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index e68c196def1a..8ab5add4ac82 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -476,7 +476,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) irq_set_msi_desc(virq, entry); /* Read config space back so we can restore after reset */ - read_msi_msg(virq, &msg); + __read_msi_msg(entry, &msg); entry->msg = msg; } From 56b72b40957947f7c08771f030102351d4c906df Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Mon, 29 Sep 2014 18:35:16 -0600 Subject: [PATCH 11/12] PCI/MSI: Use __write_msi_msg() instead of write_msi_msg() default_restore_msi_irq() already has the struct msi_desc pointer required by __write_msi_msg(), so call it directly instead of having write_msi_msg() look it up from the IRQ. No functional change. [bhelgaas: split into separate patch] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 40699a2041b5..6413c5a08373 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -120,7 +120,7 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq) } if (entry) - write_msi_msg(irq, &entry->msg); + __write_msi_msg(entry, &entry->msg); } void __weak arch_restore_msi_irqs(struct pci_dev *dev) From 5ec094057c7df5ff80f5e7fe282f47ad205fb976 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 23 Sep 2014 14:38:28 -0600 Subject: [PATCH 12/12] PCI/MSI: Remove unnecessary temporary variable The only use of "status" is to hold a value which is immediately returned, so just return and remove the variable directly. Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 6413c5a08373..2f7c92c4757a 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -920,7 +920,7 @@ EXPORT_SYMBOL(pci_msix_vec_count); **/ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) { - int status, nr_entries; + int nr_entries; int i, j; if (!pci_msi_supported(dev, nvec)) @@ -951,8 +951,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) dev_info(&dev->dev, "can't enable MSI-X (MSI IRQ already assigned)\n"); return -EINVAL; } - status = msix_capability_init(dev, entries, nvec); - return status; + return msix_capability_init(dev, entries, nvec); } EXPORT_SYMBOL(pci_enable_msix);