aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2016-12-12 12:25:13 -0500
committerBjorn Helgaas <bhelgaas@google.com>2016-12-12 12:25:13 -0500
commitb08d2e61a6f9ebf5210a047868362a5a4ff37144 (patch)
tree52cfdc7952e50e492af6225c056dd58090eae4dd
parentd34efd22acace472ad33887842117933ee631391 (diff)
parent42db500a551f97551a901e2258f84a60baf4edfc (diff)
Merge branch 'pci/host-vmd' into next
* pci/host-vmd: PCI: vmd: Fix suspend handlers defined-but-not-used warning PCI: vmd: Use SRCU as a local RCU to prevent delaying global RCU PCI: vmd: Remove unnecessary pci_set_drvdata()
-rw-r--r--drivers/pci/host/Kconfig2
-rw-r--r--drivers/pci/host/vmd.c30
2 files changed, 23 insertions, 9 deletions
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 117130968b80..898d2c48239c 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -288,7 +288,7 @@ config PCIE_ROCKCHIP
288 4 slots. 288 4 slots.
289 289
290config VMD 290config VMD
291 depends on PCI_MSI && X86_64 291 depends on PCI_MSI && X86_64 && SRCU
292 tristate "Intel Volume Management Device Driver" 292 tristate "Intel Volume Management Device Driver"
293 default N 293 default N
294 ---help--- 294 ---help---
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);