diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2016-12-12 11:25:13 -0600 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2016-12-12 11:25:13 -0600 |
commit | b08d2e61a6f9ebf5210a047868362a5a4ff37144 (patch) | |
tree | 52cfdc7952e50e492af6225c056dd58090eae4dd | |
parent | d34efd22acace472ad33887842117933ee631391 (diff) | |
parent | 42db500a551f97551a901e2258f84a60baf4edfc (diff) | |
download | linux-stable-b08d2e61a6f9ebf5210a047868362a5a4ff37144.tar.gz linux-stable-b08d2e61a6f9ebf5210a047868362a5a4ff37144.tar.bz2 linux-stable-b08d2e61a6f9ebf5210a047868362a5a4ff37144.zip |
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/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pci/host/vmd.c | 30 |
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 4 slots. config VMD - depends on PCI_MSI && X86_64 + depends on PCI_MSI && X86_64 && SRCU tristate "Intel Volume Management Device Driver" default N ---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 @@ #include <linux/module.h> #include <linux/msi.h> #include <linux/pci.h> +#include <linux/srcu.h> #include <linux/rculist.h> #include <linux/rcupdate.h> @@ -39,7 +40,6 @@ static DEFINE_RAW_SPINLOCK(list_lock); /** * struct vmd_irq - private data to map driver IRQ to the VMD shared vector * @node: list item for parent traversal. - * @rcu: RCU callback item for freeing. * @irq: back pointer to parent. * @enabled: true if driver enabled IRQ * @virq: the virtual IRQ value provided to the requesting driver. @@ -49,7 +49,6 @@ static DEFINE_RAW_SPINLOCK(list_lock); */ struct vmd_irq { struct list_head node; - struct rcu_head rcu; struct vmd_irq_list *irq; bool enabled; unsigned int virq; @@ -58,11 +57,13 @@ struct vmd_irq { /** * struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector * @irq_list: the list of irq's the VMD one demuxes to. + * @srcu: SRCU struct for local synchronization. * @count: number of child IRQs assigned to this vector; used to track * sharing. */ struct vmd_irq_list { struct list_head irq_list; + struct srcu_struct srcu; unsigned int count; }; @@ -224,14 +225,14 @@ static void vmd_msi_free(struct irq_domain *domain, struct vmd_irq *vmdirq = irq_get_chip_data(virq); unsigned long flags; - synchronize_rcu(); + synchronize_srcu(&vmdirq->irq->srcu); /* XXX: Potential optimization to rebalance */ raw_spin_lock_irqsave(&list_lock, flags); vmdirq->irq->count--; raw_spin_unlock_irqrestore(&list_lock, flags); - kfree_rcu(vmdirq, rcu); + kfree(vmdirq); } static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev, @@ -646,11 +647,12 @@ static irqreturn_t vmd_irq(int irq, void *data) { struct vmd_irq_list *irqs = data; struct vmd_irq *vmdirq; + int idx; - rcu_read_lock(); + idx = srcu_read_lock(&irqs->srcu); list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) generic_handle_irq(vmdirq->virq); - rcu_read_unlock(); + srcu_read_unlock(&irqs->srcu, idx); return IRQ_HANDLED; } @@ -696,6 +698,10 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENOMEM; for (i = 0; i < vmd->msix_count; i++) { + err = init_srcu_struct(&vmd->irqs[i].srcu); + if (err) + return err; + INIT_LIST_HEAD(&vmd->irqs[i].irq_list); err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i), 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) return 0; } +static void vmd_cleanup_srcu(struct vmd_dev *vmd) +{ + int i; + + for (i = 0; i < vmd->msix_count; i++) + cleanup_srcu_struct(&vmd->irqs[i].srcu); +} + static void vmd_remove(struct pci_dev *dev) { struct vmd_dev *vmd = pci_get_drvdata(dev); vmd_detach_resources(vmd); - pci_set_drvdata(dev, NULL); + vmd_cleanup_srcu(vmd); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_stop_root_bus(vmd->bus); pci_remove_root_bus(vmd->bus); @@ -727,7 +741,7 @@ static void vmd_remove(struct pci_dev *dev) irq_domain_remove(vmd->irq_domain); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int vmd_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); |