Commit 1f408d57 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branches 'pci/hotplug', 'pci/iommu', 'pci/irq' and 'pci/virtualization' into next

* pci/hotplug:
  PCI: pciehp: Remove ignored MRL sensor interrupt events
  PCI: pciehp: Remove unused interrupt events
  PCI: pciehp: Handle invalid data when reading from non-existent devices
  PCI: Hold pci_slot_mutex while searching bus->slots list
  PCI: Protect pci_bus->slots with pci_slot_mutex, not pci_bus_sem
  PCI: pciehp: Simplify pcie_poll_cmd()
  PCI: Use "slot" and "pci_slot" for struct hotplug_slot and struct pci_slot

* pci/iommu:
  PCI: Remove pci_ats_enabled()
  PCI: Stop caching ATS Invalidate Queue Depth
  PCI: Move ATS declarations to linux/pci.h so they're all together
  PCI: Clean up ATS error handling
  PCI: Use pci_physfn() rather than looking up physfn by hand
  PCI: Inline the ATS setup code into pci_ats_init()
  PCI: Rationalize pci_ats_queue_depth() error checking
  PCI: Reduce size of ATS structure elements
  PCI: Embed ATS info directly into struct pci_dev
  PCI: Allocate ATS struct during enumeration
  iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth

* pci/irq:
  PCI: Kill off set_irq_flags() usage

* pci/virtualization:
  PCI: Add ACS quirks for Intel I219-LM/V
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -126,7 +126,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
{
	struct pci_dev *dev;
	const char *type;
	struct pci_slot *slot;

	dev = pci_alloc_dev(bus);
	if (!dev)
@@ -145,10 +144,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
	dev->needs_freset = 0;		/* pcie fundamental reset required */
	set_pcie_port_type(dev);

	list_for_each_entry(slot, &dev->bus->slots, list)
		if (PCI_SLOT(dev->devfn) == slot->number)
			dev->slot = slot;

	pci_dev_assign_slot(dev);
	dev->vendor = get_int_prop(node, "vendor-id", 0xffff);
	dev->device = get_int_prop(node, "device-id", 0xffff);
	dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
+1 −5
Original line number Diff line number Diff line
@@ -249,7 +249,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
					 struct pci_bus *bus, int devfn)
{
	struct dev_archdata *sd;
	struct pci_slot *slot;
	struct platform_device *op;
	struct pci_dev *dev;
	const char *type;
@@ -290,10 +289,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
	dev->multifunction = 0;		/* maybe a lie? */
	set_pcie_port_type(dev);

	list_for_each_entry(slot, &dev->bus->slots, list)
		if (PCI_SLOT(dev->devfn) == slot->number)
			dev->slot = slot;

