From ad975ebad4c3ce8dcc7d0bb4db26ea5aca4cfc99 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 23 Sep 2014 12:39:54 -0600 Subject: 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 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'drivers/pci') 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 @@ out_free: * 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) { -- cgit v1.2.3 From 27e20603c54ba633ed259284d006275f13c9f95b Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 23 Sep 2014 14:25:11 -0600 Subject: 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(-) (limited to 'drivers/pci') 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) { -- cgit v1.2.3 From a06cd74cefe754341f747ddc4cf7b0058fa9bff8 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 23 Sep 2014 12:45:58 -0600 Subject: 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(-) (limited to 'drivers/pci') 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 @@ out_free: } /** - * 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); -- cgit v1.2.3 From 81052769e48609525c452d8f078a5786b673e178 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 13:27:22 +0800 Subject: 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 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/pci') 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); } -- cgit v1.2.3 From 48c3c38f003c25d50a09d3da558667c5ecd530aa Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 11:02:42 -0600 Subject: 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 --- drivers/pci/host/pcie-designware.c | 5 ++--- drivers/pci/msi.c | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/pci') 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); -- cgit v1.2.3 From 468ff15a3ab98ed7153c29c68229ffb97f15a251 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 13:27:24 +0800 Subject: 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 --- drivers/pci/pci-sysfs.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/pci') 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); -- cgit v1.2.3 From 56b72b40957947f7c08771f030102351d4c906df Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Mon, 29 Sep 2014 18:35:16 -0600 Subject: 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(-) (limited to 'drivers/pci') 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) -- cgit v1.2.3 From 5ec094057c7df5ff80f5e7fe282f47ad205fb976 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 23 Sep 2014 14:38:28 -0600 Subject: 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(-) (limited to 'drivers/pci') 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); -- cgit v1.2.3