All of lore.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 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.