mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Niklas Cassel <cassel@kernel.org>
To: "Bjorn Helgaas" <bhelgaas@google.com>,
	"Bjorn Helgaas" <helgaas@kernel.org>,
	"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
	"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
	"Manivannan Sadhasivam" <mani@kernel.org>,
	"Heiko Stuebner" <heiko@sntech.de>,
	"Yue Wang" <yue.wang@Amlogic.com>,
	"Hans Zhang" <18255117159@163.com>
Cc: "Keith Busch" <kbusch@kernel.org>,
	mx2pg@pm.me, dlemoal@kernel.org,
	"Niklas Cassel" <cassel@kernel.org>,
	"Lukas Wunner" <lukas@wunner.de>, "Frank Li" <Frank.Li@nxp.com>,
	"Mahesh Vaidya" <mahesh.vaidya@altera.com>,
	"Ricardo Pardini" <ricardo@pardini.net>,
	"Shawn Lin" <shawn.lin@rock-chips.com>,
	"Pali Rohár" <pali@kernel.org>,
	"Neil Armstrong" <neil.armstrong@linaro.org>,
	"Rob Herring" <robh@kernel.org>,
	"Jingoo Han" <jingoohan1@gmail.com>,
	"Kevin Hilman" <khilman@baylibre.com>,
	"Jerome Brunet" <jbrunet@baylibre.com>,
	"Martin Blumenstingl" <martin.blumenstingl@googlemail.com>,
	"Myron Stowe" <myron.stowe@redhat.com>,
	"Jon Mason" <jdmason@kudzu.us>,
	linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-amlogic@lists.infradead.org,
	linux-rockchip@lists.infradead.org
Subject: [RFC PATCH 3/4] PCI: Configure Root Port MPS after scanning its hierarchy
Date: Wed, 30 Sep 2026 16:50:20 +0200	[thread overview]
Message-ID: <20260930145017.1356088-9-cassel@kernel.org> (raw)
In-Reply-To: <20260930145017.1356088-6-cassel@kernel.org>

With the default MPS strategy (PCIE_BUS_DEFAULT), pci_configure_mps()
only matches each device's Maximum Payload Size (MPS) to its upstream
bridge.  Root Ports have no upstream bridge, so their MPS stays at
whatever firmware or the hardware default (128 bytes) left there, and the
hierarchy below them inherits that value even if the Root Port and all
devices below it support more.

Once the hierarchy below a Root Port has been scanned, and before drivers
are bound, raise the Root Port and every device below it to the largest
MPS they all support.  Do this from pcie_bus_configure_settings(), which
the host bridge, ACPI and hotplug paths call after scanning, and from
pci_rescan_bus() and pci_rescan_bus_bridge_resize(), which don't.

Leave a hierarchy alone if it contains a hotplug bridge other than the
Root Port, typically a Switch Downstream Port: a device hot-added below it
later can't lower the MPS of a hierarchy in use, so keep the MPS the
hierarchy already had.  pcie_find_smpss() already returns the minimum MPS
for such hierarchies, which never raises anything.  Don't raise an empty
slot directly below a Root Port either; it is evaluated when a device is
hot-added or rescanned there, which also allows raising the Root Port
again after a device that supported less has been replaced.  Hierarchies
with devices that may already have a driver bound are never changed.

Since PCIE_BUS_DEFAULT can now raise MPS above what firmware programmed,
apply the Intel 5000/5100 read completion coalescing quirk to it as well.

The other strategies are unchanged: PCIE_BUS_TUNE_OFF doesn't touch MPS,
and PCIE_BUS_SAFE, PCIE_BUS_PERFORMANCE and PCIE_BUS_PEER2PEER already
configure the hierarchy in pcie_bus_configure_settings().

Suggested-by: Manivannan Sadhasivam <mani@kernel.org>
Co-developed-by: Hans Zhang <18255117159@163.com>
Signed-off-by: Hans Zhang <18255117159@163.com>
Assisted-by: LLM
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
 drivers/pci/probe.c  | 83 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/quirks.c |  3 +-
 2 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index d8e58e5ef730..5f37b480b51d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -3083,6 +3083,82 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
 	return 0;
 }
 
