public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] PCI: Avoid capability searches in save/restore state
@ 2025-02-08  5:03 Bjorn Helgaas
  2025-02-08  5:03 ` [PATCH 1/2] PCI: Avoid pointless capability searches Bjorn Helgaas
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Bjorn Helgaas @ 2025-02-08  5:03 UTC (permalink / raw)
  To: Alex Williamson, Christian König
  Cc: linux-pci, linux-kernel, Bjorn Helgaas

From: Bjorn Helgaas <bhelgaas@google.com>

Reduce the number of times we search config space for PCI capabilities when
saving and restoring device state.

Bjorn Helgaas (2):
  PCI: Avoid pointless capability searches
  PCI: Cache offset of Resizable BAR capability

 drivers/pci/pci.c       | 36 +++++++++++++++++++++---------------
 drivers/pci/pci.h       |  1 +
 drivers/pci/pcie/aspm.c | 15 ++++++++-------
 drivers/pci/probe.c     |  1 +
 drivers/pci/vc.c        | 22 +++++++++++-----------
 include/linux/pci.h     |  1 +
 6 files changed, 43 insertions(+), 33 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] PCI: Avoid pointless capability searches
  2025-02-08  5:03 [PATCH 0/2] PCI: Avoid capability searches in save/restore state Bjorn Helgaas
@ 2025-02-08  5:03 ` Bjorn Helgaas
  2025-02-13 13:52   ` Ilpo Järvinen
  2025-02-08  5:03 ` [PATCH 2/2] PCI: Cache offset of Resizable BAR capability Bjorn Helgaas
  2025-02-12 22:35 ` [PATCH 0/2] PCI: Avoid capability searches in save/restore state Bjorn Helgaas
  2 siblings, 1 reply; 8+ messages in thread
From: Bjorn Helgaas @ 2025-02-08  5:03 UTC (permalink / raw)
  To: Alex Williamson, Christian König
  Cc: linux-pci, linux-kernel, Bjorn Helgaas

From: Bjorn Helgaas <bhelgaas@google.com>

Many of the save/restore functions in the pci_save_state() and
pci_restore_state() paths depend on both a PCI capability of the device and
a pci_cap_saved_state structure to hold the configuration data, and they
skip the operation if either is missing.

Look for the pci_cap_saved_state first so if we don't have one, we can skip
searching for the device capability, which requires several slow config
space accesses.

Remove some error messages if the pci_cap_saved_state is not found so we
don't complain about having no saved state for a capability the device
doesn't have.  We have already warned in pci_allocate_cap_save_buffers() if
the capability is present but we were unable to allocate a buffer.

Other than the message change, no functional change intended.

Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
---
 drivers/pci/pci.c       | 27 ++++++++++++++-------------
 drivers/pci/pcie/aspm.c | 15 ++++++++-------
 drivers/pci/vc.c        | 22 +++++++++++-----------
 3 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 869d204a70a3..503376bf7e75 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1686,10 +1686,8 @@ static int pci_save_pcie_state(struct pci_dev *dev)
 		return 0;
 
 	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
-	if (!save_state) {
-		pci_err(dev, "buffer not found in %s\n", __func__);
+	if (!save_state)
 		return -ENOMEM;
-	}
 
 	cap = (u16 *)&save_state->cap.data[0];
 	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &cap[i++]);
@@ -1742,19 +1740,17 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
 
 static int pci_save_pcix_state(struct pci_dev *dev)
 {
-	int pos;
 	struct pci_cap_saved_state *save_state;
+	u8 pos;
+
+	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
+	if (!save_state)
+		return -ENOMEM;
 
 	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
 	if (!pos)
 		return 0;
 
-	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
-	if (!save_state) {
-		pci_err(dev, "buffer not found in %s\n", __func__);
-		return -ENOMEM;
-	}
-
 	pci_read_config_word(dev, pos + PCI_X_CMD,
 			     (u16 *)save_state->cap.data);
 
@@ -1763,14 +1759,19 @@ static int pci_save_pcix_state(struct pci_dev *dev)
 
 static void pci_restore_pcix_state(struct pci_dev *dev)
 {
-	int i = 0, pos;
 	struct pci_cap_saved_state *save_state;
+	u8 pos;
+	int i = 0;
 	u16 *cap;
 
 	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
-	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
-	if (!save_state || !pos)
+	if (!save_state)
 		return;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+	if (!pos)
+		return;
+
 	cap = (u16 *)&save_state->cap.data[0];
 
 	pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index e0bc90597dca..007e4a082e6f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -35,16 +35,14 @@ void pci_save_ltr_state(struct pci_dev *dev)
 	if (!pci_is_pcie(dev))
 		return;
 
+	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
+	if (!save_state)
+		return;
+
 	ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
 	if (!ltr)
 		return;
 
-	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
-	if (!save_state) {
-		pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n");
-		return;
-	}
-
 	/* Some broken devices only support dword access to LTR */
 	cap = &save_state->cap.data[0];
 	pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
@@ -57,8 +55,11 @@ void pci_restore_ltr_state(struct pci_dev *dev)
 	u32 *cap;
 
 	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
+	if (!save_state)
+		return;
+
 	ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
-	if (!save_state || !ltr)
+	if (!ltr)
 		return;
 
 	/* Some broken devices only support dword access to LTR */
diff --git a/drivers/pci/vc.c b/drivers/pci/vc.c
index a4ff7f5f66dd..c39f3be518d4 100644
--- a/drivers/pci/vc.c
+++ b/drivers/pci/vc.c
@@ -355,20 +355,17 @@ int pci_save_vc_state(struct pci_dev *dev)
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
-		int pos, ret;
 		struct pci_cap_saved_state *save_state;
+		int pos, ret;
+
+		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
+		if (!save_state)
+			return -ENOMEM;
 
 		pos = pci_find_ext_capability(dev, vc_caps[i].id);
 		if (!pos)
 			continue;
 
-		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
-		if (!save_state) {
-			pci_err(dev, "%s buffer not found in %s\n",
-				vc_caps[i].name, __func__);
-			return -ENOMEM;
-		}
-
 		ret = pci_vc_do_save_buffer(dev, pos, save_state, true);
 		if (ret) {
 			pci_err(dev, "%s save unsuccessful %s\n",
@@ -392,12 +389,15 @@ void pci_restore_vc_state(struct pci_dev *dev)
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
-		int pos;
 		struct pci_cap_saved_state *save_state;
+		int pos;
+
+		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
+		if (!save_state)
+			continue;
 
 		pos = pci_find_ext_capability(dev, vc_caps[i].id);
-		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
-		if (!save_state || !pos)
+		if (!pos)
 			continue;
 
 		pci_vc_do_save_buffer(dev, pos, save_state, false);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] PCI: Cache offset of Resizable BAR capability
  2025-02-08  5:03 [PATCH 0/2] PCI: Avoid capability searches in save/restore state Bjorn Helgaas
  2025-02-08  5:03 ` [PATCH 1/2] PCI: Avoid pointless capability searches Bjorn Helgaas
