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()
This commit is contained in:
commit
b08d2e61a6
|
@ -288,7 +288,7 @@ config PCIE_ROCKCHIP
|
||||||
4 slots.
|
4 slots.
|
||||||
|
|
||||||
config VMD
|
config VMD
|
||||||
depends on PCI_MSI && X86_64
|
depends on PCI_MSI && X86_64 && SRCU
|
||||||
tristate "Intel Volume Management Device Driver"
|
tristate "Intel Volume Management Device Driver"
|
||||||
default N
|
default N
|
||||||
---help---
|
---help---
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/srcu.h>
|
||||||
#include <linux/rculist.h>
|
#include <linux/rculist.h>
|
||||||
#include <linux/rcupdate.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
|
* struct vmd_irq - private data to map driver IRQ to the VMD shared vector
|
||||||
* @node: list item for parent traversal.
|
* @node: list item for parent traversal.
|
||||||
* @rcu: RCU callback item for freeing.
|
|
||||||
* @irq: back pointer to parent.
|
* @irq: back pointer to parent.
|
||||||
* @enabled: true if driver enabled IRQ
|
* @enabled: true if driver enabled IRQ
|
||||||
* @virq: the virtual IRQ value provided to the requesting driver.
|
* @virq: the virtual IRQ value provided to the requesting driver.
|
||||||
|
@ -49,7 +49,6 @@ static DEFINE_RAW_SPINLOCK(list_lock);
|
||||||
*/
|
*/
|
||||||
struct vmd_irq {
|
struct vmd_irq {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct rcu_head rcu;
|
|
||||||
struct vmd_irq_list *irq;
|
struct vmd_irq_list *irq;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
unsigned int virq;
|
unsigned int virq;
|
||||||
|
@ -58,11 +57,13 @@ struct vmd_irq {
|
||||||
/**
|
/**
|
||||||
* struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector
|
* 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.
|
* @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
|
* @count: number of child IRQs assigned to this vector; used to track
|
||||||
* sharing.
|
* sharing.
|
||||||
*/
|
*/
|
||||||
struct vmd_irq_list {
|
struct vmd_irq_list {
|
||||||
struct list_head irq_list;
|
struct list_head irq_list;
|
||||||
|
struct srcu_struct srcu;
|
||||||
unsigned int count;
|
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);
|
struct vmd_irq *vmdirq = irq_get_chip_data(virq);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
synchronize_rcu();
|
synchronize_srcu(&vmdirq->irq->srcu);
|
||||||
|
|
||||||
/* XXX: Potential optimization to rebalance */
|
/* XXX: Potential optimization to rebalance */
|
||||||
raw_spin_lock_irqsave(&list_lock, flags);
|
raw_spin_lock_irqsave(&list_lock, flags);
|
||||||
vmdirq->irq->count--;
|
vmdirq->irq->count--;
|
||||||
raw_spin_unlock_irqrestore(&list_lock, flags);
|
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,
|
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_list *irqs = data;
|
||||||
struct vmd_irq *vmdirq;
|
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)
|
list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)
|
||||||
generic_handle_irq(vmdirq->virq);
|
generic_handle_irq(vmdirq->virq);
|
||||||
rcu_read_unlock();
|
srcu_read_unlock(&irqs->srcu, idx);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -696,6 +698,10 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < vmd->msix_count; i++) {
|
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);
|
INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
|
||||||
err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
|
err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
|
||||||
vmd_irq, 0, "vmd", &vmd->irqs[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;
|
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)
|
static void vmd_remove(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct vmd_dev *vmd = pci_get_drvdata(dev);
|
struct vmd_dev *vmd = pci_get_drvdata(dev);
|
||||||
|
|
||||||
vmd_detach_resources(vmd);
|
vmd_detach_resources(vmd);
|
||||||
pci_set_drvdata(dev, NULL);
|
vmd_cleanup_srcu(vmd);
|
||||||
sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
|
sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
|
||||||
pci_stop_root_bus(vmd->bus);
|
pci_stop_root_bus(vmd->bus);
|
||||||
pci_remove_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);
|
irq_domain_remove(vmd->irq_domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static int vmd_suspend(struct device *dev)
|
static int vmd_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = to_pci_dev(dev);
|
struct pci_dev *pdev = to_pci_dev(dev);
|
||||||
|
|
Loading…
Reference in New Issue