+static int pcie_raise_mps(struct pci_dev *dev, void *data)
+{
+	int mps = *(int *)data;
+
+	/* MPS is of type 'RsvdP' for VFs */
+	if (!pci_is_pcie(dev) || dev->is_virtfn)
+		return 0;
+
+	if (pcie_get_mps(dev) < mps && pcie_set_mps(dev, mps))
+		pci_err(dev, "can't set Max Payload Size to %d\n", mps);
+
+	return 0;
+}
+
+/*
+ * With PCIE_BUS_DEFAULT, pci_configure_mps() only matches each device to its
+ * upstream bridge, so a hierarchy inherits whatever MPS firmware, or the
+ * hardware default of 128 bytes, left in its Root Port.  Once the hierarchy
+ * below a Root Port has been enumerated, raise it to the largest MPS that all
+ * of its devices support.
+ *
+ * Leave hierarchies with a hotplug bridge other than the Root Port alone: a
+ * device hot-added below it can't lower the MPS once the hierarchy is in use.
+ * pcie_find_smpss() returns the minimum MPS for such hierarchies, which never
+ * raises anything.  A hotplug slot directly below the Root Port is fine: it
+ * is evaluated when a device is hot-added there, and an empty slot is not
+ * raised, so a Switch hot-added into it doesn't inherit a raised MPS.  Also
+ * leave hierarchies alone once any of their devices may have a driver bound.
+ */
+static void pcie_bus_raise_default_mps(struct pci_bus *bus)
+{
+	struct pci_dev *rp = bus->self;
+	u8 smpss = rp->pcie_mpss;
+	int mps, old_mps;
+
+	if (pci_pcie_type(rp) != PCI_EXP_TYPE_ROOT_PORT ||
+	    list_empty(&bus->devices) || pci_bus_in_use(bus))
+		return;
+
+	pci_walk_bus(bus, pcie_find_smpss, &smpss);
+	mps = 128 << smpss;
+	old_mps = pcie_get_mps(rp);
+	if (mps <= old_mps)
+		return;
+
+	pcie_raise_mps(rp, &mps);
+	pci_walk_bus(bus, pcie_raise_mps, &mps);
+	pci_info(rp, "Max Payload Size of hierarchy set to %d (was %d)\n",
+		 mps, old_mps);
+}
+
+/*
+ * A rescan doesn't go through pcie_bus_configure_settings(), so give the Root
+ * Port hierarchies it may have populated the same chance to be raised: every
+ * hierarchy below a rescanned root bus, or the one @bus belongs to.
+ */
+static void pcie_rescan_raise_default_mps(struct pci_bus *bus)
+{
+	struct pci_bus *child;
+	struct pci_dev *rp;
+
+	if (pcie_bus_config != PCIE_BUS_DEFAULT)
+		return;
+
+	if (pci_is_root_bus(bus)) {
+		list_for_each_entry(child, &bus->children, node)
+			if (child->self && pci_is_pcie(child->self))
+				pcie_bus_raise_default_mps(child);
+		return;
+	}
+
+	rp = pcie_find_root_port(bus->self);
+	if (rp && rp->subordinate)
+		pcie_bus_raise_default_mps(rp->subordinate);
+}
+
 /*
  * pcie_bus_configure_settings() requires that pci_walk_bus work in a top-down,
  * parents then children fashion.  If this changes, then this code will not
@@ -3098,6 +3174,11 @@ void pcie_bus_configure_settings(struct pci_bus *bus)
 	if (!pci_is_pcie(bus->self))
 		return;
 
+	if (pcie_bus_config == PCIE_BUS_DEFAULT) {
+		pcie_bus_raise_default_mps(bus);
+		return;
+	}
+
 	/*
 	 * FIXME - Peer to peer DMA is possible, though the endpoint would need
 	 * to be aware of the MPS of the destination.  To work around this,
@@ -3536,6 +3617,7 @@ unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
 	max = pci_scan_child_bus(bus);
 
 	pci_assign_unassigned_bridge_resources(bridge);
+	pcie_rescan_raise_default_mps(bus);
 
 	pci_bus_add_devices(bus);
 
@@ -3557,6 +3639,7 @@ unsigned int pci_rescan_bus(struct pci_bus *bus)
 
 	max = pci_scan_child_bus(bus);
 	pci_assign_unassigned_bus_resources(bus);
+	pcie_rescan_raise_default_mps(bus);
 	pci_bus_add_devices(bus);
 
 	return max;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index de9bbccda21f..da171f4babe4 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3452,8 +3452,7 @@ static void quirk_intel_mc_errata(struct pci_dev *dev)
 	int err;
 	u16 rcc;
 
-	if (pcie_bus_config == PCIE_BUS_TUNE_OFF ||
-	    pcie_bus_config == PCIE_BUS_DEFAULT)
+	if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
 		return;
 
 	/*
-- 
2.55.0


  parent reply	other threads:[~2026-09-30 14:50 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-30 14:50 [RFC PATCH 0/4] PCI: Fix and improve default MPS configuration Niklas Cassel
2026-09-30 14:50 ` [RFC PATCH 1/4] PCI: Update saved Max Payload Size in pcie_set_mps() Niklas Cassel
2026-09-30 14:50 ` [RFC PATCH 2/4] PCI: Match the hierarchy's MPS to a device's MPSS as necessary Niklas Cassel
2026-09-30 14:50 ` Niklas Cassel [this message]
2026-09-30 14:50 ` [RFC PATCH 4/4] PCI: meson: Remove redundant MPS configuration Niklas Cassel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260930145017.1356088-9-cassel@kernel.org \
    --to=cassel@kernel.org \
    --cc=18255117159@163.com \
    --cc=Frank.Li@nxp.com \
    --cc=bhelgaas@google.com \
    --cc=dlemoal@kernel.org \
    --cc=heiko@sntech.de \
    --cc=helgaas@kernel.org \
    --cc=jbrunet@baylibre.com \
    --cc=jdmason@kudzu.us \
    --cc=jingoohan1@gmail.com \
    --cc=kbusch@kernel.org \
    --cc=khilman@baylibre.com \
    --cc=kwilczynski@kernel.org \
    --cc=linux-amlogic@lists.infradead.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=lpieralisi@kernel.org \
    --cc=lukas@wunner.de \
    --cc=mahesh.vaidya@altera.com \
    --cc=mani@kernel.org \
    --cc=martin.blumenstingl@googlemail.com \
    --cc=mx2pg@pm.me \
    --cc=myron.stowe@redhat.com \
    --cc=neil.armstrong@linaro.org \
    --cc=pali@kernel.org \
    --cc=ricardo@pardini.net \
    --cc=robh@kernel.org \
    --cc=shawn.lin@rock-chips.com \
    --cc=yue.wang@Amlogic.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®