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

Merge branch 'pci/virtualization'

  - Fix erroneous intel-iommu dependency on CONFIG_AMD_IOMMU (Bjorn
    Helgaas)

  - Move pci_prg_resp_pasid_required() to CONFIG_PCI_PRI (Bjorn Helgaas)

  - Allow VFs to use PRI (the PF PRI is shared by the VFs, but the code
    previously didn't recognize that) (Kuppuswamy Sathyanarayanan)

  - Allow VFs to use PASID (the PF PASID capability is shared by the VFs,
    but the code previously didn't recognize that) (Kuppuswamy
    Sathyanarayanan)

  - Disconnect PF and VF ATS enablement, since ATS in PFs and associated
    VFs can be enabled independently (Kuppuswamy Sathyanarayanan)

  - Cache PRI and PASID capability offsets (Kuppuswamy Sathyanarayanan)

  - Cache the PRI PRG Response PASID Required bit (Bjorn Helgaas)

  - Consolidate ATS declarations in linux/pci-ats.h (Krzysztof Wilczynski)

  - Remove unused PRI and PASID stubs (Bjorn Helgaas)

  - Removed unnecessary EXPORT_SYMBOL_GPL() from ATS, PRI, and PASID
    interfaces that are only used by built-in IOMMU drivers (Bjorn Helgaas)

  - Hide PRI and PASID state restoration functions used only inside the PCI
    core (Bjorn Helgaas)

  - Fix the UPDCR register address in the Intel ACS quirk (Steffen
    Liebergeld)

  - Add a DMA alias quirk for the Intel VCA NTB (Slawomir Pawlowski)

  - Serialize sysfs sriov_numvfs reads vs writes (Pierre Crégut)

  - Update Cavium ACS quirk for ThunderX2 and ThunderX3 (George Cherian)

  - Unify ACS quirk implementations (Bjorn Helgaas)

* pci/virtualization:
  PCI: Unify ACS quirk desired vs provided checking
  PCI: Make ACS quirk implementations more uniform
  PCI: Apply Cavium ACS quirk to ThunderX2 and ThunderX3
  PCI/IOV: Serialize sysfs sriov_numvfs reads vs writes
  PCI: Add DMA alias quirk for Intel VCA NTB
  PCI: Fix Intel ACS quirk UPDCR register address
  PCI/ATS: Make pci_restore_pri_state(), pci_restore_pasid_state() private
  PCI/ATS: Remove unnecessary EXPORT_SYMBOL_GPL()
  PCI/ATS: Remove unused PRI and PASID stubs
  PCI/ATS: Consolidate ATS declarations in linux/pci-ats.h
  PCI/ATS: Cache PRI PRG Response PASID Required bit
  PCI/ATS: Cache PASID Capability offset
  PCI/ATS: Cache PRI Capability offset
  PCI/ATS: Disable PF/VF ATS service independently
  PCI/ATS: Handle sharing of PF PASID Capability with all VFs
  PCI/ATS: Handle sharing of PF PRI Capability with all VFs
  PCI/ATS: Move pci_prg_resp_pasid_required() to CONFIG_PCI_PRI
  iommu/vt-d: Select PCI_PRI for INTEL_IOMMU_SVM
parents e771e0bf 7cf2cba4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -207,6 +207,7 @@ config INTEL_IOMMU_SVM
	bool "Support for Shared Virtual Memory with Intel IOMMU"
	depends on INTEL_IOMMU && X86
	select PCI_PASID
	select PCI_PRI
	select MMU_NOTIFIER
	help
	  Shared Virtual Memory (SVM) provides a facility for devices
+111 −96
Original line number Diff line number Diff line
@@ -60,8 +60,6 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
		pdev = pci_physfn(dev);
		if (pdev->ats_stu != ps)
			return -EINVAL;

		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);
@@ -71,7 +69,6 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
	dev->ats_enabled = 1;
	return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_ats);

