From 5b23e8fa46ca037e0f61df919e8a08659c0e7640 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:04:44 +0000 Subject: [PATCH 1/3] PCI: vmd: Remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Wei Yongjun Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/host/vmd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c index 37e29b580be3..6614b3552b9c 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/host/vmd.c @@ -719,7 +719,6 @@ 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); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_stop_root_bus(vmd->bus); pci_remove_root_bus(vmd->bus); From 3906b91844d603153c094f636205ec9aa5454b2f Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Fri, 11 Nov 2016 16:08:45 -0700 Subject: [PATCH 2/3] PCI: vmd: Use SRCU as a local RCU to prevent delaying global RCU SRCU lets synchronize_srcu() depend on VMD-local RCU primitives, preventing long delays from locking up RCU in other systems. VMD performs a synchronize when removing a device, but will hit all IRQ lists if the device uses all VMD vectors. This patch will not help VMD's RCU synchronization, but will isolate the read side delays to the VMD subsystem. Additionally, the use of SRCU in VMD's ISR will keep it isolated from any other RCU waiters in the rest of the system. Tested using concurrent FIO and NVMe resets: [global] rw=read bs=4k direct=1 ioengine=libaio iodepth=32 norandommap timeout=300 runtime=1000000000 [nvme0] cpus_allowed=0-63 numjobs=8 filename=/dev/nvme0n1 [nvme1] cpus_allowed=0-63 numjobs=8 filename=/dev/nvme1n1 while (true) do for i in /sys/class/nvme/nvme*; do echo "Resetting ${i##*/}" echo 1 > $i/reset_controller; sleep 5 done; done Signed-off-by: Jon Derrick Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/host/Kconfig | 2 +- drivers/pci/host/vmd.c | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index d7e7c0a827c3..e020359b09bc 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -286,7 +286,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 6614b3552b9c..6c5b7fd9f0c5 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/host/vmd.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -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,11 +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); + vmd_cleanup_srcu(vmd); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_stop_root_bus(vmd->bus); pci_remove_root_bus(vmd->bus); From 42db500a551f97551a901e2258f84a60baf4edfc Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 26 Nov 2016 19:29:57 +0100 Subject: [PATCH 3/3] PCI: vmd: Fix suspend handlers defined-but-not-used warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warnings: drivers/pci/host/vmd.c:731:12: warning: ‘vmd_suspend’ defined but not used [-Wunused-function] static int vmd_suspend(struct device *dev) ^ drivers/pci/host/vmd.c:739:12: warning: ‘vmd_resume’ defined but not used [-Wunused-function] static int vmd_resume(struct device *dev) ^ Signed-off-by: Borislav Petkov Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/host/vmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c index 6c5b7fd9f0c5..18ef1a93c10a 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/host/vmd.c @@ -741,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);