Commit 2e3f280b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull pci fixes from Bjorn Helgaas:

 - Limit Max_Read_Request_Size (MRRS) on some MIPS Loongson systems
   because they don't all support MRRS > 256, and firmware doesn't
   always initialize it correctly, which meant some PCIe devices didn't
   work (Jiaxun Yang)

 - Add and use pci_enable_link_state_locked() to prevent potential
   deadlocks in vmd and qcom drivers (Johan Hovold)

 - Revert recent (v6.5) acpiphp resource assignment changes that fixed
   issues with hot-adding devices on a root bus or with large BARs, but
   introduced new issues with GPU initialization and hot-adding SCSI
   disks in QEMU VMs and (Bjorn Helgaas)

* tag 'pci-v6.7-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci:
  Revert "PCI: acpiphp: Reassign resources on bridge if necessary"
  PCI/ASPM: Add pci_disable_link_state_locked() lockdep assert
  PCI/ASPM: Clean up __pci_disable_link_state() 'sem' parameter
  PCI: qcom: Clean up ASPM comment
  PCI: qcom: Fix potential deadlock when enabling ASPM
  PCI: vmd: Fix potential deadlock when enabling ASPM
  PCI/ASPM: Add pci_enable_link_state_locked()
  PCI: loongson: Limit MRRS to 256
parents ae191417 5df12742
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -968,9 +968,12 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie)

static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata)
{
	/* Downstream devices need to be in D0 state before enabling PCI PM substates */
	/*
	 * Downstream devices need to be in D0 state before enabling PCI PM
	 * substates.
	 */
	pci_set_power_state(pdev, PCI_D0);
	pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
	pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL);

	return 0;
}
+41 −5
Original line number Diff line number Diff line
@@ -80,13 +80,49 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_LPC, system_bus_quirk);

static void loongson_mrrs_quirk(struct pci_dev *pdev)
{
/*
	 * Some Loongson PCIe ports have h/w limitations of maximum read
	 * request size. They can't handle anything larger than this. So
	 * force this limit on any devices attached under these ports.
 * Some Loongson PCIe ports have hardware limitations on their Maximum Read
 * Request Size. They can't handle anything larger than this.  Sane
 * firmware will set proper MRRS at boot, so we only need no_inc_mrrs for
 * bridges. However, some MIPS Loongson firmware doesn't set MRRS properly,
 * so we have to enforce maximum safe MRRS, which is 256 bytes.
 */
#ifdef CONFIG_MIPS
static void loongson_set_min_mrrs_quirk(struct pci_dev *pdev)
{
	struct pci_bus *bus = pdev->bus;
	struct pci_dev *bridge;
	static const struct pci_device_id bridge_devids[] = {
		{ PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
		{ 0, },
	};

	/* look for the matching bridge */
	while (!pci_is_root_bus(bus)) {
		bridge = bus->self;
		bus = bus->parent;

		if (pci_match_id(bridge_devids, bridge)) {
			if (pcie_get_readrq(pdev) > 256) {
				pci_info(pdev, "limiting MRRS to 256\n");
				pcie_set_readrq(pdev, 256);
			}
			break;
		}
	}
}
DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_set_min_mrrs_quirk);
#endif

static void loongson_mrrs_quirk(struct pci_dev *pdev)
{
	struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);

	bridge->no_inc_mrrs = 1;
+1 −1
Original line number Diff line number Diff line
@@ -751,7 +751,7 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
	if (!(features & VMD_FEAT_BIOS_PM_QUIRK))
		return 0;

	pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
	pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL);

	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);
	if (!pos)
+3 −6
Original line number Diff line number Diff line
@@ -512,15 +512,12 @@ static void enable_slot(struct acpiphp_slot *slot, bool bridge)
				if (pass && dev->subordinate) {
					check_hotplug_bridge(slot, dev);
					pcibios_resource_survey_bus(dev->subordinate);
					if (pci_is_root_bus(bus))
						__pci_bus_size_bridges(dev->subordinate, &add_list);
					__pci_bus_size_bridges(dev->subordinate,
							       &add_list);
				}
			}
		}
		if (pci_is_root_bus(bus))
		__pci_bus_assign_resources(bus, &add_list, NULL);
		else
			pci_assign_unassigned_bridge_resources(bus->self);
	}

	acpiphp_sanitize_bus(bus);