/**
 * pci_disable_ats - disable the ATS capability
@@ -79,27 +76,17 @@ EXPORT_SYMBOL_GPL(pci_enable_ats);
 */
void pci_disable_ats(struct pci_dev *dev)
{
	struct pci_dev *pdev;
	u16 ctrl;

	if (WARN_ON(!dev->ats_enabled))
		return;

	if (atomic_read(&dev->ats_ref_cnt))
		return;		/* VFs still enabled */

	if (dev->is_virtfn) {
		pdev = pci_physfn(dev);
		atomic_dec(&pdev->ats_ref_cnt);
	}

	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);

void pci_restore_ats_state(struct pci_dev *dev)
{
@@ -113,7 +100,6 @@ void pci_restore_ats_state(struct pci_dev *dev)
		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);

/**
 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
@@ -140,7 +126,6 @@ int pci_ats_queue_depth(struct pci_dev *dev)
	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);

/**
 * pci_ats_page_aligned - Return Page Aligned Request bit status.
@@ -167,9 +152,22 @@ int pci_ats_page_aligned(struct pci_dev *pdev)

	return 0;
}
EXPORT_SYMBOL_GPL(pci_ats_page_aligned);

#ifdef CONFIG_PCI_PRI
void pci_pri_init(struct pci_dev *pdev)
{
	u16 status;

	pdev->pri_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);

	if (!pdev->pri_cap)
		return;

	pci_read_config_word(pdev, pdev->pri_cap + PCI_PRI_STATUS, &status);
	if (status & PCI_PRI_STATUS_PASID)
		pdev->pasid_required = 1;
}

/**
 * pci_enable_pri - Enable PRI capability
 * @ pdev: PCI device structure
@@ -180,32 +178,41 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
{
	u16 control, status;
	u32 max_requests;
	int pos;
	int pri = pdev->pri_cap;

	/*
	 * VFs must not implement the PRI Capability.  If their PF
	 * implements PRI, it is shared by the VFs, so if the PF PRI is
	 * enabled, it is also enabled for the VF.
	 */
	if (pdev->is_virtfn) {
		if (pci_physfn(pdev)->pri_enabled)
			return 0;
		return -EINVAL;
	}

	if (WARN_ON(pdev->pri_enabled))
		return -EBUSY;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
	if (!pos)
	if (!pri)
		return -EINVAL;

	pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
	pci_read_config_word(pdev, pri + PCI_PRI_STATUS, &status);
	if (!(status & PCI_PRI_STATUS_STOPPED))
		return -EBUSY;

	pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
	pci_read_config_dword(pdev, pri + PCI_PRI_MAX_REQ, &max_requests);
	reqs = min(max_requests, reqs);
	pdev->pri_reqs_alloc = reqs;
	pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
	pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);

	control = PCI_PRI_CTRL_ENABLE;
	pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
	pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);

	pdev->pri_enabled = 1;

	return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_pri);

/**
 * pci_disable_pri - Disable PRI capability
@@ -216,18 +223,21 @@ EXPORT_SYMBOL_GPL(pci_enable_pri);
void pci_disable_pri(struct pci_dev *pdev)
{
	u16 control;
	int pos;
	int pri = pdev->pri_cap;

	/* VFs share the PF PRI */
	if (pdev->is_virtfn)
		return;

	if (WARN_ON(!pdev->pri_enabled))
		return;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
	if (!pos)
	if (!pri)
		return;

	pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
	pci_read_config_word(pdev, pri + PCI_PRI_CTRL, &control);
	control &= ~PCI_PRI_CTRL_ENABLE;
	pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
	pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);

	pdev->pri_enabled = 0;
}
@@ -241,19 +251,20 @@ void pci_restore_pri_state(struct pci_dev *pdev)
{
	u16 control = PCI_PRI_CTRL_ENABLE;
	u32 reqs = pdev->pri_reqs_alloc;
	int pos;
	int pri = pdev->pri_cap;

	if (pdev->is_virtfn)
		return;

	if (!pdev->pri_enabled)
		return;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
	if (!pos)
	if (!pri)
		return;

	pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
	pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
	pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
	pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
}
EXPORT_SYMBOL_GPL(pci_restore_pri_state);

