* [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
@ 2026-10-05 12:41 ` Niklas Cassel
0 siblings, 0 replies; 9+ messages in thread
From: Niklas Cassel @ 2026-10-05 12:41 UTC (permalink / raw)
To: Bjorn Helgaas, Heiko Stuebner, Manivannan Sadhasivam, Frank Li
Cc: Manivannan Sadhasivam, Niklas Cassel, linux-pci, linux-arm-kernel,
linux-rockchip
pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
register but leaves the copy saved by pci_save_state() alone, so the next
pci_restore_state() puts back the old value.
The PCI core does change the MPS of devices whose state has already been
saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
"pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
pciehp calls it after a hot-add. The Root Port's state was saved when it
was added and again when portdrv probed it.
Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
that saved state, without saving it first, after host->reset_root_port()
has reset the Root Port, e.g. during AER recovery or on Link Down with the
qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
larger MPS while the device below it is restored to the smaller one, so
the Root Port may send TLPs that the device treats as Malformed.
Update the saved copy of Device Control when pcie_set_mps() changes the
MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
resource assignment") does for BARs.
Fixes: 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root Ports in a platform-specific way")
Assisted-by: LLM
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
This fix was originally sent out as part of my RFC series:
https://lore.kernel.org/linux-pci/20260930145017.1356088-6-cassel@kernel.org/
But sending this fix as a separate patch, as the fix is really unrelated
to the rest of the series, so it could be picked up independently.
drivers/pci/pci.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8cc6a89130b5..f3b82eb7bfaf 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1736,6 +1736,24 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
}
+/*
+ * Update the saved copy of the Device Control register after changing it, so
+ * that pci_restore_state() doesn't put back a stale value. Device Control is
+ * the first register saved by pci_save_pcie_state().
+ */
+static void pcie_update_saved_devctl(struct pci_dev *dev, u16 clear, u16 set)
+{
+ struct pci_cap_saved_state *save_state;
+ u16 *devctl;
+
+ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ if (!save_state)
+ return;
+
+ devctl = (u16 *)&save_state->cap.data[0];
+ *devctl = (*devctl & ~clear) | set;
+}
+
static int pci_save_pcix_state(struct pci_dev *dev)
{
int pos;
@@ -5983,8 +6001,12 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_PAYLOAD, v);
+ if (ret)
+ return pcibios_err_to_errno(ret);
- return pcibios_err_to_errno(ret);
+ pcie_update_saved_devctl(dev, PCI_EXP_DEVCTL_PAYLOAD, v);
+
+ return 0;
}
EXPORT_SYMBOL(pcie_set_mps);
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
@ 2026-10-05 12:41 ` Niklas Cassel
0 siblings, 0 replies; 9+ messages in thread
From: Niklas Cassel @ 2026-10-05 12:41 UTC (permalink / raw)
To: Bjorn Helgaas, Heiko Stuebner, Manivannan Sadhasivam, Frank Li
Cc: Manivannan Sadhasivam, Niklas Cassel, linux-pci, linux-arm-kernel,
linux-rockchip
pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
register but leaves the copy saved by pci_save_state() alone, so the next
pci_restore_state() puts back the old value.
The PCI core does change the MPS of devices whose state has already been
saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
"pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
pciehp calls it after a hot-add. The Root Port's state was saved when it
was added and again when portdrv probed it.
Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
that saved state, without saving it first, after host->reset_root_port()
has reset the Root Port, e.g. during AER recovery or on Link Down with the
qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
larger MPS while the device below it is restored to the smaller one, so
the Root Port may send TLPs that the device treats as Malformed.
Update the saved copy of Device Control when pcie_set_mps() changes the
MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
resource assignment") does for BARs.
Fixes: 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root Ports in a platform-specific way")
Assisted-by: LLM
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
This fix was originally sent out as part of my RFC series:
https://lore.kernel.org/linux-pci/20260930145017.1356088-6-cassel@kernel.org/
But sending this fix as a separate patch, as the fix is really unrelated
to the rest of the series, so it could be picked up independently.
drivers/pci/pci.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8cc6a89130b5..f3b82eb7bfaf 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1736,6 +1736,24 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
}
+/*
+ * Update the saved copy of the Device Control register after changing it, so
+ * that pci_restore_state() doesn't put back a stale value. Device Control is
+ * the first register saved by pci_save_pcie_state().
+ */
+static void pcie_update_saved_devctl(struct pci_dev *dev, u16 clear, u16 set)
+{
+ struct pci_cap_saved_state *save_state;
+ u16 *devctl;
+
+ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ if (!save_state)
+ return;
+
+ devctl = (u16 *)&save_state->cap.data[0];
+ *devctl = (*devctl & ~clear) | set;
+}
+
static int pci_save_pcix_state(struct pci_dev *dev)
{
int pos;
@@ -5983,8 +6001,12 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_PAYLOAD, v);
+ if (ret)
+ return pcibios_err_to_errno(ret);
- return pcibios_err_to_errno(ret);
+ pcie_update_saved_devctl(dev, PCI_EXP_DEVCTL_PAYLOAD, v);
+
+ return 0;
}
EXPORT_SYMBOL(pcie_set_mps);
--
2.55.0
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
2026-10-05 12:41 ` Niklas Cassel
(?)
@ 2026-10-05 12:50 ` sashiko-bot
-1 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-05 12:50 UTC (permalink / raw)
To: Niklas Cassel; +Cc: linux-pci
> pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
> register but leaves the copy saved by pci_save_state() alone, so the next
> pci_restore_state() puts back the old value.
>
> The PCI core does change the MPS of devices whose state has already been
> saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
> smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
> ("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
> "pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
> pciehp calls it after a hot-add. The Root Port's state was saved when it
> was added and again when portdrv probed it.
>
> Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
> Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
> that saved state, without saving it first, after host->reset_root_port()
> has reset the Root Port, e.g. during AER recovery or on Link Down with the
> qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
> larger MPS while the device below it is restored to the smaller one, so
> the Root Port may send TLPs that the device treats as Malformed.
>
> Update the saved copy of Device Control when pcie_set_mps() changes the
> MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
> resource assignment") does for BARs.
>
> Fixes: 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root Ports in a platform-specific way")
> Assisted-by: LLM
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261005124154.2190628-2-cassel@kernel.org?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
2026-10-05 12:41 ` Niklas Cassel
@ 2026-10-05 15:56 ` Keith Busch
-1 siblings, 0 replies; 9+ messages in thread
From: Keith Busch @ 2026-10-05 15:56 UTC (permalink / raw)
To: Niklas Cassel
Cc: Bjorn Helgaas, Heiko Stuebner, Manivannan Sadhasivam, Frank Li,
Manivannan Sadhasivam, linux-pci, linux-arm-kernel,
linux-rockchip
On Mon, Oct 05, 2026 at 02:41:55PM +0200, Niklas Cassel wrote:
> pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
> register but leaves the copy saved by pci_save_state() alone, so the next
> pci_restore_state() puts back the old value.
>
> The PCI core does change the MPS of devices whose state has already been
> saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
> smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
> ("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
> "pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
> pciehp calls it after a hot-add. The Root Port's state was saved when it
> was added and again when portdrv probed it.
>
> Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
> Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
> that saved state, without saving it first, after host->reset_root_port()
> has reset the Root Port, e.g. during AER recovery or on Link Down with the
> qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
> larger MPS while the device below it is restored to the smaller one, so
> the Root Port may send TLPs that the device treats as Malformed.
>
> Update the saved copy of Device Control when pcie_set_mps() changes the
> MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
> resource assignment") does for BARs.
Looks good to me:
Reviewed-by: Keith Busch <kbusch@kernel.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
@ 2026-10-05 15:56 ` Keith Busch
0 siblings, 0 replies; 9+ messages in thread
From: Keith Busch @ 2026-10-05 15:56 UTC (permalink / raw)
To: Niklas Cassel
Cc: Bjorn Helgaas, Heiko Stuebner, Manivannan Sadhasivam, Frank Li,
Manivannan Sadhasivam, linux-pci, linux-arm-kernel,
linux-rockchip
On Mon, Oct 05, 2026 at 02:41:55PM +0200, Niklas Cassel wrote:
> pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
> register but leaves the copy saved by pci_save_state() alone, so the next
> pci_restore_state() puts back the old value.
>
> The PCI core does change the MPS of devices whose state has already been
> saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
> smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
> ("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
> "pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
> pciehp calls it after a hot-add. The Root Port's state was saved when it
> was added and again when portdrv probed it.
>
> Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
> Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
> that saved state, without saving it first, after host->reset_root_port()
> has reset the Root Port, e.g. during AER recovery or on Link Down with the
> qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
> larger MPS while the device below it is restored to the smaller one, so
> the Root Port may send TLPs that the device treats as Malformed.
>
> Update the saved copy of Device Control when pcie_set_mps() changes the
> MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
> resource assignment") does for BARs.
Looks good to me:
Reviewed-by: Keith Busch <kbusch@kernel.org>
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
2026-10-05 12:41 ` Niklas Cassel
@ 2026-10-06 12:06 ` Shawn Lin
-1 siblings, 0 replies; 9+ messages in thread
From: Shawn Lin @ 2026-10-06 12:06 UTC (permalink / raw)
To: Niklas Cassel, Bjorn Helgaas, Heiko Stuebner,
Manivannan Sadhasivam, Frank Li
Cc: shawn.lin, Manivannan Sadhasivam, linux-pci, linux-arm-kernel,
linux-rockchip
Hi Niklas,
在 2026/10/05 星期一 20:41, Niklas Cassel 写道:
> pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
> register but leaves the copy saved by pci_save_state() alone, so the next
> pci_restore_state() puts back the old value.
>
> The PCI core does change the MPS of devices whose state has already been
> saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
> smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
> ("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
> "pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
> pciehp calls it after a hot-add. The Root Port's state was saved when it
> was added and again when portdrv probed it.
>
> Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
> Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
> that saved state, without saving it first, after host->reset_root_port()
> has reset the Root Port, e.g. during AER recovery or on Link Down with the
> qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
> larger MPS while the device below it is restored to the smaller one, so
> the Root Port may send TLPs that the device treats as Malformed.
>
> Update the saved copy of Device Control when pcie_set_mps() changes the
> MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
> resource assignment") does for BARs.
>
LGTM,
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Note that I saw pcie_set_readrq() also changes Device Control register
without updating the saved copy, so the reset-restore path reverts it
too. Since you added pcie_update_saved_devctl(), mind fixing that here
as well?
> Fixes: 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root Ports in a platform-specific way")
> Assisted-by: LLM
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
> ---
> This fix was originally sent out as part of my RFC series:
> https://lore.kernel.org/linux-pci/20260930145017.1356088-6-cassel@kernel.org/
>
> But sending this fix as a separate patch, as the fix is really unrelated
> to the rest of the series, so it could be picked up independently.
>
> drivers/pci/pci.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 8cc6a89130b5..f3b82eb7bfaf 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1736,6 +1736,24 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
> pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
> }
>
> +/*
> + * Update the saved copy of the Device Control register after changing it, so
> + * that pci_restore_state() doesn't put back a stale value. Device Control is
> + * the first register saved by pci_save_pcie_state().
> + */
> +static void pcie_update_saved_devctl(struct pci_dev *dev, u16 clear, u16 set)
> +{
> + struct pci_cap_saved_state *save_state;
> + u16 *devctl;
> +
> + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
> + if (!save_state)
> + return;
> +
> + devctl = (u16 *)&save_state->cap.data[0];
> + *devctl = (*devctl & ~clear) | set;
> +}
> +
> static int pci_save_pcix_state(struct pci_dev *dev)
> {
> int pos;
> @@ -5983,8 +6001,12 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
>
> ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
> PCI_EXP_DEVCTL_PAYLOAD, v);
> + if (ret)
> + return pcibios_err_to_errno(ret);
>
> - return pcibios_err_to_errno(ret);
> + pcie_update_saved_devctl(dev, PCI_EXP_DEVCTL_PAYLOAD, v);
> +
> + return 0;
> }
> EXPORT_SYMBOL(pcie_set_mps);
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
@ 2026-10-06 12:06 ` Shawn Lin
0 siblings, 0 replies; 9+ messages in thread
From: Shawn Lin @ 2026-10-06 12:06 UTC (permalink / raw)
To: Niklas Cassel, Bjorn Helgaas, Heiko Stuebner,
Manivannan Sadhasivam, Frank Li
Cc: shawn.lin, Manivannan Sadhasivam, linux-pci, linux-arm-kernel,
linux-rockchip
Hi Niklas,
在 2026/10/05 星期一 20:41, Niklas Cassel 写道:
> pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
> register but leaves the copy saved by pci_save_state() alone, so the next
> pci_restore_state() puts back the old value.
>
> The PCI core does change the MPS of devices whose state has already been
> saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
> smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
> ("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
> "pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
> pciehp calls it after a hot-add. The Root Port's state was saved when it
> was added and again when portdrv probed it.
>
> Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
> Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
> that saved state, without saving it first, after host->reset_root_port()
> has reset the Root Port, e.g. during AER recovery or on Link Down with the
> qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
> larger MPS while the device below it is restored to the smaller one, so
> the Root Port may send TLPs that the device treats as Malformed.
>
> Update the saved copy of Device Control when pcie_set_mps() changes the
> MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
> resource assignment") does for BARs.
>
LGTM,
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Note that I saw pcie_set_readrq() also changes Device Control register
without updating the saved copy, so the reset-restore path reverts it
too. Since you added pcie_update_saved_devctl(), mind fixing that here
as well?
> Fixes: 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root Ports in a platform-specific way")
> Assisted-by: LLM
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
> ---
> This fix was originally sent out as part of my RFC series:
> https://lore.kernel.org/linux-pci/20260930145017.1356088-6-cassel@kernel.org/
>
> But sending this fix as a separate patch, as the fix is really unrelated
> to the rest of the series, so it could be picked up independently.
>
> drivers/pci/pci.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 8cc6a89130b5..f3b82eb7bfaf 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1736,6 +1736,24 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
> pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
> }
>
> +/*
> + * Update the saved copy of the Device Control register after changing it, so
> + * that pci_restore_state() doesn't put back a stale value. Device Control is
> + * the first register saved by pci_save_pcie_state().
> + */
> +static void pcie_update_saved_devctl(struct pci_dev *dev, u16 clear, u16 set)
> +{
> + struct pci_cap_saved_state *save_state;
> + u16 *devctl;
> +
> + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
> + if (!save_state)
> + return;
> +
> + devctl = (u16 *)&save_state->cap.data[0];
> + *devctl = (*devctl & ~clear) | set;
> +}
> +
> static int pci_save_pcix_state(struct pci_dev *dev)
> {
> int pos;
> @@ -5983,8 +6001,12 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
>
> ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
> PCI_EXP_DEVCTL_PAYLOAD, v);
> + if (ret)
> + return pcibios_err_to_errno(ret);
>
> - return pcibios_err_to_errno(ret);
> + pcie_update_saved_devctl(dev, PCI_EXP_DEVCTL_PAYLOAD, v);
> +
> + return 0;
> }
> EXPORT_SYMBOL(pcie_set_mps);
>
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
2026-10-05 12:41 ` Niklas Cassel
@ 2026-10-12 21:56 ` Bjorn Helgaas
-1 siblings, 0 replies; 9+ messages in thread
From: Bjorn Helgaas @ 2026-10-12 21:56 UTC (permalink / raw)
To: Niklas Cassel
Cc: Bjorn Helgaas, Heiko Stuebner, Manivannan Sadhasivam, Frank Li,
Manivannan Sadhasivam, linux-pci, linux-arm-kernel,
linux-rockchip
On Mon, Oct 05, 2026 at 02:41:55PM +0200, Niklas Cassel wrote:
> pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
> register but leaves the copy saved by pci_save_state() alone, so the next
> pci_restore_state() puts back the old value.
>
> The PCI core does change the MPS of devices whose state has already been
> saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
> smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
> ("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
> "pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
> pciehp calls it after a hot-add. The Root Port's state was saved when it
> was added and again when portdrv probed it.
>
> Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
> Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
> that saved state, without saving it first, after host->reset_root_port()
> has reset the Root Port, e.g. during AER recovery or on Link Down with the
> qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
> larger MPS while the device below it is restored to the smaller one, so
> the Root Port may send TLPs that the device treats as Malformed.
>
> Update the saved copy of Device Control when pcie_set_mps() changes the
> MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
> resource assignment") does for BARs.
>
> Fixes: 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root Ports in a platform-specific way")
> Assisted-by: LLM
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
Applied to pci/mps for v7.4, thanks!
> ---
> This fix was originally sent out as part of my RFC series:
> https://lore.kernel.org/linux-pci/20260930145017.1356088-6-cassel@kernel.org/
>
> But sending this fix as a separate patch, as the fix is really unrelated
> to the rest of the series, so it could be picked up independently.
>
> drivers/pci/pci.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 8cc6a89130b5..f3b82eb7bfaf 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1736,6 +1736,24 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
> pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
> }
>
> +/*
> + * Update the saved copy of the Device Control register after changing it, so
> + * that pci_restore_state() doesn't put back a stale value. Device Control is
> + * the first register saved by pci_save_pcie_state().
> + */
> +static void pcie_update_saved_devctl(struct pci_dev *dev, u16 clear, u16 set)
> +{
> + struct pci_cap_saved_state *save_state;
> + u16 *devctl;
> +
> + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
> + if (!save_state)
> + return;
> +
> + devctl = (u16 *)&save_state->cap.data[0];
> + *devctl = (*devctl & ~clear) | set;
> +}
> +
> static int pci_save_pcix_state(struct pci_dev *dev)
> {
> int pos;
> @@ -5983,8 +6001,12 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
>
> ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
> PCI_EXP_DEVCTL_PAYLOAD, v);
> + if (ret)
> + return pcibios_err_to_errno(ret);
>
> - return pcibios_err_to_errno(ret);
> + pcie_update_saved_devctl(dev, PCI_EXP_DEVCTL_PAYLOAD, v);
> +
> + return 0;
> }
> EXPORT_SYMBOL(pcie_set_mps);
>
> --
> 2.55.0
>
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps()
@ 2026-10-12 21:56 ` Bjorn Helgaas
0 siblings, 0 replies; 9+ messages in thread
From: Bjorn Helgaas @ 2026-10-12 21:56 UTC (permalink / raw)
To: Niklas Cassel
Cc: Bjorn Helgaas, Heiko Stuebner, Manivannan Sadhasivam, Frank Li,
Manivannan Sadhasivam, linux-pci, linux-arm-kernel,
linux-rockchip
On Mon, Oct 05, 2026 at 02:41:55PM +0200, Niklas Cassel wrote:
> pcie_set_mps() changes the Max Payload Size (MPS) in the Device Control
> register but leaves the copy saved by pci_save_state() alone, so the next
> pci_restore_state() puts back the old value.
>
> The PCI core does change the MPS of devices whose state has already been
> saved: pci_configure_mps() reduces a Root Port's MPS when a device with a
> smaller MPS Supported is hot-added directly below it (commit 9f0e89359775
> ("PCI: Match Root Port's MPS to endpoint's MPSS as necessary")), and with
> "pci=pcie_bus_safe", pcie_bus_configure_settings() can do the same when
> pciehp calls it after a hot-add. The Root Port's state was saved when it
> was added and again when portdrv probed it.
>
> Since commit 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root
> Ports in a platform-specific way"), pcibios_reset_secondary_bus() restores
> that saved state, without saving it first, after host->reset_root_port()
> has reset the Root Port, e.g. during AER recovery or on Link Down with the
> qcom and Rockchip DWC drivers. The Root Port then goes back to the old,
> larger MPS while the device below it is restored to the smaller one, so
> the Root Port may send TLPs that the device treats as Malformed.
>
> Update the saved copy of Device Control when pcie_set_mps() changes the
> MPS, like commit 909f7bf9b080 ("PCI: Update saved_config_space upon
> resource assignment") does for BARs.
>
> Fixes: 3fc686d550f6 ("PCI/ERR: Add support for resetting the Root Ports in a platform-specific way")
> Assisted-by: LLM
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
Applied to pci/mps for v7.4, thanks!
> ---
> This fix was originally sent out as part of my RFC series:
> https://lore.kernel.org/linux-pci/20260930145017.1356088-6-cassel@kernel.org/
>
> But sending this fix as a separate patch, as the fix is really unrelated
> to the rest of the series, so it could be picked up independently.
>
> drivers/pci/pci.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 8cc6a89130b5..f3b82eb7bfaf 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1736,6 +1736,24 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
> pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
> }
>
> +/*
> + * Update the saved copy of the Device Control register after changing it, so
> + * that pci_restore_state() doesn't put back a stale value. Device Control is
> + * the first register saved by pci_save_pcie_state().
> + */
> +static void pcie_update_saved_devctl(struct pci_dev *dev, u16 clear, u16 set)
> +{
> + struct pci_cap_saved_state *save_state;
> + u16 *devctl;
> +
> + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
> + if (!save_state)
> + return;
> +
> + devctl = (u16 *)&save_state->cap.data[0];
> + *devctl = (*devctl & ~clear) | set;
> +}
> +
> static int pci_save_pcix_state(struct pci_dev *dev)
> {
> int pos;
> @@ -5983,8 +6001,12 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
>
> ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
> PCI_EXP_DEVCTL_PAYLOAD, v);
> + if (ret)
> + return pcibios_err_to_errno(ret);
>
> - return pcibios_err_to_errno(ret);
> + pcie_update_saved_devctl(dev, PCI_EXP_DEVCTL_PAYLOAD, v);
> +
> + return 0;
> }
> EXPORT_SYMBOL(pcie_set_mps);
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-12 21:57 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-05 12:41 [PATCH] PCI: Update saved Max Payload Size in pcie_set_mps() Niklas Cassel
2026-10-05 12:41 ` Niklas Cassel
2026-10-05 12:50 ` sashiko-bot
2026-10-05 15:56 ` Keith Busch
2026-10-05 15:56 ` Keith Busch
2026-10-06 12:06 ` Shawn Lin
2026-10-06 12:06 ` Shawn Lin
2026-10-12 21:56 ` Bjorn Helgaas
2026-10-12 21:56 ` Bjorn Helgaas
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.