@ 2025-02-08  5:03 ` Bjorn Helgaas
  2025-02-13 13:54   ` Ilpo Järvinen
  2025-02-12 22:35 ` [PATCH 0/2] PCI: Avoid capability searches in save/restore state Bjorn Helgaas
  2 siblings, 1 reply; 8+ messages in thread
From: Bjorn Helgaas @ 2025-02-08  5:03 UTC (permalink / raw)
  To: Alex Williamson, Christian König
  Cc: linux-pci, linux-kernel, Bjorn Helgaas

From: Bjorn Helgaas <bhelgaas@google.com>

Previously most resizable BAR interfaces (pci_rebar_get_possible_sizes(),
pci_rebar_set_size(), etc) as well as pci_restore_state() searched config
space for a Resizable BAR capability.  Most devices don't have such a
capability, so this is wasted effort, especially for pci_restore_state().

Search for a Resizable BAR capability once at enumeration-time and cache
the offset so we don't have to search every time we need it.  No functional
change intended.

Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
---
 drivers/pci/pci.c   | 9 +++++++--
 drivers/pci/pci.h   | 1 +
 drivers/pci/probe.c | 1 +
 include/linux/pci.h | 1 +
 4 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 503376bf7e75..cf2632080a94 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1872,7 +1872,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
 	unsigned int pos, nbars, i;
 	u32 ctrl;
 
-	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
+	pos = pdev->rebar_cap;
 	if (!pos)
 		return;
 
@@ -3719,6 +3719,11 @@ void pci_acs_init(struct pci_dev *dev)
 	pci_enable_acs(dev);
 }
 
+void pci_rebar_init(struct pci_dev *pdev)
+{
+	pdev->rebar_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
+}
+
 /**
  * pci_rebar_find_pos - find position of resize ctrl reg for BAR
  * @pdev: PCI device
@@ -3733,7 +3738,7 @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
 	unsigned int pos, nbars, i;
 	u32 ctrl;
 
-	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
+	pos = pdev->rebar_cap;
 	if (!pos)
 		return -ENOTSUPP;
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 01e51db8d285..d7b46ddfd6d2 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -799,6 +799,7 @@ static inline int acpi_get_rc_resources(struct device *dev, const char *hid,
 }
 #endif
 
+void pci_rebar_init(struct pci_dev *pdev);
 int pci_rebar_get_current_size(struct pci_dev *pdev, int bar);
 int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size);
 static inline u64 pci_rebar_size_to_bytes(int size)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b6536ed599c3..24dd3dcfd223 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2564,6 +2564,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
 	pci_rcec_init(dev);		/* Root Complex Event Collector */
 	pci_doe_init(dev);		/* Data Object Exchange */
 	pci_tph_init(dev);		/* TLP Processing Hints */
+	pci_rebar_init(dev);		/* Resizable BAR */
 
 	pcie_report_downtraining(dev);
 	pci_init_reset_methods(dev);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 47b31ad724fa..9e5bbd996c83 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -353,6 +353,7 @@ struct pci_dev {
 	struct pci_dev  *rcec;          /* Associated RCEC device */
 #endif
 	u32		devcap;		/* PCIe Device Capabilities */
+	u16		rebar_cap;	/* Resizable BAR capability offset */
 	u8		pcie_cap;	/* PCIe capability offset */
 	u8		msi_cap;	/* MSI capability offset */
 	u8		msix_cap;	/* MSI-X capability offset */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] PCI: Avoid capability searches in save/restore state
  2025-02-08  5:03 [PATCH 0/2] PCI: Avoid capability searches in save/restore state Bjorn Helgaas
  2025-02-08  5:03 ` [PATCH 1/2] PCI: Avoid pointless capability searches Bjorn Helgaas
  2025-02-08  5:03 ` [PATCH 2/2] PCI: Cache offset of Resizable BAR capability Bjorn Helgaas
@ 2025-02-12 22:35 ` Bjorn Helgaas
  2 siblings, 0 replies; 8+ messages in thread