+47 −18
Original line number Diff line number Diff line
@@ -1041,7 +1041,7 @@ static struct pcie_link_state *pcie_aspm_get_link(struct pci_dev *pdev)
	return bridge->link_state;
}

static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool locked)
{
	struct pcie_link_state *link = pcie_aspm_get_link(pdev);

@@ -1060,7 +1060,7 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
		return -EPERM;
	}

	if (sem)
	if (!locked)
		down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
	if (state & PCIE_LINK_STATE_L0S)
@@ -1082,7 +1082,7 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
		link->clkpm_disable = 1;
	pcie_set_clkpm(link, policy_to_clkpm_state(link));
	mutex_unlock(&aspm_lock);
	if (sem)
	if (!locked)
		up_read(&pci_bus_sem);

	return 0;
@@ -1090,7 +1090,9 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)

int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
{
	return __pci_disable_link_state(pdev, state, false);
	lockdep_assert_held_read(&pci_bus_sem);

	return __pci_disable_link_state(pdev, state, true);
}
EXPORT_SYMBOL(pci_disable_link_state_locked);

@@ -1105,21 +1107,11 @@ EXPORT_SYMBOL(pci_disable_link_state_locked);
 */
int pci_disable_link_state(struct pci_dev *pdev, int state)
{
	return __pci_disable_link_state(pdev, state, true);
	return __pci_disable_link_state(pdev, state, false);
}
EXPORT_SYMBOL(pci_disable_link_state);

/**
 * pci_enable_link_state - Clear and set the default device link state so that
 * the link may be allowed to enter the specified states. Note that if the
 * BIOS didn't grant ASPM control to the OS, this does nothing because we can't
 * touch the LNKCTL register. Also note that this does not enable states
 * disabled by pci_disable_link_state(). Return 0 or a negative errno.
 *
 * @pdev: PCI device
 * @state: Mask of ASPM link states to enable
 */
int pci_enable_link_state(struct pci_dev *pdev, int state)
static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked)
{
	struct pcie_link_state *link = pcie_aspm_get_link(pdev);

@@ -1136,6 +1128,7 @@ int pci_enable_link_state(struct pci_dev *pdev, int state)
		return -EPERM;
	}

	if (!locked)
		down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
	link->aspm_default = 0;
@@ -1157,12 +1150,48 @@ int pci_enable_link_state(struct pci_dev *pdev, int state)
	link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0;
	pcie_set_clkpm(link, policy_to_clkpm_state(link));
	mutex_unlock(&aspm_lock);
	if (!locked)
		up_read(&pci_bus_sem);

	return 0;
}

/**
 * pci_enable_link_state - Clear and set the default device link state so that
 * the link may be allowed to enter the specified states. Note that if the
 * BIOS didn't grant ASPM control to the OS, this does nothing because we can't
 * touch the LNKCTL register. Also note that this does not enable states
 * disabled by pci_disable_link_state(). Return 0 or a negative errno.
 *
 * @pdev: PCI device
 * @state: Mask of ASPM link states to enable
 */
int pci_enable_link_state(struct pci_dev *pdev, int state)
{
	return __pci_enable_link_state(pdev, state, false);
}
EXPORT_SYMBOL(pci_enable_link_state);

/**
 * pci_enable_link_state_locked - Clear and set the default device link state
 * so that the link may be allowed to enter the specified states. Note that if
 * the BIOS didn't grant ASPM control to the OS, this does nothing because we
 * can't touch the LNKCTL register. Also note that this does not enable states
 * disabled by pci_disable_link_state(). Return 0 or a negative errno.
 *
 * @pdev: PCI device
 * @state: Mask of ASPM link states to enable
 *
 * Context: Caller holds pci_bus_sem read lock.
 */
int pci_enable_link_state_locked(struct pci_dev *pdev, int state)
{
	lockdep_assert_held_read(&pci_bus_sem);

	return __pci_enable_link_state(pdev, state, true);
}
EXPORT_SYMBOL(pci_enable_link_state_locked);

static int pcie_aspm_set_policy(const char *val,
				const struct kernel_param *kp)
{
Loading