Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b08d2e61 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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()
parents d34efd22 42db500a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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---
+22 −8
Original line number Diff line number Diff line
@@ -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);