Loading drivers/pci/host/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -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--- Loading drivers/pci/host/vmd.c +22 −8 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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. Loading @@ -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; Loading @@ -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; }; Loading Loading @@ -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, Loading Loading @@ -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; } Loading Loading @@ -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]); Loading @@ -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); Loading @@ -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); Loading Loading
drivers/pci/host/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -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--- Loading
drivers/pci/host/vmd.c +22 −8 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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. Loading @@ -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; Loading @@ -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; }; Loading Loading @@ -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, Loading Loading @@ -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; } Loading Loading @@ -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]); Loading @@ -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); Loading @@ -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); Loading