From: Bjorn Helgaas @ 2025-02-12 22:35 UTC (permalink / raw)
  To: Alex Williamson, Christian König
  Cc: linux-pci, linux-kernel, Bjorn Helgaas

On Fri, Feb 07, 2025 at 11:03:27PM -0600, Bjorn Helgaas wrote:
> From: Bjorn Helgaas <bhelgaas@google.com>
> 
> Reduce the number of times we search config space for PCI capabilities when
> saving and restoring device state.
> 
> Bjorn Helgaas (2):
>   PCI: Avoid pointless capability searches
>   PCI: Cache offset of Resizable BAR capability
> 
>  drivers/pci/pci.c       | 36 +++++++++++++++++++++---------------
>  drivers/pci/pci.h       |  1 +
>  drivers/pci/pcie/aspm.c | 15 ++++++++-------
>  drivers/pci/probe.c     |  1 +
>  drivers/pci/vc.c        | 22 +++++++++++-----------
>  include/linux/pci.h     |  1 +
>  6 files changed, 43 insertions(+), 33 deletions(-)

Applied to pci/enumeration for v6.15, please speak up if you see a
problem.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] PCI: Avoid pointless capability searches
  2025-02-08  5:03 ` [PATCH 1/2] PCI: Avoid pointless capability searches Bjorn Helgaas
@ 2025-02-13 13:52   ` Ilpo Järvinen
  2025-02-13 16:38     ` Bjorn Helgaas
  0 siblings, 1 reply; 8+ messages in thread
From: Ilpo Järvinen @ 2025-02-13 13:52 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Alex Williamson, Christian König, linux-pci, LKML,
	Bjorn Helgaas

On Fri, 7 Feb 2025, Bjorn Helgaas wrote:

> From: Bjorn Helgaas <bhelgaas@google.com>
> 
> Many of the save/restore functions in the pci_save_state() and
> pci_restore_state() paths depend on both a PCI capability of the device and
> a pci_cap_saved_state structure to hold the configuration data, and they
> skip the operation if either is missing.
> 
> Look for the pci_cap_saved_state first so if we don't have one, we can skip
> searching for the device capability, which requires several slow config
> space accesses.
> 
> Remove some error messages if the pci_cap_saved_state is not found so we
> don't complain about having no saved state for a capability the device
> doesn't have.  We have already warned in pci_allocate_cap_save_buffers() if
> the capability is present but we were unable to allocate a buffer.
> 
> Other than the message change, no functional change intended.
> 
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
>  drivers/pci/pci.c       | 27 ++++++++++++++-------------
>  drivers/pci/pcie/aspm.c | 15 ++++++++-------
>  drivers/pci/vc.c        | 22 +++++++++++-----------
>  3 files changed, 33 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 869d204a70a3..503376bf7e75 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1686,10 +1686,8 @@ static int pci_save_pcie_state(struct pci_dev *dev)
>  		return 0;
>  
>  	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
> -	if (!save_state) {
> -		pci_err(dev, "buffer not found in %s\n", __func__);
> +	if (!save_state)
>  		return -ENOMEM;
> -	}
>  
>  	cap = (u16 *)&save_state->cap.data[0];
>  	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &cap[i++]);
> @@ -1742,19 +1740,17 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
>  
>  static int pci_save_pcix_state(struct pci_dev *dev)
>  {
> -	int pos;
>  	struct pci_cap_saved_state *save_state;
> +	u8 pos;
> +
> +	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
> +	if (!save_state)
> +		return -ENOMEM;
>  
>  	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
>  	if (!pos)
>  		return 0;
>  
> -	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
> -	if (!save_state) {
> -		pci_err(dev, "buffer not found in %s\n", __func__);
> -		return -ENOMEM;
> -	}
> -
>  	pci_read_config_word(dev, pos + PCI_X_CMD,
>  			     (u16 *)save_state->cap.data);
>  
> @@ -1763,14 +1759,19 @@ static int pci_save_pcix_state(struct pci_dev *dev)
>  
>  static void pci_restore_pcix_state(struct pci_dev *dev)
>  {
> -	int i = 0, pos;
>  	struct pci_cap_saved_state *save_state;
> +	u8 pos;
> +	int i = 0;
>  	u16 *cap;
>  
>  	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
> -	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
> -	if (!save_state || !pos)
> +	if (!save_state)
>  		return;
> +
> +	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
> +	if (!pos)
> +		return;
> +
>  	cap = (u16 *)&save_state->cap.data[0];
>  
>  	pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
> diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
> index e0bc90597dca..007e4a082e6f 100644
> --- a/drivers/pci/pcie/aspm.c
> +++ b/drivers/pci/pcie/aspm.c
> @@ -35,16 +35,14 @@ void pci_save_ltr_state(struct pci_dev *dev)
>  	if (!pci_is_pcie(dev))
>  		return;
>  
> +	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
> +	if (!save_state)
> +		return;
> +
>  	ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
>  	if (!ltr)
>  		return;
>  
> -	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
> -	if (!save_state) {
> -		pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n");
> -		return;
> -	}
> -
>  	/* Some broken devices only support dword access to LTR */
>  	cap = &save_state->cap.data[0];
>  	pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
> @@ -57,8 +55,11 @@ void pci_restore_ltr_state(struct pci_dev *dev)
>  	u32 *cap;
>  
>  	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
> +	if (!save_state)
> +		return;
> +
>  	ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
> -	if (!save_state || !ltr)
> +	if (!ltr)
>  		return;
>  
>  	/* Some broken devices only support dword access to LTR */
> diff --git a/drivers/pci/vc.c b/drivers/pci/vc.c
> index a4ff7f5f66dd..c39f3be518d4 100644
> --- a/drivers/pci/vc.c
> +++ b/drivers/pci/vc.c
> @@ -355,20 +355,17 @@ int pci_save_vc_state(struct pci_dev *dev)
>  	int i;
>  
>  	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
> -		int pos, ret;
>  		struct pci_cap_saved_state *save_state;
> +		int pos, ret;
> +
> +		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> +		if (!save_state)
> +			return -ENOMEM;
>  
>  		pos = pci_find_ext_capability(dev, vc_caps[i].id);
>  		if (!pos)
>  			continue;
>  
> -		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> -		if (!save_state) {
> -			pci_err(dev, "%s buffer not found in %s\n",
> -				vc_caps[i].name, __func__);
> -			return -ENOMEM;
> -		}

I think this order change will cause a functional change because 
pci_allocate_vc_save_buffers() only allocated for those capabilities that 
are exist for dev. Thus, the loop will prematurely exit.

> -
>  		ret = pci_vc_do_save_buffer(dev, pos, save_state, true);
>  		if (ret) {
>  			pci_err(dev, "%s save unsuccessful %s\n",
> @@ -392,12 +389,15 @@ void pci_restore_vc_state(struct pci_dev *dev)
>  	int i;
>  
>  	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
> -		int pos;
>  		struct pci_cap_saved_state *save_state;
> +		int pos;
> +
> +		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> +		if (!save_state)
> +			continue;
>  
>  		pos = pci_find_ext_capability(dev, vc_caps[i].id);
> -		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> -		if (!save_state || !pos)
> +		if (!pos)
>  			continue;
>  
>  		pci_vc_do_save_buffer(dev, pos, save_state, false);
> 

-- 
 i.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] PCI: Cache offset of Resizable BAR capability
  2025-02-08  5:03 ` [PATCH 2/2] PCI: Cache offset of Resizable BAR capability Bjorn Helgaas