	pci_dev_assign_slot(dev);
	dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
	dev->device = of_getintprop_default(node, "device-id", 0xffff);
	dev->subsystem_vendor =
+18 −10
Original line number Diff line number Diff line
@@ -408,6 +408,10 @@ struct device_domain_info {
	struct list_head global; /* link to global list */
	u8 bus;			/* PCI bus number */
	u8 devfn;		/* PCI devfn number */
	struct {
		u8 enabled:1;
		u8 qdep;
	} ats;			/* ATS state */
	struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
	struct intel_iommu *iommu; /* IOMMU used by this device */
	struct dmar_domain *domain; /* pointer to domain */
@@ -1391,19 +1395,26 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu,

static void iommu_enable_dev_iotlb(struct device_domain_info *info)
{
	struct pci_dev *pdev;

	if (!info || !dev_is_pci(info->dev))
		return;

	pci_enable_ats(to_pci_dev(info->dev), VTD_PAGE_SHIFT);
	pdev = to_pci_dev(info->dev);
	if (pci_enable_ats(pdev, VTD_PAGE_SHIFT))
		return;

	info->ats.enabled = 1;
	info->ats.qdep = pci_ats_queue_depth(pdev);
}

static void iommu_disable_dev_iotlb(struct device_domain_info *info)
{
	if (!info->dev || !dev_is_pci(info->dev) ||
	    !pci_ats_enabled(to_pci_dev(info->dev)))
	if (!info->ats.enabled)
		return;

	pci_disable_ats(to_pci_dev(info->dev));
	info->ats.enabled = 0;
}

static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
@@ -1415,16 +1426,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,

	spin_lock_irqsave(&device_domain_lock, flags);
	list_for_each_entry(info, &domain->devices, link) {
		struct pci_dev *pdev;
		if (!info->dev || !dev_is_pci(info->dev))
			continue;

		pdev = to_pci_dev(info->dev);
		if (!pci_ats_enabled(pdev))
		if (!info->ats.enabled)
			continue;

		sid = info->bus << 8 | info->devfn;
		qdep = pci_ats_queue_depth(pdev);
		qdep = info->ats.qdep;
		qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
	}
	spin_unlock_irqrestore(&device_domain_lock, flags);
@@ -2272,6 +2278,8 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,

	info->bus = bus;
	info->devfn = devfn;
	info->ats.enabled = 0;
	info->ats.qdep = 0;
	info->dev = dev;
	info->domain = domain;
	info->iommu = iommu;
+46 −85
Original line number Diff line number Diff line
@@ -17,34 +17,15 @@

#include "pci.h"

static int ats_alloc_one(struct pci_dev *dev, int ps)
void pci_ats_init(struct pci_dev *dev)
{
	int pos;
	u16 cap;
	struct pci_ats *ats;

	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
	if (!pos)
		return -ENODEV;

	ats = kzalloc(sizeof(*ats), GFP_KERNEL);
	if (!ats)
		return -ENOMEM;

	ats->pos = pos;
	ats->stu = ps;
	pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
	ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
					    PCI_ATS_MAX_QDEP;
	dev->ats = ats;

	return 0;
}
		return;

static void ats_free_one(struct pci_dev *dev)
{
	kfree(dev->ats);
	dev->ats = NULL;
	dev->ats_cap = pos;
}

/**
@@ -56,43 +37,36 @@ static void ats_free_one(struct pci_dev *dev)
 */
int pci_enable_ats(struct pci_dev *dev, int ps)
{
	int rc;
	u16 ctrl;
	struct pci_dev *pdev;

	BUG_ON(dev->ats && dev->ats->is_enabled);

	if (ps < PCI_ATS_MIN_STU)
	if (!dev->ats_cap)
		return -EINVAL;

	if (dev->is_physfn || dev->is_virtfn) {
		struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;

		mutex_lock(&pdev->sriov->lock);
		if (pdev->ats)
			rc = pdev->ats->stu == ps ? 0 : -EINVAL;
		else
			rc = ats_alloc_one(pdev, ps);

		if (!rc)
			pdev->ats->ref_cnt++;
		mutex_unlock(&pdev->sriov->lock);
		if (rc)
			return rc;
	}
	if (WARN_ON(dev->ats_enabled))
		return -EBUSY;

	if (!dev->is_physfn) {
		rc = ats_alloc_one(dev, ps);
		if (rc)
			return rc;
	}
	if (ps < PCI_ATS_MIN_STU)
		return -EINVAL;

	/*
	 * Note that enabling ATS on a VF fails unless it's already enabled
	 * with the same STU on the PF.
	 */
	ctrl = PCI_ATS_CTRL_ENABLE;
	if (!dev->is_virtfn)
		ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
	pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
	if (dev->is_virtfn) {
		pdev = pci_physfn(dev);
		if (pdev->ats_stu != ps)
			return -EINVAL;

	dev->ats->is_enabled = 1;
		atomic_inc(&pdev->ats_ref_cnt);  /* count enabled VFs */
	} else {
		dev->ats_stu = ps;
		ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
	}
	pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);

	dev->ats_enabled = 1;
	return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_ats);
@@ -103,28 +77,25 @@ EXPORT_SYMBOL_GPL(pci_enable_ats);
 */
void pci_disable_ats(struct pci_dev *dev)
{
	struct pci_dev *pdev;
	u16 ctrl;

	BUG_ON(!dev->ats || !dev->ats->is_enabled);

	pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
	ctrl &= ~PCI_ATS_CTRL_ENABLE;
	pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);

	dev->ats->is_enabled = 0;
	if (WARN_ON(!dev->ats_enabled))
		return;

	if (dev->is_physfn || dev->is_virtfn) {
		struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
	if (atomic_read(&dev->ats_ref_cnt))
		return;		/* VFs still enabled */

		mutex_lock(&pdev->sriov->lock);
		pdev->ats->ref_cnt--;
		if (!pdev->ats->ref_cnt)
			ats_free_one(pdev);
		mutex_unlock(&pdev->sriov->lock);
	if (dev->is_virtfn) {
		pdev = pci_physfn(dev);
		atomic_dec(&pdev->ats_ref_cnt);
	}

	if (!dev->is_physfn)
		ats_free_one(dev);
	pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
	ctrl &= ~PCI_ATS_CTRL_ENABLE;
	pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);

	dev->ats_enabled = 0;
}
EXPORT_SYMBOL_GPL(pci_disable_ats);

@@ -132,16 +103,13 @@ void pci_restore_ats_state(struct pci_dev *dev)
{
	u16 ctrl;

	if (!pci_ats_enabled(dev))
	if (!dev->ats_enabled)
		return;
	if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS))
		BUG();

	ctrl = PCI_ATS_CTRL_ENABLE;
	if (!dev->is_virtfn)
		ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);

	pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
		ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
	pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
}
EXPORT_SYMBOL_GPL(pci_restore_ats_state);

@@ -159,23 +127,16 @@ EXPORT_SYMBOL_GPL(pci_restore_ats_state);
 */
int pci_ats_queue_depth(struct pci_dev *dev)
{
	int pos;
	u16 cap;

	if (!dev->ats_cap)
		return -EINVAL;

	if (dev->is_virtfn)
		return 0;

	if (dev->ats)
		return dev->ats->qdep;

	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
	if (!pos)
		return -ENODEV;

	pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);

	return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
				       PCI_ATS_MAX_QDEP;
	pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
	return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP;
}
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);

+0 −1
Original line number Diff line number Diff line
@@ -155,7 +155,6 @@ static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
{
	irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
	irq_set_chip_data(irq, domain->host_data);
	set_irq_flags(irq, IRQF_VALID);

	return 0;
}
Loading