aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/host/vmd.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-15 15:46:48 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-15 15:46:48 -0500
commit0ab7b12c49b6fbf2d4d0381374b82935f949be5f (patch)
tree7a1b48e644638c6a0a275e65715d8db37d20c88e /drivers/pci/host/vmd.c
parenta9a16a6d136593c9e6f72e481b2b86ae1d8d1fce (diff)
parentb08d2e61a6f9ebf5210a047868362a5a4ff37144 (diff)
Merge tag 'pci-v4.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas: "PCI changes: - add support for PCI on ARM64 boxes with ACPI. We already had this for theoretical spec-compliant hardware; now we're adding quirks for the actual hardware (Cavium, HiSilicon, Qualcomm, X-Gene) - add runtime PM support for hotplug ports - enable runtime suspend for Intel UHCI that uses platform-specific wakeup signaling - add yet another host bridge registration interface. We hope this is extensible enough to subsume the others - expose device revision in sysfs for DRM - to avoid device conflicts, make sure any VF BAR updates are done before enabling the VF - avoid unnecessary link retrains for ASPM - allow INTx masking on Mellanox devices that support it - allow access to non-standard VPD for Chelsio devices - update Broadcom iProc support for PAXB v2, PAXC v2, inbound DMA, etc - update Rockchip support for max-link-speed - add NVIDIA Tegra210 support - add Layerscape LS1046a support - update R-Car compatibility strings - add Qualcomm MSM8996 support - remove some uninformative bootup messages" * tag 'pci-v4.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (115 commits) PCI: Enable access to non-standard VPD for Chelsio devices (cxgb3) PCI: Expand "VPD access disabled" quirk message PCI: pciehp: Remove loading message PCI: hotplug: Remove hotplug core message PCI: Remove service driver load/unload messages PCI/AER: Log AER IRQ when claiming Root Port PCI/AER: Log errors with PCI device, not PCIe service device PCI/AER: Remove unused version macros PCI/PME: Log PME IRQ when claiming Root Port PCI/PME: Drop unused support for PMEs from Root Complex Event Collectors PCI: Move config space size macros to pci_regs.h x86/platform/intel-mid: Constify mid_pci_platform_pm PCI/ASPM: Don't retrain link if ASPM not possible PCI: iproc: Skip check for legacy IRQ on PAXC buses PCI: pciehp: Leave power indicator on when enabling already-enabled slot PCI: pciehp: Prioritize data-link event over presence detect PCI: rcar: Add gen3 fallback compatibility string for pcie-rcar PCI: rcar: Use gen2 fallback compatibility last PCI: rcar-gen2: Use gen2 fallback compatibility last PCI: rockchip: Move the deassert of pm/aclk/pclk after phy_init() ..
Diffstat (limited to 'drivers/pci/host/vmd.c')
-rw-r--r--drivers/pci/host/vmd.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c
index 37e29b580be3..18ef1a93c10a 100644
--- a/drivers/pci/host/vmd.c
+++ b/drivers/pci/host/vmd.c
@@ -19,6 +19,7 @@
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/msi.h> 20#include <linux/msi.h>
21#include <linux/pci.h> 21#include <linux/pci.h>
22#include <linux/srcu.h>
22#include <linux/rculist.h> 23#include <linux/rculist.h>
23#include <linux/rcupdate.h> 24#include <linux/rcupdate.h>
24 25
@@ -39,7 +40,6 @@ static DEFINE_RAW_SPINLOCK(list_lock);
39/** 40/**
40 * struct vmd_irq - private data to map driver IRQ to the VMD shared vector 41 * struct vmd_irq - private data to map driver IRQ to the VMD shared vector
41 * @node: list item for parent traversal. 42 * @node: list item for parent traversal.
42 * @rcu: RCU callback item for freeing.
43 * @irq: back pointer to parent. 43 * @irq: back pointer to parent.
44 * @enabled: true if driver enabled IRQ 44 * @enabled: true if driver enabled IRQ
45 * @virq: the virtual IRQ value provided to the requesting driver. 45 * @virq: the virtual IRQ value provided to the requesting driver.
@@ -49,7 +49,6 @@ static DEFINE_RAW_SPINLOCK(list_lock);
49 */ 49 */
50struct vmd_irq { 50struct vmd_irq {
51 struct list_head node; 51 struct list_head node;
52 struct rcu_head rcu;
53 struct vmd_irq_list *irq; 52 struct vmd_irq_list *irq;
54 bool enabled; 53 bool enabled;
55 unsigned int virq; 54 unsigned int virq;
@@ -58,11 +57,13 @@ struct vmd_irq {
58/** 57/**
59 * struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector 58 * struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector
60 * @irq_list: the list of irq's the VMD one demuxes to. 59 * @irq_list: the list of irq's the VMD one demuxes to.
60 * @srcu: SRCU struct for local synchronization.
61 * @count: number of child IRQs assigned to this vector; used to track 61 * @count: number of child IRQs assigned to this vector; used to track
62 * sharing. 62 * sharing.
63 */ 63 */
64struct vmd_irq_list { 64struct vmd_irq_list {
65 struct list_head irq_list; 65 struct list_head irq_list;
66 struct srcu_struct srcu;
66 unsigned int count; 67 unsigned int count;
67}; 68};
68 69
@@ -224,14 +225,14 @@ static void vmd_msi_free(struct irq_domain *domain,
224 struct vmd_irq *vmdirq = irq_get_chip_data(virq); 225 struct vmd_irq *vmdirq = irq_get_chip_data(virq);
225 unsigned long flags; 226 unsigned long flags;
226 227
227 synchronize_rcu(); 228 synchronize_srcu(&vmdirq->irq->srcu);
228 229
229 /* XXX: Potential optimization to rebalance */ 230 /* XXX: Potential optimization to rebalance */
230 raw_spin_lock_irqsave(&list_lock, flags); 231 raw_spin_lock_irqsave(&list_lock, flags);
231 vmdirq->irq->count--; 232 vmdirq->irq->count--;
232 raw_spin_unlock_irqrestore(&list_lock, flags); 233 raw_spin_unlock_irqrestore(&list_lock, flags);
233 234
234 kfree_rcu(vmdirq, rcu); 235 kfree(vmdirq);
235} 236}
236 237
237static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev, 238static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev,
@@ -646,11 +647,12 @@ static irqreturn_t vmd_irq(int irq, void *data)
646{ 647{
647 struct vmd_irq_list *irqs = data; 648 struct vmd_irq_list *irqs = data;
648 struct vmd_irq *vmdirq; 649 struct vmd_irq *vmdirq;
650 int idx;
649 651
650 rcu_read_lock(); 652 idx = srcu_read_lock(&irqs->srcu);
651 list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) 653 list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)
652 generic_handle_irq(vmdirq->virq); 654 generic_handle_irq(vmdirq->virq);
653 rcu_read_unlock(); 655 srcu_read_unlock(&irqs->srcu, idx);
654 656
655 return IRQ_HANDLED; 657 return IRQ_HANDLED;
656} 658}
@@ -696,6 +698,10 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
696 return -ENOMEM; 698 return -ENOMEM;
697 699
698 for (i = 0; i < vmd->msix_count; i++) { 700 for (i = 0; i < vmd->msix_count; i++) {
701 err = init_srcu_struct(&vmd->irqs[i].srcu);
702 if (err)
703 return err;
704
699 INIT_LIST_HEAD(&vmd->irqs[i].irq_list); 705 INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
700 err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i), 706 err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
701 vmd_irq, 0, "vmd", &vmd->irqs[i]); 707 vmd_irq, 0, "vmd", &vmd->irqs[i]);
@@ -714,12 +720,20 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
714 return 0; 720 return 0;
715} 721}
716 722
723static void vmd_cleanup_srcu(struct vmd_dev *vmd)
724{
725 int i;
726
727 for (i = 0; i < vmd->msix_count; i++)
728 cleanup_srcu_struct(&vmd->irqs[i].srcu);
729}
730
717static void vmd_remove(struct pci_dev *dev) 731static void vmd_remove(struct pci_dev *dev)
718{ 732{
719 struct vmd_dev *vmd = pci_get_drvdata(dev); 733 struct vmd_dev *vmd = pci_get_drvdata(dev);
720 734
721 vmd_detach_resources(vmd); 735 vmd_detach_resources(vmd);
722 pci_set_drvdata(dev, NULL); 736 vmd_cleanup_srcu(vmd);
723 sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); 737 sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
724 pci_stop_root_bus(vmd->bus); 738 pci_stop_root_bus(vmd->bus);
725 pci_remove_root_bus(vmd->bus); 739 pci_remove_root_bus(vmd->bus);
@@ -727,7 +741,7 @@ static void vmd_remove(struct pci_dev *dev)
727 irq_domain_remove(vmd->irq_domain); 741 irq_domain_remove(vmd->irq_domain);
728} 742}
729 743
730#ifdef CONFIG_PM 744#ifdef CONFIG_PM_SLEEP
731static int vmd_suspend(struct device *dev) 745static int vmd_suspend(struct device *dev)
732{ 746{
733 struct pci_dev *pdev = to_pci_dev(dev); 747 struct pci_dev *pdev = to_pci_dev(dev);