@ 2025-02-13 13:54   ` Ilpo Järvinen
  0 siblings, 0 replies; 8+ messages in thread
From: Ilpo Järvinen @ 2025-02-13 13:54 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Alex Williamson, Christian König, linux-pci, linux-kernel,
	Bjorn Helgaas

[-- Attachment #1: Type: text/plain, Size: 3498 bytes --]

On Fri, 7 Feb 2025, Bjorn Helgaas wrote:

> From: Bjorn Helgaas <bhelgaas@google.com>
> 
> Previously most resizable BAR interfaces (pci_rebar_get_possible_sizes(),
> pci_rebar_set_size(), etc) as well as pci_restore_state() searched config
> space for a Resizable BAR capability.  Most devices don't have such a
> capability, so this is wasted effort, especially for pci_restore_state().
> 
> Search for a Resizable BAR capability once at enumeration-time and cache
> the offset so we don't have to search every time we need it.  No functional
> change intended.
> 
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
>  drivers/pci/pci.c   | 9 +++++++--
>  drivers/pci/pci.h   | 1 +
>  drivers/pci/probe.c | 1 +
>  include/linux/pci.h | 1 +
>  4 files changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 503376bf7e75..cf2632080a94 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1872,7 +1872,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
>  	unsigned int pos, nbars, i;
>  	u32 ctrl;
>  
> -	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
> +	pos = pdev->rebar_cap;
>  	if (!pos)
>  		return;
>  
> @@ -3719,6 +3719,11 @@ void pci_acs_init(struct pci_dev *dev)
>  	pci_enable_acs(dev);
>  }
>  
> +void pci_rebar_init(struct pci_dev *pdev)
> +{
> +	pdev->rebar_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
> +}
> +
>  /**
>   * pci_rebar_find_pos - find position of resize ctrl reg for BAR
>   * @pdev: PCI device
> @@ -3733,7 +3738,7 @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
>  	unsigned int pos, nbars, i;
>  	u32 ctrl;
>  
> -	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
> +	pos = pdev->rebar_cap;
>  	if (!pos)
>  		return -ENOTSUPP;
>  
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 01e51db8d285..d7b46ddfd6d2 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -799,6 +799,7 @@ static inline int acpi_get_rc_resources(struct device *dev, const char *hid,
>  }
>  #endif
>  
> +void pci_rebar_init(struct pci_dev *pdev);
>  int pci_rebar_get_current_size(struct pci_dev *pdev, int bar);
>  int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size);
>  static inline u64 pci_rebar_size_to_bytes(int size)
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index b6536ed599c3..24dd3dcfd223 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -2564,6 +2564,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
>  	pci_rcec_init(dev);		/* Root Complex Event Collector */
>  	pci_doe_init(dev);		/* Data Object Exchange */
>  	pci_tph_init(dev);		/* TLP Processing Hints */
> +	pci_rebar_init(dev);		/* Resizable BAR */
>  
>  	pcie_report_downtraining(dev);
>  	pci_init_reset_methods(dev);
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 47b31ad724fa..9e5bbd996c83 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -353,6 +353,7 @@ struct pci_dev {
>  	struct pci_dev  *rcec;          /* Associated RCEC device */
>  #endif
>  	u32		devcap;		/* PCIe Device Capabilities */
> +	u16		rebar_cap;	/* Resizable BAR capability offset */
>  	u8		pcie_cap;	/* PCIe capability offset */
>  	u8		msi_cap;	/* MSI capability offset */
>  	u8		msix_cap;	/* MSI-X capability offset */

Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

-- 
 i.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] PCI: Avoid pointless capability searches
  2025-02-13 13:52   ` Ilpo Järvinen
