Merge branch 'pci/host-vmd' into next
authorBjorn Helgaas <bhelgaas@google.com>
Mon, 12 Dec 2016 17:25:13 +0000 (11:25 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 12 Dec 2016 17:25:13 +0000 (11:25 -0600)
* 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()

drivers/pci/host/Kconfig
drivers/pci/host/vmd.c

index 1171309..898d2c4 100644 (file)
@@ -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---
index 37e29b5..18ef1a9 100644 (file)
@@ -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);