/**
 * pci_reset_pri - Resets device's PRI state
@@ -265,24 +276,45 @@ EXPORT_SYMBOL_GPL(pci_restore_pri_state);
int pci_reset_pri(struct pci_dev *pdev)
{
	u16 control;
	int pos;
	int pri = pdev->pri_cap;

	if (pdev->is_virtfn)
		return 0;

	if (WARN_ON(pdev->pri_enabled))
		return -EBUSY;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
	if (!pos)
	if (!pri)
		return -EINVAL;

	control = PCI_PRI_CTRL_RESET;
	pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
	pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);

	return 0;
}
EXPORT_SYMBOL_GPL(pci_reset_pri);

/**
 * pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
 *				 status.
 * @pdev: PCI device structure
 *
 * Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
 */
int pci_prg_resp_pasid_required(struct pci_dev *pdev)
{
	if (pdev->is_virtfn)
		pdev = pci_physfn(pdev);

	return pdev->pasid_required;
}
#endif /* CONFIG_PCI_PRI */

#ifdef CONFIG_PCI_PASID
void pci_pasid_init(struct pci_dev *pdev)
{
	pdev->pasid_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
}

/**
 * pci_enable_pasid - Enable the PASID capability
 * @pdev: PCI device structure
@@ -295,7 +327,17 @@ EXPORT_SYMBOL_GPL(pci_reset_pri);
int pci_enable_pasid(struct pci_dev *pdev, int features)
{
	u16 control, supported;
	int pos;
	int pasid = pdev->pasid_cap;

	/*
	 * VFs must not implement the PASID Capability, but if a PF
	 * supports PASID, its VFs share the PF PASID configuration.
	 */
	if (pdev->is_virtfn) {
		if (pci_physfn(pdev)->pasid_enabled)
			return 0;
		return -EINVAL;
	}

	if (WARN_ON(pdev->pasid_enabled))
		return -EBUSY;
@@ -303,11 +345,10 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
	if (!pdev->eetlp_prefix_path)
		return -EINVAL;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
	if (!pos)
	if (!pasid)
		return -EINVAL;

	pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
	pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
	supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;

	/* User wants to enable anything unsupported? */
@@ -317,13 +358,12 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
	control = PCI_PASID_CTRL_ENABLE | features;
	pdev->pasid_features = features;

	pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
	pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);

	pdev->pasid_enabled = 1;

	return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_pasid);

/**
 * pci_disable_pasid - Disable the PASID capability
@@ -332,20 +372,22 @@ EXPORT_SYMBOL_GPL(pci_enable_pasid);
void pci_disable_pasid(struct pci_dev *pdev)
{
	u16 control = 0;
	int pos;
	int pasid = pdev->pasid_cap;

	/* VFs share the PF PASID configuration */
	if (pdev->is_virtfn)
		return;

	if (WARN_ON(!pdev->pasid_enabled))
		return;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
	if (!pos)
	if (!pasid)
		return;

	pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
	pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);

	pdev->pasid_enabled = 0;
}
EXPORT_SYMBOL_GPL(pci_disable_pasid);