@ 2025-02-13 16:38     ` Bjorn Helgaas
  2025-02-14 14:20       ` Ilpo Järvinen
  0 siblings, 1 reply; 8+ messages in thread
From: Bjorn Helgaas @ 2025-02-13 16:38 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Alex Williamson, Christian König, linux-pci, LKML,
	Bjorn Helgaas

On Thu, Feb 13, 2025 at 03:52:05PM +0200, Ilpo Järvinen wrote:
> On Fri, 7 Feb 2025, Bjorn Helgaas wrote:
> > Many of the save/restore functions in the pci_save_state() and
> > pci_restore_state() paths depend on both a PCI capability of the device and
> > a pci_cap_saved_state structure to hold the configuration data, and they
> > skip the operation if either is missing.
> > 
> > Look for the pci_cap_saved_state first so if we don't have one, we can skip
> > searching for the device capability, which requires several slow config
> > space accesses.

> > +++ b/drivers/pci/vc.c
> > @@ -355,20 +355,17 @@ int pci_save_vc_state(struct pci_dev *dev)
> >  	int i;
> >  
> >  	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
> > -		int pos, ret;
> >  		struct pci_cap_saved_state *save_state;
> > +		int pos, ret;
> > +
> > +		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > +		if (!save_state)
> > +			return -ENOMEM;
> >  
> >  		pos = pci_find_ext_capability(dev, vc_caps[i].id);
> >  		if (!pos)
> >  			continue;
> >  
> > -		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > -		if (!save_state) {
> > -			pci_err(dev, "%s buffer not found in %s\n",
> > -				vc_caps[i].name, __func__);
> > -			return -ENOMEM;
> > -		}
> 
> I think this order change will cause a functional change because 
> pci_allocate_vc_save_buffers() only allocated for those capabilities that 
> are exist for dev. Thus, the loop will prematurely exit.

