Commit 7cf2cba4 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

PCI: Unify ACS quirk desired vs provided checking



Most of the ACS quirks have a similar pattern of:

  acs_flags &= ~( <controls provided by this device> );
  return acs_flags ? 0 : 1;

Pull this out into a helper function to simplify the quirks slightly.  The
helper function is also a convenient place for comments about what the list
of ACS controls means.  No functional change intended.

Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarLogan Gunthorpe <logang@deltatee.com>
Reviewed-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent c8de8ed2
Loading
Loading
Loading
Loading
+45 −22
Original line number Diff line number Diff line
@@ -4296,6 +4296,24 @@ static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
			 quirk_chelsio_T5_disable_root_port_attributes);

/*
 * pci_acs_ctrl_enabled - compare desired ACS controls with those provided
 *			  by a device
 * @acs_ctrl_req: Bitmask of desired ACS controls
 * @acs_ctrl_ena: Bitmask of ACS controls enabled or provided implicitly by
 *		  the hardware design
 *
 * Return 1 if all ACS controls in the @acs_ctrl_req bitmask are included
 * in @acs_ctrl_ena, i.e., the device provides all the access controls the
 * caller desires.  Return 0 otherwise.
 */
static int pci_acs_ctrl_enabled(u16 acs_ctrl_req, u16 acs_ctrl_ena)
{
	if ((acs_ctrl_req & acs_ctrl_ena) == acs_ctrl_req)
		return 1;
	return 0;
}

/*
 * AMD has indicated that the devices below do not support peer-to-peer
 * in any system where they are found in the southbridge with an AMD
@@ -4339,7 +4357,7 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
	/* Filter out flags not applicable to multifunction */
	acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);

	return acs_flags & ~(PCI_ACS_RR | PCI_ACS_CR) ? 0 : 1;
	return pci_acs_ctrl_enabled(acs_flags, PCI_ACS_RR | PCI_ACS_CR);
#else
	return -ENODEV;
#endif
@@ -4377,9 +4395,8 @@ static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
	 * hardware implements and enables equivalent ACS functionality for
	 * these flags.
	 */
	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);

	return acs_flags ? 0 : 1;
	return pci_acs_ctrl_enabled(acs_flags,
		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
}

static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4389,9 +4406,8 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
	 * transactions with others, allowing masking out these bits as if they
	 * were unimplemented in the ACS capability.
	 */
	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);

	return acs_flags ? 0 : 1;
	return pci_acs_ctrl_enabled(acs_flags,
		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
}

/*
@@ -4443,17 +4459,16 @@ static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
	return false;
}

#define INTEL_PCH_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)

static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
{
	if (!pci_quirk_intel_pch_acs_match(dev))
		return -ENOTTY;

	if (dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK)
		acs_flags &= ~(INTEL_PCH_ACS_FLAGS);
		return pci_acs_ctrl_enabled(acs_flags,
			PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);

	return acs_flags ? 0 : 1;
	return pci_acs_ctrl_enabled(acs_flags, 0);
}

/*
@@ -4468,9 +4483,8 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
 */
static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags)
{
	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);

	return acs_flags ? 0 : 1;
	return pci_acs_ctrl_enabled(acs_flags,
		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
}

static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4571,7 +4585,7 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)

	pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl);

	return acs_flags & ~ctrl ? 0 : 1;
	return pci_acs_ctrl_enabled(acs_flags, ctrl);
}

static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4585,10 +4599,9 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)
	 * perform peer-to-peer with other functions, allowing us to mask out
	 * these bits as if they were unimplemented in the ACS capability.
	 */
	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
	return pci_acs_ctrl_enabled(acs_flags,
		PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
		PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);

	return acs_flags ? 0 : 1;
}

static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
@@ -4599,9 +4612,8 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
	 * Allow each Root Port to be in a separate IOMMU group by masking
	 * SV/RR/CR/UF bits.
	 */
	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);

	return acs_flags ? 0 : 1;
	return pci_acs_ctrl_enabled(acs_flags,
		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
}

static const struct pci_dev_acs_enabled {
@@ -4703,6 +4715,17 @@ static const struct pci_dev_acs_enabled {
	{ 0 }
};

/*
 * pci_dev_specific_acs_enabled - check whether device provides ACS controls
 * @dev:	PCI device
 * @acs_flags:	Bitmask of desired ACS controls
 *
 * Returns:
 *   -ENOTTY:	No quirk applies to this device; we can't tell whether the
 *		device provides the desired controls
 *   0:		Device does not provide all the desired controls
 *   >0:	Device provides all the controls in @acs_flags
 */
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
{
	const struct pci_dev_acs_enabled *i;