/**
 * pci_restore_pasid_state - Restore PASID capabilities
@@ -354,19 +396,20 @@ EXPORT_SYMBOL_GPL(pci_disable_pasid);
void pci_restore_pasid_state(struct pci_dev *pdev)
{
	u16 control;
	int pos;
	int pasid = pdev->pasid_cap;

	if (pdev->is_virtfn)
		return;

	if (!pdev->pasid_enabled)
		return;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
	if (!pos)
	if (!pasid)
		return;

	control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
	pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
	pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
}
EXPORT_SYMBOL_GPL(pci_restore_pasid_state);

/**
 * pci_pasid_features - Check which PASID features are supported
@@ -381,49 +424,20 @@ EXPORT_SYMBOL_GPL(pci_restore_pasid_state);
int pci_pasid_features(struct pci_dev *pdev)
{
	u16 supported;
	int pos;
	int pasid = pdev->pasid_cap;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
	if (!pos)
	if (pdev->is_virtfn)
		pdev = pci_physfn(pdev);

	if (!pasid)
		return -EINVAL;

	pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
	pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);

	supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;

	return supported;
}
EXPORT_SYMBOL_GPL(pci_pasid_features);

/**
 * pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
 *				 status.
 * @pdev: PCI device structure
 *
 * Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
 *
 * Even though the PRG response PASID status is read from PRI Status
 * Register, since this API will mainly be used by PASID users, this
 * function is defined within #ifdef CONFIG_PCI_PASID instead of
 * CONFIG_PCI_PRI.
 */
int pci_prg_resp_pasid_required(struct pci_dev *pdev)
{
	u16 status;
	int pos;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
	if (!pos)
		return 0;

	pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);

	if (status & PCI_PRI_STATUS_PASID)
		return 1;

	return 0;
}
EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required);

#define PASID_NUMBER_SHIFT	8
#define PASID_NUMBER_MASK	(0x1f << PASID_NUMBER_SHIFT)
@@ -437,17 +451,18 @@ EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required);
int pci_max_pasids(struct pci_dev *pdev)
{
	u16 supported;
	int pos;
	int pasid = pdev->pasid_cap;

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
	if (!pos)
	if (pdev->is_virtfn)
		pdev = pci_physfn(pdev);

	if (!pasid)
		return -EINVAL;

	pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
	pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);

	supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;

	return (1 << supported);
}
EXPORT_SYMBOL_GPL(pci_max_pasids);
#endif /* CONFIG_PCI_PASID */
+7 −1
Original line number Diff line number Diff line
@@ -254,8 +254,14 @@ static ssize_t sriov_numvfs_show(struct device *dev,
				 char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	u16 num_vfs;

	/* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */
	device_lock(&pdev->dev);
	num_vfs = pdev->sriov->num_VFs;
	device_unlock(&pdev->dev);

	return sprintf(buf, "%u\n", pdev->sriov->num_VFs);
	return sprintf(buf, "%u\n", num_vfs);
}

/*
+16 −0
Original line number Diff line number Diff line
@@ -459,6 +459,22 @@ static inline void pci_ats_init(struct pci_dev *d) { }
static inline void pci_restore_ats_state(struct pci_dev *dev) { }
#endif /* CONFIG_PCI_ATS */

#ifdef CONFIG_PCI_PRI
void pci_pri_init(struct pci_dev *dev);
void pci_restore_pri_state(struct pci_dev *pdev);
#else
static inline void pci_pri_init(struct pci_dev *dev) { }
static inline void pci_restore_pri_state(struct pci_dev *pdev) { }
#endif

#ifdef CONFIG_PCI_PASID
void pci_pasid_init(struct pci_dev *dev);
void pci_restore_pasid_state(struct pci_dev *pdev);
#else
static inline void pci_pasid_init(struct pci_dev *dev) { }
static inline void pci_restore_pasid_state(struct pci_dev *pdev) { }
#endif

#ifdef CONFIG_PCI_IOV
int pci_iov_init(struct pci_dev *dev);
void pci_iov_release(struct pci_dev *dev);
+6 −0
Original line number Diff line number Diff line
@@ -2335,6 +2335,12 @@ static void pci_init_capabilities(struct pci_dev *dev)
	/* Address Translation Services */
	pci_ats_init(dev);

	/* Page Request Interface */
	pci_pri_init(dev);

	/* Process Address Space ID */
	pci_pasid_init(dev);

	/* Enable ACS P2P upstream forwarding */
	pci_enable_acs(dev);

Loading