Oof, thank you for catching this!  I'll drop this for now.

It would be nice to make pci_save_vc_state() parallel with
pci_restore_vc_state() (and with most other pci_save_*_state()
functions) and have it return void.  But pci_save_state() returns the
pci_save_vc_state() return value, and there are ~20 pci_save_state()
callers that pay attention to that return value.

I'm not convinced there's real value in pci_save_state() error
returns, given that so few callers check it, but it definitely
requires more analysis before removing it.

> >  		ret = pci_vc_do_save_buffer(dev, pos, save_state, true);
> >  		if (ret) {
> >  			pci_err(dev, "%s save unsuccessful %s\n",
> > @@ -392,12 +389,15 @@ void pci_restore_vc_state(struct pci_dev *dev)
> >  	int i;
> >  
> >  	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
> > -		int pos;
> >  		struct pci_cap_saved_state *save_state;
> > +		int pos;
> > +
> > +		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > +		if (!save_state)
> > +			continue;
> >  
> >  		pos = pci_find_ext_capability(dev, vc_caps[i].id);
> > -		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > -		if (!save_state || !pos)
> > +		if (!pos)
> >  			continue;
> >  
> >  		pci_vc_do_save_buffer(dev, pos, save_state, false);
> > 
> 
> -- 
>  i.
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] PCI: Avoid pointless capability searches
  2025-02-13 16:38     ` Bjorn Helgaas
@ 2025-02-14 14:20       ` Ilpo Järvinen
  0 siblings, 0 replies; 8+ messages in thread
From: Ilpo Järvinen @ 2025-02-14 14:20 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Alex Williamson, Christian König, linux-pci, LKML,
	Bjorn Helgaas

[-- Attachment #1: Type: text/plain, Size: 3218 bytes --]

On Thu, 13 Feb 2025, Bjorn Helgaas wrote:

> On Thu, Feb 13, 2025 at 03:52:05PM +0200, Ilpo Järvinen wrote:
> > On Fri, 7 Feb 2025, Bjorn Helgaas wrote:
> > > Many of the save/restore functions in the pci_save_state() and
> > > pci_restore_state() paths depend on both a PCI capability of the device and
> > > a pci_cap_saved_state structure to hold the configuration data, and they
> > > skip the operation if either is missing.
> > > 
> > > Look for the pci_cap_saved_state first so if we don't have one, we can skip
> > > searching for the device capability, which requires several slow config
> > > space accesses.
> 
> > > +++ b/drivers/pci/vc.c
> > > @@ -355,20 +355,17 @@ int pci_save_vc_state(struct pci_dev *dev)
> > >  	int i;
> > >  
> > >  	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
> > > -		int pos, ret;
> > >  		struct pci_cap_saved_state *save_state;
> > > +		int pos, ret;
> > > +
> > > +		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > > +		if (!save_state)
> > > +			return -ENOMEM;
> > >  
> > >  		pos = pci_find_ext_capability(dev, vc_caps[i].id);
> > >  		if (!pos)
> > >  			continue;
> > >  
> > > -		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > > -		if (!save_state) {
> > > -			pci_err(dev, "%s buffer not found in %s\n",
> > > -				vc_caps[i].name, __func__);
> > > -			return -ENOMEM;
> > > -		}
> > 
> > I think this order change will cause a functional change because 
> > pci_allocate_vc_save_buffers() only allocated for those capabilities that 
> > are exist for dev. Thus, the loop will prematurely exit.
> 
> Oof, thank you for catching this!  I'll drop this for now.
> 
> It would be nice to make pci_save_vc_state() parallel with
> pci_restore_vc_state() (and with most other pci_save_*_state()
> functions) and have it return void.  But pci_save_state() returns the
> pci_save_vc_state() return value, and there are ~20 pci_save_state()
> callers that pay attention to that return value.
> 
> I'm not convinced there's real value in pci_save_state() error
> returns, given that so few callers check it, but it definitely
> requires more analysis before removing it.

Indeed, I also though that -ENOMEM even in the original is questionable.
These are not the real sources of the failure but just secondary effect 
from the failure that occurred earlier in _pci_add_cap_save_buffer().

-- 
 i.

> > >  		ret = pci_vc_do_save_buffer(dev, pos, save_state, true);
> > >  		if (ret) {
> > >  			pci_err(dev, "%s save unsuccessful %s\n",
> > > @@ -392,12 +389,15 @@ void pci_restore_vc_state(struct pci_dev *dev)
> > >  	int i;
> > >  
> > >  	for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
> > > -		int pos;
> > >  		struct pci_cap_saved_state *save_state;
> > > +		int pos;
> > > +
> > > +		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > > +		if (!save_state)
> > > +			continue;
> > >  
> > >  		pos = pci_find_ext_capability(dev, vc_caps[i].id);
> > > -		save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
> > > -		if (!save_state || !pos)
> > > +		if (!pos)
> > >  			continue;
> > >  
> > >  		pci_vc_do_save_buffer(dev, pos, save_state, false);


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-02-14 14:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-08  5:03 [PATCH 0/2] PCI: Avoid capability searches in save/restore state Bjorn Helgaas
2025-02-08  5:03 ` [PATCH 1/2] PCI: Avoid pointless capability searches Bjorn Helgaas
2025-02-13 13:52   ` Ilpo Järvinen
2025-02-13 16:38     ` Bjorn Helgaas
2025-02-14 14:20       ` Ilpo Järvinen
2025-02-08  5:03 ` [PATCH 2/2] PCI: Cache offset of Resizable BAR capability Bjorn Helgaas
2025-02-13 13:54   ` Ilpo Järvinen
2025-02-12 22:35 ` [PATCH 0/2] PCI: Avoid capability searches in save/restore state Bjorn Helgaas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox