Skip to contentSkip to conversation

ACPI / PCI / PCIe: Rework _OSC handling (v2)

PATCH In review Rafael J. Wysocki 4 participants 85 messages Aug 2, 2010 – Aug 6, 2010

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover ACPI / PCI / PCIe: Rework _OSC handling (v2)

Hi,

This is the second iteration of the patchset based on
https://patchwork.kernel.org/patch/114917/ and the comments I received on that patch. Hopefully, I took all of the comments into account this time.

[1/8] - Introduce acpi_pci_osc_control_query() allowing the caller to get a
mask of _OSC control bits the BIOS allows the kernel to control for a given PCI root bridge.

[2/8] - Introduce pci_aer_available() allowing the caller to check if the
AER service driver should be enabled.

[3/8] - Introduce kernel command line switch pcie_ports=.

[4/8] - Rework the PCIe port driver to request _OSC control for all serives at
once.

[5/8] - Disable PCIe port services (that might be enabled by the BIOS) during
initialization.

[6/8] - Remove the PCIe port driver modules exit function.

[7/8] - Rework acpi_pci_osc_control_set() so that it doesn't use cached
result of a query and remove the fields of struct acpi_pci_root that
aren't used any more.

[8/8] - Reorder checks in acpi_pci_osc_control_set()

Thanks,
Rafael

#1 lore raw

PATCH 1/8 ACPI / PCI: Introduce acpi_pci_osc_control_query()

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   58 ++++++++++++++++++++++++++++++++++++++++--------
 include/linux/acpi.h    |    1 
 2 files changed, 50 insertions(+), 9 deletions(-)
drivers/acpi/pci_root.c +49 -9
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,35 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @ctrl_mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *ctrl_mask)
+{
+	acpi_status status;
+	acpi_handle tmp;
+	struct acpi_pci_root *root;
+
+	if (!ctrl_mask || !(*ctrl_mask & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +436,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
#2 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

Quoted 31 lines · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
  drivers/acpi/pci_root.c |   58 ++++++++++++++++++++++++++++++++++++++++--------
  include/linux/acpi.h    |    1
  2 files changed, 50 insertions(+), 9 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +7 -2
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
  	return status;
  }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
  {
  	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support&= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;

drivers/acpi/pci_root.c static acpi_status acpi_pci_run_osc(acpi · line 242

Quoted 10 lines
drivers/acpi/pci_root.c +4 -4
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags&  OSC_PCI_SUPPORT_MASKS);
  	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control&= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control;

I think controls that are already granted to OS need to be ORed here. I.e.

		capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | *control;

Thanks,
Kenji Kaneshige

#3 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

Quoted 46 lines · Kenji Kaneshige
Quoted 31 lines · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
  drivers/acpi/pci_root.c |   58 ++++++++++++++++++++++++++++++++++++++++--------
  include/linux/acpi.h    |    1
  2 files changed, 50 insertions(+), 9 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +7 -2
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
  	return status;
  }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
  {
  	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support&= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;

drivers/acpi/pci_root.c static acpi_status acpi_pci_run_osc(acpi · line 242

Quoted 10 lines
drivers/acpi/pci_root.c +4 -4
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags&  OSC_PCI_SUPPORT_MASKS);
  	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control&= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control;

I think controls that are already granted to OS need to be ORed here. I.e.

Quoted 1 line
		capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | *control;

That's correct.

Thanks,
Rafael

#4 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Kenji Kaneshige
Quoted 46 lines · Kenji Kaneshige
Quoted 31 lines · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
  drivers/acpi/pci_root.c |   58 ++++++++++++++++++++++++++++++++++++++++--------
  include/linux/acpi.h    |    1
  2 files changed, 50 insertions(+), 9 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +7 -2
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
  	return status;
  }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
  {
  	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support&= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;

drivers/acpi/pci_root.c static acpi_status acpi_pci_run_osc(acpi · line 242

Quoted 10 lines
drivers/acpi/pci_root.c +4 -4
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags&  OSC_PCI_SUPPORT_MASKS);
  	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control&= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control;

I think controls that are already granted to OS need to be ORed here. I.e.

Quoted 1 line
		capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | *control;

That's correct.

Thanks,
Rafael

#5 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Rafael J. Wysocki
Quoted 31 lines · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
  drivers/acpi/pci_root.c |   58 ++++++++++++++++++++++++++++++++++++++++--------
  include/linux/acpi.h    |    1
  2 files changed, 50 insertions(+), 9 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +7 -2
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
  	return status;
  }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
  {
  	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support&= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;

drivers/acpi/pci_root.c static acpi_status acpi_pci_run_osc(acpi · line 242

Quoted 10 lines
drivers/acpi/pci_root.c +4 -4
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags&  OSC_PCI_SUPPORT_MASKS);
  	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control&= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control;

I think controls that are already granted to OS need to be ORed here. I.e.

		capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | *control;

Thanks,
Kenji Kaneshige

#6 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Rafael J. Wysocki
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 402

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set & *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Thanks,
Kenji Kaneshige

#7 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Rafael J. Wysocki
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 402

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set & *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Thanks,
Kenji Kaneshige

#8 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

Quoted 15 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 402

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

Quoted 8 lines
	mutex_lock(&osc_lock);
	if ((root->osc_control_set & *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Well I guess you mean:

mutex_lock(&osc_lock);
if ((root->osc_control_set & *ctrl_mask) != *ctrl_mask)
status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Thanks,
Rafael

#9 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

Quoted 32 lines · Rafael J. Wysocki
Quoted 15 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

Review

Quoted 4 lines
(quoted diff) +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

Quoted 8 lines
	mutex_lock(&osc_lock);
	if ((root->osc_control_set & *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Well I guess you mean:

(quoted diff) +0 -0
 	mutex_lock(&osc_lock);
 	if ((root->osc_control_set & *ctrl_mask) != *ctrl_mask) 
 		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
 	mutex_unlock(&osc_lock);
Quoted 1 line

Otherwise we would return with the mutex held. :-)

Updated patch is appended, please tell me what you think.

Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce acpi_pci_osc_control_query() (v2)

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   61 ++++++++++++++++++++++++++++++++++++++++--------
 include/linux/acpi.h    |    1 
 2 files changed, 53 insertions(+), 9 deletions(-)
drivers/acpi/pci_root.c +52 -9
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,38 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
+{
+	struct acpi_pci_root *root;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+
+	if (!mask || !(*mask & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +439,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
#10 lore raw

Re: [linux-pm] [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Rafael J. Wysocki
Quoted 32 lines · Rafael J. Wysocki
Quoted 15 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

Review

Quoted 4 lines
(quoted diff) +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

Quoted 8 lines
	mutex_lock(&osc_lock);
	if ((root->osc_control_set & *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Well I guess you mean:

(quoted diff) +0 -0
 	mutex_lock(&osc_lock);
 	if ((root->osc_control_set & *ctrl_mask) != *ctrl_mask) 
 		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
 	mutex_unlock(&osc_lock);
Quoted 1 line

Otherwise we would return with the mutex held. :-)

Updated patch is appended, please tell me what you think.

Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce acpi_pci_osc_control_query() (v2)

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   61 ++++++++++++++++++++++++++++++++++++++++--------
 include/linux/acpi.h    |    1 
 2 files changed, 53 insertions(+), 9 deletions(-)
drivers/acpi/pci_root.c +52 -9
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,38 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
+{
+	struct acpi_pci_root *root;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+
+	if (!mask || !(*mask & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +439,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
#11 lore raw

Re: [linux-pm] [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

Quoted 26 lines · Rafael J. Wysocki
Quoted 25 lines · Rafael J. Wysocki
Quoted 23 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 405

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set&  *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Quoted 9 lines
Quoted 8 lines

Well I guess you mean:

  	mutex_lock(&osc_lock);
  	if ((root->osc_control_set&  *ctrl_mask) != *ctrl_mask)
  		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
  	mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Oops... sorry...

Quoted 1 line

Updated patch is appended, please tell me what you think.

Looks good to me. The below (in your updated patch) was what I wanted to mean

drivers/acpi/pci_root.c out: · line 404

Quoted 6 lines
drivers/acpi/pci_root.c +6 -0
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);

Thanks,
Kenji Kaneshige

#12 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

Quoted 41 lines · Kenji Kaneshige
Quoted 26 lines · Rafael J. Wysocki
Quoted 25 lines · Rafael J. Wysocki
Quoted 23 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

Review

Quoted 4 lines
(quoted diff) +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set&  *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Quoted 9 lines
Quoted 8 lines

Well I guess you mean:

  	mutex_lock(&osc_lock);
  	if ((root->osc_control_set&  *ctrl_mask) != *ctrl_mask)
  		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
  	mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Oops... sorry...

Quoted 1 line

Updated patch is appended, please tell me what you think.

Quoted 8 lines

Looks good to me. The below (in your updated patch) was what I wanted to mean

Review

Quoted 6 lines
(quoted diff) +6 -0
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);

OK

However, I think we can put the looping into that function so that the caller doesn't have to loop.

The patch below implements that.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce acpi_pci_osc_control_query() (v3)

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   71 +++++++++++++++++++++++++++++++++++++++++-------
 include/linux/acpi.h    |    1 
 2 files changed, 63 insertions(+), 9 deletions(-)
drivers/acpi/pci_root.c +62 -9
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,48 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
+{
+	struct acpi_pci_root *root;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+	u32 ctrl = *mask;
+
+	if (!ctrl || !(ctrl & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+
+	*mask |= root->osc_control_set;
+	if ((ctrl & root->osc_control_set) == ctrl)
+		goto out;
+
+	while (*mask && *mask != ctrl) {
+		ctrl = *mask;
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+		if (ACPI_FAILURE(status))
+			break;
+	}
+
+ out:
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +449,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
#13 lore raw

Re: [linux-pm] [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Kenji Kaneshige
Quoted 41 lines · Kenji Kaneshige
Quoted 26 lines · Rafael J. Wysocki
Quoted 25 lines · Rafael J. Wysocki
Quoted 23 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

Review

Quoted 4 lines
(quoted diff) +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set&  *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Quoted 9 lines
Quoted 8 lines

Well I guess you mean:

  	mutex_lock(&osc_lock);
  	if ((root->osc_control_set&  *ctrl_mask) != *ctrl_mask)
  		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
  	mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Oops... sorry...

Quoted 1 line

Updated patch is appended, please tell me what you think.

Quoted 8 lines

Looks good to me. The below (in your updated patch) was what I wanted to mean

Review

Quoted 6 lines
(quoted diff) +6 -0
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);

OK

However, I think we can put the looping into that function so that the caller doesn't have to loop.

The patch below implements that.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce acpi_pci_osc_control_query() (v3)

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   71 +++++++++++++++++++++++++++++++++++++++++-------
 include/linux/acpi.h    |    1 
 2 files changed, 63 insertions(+), 9 deletions(-)
drivers/acpi/pci_root.c +62 -9
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,48 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
+{
+	struct acpi_pci_root *root;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+	u32 ctrl = *mask;
+
+	if (!ctrl || !(ctrl & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+
+	*mask |= root->osc_control_set;
+	if ((ctrl & root->osc_control_set) == ctrl)
+		goto out;
+
+	while (*mask && *mask != ctrl) {
+		ctrl = *mask;
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+		if (ACPI_FAILURE(status))
+			break;
+	}
+
+ out:
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +449,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
#14 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

Quoted 53 lines · Rafael J. Wysocki
Quoted 41 lines · Kenji Kaneshige
Quoted 26 lines · Rafael J. Wysocki
Quoted 25 lines · Rafael J. Wysocki
Quoted 23 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 415

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set&  *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Quoted 9 lines
Quoted 8 lines

Well I guess you mean:

  	mutex_lock(&osc_lock);
  	if ((root->osc_control_set&  *ctrl_mask) != *ctrl_mask)
  		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
  	mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Oops... sorry...

Quoted 1 line

Updated patch is appended, please tell me what you think.

Quoted 8 lines

Looks good to me. The below (in your updated patch) was what I wanted to mean

drivers/acpi/pci_root.c out: · line 414

Quoted 6 lines
drivers/acpi/pci_root.c +6 -0
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);

OK

Quoted 4 lines

However, I think we can put the looping into that function so that the caller doesn't have to loop.

The patch below implements that.

The patch below is incorrect, sorry. Please disregard it.

Thanks,
Rafael

Quoted 143 lines

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce acpi_pci_osc_control_query() (v3)

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   71 +++++++++++++++++++++++++++++++++++++++++-------
 include/linux/acpi.h    |    1 
 2 files changed, 63 insertions(+), 9 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +62 -9
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,48 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
+{
+	struct acpi_pci_root *root;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+	u32 ctrl = *mask;
+
+	if (!ctrl || !(ctrl & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+
+	*mask |= root->osc_control_set;
+	if ((ctrl & root->osc_control_set) == ctrl)
+		goto out;
+
+	while (*mask && *mask != ctrl) {
+		ctrl = *mask;
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+		if (ACPI_FAILURE(status))
+			break;
+	}
+
+ out:
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +449,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}

Index: linux-2.6/include/linux/acpi.h
===================================================================

include/linux/acpi.h +1 -0
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 

_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

#15 lore raw

Re: [linux-pm] [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Rafael J. Wysocki
Quoted 53 lines · Rafael J. Wysocki
Quoted 41 lines · Kenji Kaneshige
Quoted 26 lines · Rafael J. Wysocki
Quoted 25 lines · Rafael J. Wysocki
Quoted 23 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 415

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set&  *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Quoted 9 lines
Quoted 8 lines

Well I guess you mean:

  	mutex_lock(&osc_lock);
  	if ((root->osc_control_set&  *ctrl_mask) != *ctrl_mask)
  		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
  	mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Oops... sorry...

Quoted 1 line

Updated patch is appended, please tell me what you think.

Quoted 8 lines

Looks good to me. The below (in your updated patch) was what I wanted to mean

drivers/acpi/pci_root.c out: · line 414

Quoted 6 lines
drivers/acpi/pci_root.c +6 -0
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);

OK

Quoted 4 lines

However, I think we can put the looping into that function so that the caller doesn't have to loop.

The patch below implements that.

The patch below is incorrect, sorry. Please disregard it.

Thanks,
Rafael

Quoted 143 lines

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce acpi_pci_osc_control_query() (v3)

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   71 +++++++++++++++++++++++++++++++++++++++++-------
 include/linux/acpi.h    |    1 
 2 files changed, 63 insertions(+), 9 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +62 -9
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,48 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
+{
+	struct acpi_pci_root *root;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+	u32 ctrl = *mask;
+
+	if (!ctrl || !(ctrl & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+
+	*mask |= root->osc_control_set;
+	if ((ctrl & root->osc_control_set) == ctrl)
+		goto out;
+
+	while (*mask && *mask != ctrl) {
+		ctrl = *mask;
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+		if (ACPI_FAILURE(status))
+			break;
+	}
+
+ out:
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +449,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}

Index: linux-2.6/include/linux/acpi.h
===================================================================

include/linux/acpi.h +1 -0
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 

_______________________________________________
linux-pm mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

#16 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Rafael J. Wysocki
Quoted 26 lines · Rafael J. Wysocki
Quoted 25 lines · Rafael J. Wysocki
Quoted 23 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 405

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

	mutex_lock(&osc_lock);
	if ((root->osc_control_set&  *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Quoted 9 lines
Quoted 8 lines

Well I guess you mean:

  	mutex_lock(&osc_lock);
  	if ((root->osc_control_set&  *ctrl_mask) != *ctrl_mask)
  		status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
  	mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Oops... sorry...

Quoted 1 line

Updated patch is appended, please tell me what you think.

Looks good to me. The below (in your updated patch) was what I wanted to mean

drivers/acpi/pci_root.c out: · line 404

Quoted 6 lines
drivers/acpi/pci_root.c +6 -0
+	mutex_lock(&osc_lock);
+	if ((*mask & root->osc_control_set) == *mask)
+		*mask = root->osc_control_set;
+	else
+		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+	mutex_unlock(&osc_lock);

Thanks,
Kenji Kaneshige

#17 lore raw

Re: [PATCH 1/8] ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Kenji Kaneshige
Quoted 15 lines · Kenji Kaneshige
Quoted 1 line · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

<snip.>

drivers/acpi/pci_root.c out: · line 402

Quoted 4 lines
drivers/acpi/pci_root.c +4 -0
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+

One more comment here.

I think we can skip acpi_pci_query_osc() if all of queried controls are already granted to OS. Please see below

Quoted 8 lines
	mutex_lock(&osc_lock);
	if ((root->osc_control_set & *ctrl_mask) == *ctrl_mask) {
		*ctrl_mask = root->osc_control_set;
		goto out;
	}
	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
	mutex_unlock(&osc_lock);

out:

Well I guess you mean:

mutex_lock(&osc_lock);
if ((root->osc_control_set & *ctrl_mask) != *ctrl_mask)
status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
mutex_unlock(&osc_lock);

Otherwise we would return with the mutex held. :-)

Thanks,
Rafael

#18 lore raw

PATCH 1/8 ACPI / PCI: Introduce acpi_pci_osc_control_query()

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to obtain a mask of _OSC control bits the BIOS will allow the kernel to control for a given PCI root bridge.

---
 drivers/acpi/pci_root.c |   58 ++++++++++++++++++++++++++++++++++++++++--------
 include/linux/acpi.h    |    1 
 2 files changed, 50 insertions(+), 9 deletions(-)
drivers/acpi/pci_root.c +49 -9
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -225,21 +225,32 @@ static acpi_status acpi_pci_run_osc(acpi
 	return status;
 }
 
-static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
+static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
+					u32 support,
+					u32 *control)
 {
 	acpi_status status;
-	u32 support_set, result, capbuf[3];
+	u32 result, capbuf[3];
+
+	support &= OSC_PCI_SUPPORT_MASKS;
+	support |= root->osc_support_set;
 
-	/* do _OSC query for all possible controls */
-	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
 	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
-	capbuf[OSC_SUPPORT_TYPE] = support_set;
-	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	capbuf[OSC_SUPPORT_TYPE] = support;
+	if (control) {
+		*control &= OSC_PCI_CONTROL_MASKS;
+		capbuf[OSC_CONTROL_TYPE] = *control;
+	} else {
+		/* Run _OSC query for all possible controls. */
+		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+	}
 
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
-		root->osc_support_set = support_set;
+		root->osc_support_set = support;
 		root->osc_control_qry = result;
+		if (control)
+			*control = result;
 		root->osc_queried = 1;
 	}
 	return status;
@@ -254,7 +265,7 @@ static acpi_status acpi_pci_osc_support(
 	if (ACPI_FAILURE(status))
 		return status;
 	mutex_lock(&osc_lock);
-	status = acpi_pci_query_osc(root, flags);
+	status = acpi_pci_query_osc(root, flags, NULL);
 	mutex_unlock(&osc_lock);
 	return status;
 }
@@ -363,6 +374,35 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @ctrl_mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *ctrl_mask)
+{
+	acpi_status status;
+	acpi_handle tmp;
+	struct acpi_pci_root *root;
+
+	if (!ctrl_mask || !(*ctrl_mask & OSC_PCI_CONTROL_MASKS))
+		return AE_BAD_PARAMETER;
+
+	root = acpi_pci_find_root(handle);
+	if (!root)
+		return AE_NOT_EXIST;
+
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	mutex_lock(&osc_lock);
+	status = acpi_pci_query_osc(root, root->osc_support_set, ctrl_mask);
+	mutex_unlock(&osc_lock);
+
+	return status;
+}
+
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -396,7 +436,7 @@ acpi_status acpi_pci_osc_control_set(acp
 
 	/* Need to query controls first before requesting them */
 	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set);
+		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
 		if (ACPI_FAILURE(status))
 			goto out;
 	}
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
#19 lore raw

PATCH 2/8 PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---
 drivers/pci/pci.h             |    2 ++
 drivers/pci/pcie/aer/aerdrv.c |    9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)
drivers/pci/pci.h +2 -0
Index: linux-2.6/drivers/pci/pci.h
===================================================================
@@ -131,8 +131,10 @@ static inline void pci_msi_init_pci_dev(
 
 #ifdef CONFIG_PCIEAER
 void pci_no_aer(void);
+bool pci_aer_available(void);
 #else
 static inline void pci_no_aer(void) { }
+static inline bool pci_aer_available(void) { return false; }
 #endif
 
 static inline int pci_no_d1d2(struct pci_dev *dev)
drivers/pci/pcie/aer/aerdrv.c +6 -3
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }
#20 lore raw

PATCH 2/8 PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---
 drivers/pci/pci.h             |    2 ++
 drivers/pci/pcie/aer/aerdrv.c |    9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)
drivers/pci/pci.h +2 -0
Index: linux-2.6/drivers/pci/pci.h
===================================================================
@@ -131,8 +131,10 @@ static inline void pci_msi_init_pci_dev(
 
 #ifdef CONFIG_PCIEAER
 void pci_no_aer(void);
+bool pci_aer_available(void);
 #else
 static inline void pci_no_aer(void) { }
+static inline bool pci_aer_available(void) { return false; }
 #endif
 
 static inline int pci_no_d1d2(struct pci_dev *dev)
drivers/pci/pcie/aer/aerdrv.c +6 -3
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }
#21 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

Quoted 7 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---

(snip)

Quoted 17 lines

Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================

drivers/pci/pcie/aer/aerdrv.c +5 -0
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);

drivers/pci/pcie/aer/aerdrv.c static void aer_error_resume(struct pci_ · line 422

Quoted 10 lines
drivers/pci/pcie/aer/aerdrv.c +1 -3
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }

Breaking a big lump into small pieces often makes things clear. You should return error when AER is _NOT_ available.

if (!pci_aer_available())

	return -ENXIO;

Be careful...

Thanks,
H.Seto

#22 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Rafael J. Wysocki
Quoted 7 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---

(snip)

Quoted 17 lines

Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================

drivers/pci/pcie/aer/aerdrv.c +5 -0
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);

drivers/pci/pcie/aer/aerdrv.c static void aer_error_resume(struct pci_ · line 422

Quoted 10 lines
drivers/pci/pcie/aer/aerdrv.c +1 -3
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }

Breaking a big lump into small pieces often makes things clear. You should return error when AER is _NOT_ available.

if (!pci_aer_available())

	return -ENXIO;

Be careful...

Thanks,
H.Seto

#23 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

Quoted 40 lines · Hidetoshi Seto
Quoted 7 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---

(snip)

Quoted 17 lines

Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================

drivers/pci/pcie/aer/aerdrv.c +5 -0
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);

drivers/pci/pcie/aer/aerdrv.c static void aer_error_resume(struct pci_ · line 422

Quoted 10 lines
drivers/pci/pcie/aer/aerdrv.c +1 -3
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }

Breaking a big lump into small pieces often makes things clear. You should return error when AER is _NOT_ available.

Quoted 4 lines

if (!pci_aer_available())

	return -ENXIO;

Be careful...

Yup, sorry.

Thanks,
Rafael

#24 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

Quoted 41 lines · Rafael J. Wysocki
Quoted 40 lines · Hidetoshi Seto
Quoted 7 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---

(snip)

Quoted 17 lines

Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================

drivers/pci/pcie/aer/aerdrv.c +5 -0
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);

drivers/pci/pcie/aer/aerdrv.c static void aer_error_resume(struct pci_ · line 422

Quoted 10 lines
drivers/pci/pcie/aer/aerdrv.c +1 -3
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }

Breaking a big lump into small pieces often makes things clear. You should return error when AER is _NOT_ available.

Quoted 6 lines
Quoted 4 lines

if (!pci_aer_available())

	return -ENXIO;

Be careful...

Yup, sorry.

Corrected patch is appended.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: PCI / PCIe/ AER: Introduce pci_aer_available()

Introduce a function allowing the caller to check whether to try to enable PCIe AER.

---
 drivers/pci/pci.h             |    2 ++
 drivers/pci/pcie/aer/aerdrv.c |    9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)
drivers/pci/pci.h +2 -0
Index: linux-2.6/drivers/pci/pci.h
===================================================================
@@ -131,8 +131,10 @@ static inline void pci_msi_init_pci_dev(
 
 #ifdef CONFIG_PCIEAER
 void pci_no_aer(void);
+bool pci_aer_available(void);
 #else
 static inline void pci_no_aer(void) { }
+static inline bool pci_aer_available(void) { return false; }
 #endif
 
 static inline int pci_no_d1d2(struct pci_dev *dev)
drivers/pci/pcie/aer/aerdrv.c +6 -3
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (!pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }
#25 lore raw

Re: [linux-pm] [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Rafael J. Wysocki
Quoted 41 lines · Rafael J. Wysocki
Quoted 40 lines · Hidetoshi Seto
Quoted 7 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---

(snip)

Quoted 17 lines

Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================

drivers/pci/pcie/aer/aerdrv.c +5 -0
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);

drivers/pci/pcie/aer/aerdrv.c static void aer_error_resume(struct pci_ · line 422

Quoted 10 lines
drivers/pci/pcie/aer/aerdrv.c +1 -3
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }

Breaking a big lump into small pieces often makes things clear. You should return error when AER is _NOT_ available.

Quoted 6 lines
Quoted 4 lines

if (!pci_aer_available())

	return -ENXIO;

Be careful...

Yup, sorry.

Corrected patch is appended.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: PCI / PCIe/ AER: Introduce pci_aer_available()

Introduce a function allowing the caller to check whether to try to enable PCIe AER.

---
 drivers/pci/pci.h             |    2 ++
 drivers/pci/pcie/aer/aerdrv.c |    9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)
drivers/pci/pci.h +2 -0
Index: linux-2.6/drivers/pci/pci.h
===================================================================
@@ -131,8 +131,10 @@ static inline void pci_msi_init_pci_dev(
 
 #ifdef CONFIG_PCIEAER
 void pci_no_aer(void);
+bool pci_aer_available(void);
 #else
 static inline void pci_no_aer(void) { }
+static inline bool pci_aer_available(void) { return false; }
 #endif
 
 static inline int pci_no_d1d2(struct pci_dev *dev)
drivers/pci/pcie/aer/aerdrv.c +6 -3
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (!pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }
#26 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Hidetoshi Seto
Quoted 40 lines · Hidetoshi Seto
Quoted 7 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

---

(snip)

Quoted 17 lines

Index: linux-2.6/drivers/pci/pcie/aer/aerdrv.c
===================================================================

drivers/pci/pcie/aer/aerdrv.c +5 -0
@@ -72,6 +72,11 @@ void pci_no_aer(void)
 	pcie_aer_disable = 1;	/* has priority over 'forceload' */
 }
 
+bool pci_aer_available(void)
+{
+	return !pcie_aer_disable && pci_msi_enabled();
+}
+
 static int set_device_error_reporting(struct pci_dev *dev, void *data)
 {
 	bool enable = *((bool *)data);

drivers/pci/pcie/aer/aerdrv.c static void aer_error_resume(struct pci_ · line 422

Quoted 10 lines
drivers/pci/pcie/aer/aerdrv.c +1 -3
@@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_
  */
 static int __init aer_service_init(void)
 {
-	if (pcie_aer_disable)
-		return -ENXIO;
-	if (!pci_msi_enabled())
+	if (pci_aer_available())
 		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }

Breaking a big lump into small pieces often makes things clear. You should return error when AER is _NOT_ available.

Quoted 4 lines

if (!pci_aer_available())

	return -ENXIO;

Be careful...

Yup, sorry.

Thanks,
Rafael

#27 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Rafael J. Wysocki
Quoted 5 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

Maybe it's misnamed? How about pcie_aer_disable is not set and MSI is enabled, but there is not AER capability implemented at all?

Signature · 2 lines
Thanks,
Jike
#28 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Rafael J. Wysocki
Quoted 5 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

Maybe it's misnamed? How about pcie_aer_disable is not set and MSI is enabled, but there is not AER capability implemented at all?

Signature · 2 lines
Thanks,
Jike
#29 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

Quoted 9 lines · Jike Song
Quoted 5 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

Maybe it's misnamed? How about pcie_aer_disable is not set and MSI is enabled, but there is not AER capability implemented at all?

The BIOS is supposed to tell us about that or we will find out from the registers contents. This function tells us whether to _try_ to enable AER (ie. ask the BIOS and so on).

Thanks,
Rafael

#30 lore raw

Re: [PATCH 2/8] PCI / PCIe/ AER: Introduce pci_aer_available()

In reply to Jike Song
Quoted 9 lines · Jike Song
Quoted 5 lines · Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce a function allowing the caller to check if PCIe AER should be enabled.

Maybe it's misnamed? How about pcie_aer_disable is not set and MSI is enabled, but there is not AER capability implemented at all?

The BIOS is supposed to tell us about that or we will find out from the registers contents. This function tells us whether to _try_ to enable AER (ie. ask the BIOS and so on).

Thanks,
Rafael

#31 lore raw

PATCH 3/8 PCI / PCIe: Introduce commad line switch for disabling port services

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce kernel command line switch pcie_ports= allowing one to disable all of the native PCIe port services, so that PCIe ports are treated like PCI-to-PCI bridges.

---
 Documentation/kernel-parameters.txt |    4 ++++
 drivers/pci/pcie/portdrv.h          |    2 ++
 drivers/pci/pcie/portdrv_core.c     |    3 +++
 drivers/pci/pcie/portdrv_pci.c      |   15 +++++++++++++++
 4 files changed, 24 insertions(+)
drivers/pci/pcie/portdrv_pci.c +15 -0
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -29,6 +29,18 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+/* If this switch is set, PCIe port native services should not be enabled. */
+bool pcie_ports_disabled;
+
+static int __init pcie_port_setup(char *str)
+{
+	if (!strncmp(str, "compat", 6))
+		pcie_ports_disabled = true;
+
+	return 1;
+}
+__setup("pcie_ports=", pcie_port_setup);
+
 /* global data */
 
 static int pcie_portdrv_restore_config(struct pci_dev *dev)
@@ -301,6 +313,9 @@ static int __init pcie_portdrv_init(void
 {
 	int retval;
 
+	if (pcie_ports_disabled)
+		return -EACCES;
+
 	dmi_check_system(pcie_portdrv_dmi_table);
 
 	retval = pcie_port_bus_register();
Documentation/kernel-parameters.txt +4 -0
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
@@ -2047,6 +2047,10 @@ and is between 256 and 4096 characters. 
 		force	Enable ASPM even on devices that claim not to support it.
 			WARNING: Forcing ASPM on may cause system lockups.
 
+	pcie_ports=	[PCIE] PCIe ports handling:
+		compat	Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
+			ports driver.
+
 	pcie_pme=	[PCIE,PM] Native PCIe PME signaling options:
 			Format: {auto|force}[,nomsi]
 		auto	Use native PCIe PME signaling if the BIOS allows the
drivers/pci/pcie/portdrv.h +2 -0
Index: linux-2.6/drivers/pci/pcie/portdrv.h
===================================================================
@@ -20,6 +20,8 @@
 
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
+extern bool pcie_ports_disabled;
+
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
drivers/pci/pcie/portdrv_core.c +3 -0
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -494,6 +494,9 @@ static void pcie_port_shutdown_service(s
  */
 int pcie_port_service_register(struct pcie_port_service_driver *new)
 {
+	if (pcie_ports_disabled)
+		return -ENODEV;
+
 	new->driver.name = (char *)new->name;
 	new->driver.bus = &pcie_port_bus_type;
 	new->driver.probe = pcie_port_probe_service;
#32 lore raw

PATCH 3/8 PCI / PCIe: Introduce commad line switch for disabling port services

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Introduce kernel command line switch pcie_ports= allowing one to disable all of the native PCIe port services, so that PCIe ports are treated like PCI-to-PCI bridges.

---
 Documentation/kernel-parameters.txt |    4 ++++
 drivers/pci/pcie/portdrv.h          |    2 ++
 drivers/pci/pcie/portdrv_core.c     |    3 +++
 drivers/pci/pcie/portdrv_pci.c      |   15 +++++++++++++++
 4 files changed, 24 insertions(+)
drivers/pci/pcie/portdrv_pci.c +15 -0
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -29,6 +29,18 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+/* If this switch is set, PCIe port native services should not be enabled. */
+bool pcie_ports_disabled;
+
+static int __init pcie_port_setup(char *str)
+{
+	if (!strncmp(str, "compat", 6))
+		pcie_ports_disabled = true;
+
+	return 1;
+}
+__setup("pcie_ports=", pcie_port_setup);
+
 /* global data */
 
 static int pcie_portdrv_restore_config(struct pci_dev *dev)
@@ -301,6 +313,9 @@ static int __init pcie_portdrv_init(void
 {
 	int retval;
 
+	if (pcie_ports_disabled)
+		return -EACCES;
+
 	dmi_check_system(pcie_portdrv_dmi_table);
 
 	retval = pcie_port_bus_register();
Documentation/kernel-parameters.txt +4 -0
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
@@ -2047,6 +2047,10 @@ and is between 256 and 4096 characters. 
 		force	Enable ASPM even on devices that claim not to support it.
 			WARNING: Forcing ASPM on may cause system lockups.
 
+	pcie_ports=	[PCIE] PCIe ports handling:
+		compat	Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
+			ports driver.
+
 	pcie_pme=	[PCIE,PM] Native PCIe PME signaling options:
 			Format: {auto|force}[,nomsi]
 		auto	Use native PCIe PME signaling if the BIOS allows the
drivers/pci/pcie/portdrv.h +2 -0
Index: linux-2.6/drivers/pci/pcie/portdrv.h
===================================================================
@@ -20,6 +20,8 @@
 
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
+extern bool pcie_ports_disabled;
+
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
drivers/pci/pcie/portdrv_core.c +3 -0
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -494,6 +494,9 @@ static void pcie_port_shutdown_service(s
  */
 int pcie_port_service_register(struct pcie_port_service_driver *new)
 {
+	if (pcie_ports_disabled)
+		return -ENODEV;
+
 	new->driver.name = (char *)new->name;
 	new->driver.bus = &pcie_port_bus_type;
 	new->driver.probe = pcie_port_probe_service;
#33 lore raw

PATCH 4/8 PCI / PCIe: Ask BIOS for control of all native services at once (v6)

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

PCIe port service drivers ask the BIOS, through _OSC, for control of the services they handle. Unfortunately, each of them individually asks for control of the PCIe capability structure and if that is granted, some BIOSes expect that the other PCIe port services will be configured and handled by the kernel as well. If that is not the case (eg. one of the PCIe port service drivers is not loaded), the BIOS may be confused and may cause the system as a whole to misbehave (eg. on one of such systems enabling the native PCIe PME service without loading the native PCIe hot-plug service driver causes a storm of ACPI notify requests to appear).

For this reason rework the PCIe port driver so that (1) it checks which native PCIe port services can be enabled, according to the BIOS, and (2) it requests control of all these services simultaneously. In particular, this causes pcie_portdrv_probe() to fail if the BIOS refuses to grant control of the PCIe capability structure, which means that no native PCIe port services can be enabled for the PCIe root complex the given port belongs to.

Make it possible to override this behavior using 'pcie_ports=native' (use the PCIe native services regardless of the BIOS response to the control request), or 'pcie_ports=compat' (do not use the PCIe native services at all).

Accordingly, rework the existing PCIe port service drivers so that they don't request control of the services directly.

---
 Documentation/kernel-parameters.txt  |   13 ++---
 drivers/pci/hotplug/acpi_pcihp.c     |    4 -
 drivers/pci/hotplug/pciehp.h         |   12 ----
 drivers/pci/hotplug/pciehp_acpi.c    |    4 -
 drivers/pci/hotplug/pciehp_core.c    |    4 -
 drivers/pci/pcie/Makefile            |    3 -
 drivers/pci/pcie/aer/aerdrv_acpi.c   |   36 --------------
 drivers/pci/pcie/aer/aerdrv_core.c   |   14 -----
 drivers/pci/pcie/pme/Makefile        |    8 ---
 drivers/pci/pcie/pme/pcie_pme.c      |   64 ++-----------------------
 drivers/pci/pcie/pme/pcie_pme.h      |   28 -----------
 drivers/pci/pcie/pme/pcie_pme_acpi.c |   54 ---------------------
 drivers/pci/pcie/portdrv.h           |   20 ++++++++
 drivers/pci/pcie/portdrv_acpi.c      |   87 +++++++++++++++++++++++++++++++++++
 drivers/pci/pcie/portdrv_core.c      |   22 +++++++-
 drivers/pci/pcie/portdrv_pci.c       |   15 +++++-
 16 files changed, 158 insertions(+), 230 deletions(-)
drivers/pci/pcie/portdrv_pci.c +14 -1
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -32,10 +32,23 @@ MODULE_LICENSE("GPL");
 /* If this switch is set, PCIe port native services should not be enabled. */
 bool pcie_ports_disabled;
 
+/*
+ * If this switch is set, ACPI _OSC will be used to determine whether or not to
+ * enable PCIe port native services.
+ */
+bool pcie_ports_auto = true;
+
 static int __init pcie_port_setup(char *str)
 {
-	if (!strncmp(str, "compat", 6))
+	if (!strncmp(str, "compat", 6)) {
 		pcie_ports_disabled = true;
+	} else if (!strncmp(str, "native", 6)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = false;
+	} else if (!strncmp(str, "auto", 4)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = true;
+	}
 
 	return 1;
 }
drivers/pci/pcie/portdrv_acpi.c new file +87 -0

87 lines not on this page · raw message

drivers/pci/pcie/portdrv.h +20 -0
Index: linux-2.6/drivers/pci/pcie/portdrv.h
===================================================================
@@ -21,6 +21,7 @@
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
 extern bool pcie_ports_disabled;
+extern bool pcie_ports_auto;
 
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_register(struct pci_dev *dev);
@@ -32,6 +33,8 @@ extern void pcie_port_device_remove(stru
 extern int __must_check pcie_port_bus_register(void);
 extern void pcie_port_bus_unregister(void);
 
+struct pci_dev;
+
 #ifdef CONFIG_PCIE_PME
 extern bool pcie_pme_msi_disabled;
 
@@ -44,9 +47,26 @@ static inline bool pcie_pme_no_msi(void)
 {
 	return pcie_pme_msi_disabled;
 }
+
+extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
 #else /* !CONFIG_PCIE_PME */
 static inline void pcie_pme_disable_msi(void) {}
 static inline bool pcie_pme_no_msi(void) { return false; }
+static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
 #endif /* !CONFIG_PCIE_PME */
 
+#ifdef CONFIG_ACPI
+extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
+
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return pcie_port_acpi_setup(port, mask);
+}
+#else /* !CONFIG_ACPI */
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return 0;
+}
+#endif /* !CONFIG_ACPI */
+
 #endif /* _PORTDRV_H_ */
drivers/pci/pcie/Makefile +2 -1
Index: linux-2.6/drivers/pci/pcie/Makefile
===================================================================
@@ -6,10 +6,11 @@
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 
 pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
 # Build PCI Express AER if needed
 obj-$(CONFIG_PCIEAER)		+= aer/
 
-obj-$(CONFIG_PCIE_PME) += pme/
+obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o
drivers/pci/pcie/portdrv_core.c +19 -3
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
+#include <linux/aer.h>
 
 #include "../pci.h"
 #include "portdrv.h"
@@ -236,23 +237,38 @@ static int get_port_device_capability(st
 	int services = 0, pos;
 	u16 reg16;
 	u32 reg32;
+	int cap_mask;
+	int err;
+
+	err = pcie_port_platform_notify(dev, &cap_mask);
+	if (pcie_ports_auto) {
+		if (err)
+			return 0;
+	} else {
+		cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
+				| PCIE_PORT_SERVICE_VC;
+		if (pci_aer_available())
+			cap_mask |= PCIE_PORT_SERVICE_AER;
+	}
 
 	pos = pci_pcie_cap(dev);
 	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
 	/* Hot-Plug Capable */
-	if (reg16 & PCI_EXP_FLAGS_SLOT) {
+	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
 		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
 		if (reg32 & PCI_EXP_SLTCAP_HPC)
 			services |= PCIE_PORT_SERVICE_HP;
 	}
 	/* AER capable */
-	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+	if ((cap_mask & PCIE_PORT_SERVICE_AER)
+	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
 		services |= PCIE_PORT_SERVICE_AER;
 	/* VC support */
 	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
 		services |= PCIE_PORT_SERVICE_VC;
 	/* Root ports are capable of generating PME too */
-	if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	if ((cap_mask & PCIE_PORT_SERVICE_PME)
+	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
 		services |= PCIE_PORT_SERVICE_PME;
 
 	return services;
drivers/pci/pcie/pme/pcie_pme.c +5 -59

104 lines not on this page · raw message

drivers/pci/pcie/pme/pcie_pme.h deleted +0 -28
Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme.h
===================================================================
@@ -1,28 +0,0 @@
-/*
- * drivers/pci/pcie/pme/pcie_pme.h
- *
- * PCI Express Root Port PME signaling support
- *
- * Copyright (C) 2009 Rafael J. Wysocki <[email protected]>, Novell Inc.
- */
-
-#ifndef _PCIE_PME_H_
-#define _PCIE_PME_H_
-
-struct pcie_device;
-
-#ifdef CONFIG_ACPI
-extern int pcie_pme_acpi_setup(struct pcie_device *srv);
-
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return pcie_pme_acpi_setup(srv);
-}
-#else /* !CONFIG_ACPI */
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return 0;
-}
-#endif /* !CONFIG_ACPI */
-
-#endif
drivers/pci/pcie/pme/pcie_pme_acpi.c deleted +0 -54

54 lines not on this page · raw message

drivers/pci/pcie/pme/Makefile deleted +0 -8
Index: linux-2.6/drivers/pci/pcie/pme/Makefile
===================================================================
@@ -1,8 +0,0 @@
-#
-# Makefile for PCI-Express Root Port PME signaling driver
-#
-
-obj-$(CONFIG_PCIE_PME) += pmedriver.o
-
-pmedriver-objs := pcie_pme.o
-pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
drivers/pci/pcie/aer/aerdrv_acpi.c +0 -36
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_acpi.c
===================================================================
@@ -19,42 +19,6 @@
 #include <acpi/apei.h>
 #include "aerdrv.h"
 
-/**
- * aer_osc_setup - run ACPI _OSC method
- * @pciedev: pcie_device which AER is being enabled on
- *
- * @return: Zero on success. Nonzero otherwise.
- *
- * Invoked when PCIe bus loads AER service driver. To avoid conflict with
- * BIOS AER support requires BIOS to yield AER control to OS native driver.
- **/
-int aer_osc_setup(struct pcie_device *pciedev)
-{
-	acpi_status status = AE_NOT_FOUND;
-	struct pci_dev *pdev = pciedev->port;
-	acpi_handle handle = NULL;
-
-	if (acpi_pci_disabled)
-		return -1;
-
-	handle = acpi_find_root_bridge_handle(pdev);
-	if (handle) {
-		status = acpi_pci_osc_control_set(handle,
-					OSC_PCI_EXPRESS_AER_CONTROL |
-					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	}
-
-	if (ACPI_FAILURE(status)) {
-		dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't "
-			   "init device: %s\n",
-			   (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
-			   "no _OSC support" : "_OSC failed");
-		return -1;
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 static inline int hest_match_pci(struct acpi_hest_aer_common *p,
 				 struct pci_dev *pci)
drivers/pci/pcie/aer/aerdrv_core.c +1 -13
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_core.c
===================================================================
@@ -771,22 +771,10 @@ void aer_isr(struct work_struct *work)
  */
 int aer_init(struct pcie_device *dev)
 {
-	if (pcie_aer_get_firmware_first(dev->port)) {
-		dev_printk(KERN_DEBUG, &dev->device,
-			   "PCIe errors handled by platform firmware.\n");
-		goto out;
-	}
-
-	if (aer_osc_setup(dev))
-		goto out;
-
-	return 0;
-out:
 	if (forceload) {
 		dev_printk(KERN_DEBUG, &dev->device,
 			   "aerdrv forceload requested.\n");
 		pcie_aer_force_firmware_first(dev->port, 0);
-		return 0;
 	}
-	return -ENXIO;
+	return 0;
 }
drivers/pci/hotplug/acpi_pcihp.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================
@@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware
 	acpi_handle chandle, handle;
 	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		  OSC_SHPC_NATIVE_HP_CONTROL |
-		  OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+	flags &= OSC_SHPC_NATIVE_HP_CONTROL;
 	if (!flags) {
 		err("Invalid flags %u specified!\n", flags);
 		return -EINVAL;
drivers/pci/hotplug/pciehp.h +0 -12
Index: linux-2.6/drivers/pci/hotplug/pciehp.h
===================================================================
@@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(
 {
 	pciehp_acpi_slot_detection_init();
 }
-
-static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
-{
-	int retval;
-	u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		     OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	retval = acpi_get_hp_hw_control_from_firmware(dev, flags);
-	if (retval)
-		return retval;
-	return pciehp_acpi_slot_detection_check(dev);
-}
 #else
 #define pciehp_firmware_init()				do {} while (0)
-#define pciehp_get_hp_hw_control_from_firmware(dev) 	0
 #endif 				/* CONFIG_ACPI */
 #endif				/* _PCIEHP_H */
drivers/pci/hotplug/pciehp_core.c +2 -2
Index: linux-2.6/drivers/pci/hotplug/pciehp_core.c
===================================================================
@@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644);
 MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
-MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
+MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing");
 
 #define PCIE_MODULE_NAME "pciehp"
 
@@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_devi
 		dev_info(&dev->device,
 			 "Bypassing BIOS check for pciehp use on %s\n",
 			 pci_name(dev->port));
-	else if (pciehp_get_hp_hw_control_from_firmware(dev->port))
+	else if (pciehp_acpi_slot_detection_check(dev->port))
 		goto err_out_none;
 
 	ctrl = pcie_init(dev);
drivers/pci/hotplug/pciehp_acpi.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/pciehp_acpi.c
===================================================================
@@ -85,9 +85,7 @@ static int __init dummy_probe(struct pci
 	acpi_handle handle;
 	struct dummy_slot *slot, *tmp;
 	struct pci_dev *pdev = dev->port;
-	/* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
-	if (pciehp_get_hp_hw_control_from_firmware(pdev))
-		return -ENODEV;
+
 	pos = pci_pcie_cap(pdev);
 	if (!pos)
 		return -ENODEV;
Documentation/kernel-parameters.txt +6 -7
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
@@ -2048,18 +2048,17 @@ and is between 256 and 4096 characters. 
 			WARNING: Forcing ASPM on may cause system lockups.
 
 	pcie_ports=	[PCIE] PCIe ports handling:
+		auto	Ask the BIOS whether or not to use native PCIe services
+			associated with PCIe ports (PME, hot-plug, AER).  Use
+			them only if that is allowed by the BIOS.
+		native	Use native PCIe services associated with PCIe ports
+			unconditionally.
 		compat	Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
 			ports driver.
 
 	pcie_pme=	[PCIE,PM] Native PCIe PME signaling options:
-			Format: {auto|force}[,nomsi]
-		auto	Use native PCIe PME signaling if the BIOS allows the
-			kernel to control PCIe config registers of root ports.
-		force	Use native PCIe PME signaling even if the BIOS refuses
-			to allow the kernel to control the relevant PCIe config
-			registers.
 		nomsi	Do not use MSI for native PCIe PME signaling (this makes
-			all PCIe root ports use INTx for everything).
+			all PCIe root ports use INTx for all services).
 
 	pcmv=		[HW,PCMCIA] BadgePAD 4
 
#34 lore raw

Re: [PATCH 4/8] PCI / PCIe: Ask BIOS for control of all native services at once (v6)

Quoted 11 lines · Rafael J. Wysocki
drivers/pci/pcie/portdrv_acpi.c new file +11 -0
+int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
+{
+	acpi_status status;
+	acpi_handle handle;
+	u32 flags;
+
+	if (acpi_pci_disabled)
+		return 0;
+
+	handle = acpi_find_root_bridge_handle(port);
+	if (!handle)

drivers/pci/pcie/portdrv_acpi.c line 54

Quoted 10 lines
drivers/pci/pcie/portdrv_acpi.c new file +10 -0
+		return -EINVAL;
+
+	flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+		| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+		| OSC_PCI_EXPRESS_PME_CONTROL;
+
+	if (pcie_aer_get_firmware_first(port))
+		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
+	else if (pci_aer_available())
+		flags |= OSC_PCI_EXPRESS_AER_CONTROL;

Is the debug message necessary even when AER is not available? At least current code doesn't output such strings when pci=noaer, since AER service driver is not loaded.

if (pci_aer_available()) {
	if (pcie_aer_get_firmware_first(port))
		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
	else
		flags |= OSC_PCI_EXPRESS_AER_CONTROL;
}

Thanks,
H.Seto

#35 lore raw

Re: [PATCH 4/8] PCI / PCIe: Ask BIOS for control of all native services at once (v6)

Quoted 27 lines · Hidetoshi Seto
Quoted 11 lines · Rafael J. Wysocki
(quoted diff) +11 -0
+int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
+{
+	acpi_status status;
+	acpi_handle handle;
+	u32 flags;
+
+	if (acpi_pci_disabled)
+		return 0;
+
+	handle = acpi_find_root_bridge_handle(port);
+	if (!handle)

Review

Quoted 10 lines
(quoted diff) +10 -0
+		return -EINVAL;
+
+	flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+		| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+		| OSC_PCI_EXPRESS_PME_CONTROL;
+
+	if (pcie_aer_get_firmware_first(port))
+		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
+	else if (pci_aer_available())
+		flags |= OSC_PCI_EXPRESS_AER_CONTROL;

Is the debug message necessary even when AER is not available? At least current code doesn't output such strings when pci=noaer, since AER service driver is not loaded.

Quoted 6 lines
if (pci_aer_available()) {
	if (pcie_aer_get_firmware_first(port))
		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
	else
		flags |= OSC_PCI_EXPRESS_AER_CONTROL;
}

OK, updated patch is appended.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: PCI / PCIe: Ask BIOS for control of all native services at once (v7)

PCIe port service drivers ask the BIOS, through _OSC, for control of the services they handle. Unfortunately, each of them individually asks for control of the PCIe capability structure and if that is granted, some BIOSes expect that the other PCIe port services will be configured and handled by the kernel as well. If that is not the case (eg. one of the PCIe port service drivers is not loaded), the BIOS may be confused and may cause the system as a whole to misbehave (eg. on one of such systems enabling the native PCIe PME service without loading the native PCIe hot-plug service driver causes a storm of ACPI notify requests to appear).

For this reason rework the PCIe port driver so that (1) it checks which native PCIe port services can be enabled, according to the BIOS, and (2) it requests control of all these services simultaneously. In particular, this causes pcie_portdrv_probe() to fail if the BIOS refuses to grant control of the PCIe capability structure, which means that no native PCIe port services can be enabled for the PCIe root complex the given port belongs to.

Make it possible to override this behavior using 'pcie_ports=native' (use the PCIe native services regardless of the BIOS response to the control request), or 'pcie_ports=compat' (do not use the PCIe native services at all).

Accordingly, rework the existing PCIe port service drivers so that they don't request control of the services directly.

---
 Documentation/kernel-parameters.txt  |   13 ++---
 drivers/pci/hotplug/acpi_pcihp.c     |    4 -
 drivers/pci/hotplug/pciehp.h         |   12 ----
 drivers/pci/hotplug/pciehp_acpi.c    |    4 -
 drivers/pci/hotplug/pciehp_core.c    |    4 -
 drivers/pci/pcie/Makefile            |    3 -
 drivers/pci/pcie/aer/aerdrv_acpi.c   |   36 --------------
 drivers/pci/pcie/aer/aerdrv_core.c   |   14 -----
 drivers/pci/pcie/pme/Makefile        |    8 ---
 drivers/pci/pcie/pme/pcie_pme.c      |   64 +------------------------
 drivers/pci/pcie/pme/pcie_pme.h      |   28 -----------
 drivers/pci/pcie/pme/pcie_pme_acpi.c |   54 ---------------------
 drivers/pci/pcie/portdrv.h           |   20 +++++++
 drivers/pci/pcie/portdrv_acpi.c      |   89 +++++++++++++++++++++++++++++++++++
 drivers/pci/pcie/portdrv_core.c      |   22 +++++++-
 drivers/pci/pcie/portdrv_pci.c       |   15 +++++
 16 files changed, 160 insertions(+), 230 deletions(-)
drivers/pci/pcie/portdrv_pci.c +14 -1
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -32,10 +32,23 @@ MODULE_LICENSE("GPL");
 /* If this switch is set, PCIe port native services should not be enabled. */
 bool pcie_ports_disabled;
 
+/*
+ * If this switch is set, ACPI _OSC will be used to determine whether or not to
+ * enable PCIe port native services.
+ */
+bool pcie_ports_auto = true;
+
 static int __init pcie_port_setup(char *str)
 {
-	if (!strncmp(str, "compat", 6))
+	if (!strncmp(str, "compat", 6)) {
 		pcie_ports_disabled = true;
+	} else if (!strncmp(str, "native", 6)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = false;
+	} else if (!strncmp(str, "auto", 4)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = true;
+	}
 
 	return 1;
 }
drivers/pci/pcie/portdrv_acpi.c new file +89 -0

89 lines not on this page · raw message

drivers/pci/pcie/portdrv.h +20 -0
Index: linux-2.6/drivers/pci/pcie/portdrv.h
===================================================================
@@ -21,6 +21,7 @@
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
 extern bool pcie_ports_disabled;
+extern bool pcie_ports_auto;
 
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_register(struct pci_dev *dev);
@@ -32,6 +33,8 @@ extern void pcie_port_device_remove(stru
 extern int __must_check pcie_port_bus_register(void);
 extern void pcie_port_bus_unregister(void);
 
+struct pci_dev;
+
 #ifdef CONFIG_PCIE_PME
 extern bool pcie_pme_msi_disabled;
 
@@ -44,9 +47,26 @@ static inline bool pcie_pme_no_msi(void)
 {
 	return pcie_pme_msi_disabled;
 }
+
+extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
 #else /* !CONFIG_PCIE_PME */
 static inline void pcie_pme_disable_msi(void) {}
 static inline bool pcie_pme_no_msi(void) { return false; }
+static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
 #endif /* !CONFIG_PCIE_PME */
 
+#ifdef CONFIG_ACPI
+extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
+
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return pcie_port_acpi_setup(port, mask);
+}
+#else /* !CONFIG_ACPI */
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return 0;
+}
+#endif /* !CONFIG_ACPI */
+
 #endif /* _PORTDRV_H_ */
drivers/pci/pcie/Makefile +2 -1
Index: linux-2.6/drivers/pci/pcie/Makefile
===================================================================
@@ -6,10 +6,11 @@
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 
 pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
 # Build PCI Express AER if needed
 obj-$(CONFIG_PCIEAER)		+= aer/
 
-obj-$(CONFIG_PCIE_PME) += pme/
+obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o
drivers/pci/pcie/portdrv_core.c +19 -3
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
+#include <linux/aer.h>
 
 #include "../pci.h"
 #include "portdrv.h"
@@ -236,23 +237,38 @@ static int get_port_device_capability(st
 	int services = 0, pos;
 	u16 reg16;
 	u32 reg32;
+	int cap_mask;
+	int err;
+
+	err = pcie_port_platform_notify(dev, &cap_mask);
+	if (pcie_ports_auto) {
+		if (err)
+			return 0;
+	} else {
+		cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
+				| PCIE_PORT_SERVICE_VC;
+		if (pci_aer_available())
+			cap_mask |= PCIE_PORT_SERVICE_AER;
+	}
 
 	pos = pci_pcie_cap(dev);
 	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
 	/* Hot-Plug Capable */
-	if (reg16 & PCI_EXP_FLAGS_SLOT) {
+	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
 		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
 		if (reg32 & PCI_EXP_SLTCAP_HPC)
 			services |= PCIE_PORT_SERVICE_HP;
 	}
 	/* AER capable */
-	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+	if ((cap_mask & PCIE_PORT_SERVICE_AER)
+	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
 		services |= PCIE_PORT_SERVICE_AER;
 	/* VC support */
 	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
 		services |= PCIE_PORT_SERVICE_VC;
 	/* Root ports are capable of generating PME too */
-	if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	if ((cap_mask & PCIE_PORT_SERVICE_PME)
+	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
 		services |= PCIE_PORT_SERVICE_PME;
 
 	return services;
drivers/pci/pcie/pme/pcie_pme.c +5 -59

104 lines not on this page · raw message

drivers/pci/pcie/pme/pcie_pme.h deleted +0 -28
Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme.h
===================================================================
@@ -1,28 +0,0 @@
-/*
- * drivers/pci/pcie/pme/pcie_pme.h
- *
- * PCI Express Root Port PME signaling support
- *
- * Copyright (C) 2009 Rafael J. Wysocki <[email protected]>, Novell Inc.
- */
-
-#ifndef _PCIE_PME_H_
-#define _PCIE_PME_H_
-
-struct pcie_device;
-
-#ifdef CONFIG_ACPI
-extern int pcie_pme_acpi_setup(struct pcie_device *srv);
-
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return pcie_pme_acpi_setup(srv);
-}
-#else /* !CONFIG_ACPI */
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return 0;
-}
-#endif /* !CONFIG_ACPI */
-
-#endif
drivers/pci/pcie/pme/pcie_pme_acpi.c deleted +0 -54

54 lines not on this page · raw message

drivers/pci/pcie/pme/Makefile deleted +0 -8
Index: linux-2.6/drivers/pci/pcie/pme/Makefile
===================================================================
@@ -1,8 +0,0 @@
-#
-# Makefile for PCI-Express Root Port PME signaling driver
-#
-
-obj-$(CONFIG_PCIE_PME) += pmedriver.o
-
-pmedriver-objs := pcie_pme.o
-pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
drivers/pci/pcie/aer/aerdrv_acpi.c +0 -36
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_acpi.c
===================================================================
@@ -19,42 +19,6 @@
 #include <acpi/apei.h>
 #include "aerdrv.h"
 
-/**
- * aer_osc_setup - run ACPI _OSC method
- * @pciedev: pcie_device which AER is being enabled on
- *
- * @return: Zero on success. Nonzero otherwise.
- *
- * Invoked when PCIe bus loads AER service driver. To avoid conflict with
- * BIOS AER support requires BIOS to yield AER control to OS native driver.
- **/
-int aer_osc_setup(struct pcie_device *pciedev)
-{
-	acpi_status status = AE_NOT_FOUND;
-	struct pci_dev *pdev = pciedev->port;
-	acpi_handle handle = NULL;
-
-	if (acpi_pci_disabled)
-		return -1;
-
-	handle = acpi_find_root_bridge_handle(pdev);
-	if (handle) {
-		status = acpi_pci_osc_control_set(handle,
-					OSC_PCI_EXPRESS_AER_CONTROL |
-					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	}
-
-	if (ACPI_FAILURE(status)) {
-		dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't "
-			   "init device: %s\n",
-			   (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
-			   "no _OSC support" : "_OSC failed");
-		return -1;
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 static inline int hest_match_pci(struct acpi_hest_aer_common *p,
 				 struct pci_dev *pci)
drivers/pci/pcie/aer/aerdrv_core.c +1 -13
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_core.c
===================================================================
@@ -771,22 +771,10 @@ void aer_isr(struct work_struct *work)
  */
 int aer_init(struct pcie_device *dev)
 {
-	if (pcie_aer_get_firmware_first(dev->port)) {
-		dev_printk(KERN_DEBUG, &dev->device,
-			   "PCIe errors handled by platform firmware.\n");
-		goto out;
-	}
-
-	if (aer_osc_setup(dev))
-		goto out;
-
-	return 0;
-out:
 	if (forceload) {
 		dev_printk(KERN_DEBUG, &dev->device,
 			   "aerdrv forceload requested.\n");
 		pcie_aer_force_firmware_first(dev->port, 0);
-		return 0;
 	}
-	return -ENXIO;
+	return 0;
 }
drivers/pci/hotplug/acpi_pcihp.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================
@@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware
 	acpi_handle chandle, handle;
 	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		  OSC_SHPC_NATIVE_HP_CONTROL |
-		  OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+	flags &= OSC_SHPC_NATIVE_HP_CONTROL;
 	if (!flags) {
 		err("Invalid flags %u specified!\n", flags);
 		return -EINVAL;
drivers/pci/hotplug/pciehp.h +0 -12
Index: linux-2.6/drivers/pci/hotplug/pciehp.h
===================================================================
@@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(
 {
 	pciehp_acpi_slot_detection_init();
 }
-
-static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
-{
-	int retval;
-	u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		     OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	retval = acpi_get_hp_hw_control_from_firmware(dev, flags);
-	if (retval)
-		return retval;
-	return pciehp_acpi_slot_detection_check(dev);
-}
 #else
 #define pciehp_firmware_init()				do {} while (0)
-#define pciehp_get_hp_hw_control_from_firmware(dev) 	0
 #endif 				/* CONFIG_ACPI */
 #endif				/* _PCIEHP_H */
drivers/pci/hotplug/pciehp_core.c +2 -2
Index: linux-2.6/drivers/pci/hotplug/pciehp_core.c
===================================================================
@@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644);
 MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
-MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
+MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing");
 
 #define PCIE_MODULE_NAME "pciehp"
 
@@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_devi
 		dev_info(&dev->device,
 			 "Bypassing BIOS check for pciehp use on %s\n",
 			 pci_name(dev->port));
-	else if (pciehp_get_hp_hw_control_from_firmware(dev->port))
+	else if (pciehp_acpi_slot_detection_check(dev->port))
 		goto err_out_none;
 
 	ctrl = pcie_init(dev);
drivers/pci/hotplug/pciehp_acpi.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/pciehp_acpi.c
===================================================================
@@ -85,9 +85,7 @@ static int __init dummy_probe(struct pci
 	acpi_handle handle;
 	struct dummy_slot *slot, *tmp;
 	struct pci_dev *pdev = dev->port;
-	/* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
-	if (pciehp_get_hp_hw_control_from_firmware(pdev))
-		return -ENODEV;
+
 	pos = pci_pcie_cap(pdev);
 	if (!pos)
 		return -ENODEV;
Documentation/kernel-parameters.txt +6 -7
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
@@ -2048,18 +2048,17 @@ and is between 256 and 4096 characters. 
 			WARNING: Forcing ASPM on may cause system lockups.
 
 	pcie_ports=	[PCIE] PCIe ports handling:
+		auto	Ask the BIOS whether or not to use native PCIe services
+			associated with PCIe ports (PME, hot-plug, AER).  Use
+			them only if that is allowed by the BIOS.
+		native	Use native PCIe services associated with PCIe ports
+			unconditionally.
 		compat	Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
 			ports driver.
 
 	pcie_pme=	[PCIE,PM] Native PCIe PME signaling options:
-			Format: {auto|force}[,nomsi]
-		auto	Use native PCIe PME signaling if the BIOS allows the
-			kernel to control PCIe config registers of root ports.
-		force	Use native PCIe PME signaling even if the BIOS refuses
-			to allow the kernel to control the relevant PCIe config
-			registers.
 		nomsi	Do not use MSI for native PCIe PME signaling (this makes
-			all PCIe root ports use INTx for everything).
+			all PCIe root ports use INTx for all services).
 
 	pcmv=		[HW,PCMCIA] BadgePAD 4
 
#36 lore raw

Re: [PATCH 4/8] PCI / PCIe: Ask BIOS for control of all native services at once (v6)

In reply to Hidetoshi Seto
Quoted 27 lines · Hidetoshi Seto
Quoted 11 lines · Rafael J. Wysocki
(quoted diff) +11 -0
+int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
+{
+	acpi_status status;
+	acpi_handle handle;
+	u32 flags;
+
+	if (acpi_pci_disabled)
+		return 0;
+
+	handle = acpi_find_root_bridge_handle(port);
+	if (!handle)

Review

Quoted 10 lines
(quoted diff) +10 -0
+		return -EINVAL;
+
+	flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+		| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+		| OSC_PCI_EXPRESS_PME_CONTROL;
+
+	if (pcie_aer_get_firmware_first(port))
+		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
+	else if (pci_aer_available())
+		flags |= OSC_PCI_EXPRESS_AER_CONTROL;

Is the debug message necessary even when AER is not available? At least current code doesn't output such strings when pci=noaer, since AER service driver is not loaded.

Quoted 6 lines
if (pci_aer_available()) {
	if (pcie_aer_get_firmware_first(port))
		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
	else
		flags |= OSC_PCI_EXPRESS_AER_CONTROL;
}

OK, updated patch is appended.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: PCI / PCIe: Ask BIOS for control of all native services at once (v7)

PCIe port service drivers ask the BIOS, through _OSC, for control of the services they handle. Unfortunately, each of them individually asks for control of the PCIe capability structure and if that is granted, some BIOSes expect that the other PCIe port services will be configured and handled by the kernel as well. If that is not the case (eg. one of the PCIe port service drivers is not loaded), the BIOS may be confused and may cause the system as a whole to misbehave (eg. on one of such systems enabling the native PCIe PME service without loading the native PCIe hot-plug service driver causes a storm of ACPI notify requests to appear).

For this reason rework the PCIe port driver so that (1) it checks which native PCIe port services can be enabled, according to the BIOS, and (2) it requests control of all these services simultaneously. In particular, this causes pcie_portdrv_probe() to fail if the BIOS refuses to grant control of the PCIe capability structure, which means that no native PCIe port services can be enabled for the PCIe root complex the given port belongs to.

Make it possible to override this behavior using 'pcie_ports=native' (use the PCIe native services regardless of the BIOS response to the control request), or 'pcie_ports=compat' (do not use the PCIe native services at all).

Accordingly, rework the existing PCIe port service drivers so that they don't request control of the services directly.

---
 Documentation/kernel-parameters.txt  |   13 ++---
 drivers/pci/hotplug/acpi_pcihp.c     |    4 -
 drivers/pci/hotplug/pciehp.h         |   12 ----
 drivers/pci/hotplug/pciehp_acpi.c    |    4 -
 drivers/pci/hotplug/pciehp_core.c    |    4 -
 drivers/pci/pcie/Makefile            |    3 -
 drivers/pci/pcie/aer/aerdrv_acpi.c   |   36 --------------
 drivers/pci/pcie/aer/aerdrv_core.c   |   14 -----
 drivers/pci/pcie/pme/Makefile        |    8 ---
 drivers/pci/pcie/pme/pcie_pme.c      |   64 +------------------------
 drivers/pci/pcie/pme/pcie_pme.h      |   28 -----------
 drivers/pci/pcie/pme/pcie_pme_acpi.c |   54 ---------------------
 drivers/pci/pcie/portdrv.h           |   20 +++++++
 drivers/pci/pcie/portdrv_acpi.c      |   89 +++++++++++++++++++++++++++++++++++
 drivers/pci/pcie/portdrv_core.c      |   22 +++++++-
 drivers/pci/pcie/portdrv_pci.c       |   15 +++++
 16 files changed, 160 insertions(+), 230 deletions(-)
drivers/pci/pcie/portdrv_pci.c +14 -1
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -32,10 +32,23 @@ MODULE_LICENSE("GPL");
 /* If this switch is set, PCIe port native services should not be enabled. */
 bool pcie_ports_disabled;
 
+/*
+ * If this switch is set, ACPI _OSC will be used to determine whether or not to
+ * enable PCIe port native services.
+ */
+bool pcie_ports_auto = true;
+
 static int __init pcie_port_setup(char *str)
 {
-	if (!strncmp(str, "compat", 6))
+	if (!strncmp(str, "compat", 6)) {
 		pcie_ports_disabled = true;
+	} else if (!strncmp(str, "native", 6)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = false;
+	} else if (!strncmp(str, "auto", 4)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = true;
+	}
 
 	return 1;
 }
drivers/pci/pcie/portdrv_acpi.c new file +89 -0

89 lines not on this page · raw message

drivers/pci/pcie/portdrv.h +20 -0
Index: linux-2.6/drivers/pci/pcie/portdrv.h
===================================================================
@@ -21,6 +21,7 @@
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
 extern bool pcie_ports_disabled;
+extern bool pcie_ports_auto;
 
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_register(struct pci_dev *dev);
@@ -32,6 +33,8 @@ extern void pcie_port_device_remove(stru
 extern int __must_check pcie_port_bus_register(void);
 extern void pcie_port_bus_unregister(void);
 
+struct pci_dev;
+
 #ifdef CONFIG_PCIE_PME
 extern bool pcie_pme_msi_disabled;
 
@@ -44,9 +47,26 @@ static inline bool pcie_pme_no_msi(void)
 {
 	return pcie_pme_msi_disabled;
 }
+
+extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
 #else /* !CONFIG_PCIE_PME */
 static inline void pcie_pme_disable_msi(void) {}
 static inline bool pcie_pme_no_msi(void) { return false; }
+static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
 #endif /* !CONFIG_PCIE_PME */
 
+#ifdef CONFIG_ACPI
+extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
+
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return pcie_port_acpi_setup(port, mask);
+}
+#else /* !CONFIG_ACPI */
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return 0;
+}
+#endif /* !CONFIG_ACPI */
+
 #endif /* _PORTDRV_H_ */
drivers/pci/pcie/Makefile +2 -1
Index: linux-2.6/drivers/pci/pcie/Makefile
===================================================================
@@ -6,10 +6,11 @@
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 
 pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
 # Build PCI Express AER if needed
 obj-$(CONFIG_PCIEAER)		+= aer/
 
-obj-$(CONFIG_PCIE_PME) += pme/
+obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o
drivers/pci/pcie/portdrv_core.c +19 -3
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
+#include <linux/aer.h>
 
 #include "../pci.h"
 #include "portdrv.h"
@@ -236,23 +237,38 @@ static int get_port_device_capability(st
 	int services = 0, pos;
 	u16 reg16;
 	u32 reg32;
+	int cap_mask;
+	int err;
+
+	err = pcie_port_platform_notify(dev, &cap_mask);
+	if (pcie_ports_auto) {
+		if (err)
+			return 0;
+	} else {
+		cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
+				| PCIE_PORT_SERVICE_VC;
+		if (pci_aer_available())
+			cap_mask |= PCIE_PORT_SERVICE_AER;
+	}
 
 	pos = pci_pcie_cap(dev);
 	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
 	/* Hot-Plug Capable */
-	if (reg16 & PCI_EXP_FLAGS_SLOT) {
+	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
 		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
 		if (reg32 & PCI_EXP_SLTCAP_HPC)
 			services |= PCIE_PORT_SERVICE_HP;
 	}
 	/* AER capable */
-	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+	if ((cap_mask & PCIE_PORT_SERVICE_AER)
+	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
 		services |= PCIE_PORT_SERVICE_AER;
 	/* VC support */
 	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
 		services |= PCIE_PORT_SERVICE_VC;
 	/* Root ports are capable of generating PME too */
-	if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	if ((cap_mask & PCIE_PORT_SERVICE_PME)
+	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
 		services |= PCIE_PORT_SERVICE_PME;
 
 	return services;
drivers/pci/pcie/pme/pcie_pme.c +5 -59

104 lines not on this page · raw message

drivers/pci/pcie/pme/pcie_pme.h deleted +0 -28
Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme.h
===================================================================
@@ -1,28 +0,0 @@
-/*
- * drivers/pci/pcie/pme/pcie_pme.h
- *
- * PCI Express Root Port PME signaling support
- *
- * Copyright (C) 2009 Rafael J. Wysocki <[email protected]>, Novell Inc.
- */
-
-#ifndef _PCIE_PME_H_
-#define _PCIE_PME_H_
-
-struct pcie_device;
-
-#ifdef CONFIG_ACPI
-extern int pcie_pme_acpi_setup(struct pcie_device *srv);
-
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return pcie_pme_acpi_setup(srv);
-}
-#else /* !CONFIG_ACPI */
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return 0;
-}
-#endif /* !CONFIG_ACPI */
-
-#endif
drivers/pci/pcie/pme/pcie_pme_acpi.c deleted +0 -54

54 lines not on this page · raw message

drivers/pci/pcie/pme/Makefile deleted +0 -8
Index: linux-2.6/drivers/pci/pcie/pme/Makefile
===================================================================
@@ -1,8 +0,0 @@
-#
-# Makefile for PCI-Express Root Port PME signaling driver
-#
-
-obj-$(CONFIG_PCIE_PME) += pmedriver.o
-
-pmedriver-objs := pcie_pme.o
-pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
drivers/pci/pcie/aer/aerdrv_acpi.c +0 -36
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_acpi.c
===================================================================
@@ -19,42 +19,6 @@
 #include <acpi/apei.h>
 #include "aerdrv.h"
 
-/**
- * aer_osc_setup - run ACPI _OSC method
- * @pciedev: pcie_device which AER is being enabled on
- *
- * @return: Zero on success. Nonzero otherwise.
- *
- * Invoked when PCIe bus loads AER service driver. To avoid conflict with
- * BIOS AER support requires BIOS to yield AER control to OS native driver.
- **/
-int aer_osc_setup(struct pcie_device *pciedev)
-{
-	acpi_status status = AE_NOT_FOUND;
-	struct pci_dev *pdev = pciedev->port;
-	acpi_handle handle = NULL;
-
-	if (acpi_pci_disabled)
-		return -1;
-
-	handle = acpi_find_root_bridge_handle(pdev);
-	if (handle) {
-		status = acpi_pci_osc_control_set(handle,
-					OSC_PCI_EXPRESS_AER_CONTROL |
-					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	}
-
-	if (ACPI_FAILURE(status)) {
-		dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't "
-			   "init device: %s\n",
-			   (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
-			   "no _OSC support" : "_OSC failed");
-		return -1;
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 static inline int hest_match_pci(struct acpi_hest_aer_common *p,
 				 struct pci_dev *pci)
drivers/pci/pcie/aer/aerdrv_core.c +1 -13
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_core.c
===================================================================
@@ -771,22 +771,10 @@ void aer_isr(struct work_struct *work)
  */
 int aer_init(struct pcie_device *dev)
 {
-	if (pcie_aer_get_firmware_first(dev->port)) {
-		dev_printk(KERN_DEBUG, &dev->device,
-			   "PCIe errors handled by platform firmware.\n");
-		goto out;
-	}
-
-	if (aer_osc_setup(dev))
-		goto out;
-
-	return 0;
-out:
 	if (forceload) {
 		dev_printk(KERN_DEBUG, &dev->device,
 			   "aerdrv forceload requested.\n");
 		pcie_aer_force_firmware_first(dev->port, 0);
-		return 0;
 	}
-	return -ENXIO;
+	return 0;
 }
drivers/pci/hotplug/acpi_pcihp.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================
@@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware
 	acpi_handle chandle, handle;
 	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		  OSC_SHPC_NATIVE_HP_CONTROL |
-		  OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+	flags &= OSC_SHPC_NATIVE_HP_CONTROL;
 	if (!flags) {
 		err("Invalid flags %u specified!\n", flags);
 		return -EINVAL;
drivers/pci/hotplug/pciehp.h +0 -12
Index: linux-2.6/drivers/pci/hotplug/pciehp.h
===================================================================
@@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(
 {
 	pciehp_acpi_slot_detection_init();
 }
-
-static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
-{
-	int retval;
-	u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		     OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	retval = acpi_get_hp_hw_control_from_firmware(dev, flags);
-	if (retval)
-		return retval;
-	return pciehp_acpi_slot_detection_check(dev);
-}
 #else
 #define pciehp_firmware_init()				do {} while (0)
-#define pciehp_get_hp_hw_control_from_firmware(dev) 	0
 #endif 				/* CONFIG_ACPI */
 #endif				/* _PCIEHP_H */
drivers/pci/hotplug/pciehp_core.c +2 -2
Index: linux-2.6/drivers/pci/hotplug/pciehp_core.c
===================================================================
@@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644);
 MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
-MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
+MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing");
 
 #define PCIE_MODULE_NAME "pciehp"
 
@@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_devi
 		dev_info(&dev->device,
 			 "Bypassing BIOS check for pciehp use on %s\n",
 			 pci_name(dev->port));
-	else if (pciehp_get_hp_hw_control_from_firmware(dev->port))
+	else if (pciehp_acpi_slot_detection_check(dev->port))
 		goto err_out_none;
 
 	ctrl = pcie_init(dev);
drivers/pci/hotplug/pciehp_acpi.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/pciehp_acpi.c
===================================================================
@@ -85,9 +85,7 @@ static int __init dummy_probe(struct pci
 	acpi_handle handle;
 	struct dummy_slot *slot, *tmp;
 	struct pci_dev *pdev = dev->port;
-	/* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
-	if (pciehp_get_hp_hw_control_from_firmware(pdev))
-		return -ENODEV;
+
 	pos = pci_pcie_cap(pdev);
 	if (!pos)
 		return -ENODEV;
Documentation/kernel-parameters.txt +6 -7
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
@@ -2048,18 +2048,17 @@ and is between 256 and 4096 characters. 
 			WARNING: Forcing ASPM on may cause system lockups.
 
 	pcie_ports=	[PCIE] PCIe ports handling:
+		auto	Ask the BIOS whether or not to use native PCIe services
+			associated with PCIe ports (PME, hot-plug, AER).  Use
+			them only if that is allowed by the BIOS.
+		native	Use native PCIe services associated with PCIe ports
+			unconditionally.
 		compat	Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
 			ports driver.
 
 	pcie_pme=	[PCIE,PM] Native PCIe PME signaling options:
-			Format: {auto|force}[,nomsi]
-		auto	Use native PCIe PME signaling if the BIOS allows the
-			kernel to control PCIe config registers of root ports.
-		force	Use native PCIe PME signaling even if the BIOS refuses
-			to allow the kernel to control the relevant PCIe config
-			registers.
 		nomsi	Do not use MSI for native PCIe PME signaling (this makes
-			all PCIe root ports use INTx for everything).
+			all PCIe root ports use INTx for all services).
 
 	pcmv=		[HW,PCMCIA] BadgePAD 4
 
#37 lore raw

Re: [PATCH 4/8] PCI / PCIe: Ask BIOS for control of all native services at once (v6)

In reply to Rafael J. Wysocki
Quoted 11 lines · Rafael J. Wysocki
drivers/pci/pcie/portdrv_acpi.c new file +11 -0
+int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
+{
+	acpi_status status;
+	acpi_handle handle;
+	u32 flags;
+
+	if (acpi_pci_disabled)
+		return 0;
+
+	handle = acpi_find_root_bridge_handle(port);
+	if (!handle)

drivers/pci/pcie/portdrv_acpi.c line 54

Quoted 10 lines
drivers/pci/pcie/portdrv_acpi.c new file +10 -0
+		return -EINVAL;
+
+	flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+		| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+		| OSC_PCI_EXPRESS_PME_CONTROL;
+
+	if (pcie_aer_get_firmware_first(port))
+		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
+	else if (pci_aer_available())
+		flags |= OSC_PCI_EXPRESS_AER_CONTROL;

Is the debug message necessary even when AER is not available? At least current code doesn't output such strings when pci=noaer, since AER service driver is not loaded.

if (pci_aer_available()) {
	if (pcie_aer_get_firmware_first(port))
		dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
	else
		flags |= OSC_PCI_EXPRESS_AER_CONTROL;
}

Thanks,
H.Seto

#38 lore raw

Re: [PATCH 4/8] PCI / PCIe: Ask BIOS for control of all native services at once (v6)

In reply to Rafael J. Wysocki

Rafael,

I found that following 2 hunks break kernel build with O= option.

Quoted 7 lines · Rafael J. Wysocki

Index: linux-2.6/drivers/pci/pcie/Makefile
===================================================================

drivers/pci/pcie/Makefile +0 -0
@@ -6,10 +6,11 @@
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 

drivers/pci/pcie/Makefile line 16

Quoted 10 lines
drivers/pci/pcie/Makefile +2 -1
 pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
 # Build PCI Express AER if needed
 obj-$(CONFIG_PCIEAER)		+= aer/
 
-obj-$(CONFIG_PCIE_PME) += pme/
+obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o

and

drivers/pci/pcie/pme/Makefile line 8

Quoted 13 lines

Index: linux-2.6/drivers/pci/pcie/pme/Makefile
===================================================================

drivers/pci/pcie/pme/Makefile deleted +0 -8
@@ -1,8 +0,0 @@
-#
-# Makefile for PCI-Express Root Port PME signaling driver
-#
-
-obj-$(CONFIG_PCIE_PME) += pmedriver.o
-
-pmedriver-objs := pcie_pme.o
-pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
$ make -j12 O=../gitbuild/
  GEN     /home/seto/gitbuild/Makefile
  CHK     include/linux/version.h
  Using /home/seto/GIT-linux as source for kernel
  CHK     include/generated/utsrelease.h
  CALL    /home/seto/GIT-linux/scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  CC      drivers/pci/pcie/pme/pcie_pme.o
Assembler messages:
Fatal error: can't create drivers/pci/pcie/pme/.tmp_pcie_pme.o: No such file or directory
make[4]: *** [drivers/pci/pcie/pme/pcie_pme.o] Error 2
make[3]: *** [drivers/pci/pcie] Error 2
make[2]: *** [drivers/pci] Error 2
make[1]: *** [drivers] Error 2
make: *** [sub-make] Error 2
$

It seems that the error is because directory pme/ is not created in the working tree.

Thanks,
H.Seto

#39 lore raw

Re: [PATCH 4/8] PCI / PCIe: Ask BIOS for control of all native services at once (v6)

Quoted 56 lines · Hidetoshi Seto

Rafael,

I found that following 2 hunks break kernel build with O= option.

Quoted 7 lines · Rafael J. Wysocki

Index: linux-2.6/drivers/pci/pcie/Makefile
===================================================================

drivers/pci/pcie/Makefile +0 -0
@@ -6,10 +6,11 @@
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 

drivers/pci/pcie/Makefile line 16

Quoted 10 lines
drivers/pci/pcie/Makefile +2 -1
 pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
 # Build PCI Express AER if needed
 obj-$(CONFIG_PCIEAER)		+= aer/
 
-obj-$(CONFIG_PCIE_PME) += pme/
+obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o

and

drivers/pci/pcie/pme/Makefile line 8

Quoted 13 lines

Index: linux-2.6/drivers/pci/pcie/pme/Makefile
===================================================================

drivers/pci/pcie/pme/Makefile deleted +0 -8
@@ -1,8 +0,0 @@
-#
-# Makefile for PCI-Express Root Port PME signaling driver
-#
-
-obj-$(CONFIG_PCIE_PME) += pmedriver.o
-
-pmedriver-objs := pcie_pme.o
-pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
$ make -j12 O=../gitbuild/
  GEN     /home/seto/gitbuild/Makefile
  CHK     include/linux/version.h
  Using /home/seto/GIT-linux as source for kernel
  CHK     include/generated/utsrelease.h
  CALL    /home/seto/GIT-linux/scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  CC      drivers/pci/pcie/pme/pcie_pme.o
Assembler messages:
Fatal error: can't create drivers/pci/pcie/pme/.tmp_pcie_pme.o: No such file or directory
make[4]: *** [drivers/pci/pcie/pme/pcie_pme.o] Error 2
make[3]: *** [drivers/pci/pcie] Error 2
make[2]: *** [drivers/pci] Error 2
make[1]: *** [drivers] Error 2
make: *** [sub-make] Error 2
$
Quoted 2 lines

It seems that the error is because directory pme/ is not created in the working tree.

Hmm. That seems to be correct, but I'm not sure how to resolve it.

If I move pcie_pme.c to pcie/ in the same patch, the changes in that file will not be clearly visible.

Perhaps I'll add a separate patch that will remove the Makefile from pme/ and move pcie_pme.c to pcie/.

Thanks,
Rafael

#40 lore raw

Re: [PATCH 4/8] PCI / PCIe: Ask BIOS for control of all native services at once (v6)

In reply to Rafael J. Wysocki

Rafael,

I found that following 2 hunks break kernel build with O= option.

Quoted 7 lines · Rafael J. Wysocki

Index: linux-2.6/drivers/pci/pcie/Makefile
===================================================================

drivers/pci/pcie/Makefile +0 -0
@@ -6,10 +6,11 @@
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 

drivers/pci/pcie/Makefile line 16

Quoted 10 lines
drivers/pci/pcie/Makefile +2 -1
 pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
 # Build PCI Express AER if needed
 obj-$(CONFIG_PCIEAER)		+= aer/
 
-obj-$(CONFIG_PCIE_PME) += pme/
+obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o

and

drivers/pci/pcie/pme/Makefile line 8

Quoted 13 lines

Index: linux-2.6/drivers/pci/pcie/pme/Makefile
===================================================================

drivers/pci/pcie/pme/Makefile deleted +0 -8
@@ -1,8 +0,0 @@
-#
-# Makefile for PCI-Express Root Port PME signaling driver
-#
-
-obj-$(CONFIG_PCIE_PME) += pmedriver.o
-
-pmedriver-objs := pcie_pme.o
-pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
$ make -j12 O=../gitbuild/
  GEN     /home/seto/gitbuild/Makefile
  CHK     include/linux/version.h
  Using /home/seto/GIT-linux as source for kernel
  CHK     include/generated/utsrelease.h
  CALL    /home/seto/GIT-linux/scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  CC      drivers/pci/pcie/pme/pcie_pme.o
Assembler messages:
Fatal error: can't create drivers/pci/pcie/pme/.tmp_pcie_pme.o: No such file or directory
make[4]: *** [drivers/pci/pcie/pme/pcie_pme.o] Error 2
make[3]: *** [drivers/pci/pcie] Error 2
make[2]: *** [drivers/pci] Error 2
make[1]: *** [drivers] Error 2
make: *** [sub-make] Error 2
$

It seems that the error is because directory pme/ is not created in the working tree.

Thanks,
H.Seto

#41 lore raw

PATCH 4/8 PCI / PCIe: Ask BIOS for control of all native services at once (v6)

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

PCIe port service drivers ask the BIOS, through _OSC, for control of the services they handle. Unfortunately, each of them individually asks for control of the PCIe capability structure and if that is granted, some BIOSes expect that the other PCIe port services will be configured and handled by the kernel as well. If that is not the case (eg. one of the PCIe port service drivers is not loaded), the BIOS may be confused and may cause the system as a whole to misbehave (eg. on one of such systems enabling the native PCIe PME service without loading the native PCIe hot-plug service driver causes a storm of ACPI notify requests to appear).

For this reason rework the PCIe port driver so that (1) it checks which native PCIe port services can be enabled, according to the BIOS, and (2) it requests control of all these services simultaneously. In particular, this causes pcie_portdrv_probe() to fail if the BIOS refuses to grant control of the PCIe capability structure, which means that no native PCIe port services can be enabled for the PCIe root complex the given port belongs to.

Make it possible to override this behavior using 'pcie_ports=native' (use the PCIe native services regardless of the BIOS response to the control request), or 'pcie_ports=compat' (do not use the PCIe native services at all).

Accordingly, rework the existing PCIe port service drivers so that they don't request control of the services directly.

---
 Documentation/kernel-parameters.txt  |   13 ++---
 drivers/pci/hotplug/acpi_pcihp.c     |    4 -
 drivers/pci/hotplug/pciehp.h         |   12 ----
 drivers/pci/hotplug/pciehp_acpi.c    |    4 -
 drivers/pci/hotplug/pciehp_core.c    |    4 -
 drivers/pci/pcie/Makefile            |    3 -
 drivers/pci/pcie/aer/aerdrv_acpi.c   |   36 --------------
 drivers/pci/pcie/aer/aerdrv_core.c   |   14 -----
 drivers/pci/pcie/pme/Makefile        |    8 ---
 drivers/pci/pcie/pme/pcie_pme.c      |   64 ++-----------------------
 drivers/pci/pcie/pme/pcie_pme.h      |   28 -----------
 drivers/pci/pcie/pme/pcie_pme_acpi.c |   54 ---------------------
 drivers/pci/pcie/portdrv.h           |   20 ++++++++
 drivers/pci/pcie/portdrv_acpi.c      |   87 +++++++++++++++++++++++++++++++++++
 drivers/pci/pcie/portdrv_core.c      |   22 +++++++-
 drivers/pci/pcie/portdrv_pci.c       |   15 +++++-
 16 files changed, 158 insertions(+), 230 deletions(-)
drivers/pci/pcie/portdrv_pci.c +14 -1
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -32,10 +32,23 @@ MODULE_LICENSE("GPL");
 /* If this switch is set, PCIe port native services should not be enabled. */
 bool pcie_ports_disabled;
 
+/*
+ * If this switch is set, ACPI _OSC will be used to determine whether or not to
+ * enable PCIe port native services.
+ */
+bool pcie_ports_auto = true;
+
 static int __init pcie_port_setup(char *str)
 {
-	if (!strncmp(str, "compat", 6))
+	if (!strncmp(str, "compat", 6)) {
 		pcie_ports_disabled = true;
+	} else if (!strncmp(str, "native", 6)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = false;
+	} else if (!strncmp(str, "auto", 4)) {
+		pcie_ports_disabled = false;
+		pcie_ports_auto = true;
+	}
 
 	return 1;
 }
drivers/pci/pcie/portdrv_acpi.c new file +87 -0

87 lines not on this page · raw message

drivers/pci/pcie/portdrv.h +20 -0
Index: linux-2.6/drivers/pci/pcie/portdrv.h
===================================================================
@@ -21,6 +21,7 @@
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
 extern bool pcie_ports_disabled;
+extern bool pcie_ports_auto;
 
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_register(struct pci_dev *dev);
@@ -32,6 +33,8 @@ extern void pcie_port_device_remove(stru
 extern int __must_check pcie_port_bus_register(void);
 extern void pcie_port_bus_unregister(void);
 
+struct pci_dev;
+
 #ifdef CONFIG_PCIE_PME
 extern bool pcie_pme_msi_disabled;
 
@@ -44,9 +47,26 @@ static inline bool pcie_pme_no_msi(void)
 {
 	return pcie_pme_msi_disabled;
 }
+
+extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
 #else /* !CONFIG_PCIE_PME */
 static inline void pcie_pme_disable_msi(void) {}
 static inline bool pcie_pme_no_msi(void) { return false; }
+static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
 #endif /* !CONFIG_PCIE_PME */
 
+#ifdef CONFIG_ACPI
+extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
+
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return pcie_port_acpi_setup(port, mask);
+}
+#else /* !CONFIG_ACPI */
+static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
+{
+	return 0;
+}
+#endif /* !CONFIG_ACPI */
+
 #endif /* _PORTDRV_H_ */
drivers/pci/pcie/Makefile +2 -1
Index: linux-2.6/drivers/pci/pcie/Makefile
===================================================================
@@ -6,10 +6,11 @@
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 
 pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+pcieportdrv-$(CONFIG_ACPI)	+= portdrv_acpi.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
 # Build PCI Express AER if needed
 obj-$(CONFIG_PCIEAER)		+= aer/
 
-obj-$(CONFIG_PCIE_PME) += pme/
+obj-$(CONFIG_PCIE_PME) += pme/pcie_pme.o
drivers/pci/pcie/portdrv_core.c +19 -3
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
+#include <linux/aer.h>
 
 #include "../pci.h"
 #include "portdrv.h"
@@ -236,23 +237,38 @@ static int get_port_device_capability(st
 	int services = 0, pos;
 	u16 reg16;
 	u32 reg32;
+	int cap_mask;
+	int err;
+
+	err = pcie_port_platform_notify(dev, &cap_mask);
+	if (pcie_ports_auto) {
+		if (err)
+			return 0;
+	} else {
+		cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
+				| PCIE_PORT_SERVICE_VC;
+		if (pci_aer_available())
+			cap_mask |= PCIE_PORT_SERVICE_AER;
+	}
 
 	pos = pci_pcie_cap(dev);
 	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
 	/* Hot-Plug Capable */
-	if (reg16 & PCI_EXP_FLAGS_SLOT) {
+	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
 		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
 		if (reg32 & PCI_EXP_SLTCAP_HPC)
 			services |= PCIE_PORT_SERVICE_HP;
 	}
 	/* AER capable */
-	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+	if ((cap_mask & PCIE_PORT_SERVICE_AER)
+	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
 		services |= PCIE_PORT_SERVICE_AER;
 	/* VC support */
 	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
 		services |= PCIE_PORT_SERVICE_VC;
 	/* Root ports are capable of generating PME too */
-	if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	if ((cap_mask & PCIE_PORT_SERVICE_PME)
+	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
 		services |= PCIE_PORT_SERVICE_PME;
 
 	return services;
drivers/pci/pcie/pme/pcie_pme.c +5 -59

104 lines not on this page · raw message

drivers/pci/pcie/pme/pcie_pme.h deleted +0 -28
Index: linux-2.6/drivers/pci/pcie/pme/pcie_pme.h
===================================================================
@@ -1,28 +0,0 @@
-/*
- * drivers/pci/pcie/pme/pcie_pme.h
- *
- * PCI Express Root Port PME signaling support
- *
- * Copyright (C) 2009 Rafael J. Wysocki <[email protected]>, Novell Inc.
- */
-
-#ifndef _PCIE_PME_H_
-#define _PCIE_PME_H_
-
-struct pcie_device;
-
-#ifdef CONFIG_ACPI
-extern int pcie_pme_acpi_setup(struct pcie_device *srv);
-
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return pcie_pme_acpi_setup(srv);
-}
-#else /* !CONFIG_ACPI */
-static inline int pcie_pme_platform_notify(struct pcie_device *srv)
-{
-	return 0;
-}
-#endif /* !CONFIG_ACPI */
-
-#endif
drivers/pci/pcie/pme/pcie_pme_acpi.c deleted +0 -54

54 lines not on this page · raw message

drivers/pci/pcie/pme/Makefile deleted +0 -8
Index: linux-2.6/drivers/pci/pcie/pme/Makefile
===================================================================
@@ -1,8 +0,0 @@
-#
-# Makefile for PCI-Express Root Port PME signaling driver
-#
-
-obj-$(CONFIG_PCIE_PME) += pmedriver.o
-
-pmedriver-objs := pcie_pme.o
-pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o
drivers/pci/pcie/aer/aerdrv_acpi.c +0 -36
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_acpi.c
===================================================================
@@ -19,42 +19,6 @@
 #include <acpi/apei.h>
 #include "aerdrv.h"
 
-/**
- * aer_osc_setup - run ACPI _OSC method
- * @pciedev: pcie_device which AER is being enabled on
- *
- * @return: Zero on success. Nonzero otherwise.
- *
- * Invoked when PCIe bus loads AER service driver. To avoid conflict with
- * BIOS AER support requires BIOS to yield AER control to OS native driver.
- **/
-int aer_osc_setup(struct pcie_device *pciedev)
-{
-	acpi_status status = AE_NOT_FOUND;
-	struct pci_dev *pdev = pciedev->port;
-	acpi_handle handle = NULL;
-
-	if (acpi_pci_disabled)
-		return -1;
-
-	handle = acpi_find_root_bridge_handle(pdev);
-	if (handle) {
-		status = acpi_pci_osc_control_set(handle,
-					OSC_PCI_EXPRESS_AER_CONTROL |
-					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	}
-
-	if (ACPI_FAILURE(status)) {
-		dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't "
-			   "init device: %s\n",
-			   (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
-			   "no _OSC support" : "_OSC failed");
-		return -1;
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 static inline int hest_match_pci(struct acpi_hest_aer_common *p,
 				 struct pci_dev *pci)
drivers/pci/pcie/aer/aerdrv_core.c +1 -13
Index: linux-2.6/drivers/pci/pcie/aer/aerdrv_core.c
===================================================================
@@ -771,22 +771,10 @@ void aer_isr(struct work_struct *work)
  */
 int aer_init(struct pcie_device *dev)
 {
-	if (pcie_aer_get_firmware_first(dev->port)) {
-		dev_printk(KERN_DEBUG, &dev->device,
-			   "PCIe errors handled by platform firmware.\n");
-		goto out;
-	}
-
-	if (aer_osc_setup(dev))
-		goto out;
-
-	return 0;
-out:
 	if (forceload) {
 		dev_printk(KERN_DEBUG, &dev->device,
 			   "aerdrv forceload requested.\n");
 		pcie_aer_force_firmware_first(dev->port, 0);
-		return 0;
 	}
-	return -ENXIO;
+	return 0;
 }
drivers/pci/hotplug/acpi_pcihp.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================
@@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware
 	acpi_handle chandle, handle;
 	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
-	flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		  OSC_SHPC_NATIVE_HP_CONTROL |
-		  OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+	flags &= OSC_SHPC_NATIVE_HP_CONTROL;
 	if (!flags) {
 		err("Invalid flags %u specified!\n", flags);
 		return -EINVAL;
drivers/pci/hotplug/pciehp.h +0 -12
Index: linux-2.6/drivers/pci/hotplug/pciehp.h
===================================================================
@@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(
 {
 	pciehp_acpi_slot_detection_init();
 }
-
-static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
-{
-	int retval;
-	u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
-		     OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-	retval = acpi_get_hp_hw_control_from_firmware(dev, flags);
-	if (retval)
-		return retval;
-	return pciehp_acpi_slot_detection_check(dev);
-}
 #else
 #define pciehp_firmware_init()				do {} while (0)
-#define pciehp_get_hp_hw_control_from_firmware(dev) 	0
 #endif 				/* CONFIG_ACPI */
 #endif				/* _PCIEHP_H */
drivers/pci/hotplug/pciehp_core.c +2 -2
Index: linux-2.6/drivers/pci/hotplug/pciehp_core.c
===================================================================
@@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644);
 MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
-MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
+MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing");
 
 #define PCIE_MODULE_NAME "pciehp"
 
@@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_devi
 		dev_info(&dev->device,
 			 "Bypassing BIOS check for pciehp use on %s\n",
 			 pci_name(dev->port));
-	else if (pciehp_get_hp_hw_control_from_firmware(dev->port))
+	else if (pciehp_acpi_slot_detection_check(dev->port))
 		goto err_out_none;
 
 	ctrl = pcie_init(dev);
drivers/pci/hotplug/pciehp_acpi.c +1 -3
Index: linux-2.6/drivers/pci/hotplug/pciehp_acpi.c
===================================================================
@@ -85,9 +85,7 @@ static int __init dummy_probe(struct pci
 	acpi_handle handle;
 	struct dummy_slot *slot, *tmp;
 	struct pci_dev *pdev = dev->port;
-	/* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
-	if (pciehp_get_hp_hw_control_from_firmware(pdev))
-		return -ENODEV;
+
 	pos = pci_pcie_cap(pdev);
 	if (!pos)
 		return -ENODEV;
Documentation/kernel-parameters.txt +6 -7
Index: linux-2.6/Documentation/kernel-parameters.txt
===================================================================
@@ -2048,18 +2048,17 @@ and is between 256 and 4096 characters. 
 			WARNING: Forcing ASPM on may cause system lockups.
 
 	pcie_ports=	[PCIE] PCIe ports handling:
+		auto	Ask the BIOS whether or not to use native PCIe services
+			associated with PCIe ports (PME, hot-plug, AER).  Use
+			them only if that is allowed by the BIOS.
+		native	Use native PCIe services associated with PCIe ports
+			unconditionally.
 		compat	Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
 			ports driver.
 
 	pcie_pme=	[PCIE,PM] Native PCIe PME signaling options:
-			Format: {auto|force}[,nomsi]
-		auto	Use native PCIe PME signaling if the BIOS allows the
-			kernel to control PCIe config registers of root ports.
-		force	Use native PCIe PME signaling even if the BIOS refuses
-			to allow the kernel to control the relevant PCIe config
-			registers.
 		nomsi	Do not use MSI for native PCIe PME signaling (this makes
-			all PCIe root ports use INTx for everything).
+			all PCIe root ports use INTx for all services).
 
 	pcmv=		[HW,PCMCIA] BadgePAD 4
 
#42 lore raw

PATCH 5/8 PCI / PCIe: Disable PCIe port services during port initialization

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

In principle PCIe port services may be enabled by the BIOS, so it's better to disable them during port initialization to avoid spurious events from being generated.

---
 drivers/pci/pcie/portdrv_core.c |   29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)
drivers/pci/pcie/portdrv_core.c +26 -3
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -256,20 +256,43 @@ static int get_port_device_capability(st
 	/* Hot-Plug Capable */
 	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
 		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
-		if (reg32 & PCI_EXP_SLTCAP_HPC)
+		if (reg32 & PCI_EXP_SLTCAP_HPC) {
 			services |= PCIE_PORT_SERVICE_HP;
+			/*
+			 * Disable hot-plug interrupts in case they have been
+			 * enabled by the BIOS and the hot-plug service driver
+			 * is not loaded.
+			 */
+			pos += PCI_EXP_SLTCTL;
+			pci_read_config_word(dev, pos, &reg16);
+			reg16 &= ~(PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE);
+			pci_write_config_word(dev, pos, reg16);
+		}
 	}
 	/* AER capable */
 	if ((cap_mask & PCIE_PORT_SERVICE_AER)
-	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) {
 		services |= PCIE_PORT_SERVICE_AER;
+		/*
+		 * Disable AER on this port in case it's been enabled by the
+		 * BIOS (the AER service driver will enable it when necessary).
+		 */
+		pci_disable_pcie_error_reporting(dev);
+	}
 	/* VC support */
 	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
 		services |= PCIE_PORT_SERVICE_VC;
 	/* Root ports are capable of generating PME too */
 	if ((cap_mask & PCIE_PORT_SERVICE_PME)
-	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
 		services |= PCIE_PORT_SERVICE_PME;
+		/*
+		 * Disable PME interrupt on this port in case it's been enabled
+		 * by the BIOS (the PME service driver will enable it when
+		 * necessary).
+		 */
+		pcie_pme_interrupt_enable(dev, false);
+	}
 
 	return services;
 }
#43 lore raw

PATCH 5/8 PCI / PCIe: Disable PCIe port services during port initialization

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

In principle PCIe port services may be enabled by the BIOS, so it's better to disable them during port initialization to avoid spurious events from being generated.

---
 drivers/pci/pcie/portdrv_core.c |   29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)
drivers/pci/pcie/portdrv_core.c +26 -3
Index: linux-2.6/drivers/pci/pcie/portdrv_core.c
===================================================================
@@ -256,20 +256,43 @@ static int get_port_device_capability(st
 	/* Hot-Plug Capable */
 	if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) {
 		pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
-		if (reg32 & PCI_EXP_SLTCAP_HPC)
+		if (reg32 & PCI_EXP_SLTCAP_HPC) {
 			services |= PCIE_PORT_SERVICE_HP;
+			/*
+			 * Disable hot-plug interrupts in case they have been
+			 * enabled by the BIOS and the hot-plug service driver
+			 * is not loaded.
+			 */
+			pos += PCI_EXP_SLTCTL;
+			pci_read_config_word(dev, pos, &reg16);
+			reg16 &= ~(PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE);
+			pci_write_config_word(dev, pos, reg16);
+		}
 	}
 	/* AER capable */
 	if ((cap_mask & PCIE_PORT_SERVICE_AER)
-	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
+	    && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) {
 		services |= PCIE_PORT_SERVICE_AER;
+		/*
+		 * Disable AER on this port in case it's been enabled by the
+		 * BIOS (the AER service driver will enable it when necessary).
+		 */
+		pci_disable_pcie_error_reporting(dev);
+	}
 	/* VC support */
 	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
 		services |= PCIE_PORT_SERVICE_VC;
 	/* Root ports are capable of generating PME too */
 	if ((cap_mask & PCIE_PORT_SERVICE_PME)
-	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+	    && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
 		services |= PCIE_PORT_SERVICE_PME;
+		/*
+		 * Disable PME interrupt on this port in case it's been enabled
+		 * by the BIOS (the PME service driver will enable it when
+		 * necessary).
+		 */
+		pcie_pme_interrupt_enable(dev, false);
+	}
 
 	return services;
 }
#44 lore raw

PATCH 6/8 PCI / PCIe: Remove the port driver module exit routine

In reply to Rafael J. Wysocki

From: Kenji Kaneshige <[email protected]>

The PCIe port driver's module exit routine is never used, so drop it.

---
 drivers/pci/pcie/portdrv_pci.c |    7 -------
 1 file changed, 7 deletions(-)
drivers/pci/pcie/portdrv_pci.c +0 -7
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -343,11 +343,4 @@ static int __init pcie_portdrv_init(void
 	return retval;
 }
 
-static void __exit pcie_portdrv_exit(void)
-{
-	pci_unregister_driver(&pcie_portdriver);
-	pcie_port_bus_unregister();
-}
-
 module_init(pcie_portdrv_init);
-module_exit(pcie_portdrv_exit);
#45 lore raw

PATCH 6/8 PCI / PCIe: Remove the port driver module exit routine

In reply to Rafael J. Wysocki

From: Kenji Kaneshige <[email protected]>

The PCIe port driver's module exit routine is never used, so drop it.

---
 drivers/pci/pcie/portdrv_pci.c |    7 -------
 1 file changed, 7 deletions(-)
drivers/pci/pcie/portdrv_pci.c +0 -7
Index: linux-2.6/drivers/pci/pcie/portdrv_pci.c
===================================================================
@@ -343,11 +343,4 @@ static int __init pcie_portdrv_init(void
 	return retval;
 }
 
-static void __exit pcie_portdrv_exit(void)
-{
-	pci_unregister_driver(&pcie_portdriver);
-	pcie_port_bus_unregister();
-}
-
 module_init(pcie_portdrv_init);
-module_exit(pcie_portdrv_exit);
#46 lore raw

PATCH 7/8 ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

---
 drivers/acpi/pci_root.c |   15 ---------------
 include/acpi/acpi_bus.h |    3 ---
 2 files changed, 18 deletions(-)
drivers/acpi/pci_root.c +0 -15
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(st
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
 		root->osc_support_set = support;
-		root->osc_control_qry = result;
 		if (control)
 			*control = result;
-		root->osc_queried = 1;
 	}
 	return status;
 }
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
 	if ((root->osc_control_set & control_req) == control_req)
 		goto out;
 
-	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry & control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
-		status = AE_SUPPORT;
-		goto out;
-	}
-
 	capbuf[OSC_QUERY_TYPE] = 0;
 	capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
 	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
include/acpi/acpi_bus.h +0 -3
Index: linux-2.6/include/acpi/acpi_bus.h
===================================================================
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
 };
 
 /* helper */
#47 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 39 lines · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

---
  drivers/acpi/pci_root.c |   15 ---------------
  include/acpi/acpi_bus.h |    3 ---
  2 files changed, 18 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +0 -4
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(st
  	status = acpi_pci_run_osc(root->device->handle, capbuf,&result);
  	if (ACPI_SUCCESS(status)) {
  		root->osc_support_set = support;
-		root->osc_control_qry = result;
  		if (control)
  			*control = result;
-		root->osc_queried = 1;
  	}
  	return status;
  }
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
  	if ((root->osc_control_set&  control_req) == control_req)
  		goto out;
 
-	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
drivers/acpi/pci_root.c +0 -10
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry&  control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
-		status = AE_SUPPORT;
-		goto out;
-	}

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

So the code needs to be

	status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
	if (ACPI_FAILURE(status))
		goto out;

Thanks,
Kenji Kaneshige

#48 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki
Quoted 39 lines · Rafael J. Wysocki

From: Rafael J. Wysocki<[email protected]>

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

---
  drivers/acpi/pci_root.c |   15 ---------------
  include/acpi/acpi_bus.h |    3 ---
  2 files changed, 18 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +0 -4
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(st
  	status = acpi_pci_run_osc(root->device->handle, capbuf,&result);
  	if (ACPI_SUCCESS(status)) {
  		root->osc_support_set = support;
-		root->osc_control_qry = result;
  		if (control)
  			*control = result;
-		root->osc_queried = 1;
  	}
  	return status;
  }
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
  	if ((root->osc_control_set&  control_req) == control_req)
  		goto out;
 
-	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
drivers/acpi/pci_root.c +0 -10
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry&  control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
-		status = AE_SUPPORT;
-		goto out;
-	}

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

So the code needs to be

	status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
	if (ACPI_FAILURE(status))
		goto out;

Thanks,
Kenji Kaneshige

#49 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
drivers/acpi/pci_root.c +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
      if ((root->osc_control_set&  control_req) == control_req)
          goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
drivers/acpi/pci_root.c +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&  control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 5 lines

So the code needs to be

    status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
    if (ACPI_FAILURE(status))
        goto out;

Hum, since acpi_status acpi_pci_osc_control_set() is an exported function, we cannot be too careful here.

OTOH, I think this second query should be done in caller too, i.e. pcie_port_acpi_setup() in patch [4/8].

Now:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    acpi_pci_osc_control_query(handle, &flags);
    /* note: flags might be changed after query */
    acpi_pci_osc_control_set(handle, flags);

}

Strictly, it could be like:

New:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    do {
      pre_flags = flags;
      acpi_pci_osc_control_query(handle, &flags);
    } while (flags && pre_flags != flags);
    if (flags)
      acpi_pci_osc_control_set(handle, flags);

}

IMHO these checks are kind of preventive guard for corner cases, and I suppose it can be implemented by an incremental patch later.

Thanks,
H.Seto

#50 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 55 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
drivers/acpi/pci_root.c +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
      if ((root->osc_control_set&  control_req) == control_req)
          goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
drivers/acpi/pci_root.c +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&  control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 5 lines

So the code needs to be

    status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
    if (ACPI_FAILURE(status))
        goto out;

Hum, since acpi_status acpi_pci_osc_control_set() is an exported function, we cannot be too careful here.

OTOH, I think this second query should be done in caller too, i.e. pcie_port_acpi_setup() in patch [4/8].

Now:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    acpi_pci_osc_control_query(handle, &flags);
    /* note: flags might be changed after query */
    acpi_pci_osc_control_set(handle, flags);

}

Strictly, it could be like:

New:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    do {
      pre_flags = flags;
      acpi_pci_osc_control_query(handle, &flags);
    } while (flags && pre_flags != flags);
    if (flags)
      acpi_pci_osc_control_set(handle, flags);
Quoted 4 lines

}

IMHO these checks are kind of preventive guard for corner cases, and I suppose it can be implemented by an incremental patch later.

OK

The assumption here is that the BIOS would only mask the bits it's not going to grant control of and will do it in a consistent way. So, I guess the purpose of the change above would be to protect us from buggy BIOSes.

Thanks,
Rafael

#51 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 55 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
drivers/acpi/pci_root.c +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
      if ((root->osc_control_set&  control_req) == control_req)
          goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
drivers/acpi/pci_root.c +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&  control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 5 lines

So the code needs to be

    status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
    if (ACPI_FAILURE(status))
        goto out;

Hum, since acpi_status acpi_pci_osc_control_set() is an exported function, we cannot be too careful here.

OTOH, I think this second query should be done in caller too, i.e. pcie_port_acpi_setup() in patch [4/8].

Now:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    acpi_pci_osc_control_query(handle, &flags);
    /* note: flags might be changed after query */
    acpi_pci_osc_control_set(handle, flags);

}

Strictly, it could be like:

New:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    do {
      pre_flags = flags;
      acpi_pci_osc_control_query(handle, &flags);
    } while (flags && pre_flags != flags);
    if (flags)
      acpi_pci_osc_control_set(handle, flags);
Quoted 4 lines

}

IMHO these checks are kind of preventive guard for corner cases, and I suppose it can be implemented by an incremental patch later.

OK

The assumption here is that the BIOS would only mask the bits it's not going to grant control of and will do it in a consistent way. So, I guess the purpose of the change above would be to protect us from buggy BIOSes.

Thanks,
Rafael

#52 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 58 lines · Rafael J. Wysocki
Quoted 57 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
      if ((root->osc_control_set&  control_req) == control_req)
          goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&  control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 5 lines

So the code needs to be

    status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
    if (ACPI_FAILURE(status))
        goto out;

Hum, since acpi_status acpi_pci_osc_control_set() is an exported function, we cannot be too careful here.

OTOH, I think this second query should be done in caller too, i.e. pcie_port_acpi_setup() in patch [4/8].

Now:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    acpi_pci_osc_control_query(handle, &flags);
    /* note: flags might be changed after query */
    acpi_pci_osc_control_set(handle, flags);

}

Strictly, it could be like:

New:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    do {
      pre_flags = flags;
      acpi_pci_osc_control_query(handle, &flags);
    } while (flags && pre_flags != flags);
    if (flags)
      acpi_pci_osc_control_set(handle, flags);

}

Quoted 8 lines
Quoted 2 lines

IMHO these checks are kind of preventive guard for corner cases, and I suppose it can be implemented by an incremental patch later.

OK

The assumption here is that the BIOS would only mask the bits it's not going to grant control of and will do it in a consistent way. So, I guess the purpose of the change above would be to protect us from buggy BIOSes.

What about the appended patch (on top of 4/8)?

Rafael

---
 drivers/pci/pcie/portdrv_acpi.c |   15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/pci/pcie/portdrv_acpi.c +9 -6
Index: linux-2.6/drivers/pci/pcie/portdrv_acpi.c
===================================================================
@@ -35,7 +35,7 @@ int pcie_port_acpi_setup(struct pci_dev 
 {
 	acpi_status status;
 	acpi_handle handle;
-	u32 flags;
+	u32 flags, prev_flags = 0;
 
 	if (acpi_pci_disabled)
 		return 0;
@@ -55,11 +55,14 @@ int pcie_port_acpi_setup(struct pci_dev 
 			flags |= OSC_PCI_EXPRESS_AER_CONTROL;
 	}
 
-	status = acpi_pci_osc_control_query(handle, &flags);
-	if (ACPI_FAILURE(status)) {
-		dev_dbg(&port->dev, "ACPI _OSC query failed (code %d)\n",
-			status);
-		return -ENODEV;
+	while (flags != prev_flags) {
+		prev_flags = flags;
+		status = acpi_pci_osc_control_query(handle, &flags);
+		if (ACPI_FAILURE(status)) {
+			dev_dbg(&port->dev,
+				"ACPI _OSC query failed (code %d)\n", status);
+			return -ENODEV;
+		}
 	}
 
 	if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
#53 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

	query = control_req;
	status = acpi_pci_query_osc(root, root->osc_support_set, &query);
	if (ACPI_FAILURE(status))
		goto out;
	if ((query & control_req) != control_req) {
		printk_(KERN_DEBUG
			"Firmware did not grant requested _OSC control\n");
		status = AE_SUPPORT;
		goto out;
	}

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
	...
	query = control_req;
	status = acpi_pci_query_osc(root, root->osc_support_set, &query);
	if (ACPI_FAILURE(status))
		goto out;
	if ((query & control_req) != control_req) {
		printk_(KERN_DEBUG
			"Firmware did not grant requested _OSC control\n");
		status = AE_SUPPORT;
		*flags = (query & control_req);
		goto out;
	}
	...
}

And do as follows in pcie_port_acpi_setup()

	status = acpi_pci_osc_control_set(handle, &flags);
	if (status == AE_SUPPORT)  {
		/* 2nd try */
		status = acpi_pci_osc_control_set(handle, &flags);
	}
	if (ACPI_FAILURE(status)) {
	...

What do you think about this?

Thanks,
Kenji Kaneshige

#54 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

=====

From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Do not preserve _OSC control bits returned by a query (v3)

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

[v3: HS: keep query in acpi_pci_osc_control_set]

---
 drivers/acpi/pci_root.c |   13 +++++--------
 include/acpi/acpi_bus.h |    3 ---
 2 files changed, 5 insertions(+), 11 deletions(-)
drivers/acpi/pci_root.c +5 -8
index d3110d6..ec03c19 100644
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
 		root->osc_support_set = support;
-		root->osc_control_qry = result;
 		if (control)
 			*control = result;
-		root->osc_queried = 1;
 	}
 	return status;
 }
@@ -438,12 +436,11 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 		goto out;
 
 	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry & control_req) != control_req) {
+	result = control_req;
+	status = acpi_pci_query_osc(root, root->osc_support_set, &result);
+	if (ACPI_FAILURE(status))
+		goto out;
+	if ((result & control_req) != control_req) {
 		printk(KERN_DEBUG
 		       "Firmware did not grant requested _OSC control\n");
 		status = AE_SUPPORT;
include/acpi/acpi_bus.h +0 -3
index baacd98..4de84ce 100644
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
 };
 
 /* helper */
Signature · 1 line
1.7.2
#55 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Kenji Kaneshige
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

=====

From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Do not preserve _OSC control bits returned by a query (v3)

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

[v3: HS: keep query in acpi_pci_osc_control_set]

---
 drivers/acpi/pci_root.c |   13 +++++--------
 include/acpi/acpi_bus.h |    3 ---
 2 files changed, 5 insertions(+), 11 deletions(-)
drivers/acpi/pci_root.c +5 -8
index d3110d6..ec03c19 100644
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
 		root->osc_support_set = support;
-		root->osc_control_qry = result;
 		if (control)
 			*control = result;
-		root->osc_queried = 1;
 	}
 	return status;
 }
@@ -438,12 +436,11 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 		goto out;
 
 	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry & control_req) != control_req) {
+	result = control_req;
+	status = acpi_pci_query_osc(root, root->osc_support_set, &result);
+	if (ACPI_FAILURE(status))
+		goto out;
+	if ((result & control_req) != control_req) {
 		printk(KERN_DEBUG
 		       "Firmware did not grant requested _OSC control\n");
 		status = AE_SUPPORT;
include/acpi/acpi_bus.h +0 -3
index baacd98..4de84ce 100644
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
 };
 
 /* helper */
Signature · 1 line
1.7.2
#56 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 55 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
        if ((root->osc_control_set&    control_req) == control_req)
            goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&    control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

      status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
      if (ACPI_FAILURE(status))
          goto out;

Sorry, that should have been

     query = control_req;
     status = acpi_pci_query_osc(root, root->osc_support_set,&query);
     if (ACPI_FAILURE(status))
         goto out;
     if ((query&  control_req) != control_req) {
         printk_(KERN_DEBUG
             "Firmware did not grant requested _OSC control\n");
         status = AE_SUPPORT;
         goto out;
     }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 1 line

I think the following patch is what you mean.

Thank you! Yes, it is what I meant.
And the patch looks good to me.

Thanks,
Kenji Kaneshige

Quoted 76 lines

And... (Continue to next post)

Thanks,
H.Seto

=====

From: Rafael J. Wysocki<[email protected]>
Subject: ACPI / PCI: Do not preserve _OSC control bits returned by a query (v3)

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

[v3: HS: keep query in acpi_pci_osc_control_set]

---
  drivers/acpi/pci_root.c |   13 +++++--------
  include/acpi/acpi_bus.h |    3 ---
  2 files changed, 5 insertions(+), 11 deletions(-)
drivers/acpi/pci_root.c +5 -8
index d3110d6..ec03c19 100644
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
  	status = acpi_pci_run_osc(root->device->handle, capbuf,&result);
  	if (ACPI_SUCCESS(status)) {
  		root->osc_support_set = support;
-		root->osc_control_qry = result;
  		if (control)
  			*control = result;
-		root->osc_queried = 1;
  	}
  	return status;
  }
@@ -438,12 +436,11 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
  		goto out;
 
  	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry&  control_req) != control_req) {
+	result = control_req;
+	status = acpi_pci_query_osc(root, root->osc_support_set,&result);
+	if (ACPI_FAILURE(status))
+		goto out;
+	if ((result&  control_req) != control_req) {
  		printk(KERN_DEBUG
  		       "Firmware did not grant requested _OSC control\n");
  		status = AE_SUPPORT;
include/acpi/acpi_bus.h +0 -3
index baacd98..4de84ce 100644
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
  	u32 osc_support_set;	/* _OSC state of support bits */
  	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
  };
 
  /* helper */
#57 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 55 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
        if ((root->osc_control_set&    control_req) == control_req)
            goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&    control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

      status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
      if (ACPI_FAILURE(status))
          goto out;

Sorry, that should have been

     query = control_req;
     status = acpi_pci_query_osc(root, root->osc_support_set,&query);
     if (ACPI_FAILURE(status))
         goto out;
     if ((query&  control_req) != control_req) {
         printk_(KERN_DEBUG
             "Firmware did not grant requested _OSC control\n");
         status = AE_SUPPORT;
         goto out;
     }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 1 line

I think the following patch is what you mean.

Thank you! Yes, it is what I meant.
And the patch looks good to me.

Thanks,
Kenji Kaneshige

Quoted 76 lines

And... (Continue to next post)

Thanks,
H.Seto

=====

From: Rafael J. Wysocki<[email protected]>
Subject: ACPI / PCI: Do not preserve _OSC control bits returned by a query (v3)

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

[v3: HS: keep query in acpi_pci_osc_control_set]

---
  drivers/acpi/pci_root.c |   13 +++++--------
  include/acpi/acpi_bus.h |    3 ---
  2 files changed, 5 insertions(+), 11 deletions(-)
drivers/acpi/pci_root.c +5 -8
index d3110d6..ec03c19 100644
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
  	status = acpi_pci_run_osc(root->device->handle, capbuf,&result);
  	if (ACPI_SUCCESS(status)) {
  		root->osc_support_set = support;
-		root->osc_control_qry = result;
  		if (control)
  			*control = result;
-		root->osc_queried = 1;
  	}
  	return status;
  }
@@ -438,12 +436,11 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
  		goto out;
 
  	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry&  control_req) != control_req) {
+	result = control_req;
+	status = acpi_pci_query_osc(root, root->osc_support_set,&result);
+	if (ACPI_FAILURE(status))
+		goto out;
+	if ((result&  control_req) != control_req) {
  		printk(KERN_DEBUG
  		       "Firmware did not grant requested _OSC control\n");
  		status = AE_SUPPORT;
include/acpi/acpi_bus.h +0 -3
index baacd98..4de84ce 100644
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
  	u32 osc_support_set;	/* _OSC state of support bits */
  	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
  };
 
  /* helper */
#58 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 55 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 6 lines

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

OK, I'll repalce my 7/8 with the patch below.

Thanks,
Rafael

Quoted 71 lines

=====

From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Do not preserve _OSC control bits returned by a query (v3)

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

[v3: HS: keep query in acpi_pci_osc_control_set]

---
 drivers/acpi/pci_root.c |   13 +++++--------
 include/acpi/acpi_bus.h |    3 ---
 2 files changed, 5 insertions(+), 11 deletions(-)
drivers/acpi/pci_root.c +5 -8
index d3110d6..ec03c19 100644
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
 		root->osc_support_set = support;
-		root->osc_control_qry = result;
 		if (control)
 			*control = result;
-		root->osc_queried = 1;
 	}
 	return status;
 }
@@ -438,12 +436,11 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 		goto out;
 
 	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry & control_req) != control_req) {
+	result = control_req;
+	status = acpi_pci_query_osc(root, root->osc_support_set, &result);
+	if (ACPI_FAILURE(status))
+		goto out;
+	if ((result & control_req) != control_req) {
 		printk(KERN_DEBUG
 		       "Firmware did not grant requested _OSC control\n");
 		status = AE_SUPPORT;
include/acpi/acpi_bus.h +0 -3
index baacd98..4de84ce 100644
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
 };
 
 /* helper */
#59 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 55 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 6 lines

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

OK, I'll repalce my 7/8 with the patch below.

Thanks,
Rafael

Quoted 71 lines

=====

From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Do not preserve _OSC control bits returned by a query (v3)

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

[v3: HS: keep query in acpi_pci_osc_control_set]

---
 drivers/acpi/pci_root.c |   13 +++++--------
 include/acpi/acpi_bus.h |    3 ---
 2 files changed, 5 insertions(+), 11 deletions(-)
drivers/acpi/pci_root.c +5 -8
index d3110d6..ec03c19 100644
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
 		root->osc_support_set = support;
-		root->osc_control_qry = result;
 		if (control)
 			*control = result;
-		root->osc_queried = 1;
 	}
 	return status;
 }
@@ -438,12 +436,11 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 		goto out;
 
 	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry & control_req) != control_req) {
+	result = control_req;
+	status = acpi_pci_query_osc(root, root->osc_support_set, &result);
+	if (ACPI_FAILURE(status))
+		goto out;
+	if ((result & control_req) != control_req) {
 		printk(KERN_DEBUG
 		       "Firmware did not grant requested _OSC control\n");
 		status = AE_SUPPORT;
include/acpi/acpi_bus.h +0 -3
index baacd98..4de84ce 100644
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
 };
 
 /* helper */
#60 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 56 lines · Rafael J. Wysocki
Quoted 55 lines · Hidetoshi Seto
Quoted 53 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 8 lines
Quoted 6 lines

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

OK, I'll repalce my 7/8 with the patch below.

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

Given that acpi_pci_osc_control_query() is introduced by
https://patchwork.kernel.org/patch/117176/ , the helper may be implemented like in the appended patch.

After that patch, the $subject patch can be applied without any modifications to remove the no-longer-used fields in struct acpi_pci_root.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce function for requesting _OSC controls safely

Calling raw acpi_pci_osc_control_set() is generally unsafe, because it may return error code even if control of some requested features have been granted by the BIOS. For this reason the callers of acpi_pci_osc_control_set() should call acpi_pci_osc_control_query() before it to make sure that the BIOS is willing to grant control of the requested features.

Introduce helper function acpi_pci_osc_control_set_safe() allowing a caller of acpi_pci_osc_control_set() who is not interested in the control bits returned by acpi_pci_osc_control_query() to request control of _OSC features in a safe way.

Make acpi_get_hp_hw_control_from_firmware() use the new function.

---
 drivers/acpi/pci_root.c          |   24 ++++++++++++++++++++++++
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 include/linux/acpi.h             |    1 +
 3 files changed, 26 insertions(+), 1 deletion(-)
drivers/acpi/pci_root.c +24 -0
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -472,6 +472,30 @@ out:
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
+/**
+ * acpi_pci_osc_control_set_safe - Query and set _OSC control bit mask.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @flags: Mask of _OSC bits to query and set.
+ *
+ * Check if the BIOS is willing to grant control of the features represented
+ * by @flags and request control of these features from it.
+ **/
+acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags)
+{
+	acpi_status status;
+	u32 ctrl = flags;
+
+	status = acpi_pci_osc_control_query(handle, &flags);
+	if (ACPI_FAILURE(status))
+		return status;
+	if ((ctrl & flags) != ctrl)
+		return AE_SUPPORT;
+
+	status = acpi_pci_osc_control_set(handle, flags);
+	return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set_safe);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
 	unsigned long long segment, bus;
drivers/pci/hotplug/acpi_pcihp.c +1 -1
Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set_safe(handle, flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -307,6 +307,7 @@ acpi_status acpi_run_osc(acpi_handle han
 
 extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */
#61 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 64 lines · Rafael J. Wysocki
Quoted 63 lines · Rafael J. Wysocki
Quoted 61 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

Quoted 8 lines
Quoted 1 line

OK, I'll repalce my 7/8 with the patch below.

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Ugh... there are only 2 callers now and both of them are in the majority. I don't think it is a time to take care of an invisible minority who might require acpi_pci_osc_raw() to complete its work.

Quoted 4 lines

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

So we can recommend all of callers not to call acpi_pci_osc_control_query() before acpi_pci_osc_control_set().

I suppose that almost all of "the majority" just want to set fixed set of controls and they will just return error when fails anyway.

Quoted 5 lines

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

I'm afraid the "two" is not enough for the minority.

Therefore I don't think it is a time to prepare for such an inexistent minor usage.

Quoted 91 lines

Given that acpi_pci_osc_control_query() is introduced by
https://patchwork.kernel.org/patch/117176/ , the helper may be implemented like in the appended patch.

After that patch, the $subject patch can be applied without any modifications to remove the no-longer-used fields in struct acpi_pci_root.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce function for requesting _OSC controls safely

Calling raw acpi_pci_osc_control_set() is generally unsafe, because it may return error code even if control of some requested features have been granted by the BIOS. For this reason the callers of acpi_pci_osc_control_set() should call acpi_pci_osc_control_query() before it to make sure that the BIOS is willing to grant control of the requested features.

Introduce helper function acpi_pci_osc_control_set_safe() allowing a caller of acpi_pci_osc_control_set() who is not interested in the control bits returned by acpi_pci_osc_control_query() to request control of _OSC features in a safe way.

Make acpi_get_hp_hw_control_from_firmware() use the new function.

---
 drivers/acpi/pci_root.c          |   24 ++++++++++++++++++++++++
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 include/linux/acpi.h             |    1 +
 3 files changed, 26 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +24 -0
@@ -472,6 +472,30 @@ out:
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
+/**
+ * acpi_pci_osc_control_set_safe - Query and set _OSC control bit mask.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @flags: Mask of _OSC bits to query and set.
+ *
+ * Check if the BIOS is willing to grant control of the features represented
+ * by @flags and request control of these features from it.
+ **/
+acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags)
+{
+	acpi_status status;
+	u32 ctrl = flags;
+
+	status = acpi_pci_osc_control_query(handle, &flags);
+	if (ACPI_FAILURE(status))
+		return status;
+	if ((ctrl & flags) != ctrl)
+		return AE_SUPPORT;
+
+	status = acpi_pci_osc_control_set(handle, flags);
+	return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set_safe);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
 	unsigned long long segment, bus;

Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================

drivers/pci/hotplug/acpi_pcihp.c +1 -1
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set_safe(handle, flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)

Index: linux-2.6/include/linux/acpi.h
===================================================================

include/linux/acpi.h acpi_status acpi_run_osc(acpi_handle han · line 313

Quoted 7 lines
include/linux/acpi.h +1 -0
@@ -307,6 +307,7 @@ acpi_status acpi_run_osc(acpi_handle han
 
 extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */

So I'd like to say NAK against this patch, sorry.

Thanks,
H.Seto

#62 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 79 lines · Hidetoshi Seto
Quoted 64 lines · Rafael J. Wysocki
Quoted 63 lines · Rafael J. Wysocki
Quoted 61 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

Quoted 8 lines
Quoted 1 line

OK, I'll repalce my 7/8 with the patch below.

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Ugh... there are only 2 callers now and both of them are in the majority. I don't think it is a time to take care of an invisible minority who might require acpi_pci_osc_raw() to complete its work.

Quoted 1 line
Quoted 6 lines
Quoted 3 lines

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

So we can recommend all of callers not to call acpi_pci_osc_control_query() before acpi_pci_osc_control_set().

Please consider pcie_port_acpi_setup() in [4/8].

It has to do the query by itself, because it may not request the controls _even_ _if_ _the_ _query_ _is_ _successful_. Namely, if the result of the query is that the BIOS won't let us control the PCIe Capability Structure, pcie_port_acpi_setup() should return error code instead of requesting control of the other features. Now, if you put the query into acpi_pci_osc_control_set(), it won't be able to recognize this corner case and handle it correctly.

Quoted 9 lines

I suppose that almost all of "the majority" just want to set fixed set of controls and they will just return error when fails anyway.

Quoted 5 lines

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

Quoted 4 lines

I'm afraid the "two" is not enough for the minority.

Therefore I don't think it is a time to prepare for such an inexistent minor usage.

As explained above, I think there is a reason to do that, because pcie_port_acpi_setup() has to run a query anyway.

Quoted 91 lines
Quoted 91 lines

Given that acpi_pci_osc_control_query() is introduced by
https://patchwork.kernel.org/patch/117176/ , the helper may be implemented like in the appended patch.

After that patch, the $subject patch can be applied without any modifications to remove the no-longer-used fields in struct acpi_pci_root.

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce function for requesting _OSC controls safely

Calling raw acpi_pci_osc_control_set() is generally unsafe, because it may return error code even if control of some requested features have been granted by the BIOS. For this reason the callers of acpi_pci_osc_control_set() should call acpi_pci_osc_control_query() before it to make sure that the BIOS is willing to grant control of the requested features.

Introduce helper function acpi_pci_osc_control_set_safe() allowing a caller of acpi_pci_osc_control_set() who is not interested in the control bits returned by acpi_pci_osc_control_query() to request control of _OSC features in a safe way.

Make acpi_get_hp_hw_control_from_firmware() use the new function.

---
 drivers/acpi/pci_root.c          |   24 ++++++++++++++++++++++++
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 include/linux/acpi.h             |    1 +
 3 files changed, 26 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +24 -0
@@ -472,6 +472,30 @@ out:
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
+/**
+ * acpi_pci_osc_control_set_safe - Query and set _OSC control bit mask.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @flags: Mask of _OSC bits to query and set.
+ *
+ * Check if the BIOS is willing to grant control of the features represented
+ * by @flags and request control of these features from it.
+ **/
+acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags)
+{
+	acpi_status status;
+	u32 ctrl = flags;
+
+	status = acpi_pci_osc_control_query(handle, &flags);
+	if (ACPI_FAILURE(status))
+		return status;
+	if ((ctrl & flags) != ctrl)
+		return AE_SUPPORT;
+
+	status = acpi_pci_osc_control_set(handle, flags);
+	return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set_safe);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
 	unsigned long long segment, bus;

Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================

drivers/pci/hotplug/acpi_pcihp.c +1 -1
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set_safe(handle, flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)

Index: linux-2.6/include/linux/acpi.h
===================================================================

include/linux/acpi.h +1 -0
@@ -307,6 +307,7 @@ acpi_status acpi_run_osc(acpi_handle han
 
 extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
Quoted 5 lines

include/linux/acpi.h acpi_status acpi_run_osc(acpi_handle han · line 313

Quoted 3 lines
include/linux/acpi.h +0 -0
 #else	/* !CONFIG_ACPI */

So I'd like to say NAK against this patch, sorry.

IMHO you've not given a sufficient reason for that.

Thanks,
Rafael

#63 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line · Hidetoshi Seto

(2010/08/05 8:51), Rafael J. Wysocki wrote:

<snip>

Quoted 21 lines
Quoted 12 lines
Quoted 6 lines

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Ugh... there are only 2 callers now and both of them are in the majority. I don't think it is a time to take care of an invisible minority who might require acpi_pci_osc_raw() to complete its work.

Quoted 1 line
Quoted 6 lines
Quoted 3 lines

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

So we can recommend all of callers not to call acpi_pci_osc_control_query() before acpi_pci_osc_control_set().

Please consider pcie_port_acpi_setup() in [4/8].

Quoted 7 lines

It has to do the query by itself, because it may not request the controls _even_ _if_ _the_ _query_ _is_ _successful_. Namely, if the result of the query is that the BIOS won't let us control the PCIe Capability Structure, pcie_port_acpi_setup() should return error code instead of requesting control of the other features. Now, if you put the query into acpi_pci_osc_control_set(), it won't be able to recognize this corner case and handle it correctly.

Then please rewrite your pcie_port_acpi_setup() to clarify that it cannot live without separated "query" and "set".

I already stated that current pcie_port_acpi_setup() can do its work using a modified acpi_pci_osc_control_set().
https://patchwork.kernel.org/patch/116976/

Or you might invent new function like:
acpi_pci_osc_control_set2(*dev, required_bits, optional_bits)

Anyway I'm going to cancel my plan to test your patches today.

Quoted 9 lines
Quoted 9 lines

I suppose that almost all of "the majority" just want to set fixed set of controls and they will just return error when fails anyway.

Quoted 5 lines

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

Quoted 7 lines
Quoted 4 lines

I'm afraid the "two" is not enough for the minority.

Therefore I don't think it is a time to prepare for such an inexistent minor usage.

As explained above, I think there is a reason to do that, because pcie_port_acpi_setup() has to run a query anyway.

I believe I already reviewed your patch enough, but I couldn't find out the reason that you are claiming now.

If that helps, one of the reasons why I can accept Kaneshige-san's suggestion to have a smart acpi_pci_osc_control_set() instead of separated functions is because I remember a function pci_enable_msix() that returns '0' on success, '< 0' on failure, and '> 0' when retry might be possible with the returned value.

Thanks,
H.Seto

#64 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki
Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line · Hidetoshi Seto

(2010/08/05 8:51), Rafael J. Wysocki wrote:

<snip>

Quoted 21 lines
Quoted 12 lines
Quoted 6 lines

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Ugh... there are only 2 callers now and both of them are in the majority. I don't think it is a time to take care of an invisible minority who might require acpi_pci_osc_raw() to complete its work.

Quoted 1 line
Quoted 6 lines
Quoted 3 lines

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

So we can recommend all of callers not to call acpi_pci_osc_control_query() before acpi_pci_osc_control_set().

Please consider pcie_port_acpi_setup() in [4/8].

Quoted 7 lines

It has to do the query by itself, because it may not request the controls _even_ _if_ _the_ _query_ _is_ _successful_. Namely, if the result of the query is that the BIOS won't let us control the PCIe Capability Structure, pcie_port_acpi_setup() should return error code instead of requesting control of the other features. Now, if you put the query into acpi_pci_osc_control_set(), it won't be able to recognize this corner case and handle it correctly.

Then please rewrite your pcie_port_acpi_setup() to clarify that it cannot live without separated "query" and "set".

I already stated that current pcie_port_acpi_setup() can do its work using a modified acpi_pci_osc_control_set().
https://patchwork.kernel.org/patch/116976/

Or you might invent new function like:
acpi_pci_osc_control_set2(*dev, required_bits, optional_bits)

Anyway I'm going to cancel my plan to test your patches today.

Quoted 9 lines
Quoted 9 lines

I suppose that almost all of "the majority" just want to set fixed set of controls and they will just return error when fails anyway.

Quoted 5 lines

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

Quoted 7 lines
Quoted 4 lines

I'm afraid the "two" is not enough for the minority.

Therefore I don't think it is a time to prepare for such an inexistent minor usage.

As explained above, I think there is a reason to do that, because pcie_port_acpi_setup() has to run a query anyway.

I believe I already reviewed your patch enough, but I couldn't find out the reason that you are claiming now.

If that helps, one of the reasons why I can accept Kaneshige-san's suggestion to have a smart acpi_pci_osc_control_set() instead of separated functions is because I remember a function pci_enable_msix() that returns '0' on success, '< 0' on failure, and '> 0' when retry might be possible with the returned value.

Thanks,
H.Seto

#65 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 79 lines · Hidetoshi Seto
Quoted 64 lines · Rafael J. Wysocki
Quoted 63 lines · Rafael J. Wysocki
Quoted 61 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

Quoted 8 lines
Quoted 1 line

OK, I'll repalce my 7/8 with the patch below.

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Ugh... there are only 2 callers now and both of them are in the majority. I don't think it is a time to take care of an invisible minority who might require acpi_pci_osc_raw() to complete its work.

Quoted 1 line
Quoted 6 lines
Quoted 3 lines

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

So we can recommend all of callers not to call acpi_pci_osc_control_query() before acpi_pci_osc_control_set().

Please consider pcie_port_acpi_setup() in [4/8].

It has to do the query by itself, because it may not request the controls _even_ _if_ _the_ _query_ _is_ _successful_. Namely, if the result of the query is that the BIOS won't let us control the PCIe Capability Structure, pcie_port_acpi_setup() should return error code instead of requesting control of the other features. Now, if you put the query into acpi_pci_osc_control_set(), it won't be able to recognize this corner case and handle it correctly.

Quoted 9 lines

I suppose that almost all of "the majority" just want to set fixed set of controls and they will just return error when fails anyway.

Quoted 5 lines

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

Quoted 4 lines

I'm afraid the "two" is not enough for the minority.

Therefore I don't think it is a time to prepare for such an inexistent minor usage.

As explained above, I think there is a reason to do that, because pcie_port_acpi_setup() has to run a query anyway.

Quoted 91 lines
Quoted 91 lines

Given that acpi_pci_osc_control_query() is introduced by
https://patchwork.kernel.org/patch/117176/ , the helper may be implemented like in the appended patch.

After that patch, the $subject patch can be applied without any modifications to remove the no-longer-used fields in struct acpi_pci_root.

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce function for requesting _OSC controls safely

Calling raw acpi_pci_osc_control_set() is generally unsafe, because it may return error code even if control of some requested features have been granted by the BIOS. For this reason the callers of acpi_pci_osc_control_set() should call acpi_pci_osc_control_query() before it to make sure that the BIOS is willing to grant control of the requested features.

Introduce helper function acpi_pci_osc_control_set_safe() allowing a caller of acpi_pci_osc_control_set() who is not interested in the control bits returned by acpi_pci_osc_control_query() to request control of _OSC features in a safe way.

Make acpi_get_hp_hw_control_from_firmware() use the new function.

---
 drivers/acpi/pci_root.c          |   24 ++++++++++++++++++++++++
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 include/linux/acpi.h             |    1 +
 3 files changed, 26 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +24 -0
@@ -472,6 +472,30 @@ out:
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
+/**
+ * acpi_pci_osc_control_set_safe - Query and set _OSC control bit mask.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @flags: Mask of _OSC bits to query and set.
+ *
+ * Check if the BIOS is willing to grant control of the features represented
+ * by @flags and request control of these features from it.
+ **/
+acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags)
+{
+	acpi_status status;
+	u32 ctrl = flags;
+
+	status = acpi_pci_osc_control_query(handle, &flags);
+	if (ACPI_FAILURE(status))
+		return status;
+	if ((ctrl & flags) != ctrl)
+		return AE_SUPPORT;
+
+	status = acpi_pci_osc_control_set(handle, flags);
+	return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set_safe);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
 	unsigned long long segment, bus;

Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================

drivers/pci/hotplug/acpi_pcihp.c +1 -1
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set_safe(handle, flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)

Index: linux-2.6/include/linux/acpi.h
===================================================================

include/linux/acpi.h +1 -0
@@ -307,6 +307,7 @@ acpi_status acpi_run_osc(acpi_handle han
 
 extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
Quoted 5 lines

include/linux/acpi.h acpi_status acpi_run_osc(acpi_handle han · line 313

Quoted 3 lines
include/linux/acpi.h +0 -0
 #else	/* !CONFIG_ACPI */

So I'd like to say NAK against this patch, sorry.

IMHO you've not given a sufficient reason for that.

Thanks,
Rafael

#66 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki
Quoted 64 lines · Rafael J. Wysocki
Quoted 63 lines · Rafael J. Wysocki
Quoted 61 lines · Hidetoshi Seto
Quoted 45 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }
Quoted 8 lines

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

Quoted 8 lines
Quoted 1 line

OK, I'll repalce my 7/8 with the patch below.

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Ugh... there are only 2 callers now and both of them are in the majority. I don't think it is a time to take care of an invisible minority who might require acpi_pci_osc_raw() to complete its work.

Quoted 4 lines

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

So we can recommend all of callers not to call acpi_pci_osc_control_query() before acpi_pci_osc_control_set().

I suppose that almost all of "the majority" just want to set fixed set of controls and they will just return error when fails anyway.

Quoted 5 lines

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

I'm afraid the "two" is not enough for the minority.

Therefore I don't think it is a time to prepare for such an inexistent minor usage.

Quoted 91 lines

Given that acpi_pci_osc_control_query() is introduced by
https://patchwork.kernel.org/patch/117176/ , the helper may be implemented like in the appended patch.

After that patch, the $subject patch can be applied without any modifications to remove the no-longer-used fields in struct acpi_pci_root.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce function for requesting _OSC controls safely

Calling raw acpi_pci_osc_control_set() is generally unsafe, because it may return error code even if control of some requested features have been granted by the BIOS. For this reason the callers of acpi_pci_osc_control_set() should call acpi_pci_osc_control_query() before it to make sure that the BIOS is willing to grant control of the requested features.

Introduce helper function acpi_pci_osc_control_set_safe() allowing a caller of acpi_pci_osc_control_set() who is not interested in the control bits returned by acpi_pci_osc_control_query() to request control of _OSC features in a safe way.

Make acpi_get_hp_hw_control_from_firmware() use the new function.

---
 drivers/acpi/pci_root.c          |   24 ++++++++++++++++++++++++
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 include/linux/acpi.h             |    1 +
 3 files changed, 26 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================

drivers/acpi/pci_root.c +24 -0
@@ -472,6 +472,30 @@ out:
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
+/**
+ * acpi_pci_osc_control_set_safe - Query and set _OSC control bit mask.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @flags: Mask of _OSC bits to query and set.
+ *
+ * Check if the BIOS is willing to grant control of the features represented
+ * by @flags and request control of these features from it.
+ **/
+acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags)
+{
+	acpi_status status;
+	u32 ctrl = flags;
+
+	status = acpi_pci_osc_control_query(handle, &flags);
+	if (ACPI_FAILURE(status))
+		return status;
+	if ((ctrl & flags) != ctrl)
+		return AE_SUPPORT;
+
+	status = acpi_pci_osc_control_set(handle, flags);
+	return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set_safe);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
 	unsigned long long segment, bus;

Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================

drivers/pci/hotplug/acpi_pcihp.c +1 -1
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set_safe(handle, flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)

Index: linux-2.6/include/linux/acpi.h
===================================================================

include/linux/acpi.h acpi_status acpi_run_osc(acpi_handle han · line 313

Quoted 7 lines
include/linux/acpi.h +1 -0
@@ -307,6 +307,7 @@ acpi_status acpi_run_osc(acpi_handle han
 
 extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */

So I'd like to say NAK against this patch, sorry.

Thanks,
H.Seto

#67 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki
Quoted 56 lines · Rafael J. Wysocki
Quoted 55 lines · Hidetoshi Seto
Quoted 53 lines · Kenji Kaneshige
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        goto out;
    }

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 8 lines
Quoted 6 lines

I think the following patch is what you mean.

And... (Continue to next post)

Thanks,
H.Seto

OK, I'll repalce my 7/8 with the patch below.

Actually, having reconsidered that, I don't think this approach is valid.

First, it has the problem that if acpi_pci_osc_control_set() returns error code, the caller doesn't really know whether the query failed, or the final request failed. Arguably, it won't matter for the majority of callers, but some of them might be interested in knowing that in principle.

Second, the callers that call acpi_pci_osc_control_query() before acpi_pci_osc_control_set() don't need the additional query inside of acpi_pci_osc_control_set().

Therefore I'd prefer to have two separate functions, one for querying and the other for requesting control. Then, we can provide a helper that calls the both of them for the callers of acpi_pci_osc_control_set() that don't need to call acpi_pci_osc_control_query() directly by themselves.

Given that acpi_pci_osc_control_query() is introduced by
https://patchwork.kernel.org/patch/117176/ , the helper may be implemented like in the appended patch.

After that patch, the $subject patch can be applied without any modifications to remove the no-longer-used fields in struct acpi_pci_root.

Thanks,
Rafael

---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / PCI: Introduce function for requesting _OSC controls safely

Calling raw acpi_pci_osc_control_set() is generally unsafe, because it may return error code even if control of some requested features have been granted by the BIOS. For this reason the callers of acpi_pci_osc_control_set() should call acpi_pci_osc_control_query() before it to make sure that the BIOS is willing to grant control of the requested features.

Introduce helper function acpi_pci_osc_control_set_safe() allowing a caller of acpi_pci_osc_control_set() who is not interested in the control bits returned by acpi_pci_osc_control_query() to request control of _OSC features in a safe way.

Make acpi_get_hp_hw_control_from_firmware() use the new function.

---
 drivers/acpi/pci_root.c          |   24 ++++++++++++++++++++++++
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 include/linux/acpi.h             |    1 +
 3 files changed, 26 insertions(+), 1 deletion(-)
drivers/acpi/pci_root.c +24 -0
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -472,6 +472,30 @@ out:
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
+/**
+ * acpi_pci_osc_control_set_safe - Query and set _OSC control bit mask.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @flags: Mask of _OSC bits to query and set.
+ *
+ * Check if the BIOS is willing to grant control of the features represented
+ * by @flags and request control of these features from it.
+ **/
+acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags)
+{
+	acpi_status status;
+	u32 ctrl = flags;
+
+	status = acpi_pci_osc_control_query(handle, &flags);
+	if (ACPI_FAILURE(status))
+		return status;
+	if ((ctrl & flags) != ctrl)
+		return AE_SUPPORT;
+
+	status = acpi_pci_osc_control_set(handle, flags);
+	return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_set_safe);
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
 	unsigned long long segment, bus;
drivers/pci/hotplug/acpi_pcihp.c +1 -1
Index: linux-2.6/drivers/pci/hotplug/acpi_pcihp.c
===================================================================
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set_safe(handle, flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)
include/linux/acpi.h +1 -0
Index: linux-2.6/include/linux/acpi.h
===================================================================
@@ -307,6 +307,7 @@ acpi_status acpi_run_osc(acpi_handle han
 
 extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
 extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set_safe(acpi_handle handle, u32 flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */
#68 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Kenji Kaneshige
Quoted 35 lines · Kenji Kaneshige

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
    ...
    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        *flags = (query & control_req);
        goto out;
    }
    ...
}

And do as follows in pcie_port_acpi_setup()

    status = acpi_pci_osc_control_set(handle, &flags);
    if (status == AE_SUPPORT)  {
        /* 2nd try */
        status = acpi_pci_osc_control_set(handle, &flags);
    }
    if (ACPI_FAILURE(status)) {
    ...
Quoted 1 line

What do you think about this?

I think it makes sense, though some minor cares are required.

Does this incremental patch (apply after [8/8]) looks good? If it is OK, I'll test these 8+1 patches within the next 2days.

Thanks,
H.Seto

=====
Subject: ACPI/PCI: Unify acpi_pci_osc_control_*()

Now AE_SUPPORT of acpi_pci_osc_control_set() tells not only that query fails with the requested control bits but also that the result of query is stored into the pointed place.

This allow user to retry acpi_pci_osc_control_set() with the result of query.

---
 drivers/acpi/pci_root.c          |   54 +++++++++++--------------------------
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 drivers/pci/pcie/portdrv_acpi.c  |   23 +++++++---------
 include/linux/acpi.h             |    3 +-
 4 files changed, 28 insertions(+), 54 deletions(-)
drivers/acpi/pci_root.c +16 -38
index 061e6f4..9a288df 100644
@@ -372,38 +372,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
- /**
- * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
- * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
- * @mask: Mask of _OSC bits to query and the place to put the result into.
- **/
-acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
-{
-	struct acpi_pci_root *root;
-	acpi_handle tmp;
-	acpi_status status = AE_OK;
-
-	if (!mask || !(*mask & OSC_PCI_CONTROL_MASKS))
-		return AE_BAD_PARAMETER;
-
-	root = acpi_pci_find_root(handle);
-	if (!root)
-		return AE_NOT_EXIST;
-
-	status = acpi_get_handle(handle, "_OSC", &tmp);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	mutex_lock(&osc_lock);
-	if ((*mask & root->osc_control_set) == *mask)
-		*mask = root->osc_control_set;
-	else
-		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
-	mutex_unlock(&osc_lock);
-
-	return status;
-}
-
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
  *
  * Attempt to take control from Firmware on requested control bits.
  **/
-acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
+acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)
 {
 	acpi_status status;
 	u32 control_req, result, capbuf[3];
 	acpi_handle tmp;
 	struct acpi_pci_root *root;
 
-	control_req = (flags & OSC_PCI_CONTROL_MASKS);
+	if (!flags)
+		return AE_BAD_PARAMETER;
+
+	control_req = (*flags & OSC_PCI_CONTROL_MASKS);
 	if (!control_req)
 		return AE_TYPE;
 
@@ -432,8 +403,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 
 	mutex_lock(&osc_lock);
 	/* No need to evaluate _OSC if the control was already granted. */
-	if ((root->osc_control_set & control_req) == control_req)
+	if ((root->osc_control_set & control_req) == control_req) {
+		*flags = root->osc_control_set;
 		goto out;
+	}
 
 	/* Need to query controls first before requesting them */
 	result = control_req;
@@ -441,8 +414,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	if (ACPI_FAILURE(status))
 		goto out;
 	if ((result & control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
+		printk(KERN_DEBUG PREFIX
+		       "Firmware did not grant requested _OSC control: %x/%x\n",
+		       control_req, result);
+		*flags = result;
 		status = AE_SUPPORT;
 		goto out;
 	}
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
 	status = acpi_pci_run_osc(handle, capbuf, &result);
 	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;
+	else
+		printk(KERN_WARNING FW_BUG PREFIX
+		       "_OSC did not grant controls that passed query\n");
 out:
 	mutex_unlock(&osc_lock);
 	return status;
drivers/pci/hotplug/acpi_pcihp.c +1 -1
index 12ea415..675181d 100644
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set(handle, &flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)
drivers/pci/pcie/portdrv_acpi.c +10 -13
index a07a70e..764d0b3 100644
@@ -55,20 +55,17 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
 			flags |= OSC_PCI_EXPRESS_AER_CONTROL;
 	}
 
-	status = acpi_pci_osc_control_query(handle, &flags);
-	if (ACPI_FAILURE(status)) {
-		dev_dbg(&port->dev, "ACPI _OSC query failed (code %d)\n",
-			status);
-		return -ENODEV;
+retry:
+	status = acpi_pci_osc_control_set(handle, &flags);
+	if (status == AE_SUPPORT) {
+		if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
+			dev_dbg(&port->dev, "BIOS refuses to grant control of "
+				"PCIe Capability Structure\n");
+			return -EACCES;
+		}
+		if (flags & ~OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+			goto retry;
 	}
-
-	if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
-		dev_dbg(&port->dev, "BIOS refuses to grant control of PCIe "
-			"Capability Structure\n");
-		return -EACCES;
-	}
-
-	status = acpi_pci_osc_control_set(handle, flags);
 	if (ACPI_FAILURE(status)) {
 		dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
 			status);
include/linux/acpi.h +1 -2
index a9afe9c..1b5aac6 100644
@@ -305,8 +305,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
-extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
-extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */
Signature · 1 line
1.7.2
#69 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 63 lines · Hidetoshi Seto
Quoted 35 lines · Kenji Kaneshige

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
     ...
     query = control_req;
     status = acpi_pci_query_osc(root, root->osc_support_set,&query);
     if (ACPI_FAILURE(status))
         goto out;
     if ((query&  control_req) != control_req) {
         printk_(KERN_DEBUG
             "Firmware did not grant requested _OSC control\n");
         status = AE_SUPPORT;
         *flags = (query&  control_req);
         goto out;
     }
     ...
}

And do as follows in pcie_port_acpi_setup()

     status = acpi_pci_osc_control_set(handle,&flags);
     if (status == AE_SUPPORT)  {
         /* 2nd try */
         status = acpi_pci_osc_control_set(handle,&flags);
     }
     if (ACPI_FAILURE(status)) {
     ...
Quoted 1 line

What do you think about this?

I think it makes sense, though some minor cares are required.

Does this incremental patch (apply after [8/8]) looks good? If it is OK, I'll test these 8+1 patches within the next 2days.

Thanks,
H.Seto

=====
Subject: ACPI/PCI: Unify acpi_pci_osc_control_*()

Now AE_SUPPORT of acpi_pci_osc_control_set() tells not only that query fails with the requested control bits but also that the result of query is stored into the pointed place.

This allow user to retry acpi_pci_osc_control_set() with the result of query.

---
  drivers/acpi/pci_root.c          |   54 +++++++++++--------------------------
  drivers/pci/hotplug/acpi_pcihp.c |    2 +-
  drivers/pci/pcie/portdrv_acpi.c  |   23 +++++++---------
  include/linux/acpi.h             |    3 +-
  4 files changed, 28 insertions(+), 54 deletions(-)

<snip.>

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask) · line 381

Quoted 7 lines

/**
* acpi_pci_osc_control_set - commit requested control to Firmware
* @handle: acpi_handle for the target ACPI object

drivers/acpi/pci_root.c +0 -0
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
   *
   * Attempt to take control from Firmware on requested control bits.
   **/

Updating description of this function would be appreciated.

<snip.>

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) · line 430

Quoted 6 lines
drivers/acpi/pci_root.c +1 -1
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
  	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
  	status = acpi_pci_run_osc(handle, capbuf,&result);
  	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;

I don't think we need to update *flags here, though it depends on the design of this function interface.
IMHO, updating *flags only when AE_SUPPORT is returned is easy to understand.

Others looks good to me.

Thanks,
Kenji Kaneshige

#70 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 79 lines · Kenji Kaneshige
Quoted 63 lines · Hidetoshi Seto
Quoted 35 lines · Kenji Kaneshige

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
     ...
     query = control_req;
     status = acpi_pci_query_osc(root, root->osc_support_set,&query);
     if (ACPI_FAILURE(status))
         goto out;
     if ((query&  control_req) != control_req) {
         printk_(KERN_DEBUG
             "Firmware did not grant requested _OSC control\n");
         status = AE_SUPPORT;
         *flags = (query&  control_req);
         goto out;
     }
     ...
}

And do as follows in pcie_port_acpi_setup()

     status = acpi_pci_osc_control_set(handle,&flags);
     if (status == AE_SUPPORT)  {
         /* 2nd try */
         status = acpi_pci_osc_control_set(handle,&flags);
     }
     if (ACPI_FAILURE(status)) {
     ...
Quoted 1 line

What do you think about this?

I think it makes sense, though some minor cares are required.

Does this incremental patch (apply after [8/8]) looks good? If it is OK, I'll test these 8+1 patches within the next 2days.

Thanks,
H.Seto

=====
Subject: ACPI/PCI: Unify acpi_pci_osc_control_*()

Now AE_SUPPORT of acpi_pci_osc_control_set() tells not only that query fails with the requested control bits but also that the result of query is stored into the pointed place.

This allow user to retry acpi_pci_osc_control_set() with the result of query.

---
  drivers/acpi/pci_root.c          |   54 +++++++++++--------------------------
  drivers/pci/hotplug/acpi_pcihp.c |    2 +-
  drivers/pci/pcie/portdrv_acpi.c  |   23 +++++++---------
  include/linux/acpi.h             |    3 +-
  4 files changed, 28 insertions(+), 54 deletions(-)

<snip.>

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask) · line 381

Quoted 7 lines

/**
* acpi_pci_osc_control_set - commit requested control to Firmware
* @handle: acpi_handle for the target ACPI object

drivers/acpi/pci_root.c +0 -0
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
   *
   * Attempt to take control from Firmware on requested control bits.
   **/

Updating description of this function would be appreciated.

<snip.>

Quoted 10 lines

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) · line 430

Quoted 6 lines
drivers/acpi/pci_root.c +1 -1
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
  	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
  	status = acpi_pci_run_osc(handle, capbuf,&result);
  	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;

I don't think we need to update *flags here, though it depends on the design of this function interface.
IMHO, updating *flags only when AE_SUPPORT is returned is easy to understand.

I think the patch is correct. We should update *flags in any case so that the caller can check what's the full mask of granted controls even if it asked for fewer control bits.

Thanks,
Rafael

#71 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

Quoted 11 lines · Rafael J. Wysocki
Quoted 10 lines · Kenji Kaneshige

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask) · line 381

Quoted 7 lines · Hidetoshi Seto

/**
* acpi_pci_osc_control_set - commit requested control to Firmware
* @handle: acpi_handle for the target ACPI object

drivers/acpi/pci_root.c +0 -0
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
   *
   * Attempt to take control from Firmware on requested control bits.
   **/

Updating description of this function would be appreciated.

OK, I will do it.

Quoted 11 lines
Quoted 10 lines

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) · line 430

Quoted 6 lines
drivers/acpi/pci_root.c +1 -1
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
  	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
  	status = acpi_pci_run_osc(handle, capbuf,&result);
  	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;

I don't think we need to update *flags here, though it depends on the design of this function interface.
IMHO, updating *flags only when AE_SUPPORT is returned is easy to understand.

Quoted 3 lines

I think the patch is correct. We should update *flags in any case so that the caller can check what's the full mask of granted controls even if it asked for fewer control bits.

My idea (that will be what I'll add to the description of function) is:

On success, OS takes all of requested control(s) and *flags is updated with set of controls now OS have.
If AE_SUPPORT returns, none of control settings are changed since Firmware rejects granting some of requested controls. *flags is updated with set of controls with rejected bits cleared.
All other cases mean failure, none of control settings are changed, and *flags is unchanged.

Thanks,
H.Seto

#72 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki
Quoted 11 lines · Rafael J. Wysocki
Quoted 10 lines · Kenji Kaneshige

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask) · line 381

Quoted 7 lines · Hidetoshi Seto

/**
* acpi_pci_osc_control_set - commit requested control to Firmware
* @handle: acpi_handle for the target ACPI object

drivers/acpi/pci_root.c +0 -0
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
   *
   * Attempt to take control from Firmware on requested control bits.
   **/

Updating description of this function would be appreciated.

OK, I will do it.

Quoted 11 lines
Quoted 10 lines

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) · line 430

Quoted 6 lines
drivers/acpi/pci_root.c +1 -1
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
  	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
  	status = acpi_pci_run_osc(handle, capbuf,&result);
  	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;

I don't think we need to update *flags here, though it depends on the design of this function interface.
IMHO, updating *flags only when AE_SUPPORT is returned is easy to understand.

Quoted 3 lines

I think the patch is correct. We should update *flags in any case so that the caller can check what's the full mask of granted controls even if it asked for fewer control bits.

My idea (that will be what I'll add to the description of function) is:

On success, OS takes all of requested control(s) and *flags is updated with set of controls now OS have.
If AE_SUPPORT returns, none of control settings are changed since Firmware rejects granting some of requested controls. *flags is updated with set of controls with rejected bits cleared.
All other cases mean failure, none of control settings are changed, and *flags is unchanged.

Thanks,
H.Seto

#73 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 63 lines · Hidetoshi Seto
Quoted 35 lines · Kenji Kaneshige

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
     ...
     query = control_req;
     status = acpi_pci_query_osc(root, root->osc_support_set,&query);
     if (ACPI_FAILURE(status))
         goto out;
     if ((query&  control_req) != control_req) {
         printk_(KERN_DEBUG
             "Firmware did not grant requested _OSC control\n");
         status = AE_SUPPORT;
         *flags = (query&  control_req);
         goto out;
     }
     ...
}

And do as follows in pcie_port_acpi_setup()

     status = acpi_pci_osc_control_set(handle,&flags);
     if (status == AE_SUPPORT)  {
         /* 2nd try */
         status = acpi_pci_osc_control_set(handle,&flags);
     }
     if (ACPI_FAILURE(status)) {
     ...
Quoted 1 line

What do you think about this?

I think it makes sense, though some minor cares are required.

Does this incremental patch (apply after [8/8]) looks good? If it is OK, I'll test these 8+1 patches within the next 2days.

Thanks,
H.Seto

=====
Subject: ACPI/PCI: Unify acpi_pci_osc_control_*()

Now AE_SUPPORT of acpi_pci_osc_control_set() tells not only that query fails with the requested control bits but also that the result of query is stored into the pointed place.

This allow user to retry acpi_pci_osc_control_set() with the result of query.

---
  drivers/acpi/pci_root.c          |   54 +++++++++++--------------------------
  drivers/pci/hotplug/acpi_pcihp.c |    2 +-
  drivers/pci/pcie/portdrv_acpi.c  |   23 +++++++---------
  include/linux/acpi.h             |    3 +-
  4 files changed, 28 insertions(+), 54 deletions(-)

<snip.>

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask) · line 381

Quoted 7 lines

/**
* acpi_pci_osc_control_set - commit requested control to Firmware
* @handle: acpi_handle for the target ACPI object

drivers/acpi/pci_root.c +0 -0
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
   *
   * Attempt to take control from Firmware on requested control bits.
   **/

Updating description of this function would be appreciated.

<snip.>

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) · line 430

Quoted 6 lines
drivers/acpi/pci_root.c +1 -1
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
  	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
  	status = acpi_pci_run_osc(handle, capbuf,&result);
  	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;

I don't think we need to update *flags here, though it depends on the design of this function interface.
IMHO, updating *flags only when AE_SUPPORT is returned is easy to understand.

Others looks good to me.

Thanks,
Kenji Kaneshige

#74 lore raw

Re: [linux-pm] [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 49 lines · Hidetoshi Seto
Quoted 35 lines · Kenji Kaneshige

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
    ...
    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        *flags = (query & control_req);
        goto out;
    }
    ...
}

And do as follows in pcie_port_acpi_setup()

    status = acpi_pci_osc_control_set(handle, &flags);
    if (status == AE_SUPPORT)  {
        /* 2nd try */
        status = acpi_pci_osc_control_set(handle, &flags);
    }
    if (ACPI_FAILURE(status)) {
    ...
Quoted 1 line

What do you think about this?

I think it makes sense, though some minor cares are required.

Does this incremental patch (apply after [8/8]) looks good? If it is OK, I'll test these 8+1 patches within the next 2days.

Thanks,
H.Seto

=====
Subject: ACPI/PCI: Unify acpi_pci_osc_control_*()

Quoted 8 lines

Now AE_SUPPORT of acpi_pci_osc_control_set() tells not only that query fails with the requested control bits but also that the result of query is stored into the pointed place.

This allow user to retry acpi_pci_osc_control_set() with the result of query.

It looks good to me.

Thanks,
Rafael

Quoted 170 lines
---
 drivers/acpi/pci_root.c          |   54 +++++++++++--------------------------
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 drivers/pci/pcie/portdrv_acpi.c  |   23 +++++++---------
 include/linux/acpi.h             |    3 +-
 4 files changed, 28 insertions(+), 54 deletions(-)
drivers/acpi/pci_root.c +16 -38
index 061e6f4..9a288df 100644
@@ -372,38 +372,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
- /**
- * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
- * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
- * @mask: Mask of _OSC bits to query and the place to put the result into.
- **/
-acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
-{
-	struct acpi_pci_root *root;
-	acpi_handle tmp;
-	acpi_status status = AE_OK;
-
-	if (!mask || !(*mask & OSC_PCI_CONTROL_MASKS))
-		return AE_BAD_PARAMETER;
-
-	root = acpi_pci_find_root(handle);
-	if (!root)
-		return AE_NOT_EXIST;
-
-	status = acpi_get_handle(handle, "_OSC", &tmp);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	mutex_lock(&osc_lock);
-	if ((*mask & root->osc_control_set) == *mask)
-		*mask = root->osc_control_set;
-	else
-		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
-	mutex_unlock(&osc_lock);
-
-	return status;
-}
-
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
  *
  * Attempt to take control from Firmware on requested control bits.
  **/
-acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
+acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)
 {
 	acpi_status status;
 	u32 control_req, result, capbuf[3];
 	acpi_handle tmp;
 	struct acpi_pci_root *root;
 
-	control_req = (flags & OSC_PCI_CONTROL_MASKS);
+	if (!flags)
+		return AE_BAD_PARAMETER;
+
+	control_req = (*flags & OSC_PCI_CONTROL_MASKS);
 	if (!control_req)
 		return AE_TYPE;
 
@@ -432,8 +403,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 
 	mutex_lock(&osc_lock);
 	/* No need to evaluate _OSC if the control was already granted. */
-	if ((root->osc_control_set & control_req) == control_req)
+	if ((root->osc_control_set & control_req) == control_req) {
+		*flags = root->osc_control_set;
 		goto out;
+	}
 
 	/* Need to query controls first before requesting them */
 	result = control_req;
@@ -441,8 +414,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	if (ACPI_FAILURE(status))
 		goto out;
 	if ((result & control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
+		printk(KERN_DEBUG PREFIX
+		       "Firmware did not grant requested _OSC control: %x/%x\n",
+		       control_req, result);
+		*flags = result;
 		status = AE_SUPPORT;
 		goto out;
 	}
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
 	status = acpi_pci_run_osc(handle, capbuf, &result);
 	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;
+	else
+		printk(KERN_WARNING FW_BUG PREFIX
+		       "_OSC did not grant controls that passed query\n");
 out:
 	mutex_unlock(&osc_lock);
 	return status;
drivers/pci/hotplug/acpi_pcihp.c +1 -1
index 12ea415..675181d 100644
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set(handle, &flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)
drivers/pci/pcie/portdrv_acpi.c +10 -13
index a07a70e..764d0b3 100644
@@ -55,20 +55,17 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
 			flags |= OSC_PCI_EXPRESS_AER_CONTROL;
 	}
 
-	status = acpi_pci_osc_control_query(handle, &flags);
-	if (ACPI_FAILURE(status)) {
-		dev_dbg(&port->dev, "ACPI _OSC query failed (code %d)\n",
-			status);
-		return -ENODEV;
+retry:
+	status = acpi_pci_osc_control_set(handle, &flags);
+	if (status == AE_SUPPORT) {
+		if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
+			dev_dbg(&port->dev, "BIOS refuses to grant control of "
+				"PCIe Capability Structure\n");
+			return -EACCES;
+		}
+		if (flags & ~OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+			goto retry;
 	}
-
-	if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
-		dev_dbg(&port->dev, "BIOS refuses to grant control of PCIe "
-			"Capability Structure\n");
-		return -EACCES;
-	}
-
-	status = acpi_pci_osc_control_set(handle, flags);
 	if (ACPI_FAILURE(status)) {
 		dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
 			status);
include/linux/acpi.h +1 -2
index a9afe9c..1b5aac6 100644
@@ -305,8 +305,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
-extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
-extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */
#75 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Hidetoshi Seto
Quoted 49 lines · Hidetoshi Seto
Quoted 35 lines · Kenji Kaneshige

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
    ...
    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        *flags = (query & control_req);
        goto out;
    }
    ...
}

And do as follows in pcie_port_acpi_setup()

    status = acpi_pci_osc_control_set(handle, &flags);
    if (status == AE_SUPPORT)  {
        /* 2nd try */
        status = acpi_pci_osc_control_set(handle, &flags);
    }
    if (ACPI_FAILURE(status)) {
    ...
Quoted 1 line

What do you think about this?

I think it makes sense, though some minor cares are required.

Does this incremental patch (apply after [8/8]) looks good? If it is OK, I'll test these 8+1 patches within the next 2days.

Thanks,
H.Seto

=====
Subject: ACPI/PCI: Unify acpi_pci_osc_control_*()

Quoted 8 lines

Now AE_SUPPORT of acpi_pci_osc_control_set() tells not only that query fails with the requested control bits but also that the result of query is stored into the pointed place.

This allow user to retry acpi_pci_osc_control_set() with the result of query.

It looks good to me.

Thanks,
Rafael

Quoted 170 lines
---
 drivers/acpi/pci_root.c          |   54 +++++++++++--------------------------
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 drivers/pci/pcie/portdrv_acpi.c  |   23 +++++++---------
 include/linux/acpi.h             |    3 +-
 4 files changed, 28 insertions(+), 54 deletions(-)
drivers/acpi/pci_root.c +16 -38
index 061e6f4..9a288df 100644
@@ -372,38 +372,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
- /**
- * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
- * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
- * @mask: Mask of _OSC bits to query and the place to put the result into.
- **/
-acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
-{
-	struct acpi_pci_root *root;
-	acpi_handle tmp;
-	acpi_status status = AE_OK;
-
-	if (!mask || !(*mask & OSC_PCI_CONTROL_MASKS))
-		return AE_BAD_PARAMETER;
-
-	root = acpi_pci_find_root(handle);
-	if (!root)
-		return AE_NOT_EXIST;
-
-	status = acpi_get_handle(handle, "_OSC", &tmp);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	mutex_lock(&osc_lock);
-	if ((*mask & root->osc_control_set) == *mask)
-		*mask = root->osc_control_set;
-	else
-		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
-	mutex_unlock(&osc_lock);
-
-	return status;
-}
-
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
  *
  * Attempt to take control from Firmware on requested control bits.
  **/
-acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
+acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)
 {
 	acpi_status status;
 	u32 control_req, result, capbuf[3];
 	acpi_handle tmp;
 	struct acpi_pci_root *root;
 
-	control_req = (flags & OSC_PCI_CONTROL_MASKS);
+	if (!flags)
+		return AE_BAD_PARAMETER;
+
+	control_req = (*flags & OSC_PCI_CONTROL_MASKS);
 	if (!control_req)
 		return AE_TYPE;
 
@@ -432,8 +403,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 
 	mutex_lock(&osc_lock);
 	/* No need to evaluate _OSC if the control was already granted. */
-	if ((root->osc_control_set & control_req) == control_req)
+	if ((root->osc_control_set & control_req) == control_req) {
+		*flags = root->osc_control_set;
 		goto out;
+	}
 
 	/* Need to query controls first before requesting them */
 	result = control_req;
@@ -441,8 +414,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	if (ACPI_FAILURE(status))
 		goto out;
 	if ((result & control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
+		printk(KERN_DEBUG PREFIX
+		       "Firmware did not grant requested _OSC control: %x/%x\n",
+		       control_req, result);
+		*flags = result;
 		status = AE_SUPPORT;
 		goto out;
 	}
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
 	status = acpi_pci_run_osc(handle, capbuf, &result);
 	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;
+	else
+		printk(KERN_WARNING FW_BUG PREFIX
+		       "_OSC did not grant controls that passed query\n");
 out:
 	mutex_unlock(&osc_lock);
 	return status;
drivers/pci/hotplug/acpi_pcihp.c +1 -1
index 12ea415..675181d 100644
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set(handle, &flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)
drivers/pci/pcie/portdrv_acpi.c +10 -13
index a07a70e..764d0b3 100644
@@ -55,20 +55,17 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
 			flags |= OSC_PCI_EXPRESS_AER_CONTROL;
 	}
 
-	status = acpi_pci_osc_control_query(handle, &flags);
-	if (ACPI_FAILURE(status)) {
-		dev_dbg(&port->dev, "ACPI _OSC query failed (code %d)\n",
-			status);
-		return -ENODEV;
+retry:
+	status = acpi_pci_osc_control_set(handle, &flags);
+	if (status == AE_SUPPORT) {
+		if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
+			dev_dbg(&port->dev, "BIOS refuses to grant control of "
+				"PCIe Capability Structure\n");
+			return -EACCES;
+		}
+		if (flags & ~OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+			goto retry;
 	}
-
-	if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
-		dev_dbg(&port->dev, "BIOS refuses to grant control of PCIe "
-			"Capability Structure\n");
-		return -EACCES;
-	}
-
-	status = acpi_pci_osc_control_set(handle, flags);
 	if (ACPI_FAILURE(status)) {
 		dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
 			status);
include/linux/acpi.h +1 -2
index a9afe9c..1b5aac6 100644
@@ -305,8 +305,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
-extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
-extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */
#76 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Kenji Kaneshige
Quoted 35 lines · Kenji Kaneshige

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
    ...
    query = control_req;
    status = acpi_pci_query_osc(root, root->osc_support_set, &query);
    if (ACPI_FAILURE(status))
        goto out;
    if ((query & control_req) != control_req) {
        printk_(KERN_DEBUG
            "Firmware did not grant requested _OSC control\n");
        status = AE_SUPPORT;
        *flags = (query & control_req);
        goto out;
    }
    ...
}

And do as follows in pcie_port_acpi_setup()

    status = acpi_pci_osc_control_set(handle, &flags);
    if (status == AE_SUPPORT)  {
        /* 2nd try */
        status = acpi_pci_osc_control_set(handle, &flags);
    }
    if (ACPI_FAILURE(status)) {
    ...
Quoted 1 line

What do you think about this?

I think it makes sense, though some minor cares are required.

Does this incremental patch (apply after [8/8]) looks good? If it is OK, I'll test these 8+1 patches within the next 2days.

Thanks,
H.Seto

=====
Subject: ACPI/PCI: Unify acpi_pci_osc_control_*()

Now AE_SUPPORT of acpi_pci_osc_control_set() tells not only that query fails with the requested control bits but also that the result of query is stored into the pointed place.

This allow user to retry acpi_pci_osc_control_set() with the result of query.

---
 drivers/acpi/pci_root.c          |   54 +++++++++++--------------------------
 drivers/pci/hotplug/acpi_pcihp.c |    2 +-
 drivers/pci/pcie/portdrv_acpi.c  |   23 +++++++---------
 include/linux/acpi.h             |    3 +-
 4 files changed, 28 insertions(+), 54 deletions(-)
drivers/acpi/pci_root.c +16 -38
index 061e6f4..9a288df 100644
@@ -372,38 +372,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
 
- /**
- * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
- * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
- * @mask: Mask of _OSC bits to query and the place to put the result into.
- **/
-acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
-{
-	struct acpi_pci_root *root;
-	acpi_handle tmp;
-	acpi_status status = AE_OK;
-
-	if (!mask || !(*mask & OSC_PCI_CONTROL_MASKS))
-		return AE_BAD_PARAMETER;
-
-	root = acpi_pci_find_root(handle);
-	if (!root)
-		return AE_NOT_EXIST;
-
-	status = acpi_get_handle(handle, "_OSC", &tmp);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	mutex_lock(&osc_lock);
-	if ((*mask & root->osc_control_set) == *mask)
-		*mask = root->osc_control_set;
-	else
-		status = acpi_pci_query_osc(root, root->osc_support_set, mask);
-	mutex_unlock(&osc_lock);
-
-	return status;
-}
-
 /**
  * acpi_pci_osc_control_set - commit requested control to Firmware
  * @handle: acpi_handle for the target ACPI object
@@ -411,14 +379,17 @@ acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
  *
  * Attempt to take control from Firmware on requested control bits.
  **/
-acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
+acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)
 {
 	acpi_status status;
 	u32 control_req, result, capbuf[3];
 	acpi_handle tmp;
 	struct acpi_pci_root *root;
 
-	control_req = (flags & OSC_PCI_CONTROL_MASKS);
+	if (!flags)
+		return AE_BAD_PARAMETER;
+
+	control_req = (*flags & OSC_PCI_CONTROL_MASKS);
 	if (!control_req)
 		return AE_TYPE;
 
@@ -432,8 +403,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 
 	mutex_lock(&osc_lock);
 	/* No need to evaluate _OSC if the control was already granted. */
-	if ((root->osc_control_set & control_req) == control_req)
+	if ((root->osc_control_set & control_req) == control_req) {
+		*flags = root->osc_control_set;
 		goto out;
+	}
 
 	/* Need to query controls first before requesting them */
 	result = control_req;
@@ -441,8 +414,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	if (ACPI_FAILURE(status))
 		goto out;
 	if ((result & control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
+		printk(KERN_DEBUG PREFIX
+		       "Firmware did not grant requested _OSC control: %x/%x\n",
+		       control_req, result);
+		*flags = result;
 		status = AE_SUPPORT;
 		goto out;
 	}
@@ -452,7 +427,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
 	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
 	status = acpi_pci_run_osc(handle, capbuf, &result);
 	if (ACPI_SUCCESS(status))
-		root->osc_control_set = result;
+		root->osc_control_set = *flags = result;
+	else
+		printk(KERN_WARNING FW_BUG PREFIX
+		       "_OSC did not grant controls that passed query\n");
 out:
 	mutex_unlock(&osc_lock);
 	return status;
drivers/pci/hotplug/acpi_pcihp.c +1 -1
index 12ea415..675181d 100644
@@ -358,7 +358,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
 		dbg("Trying to get hotplug control for %s\n",
 				(char *)string.pointer);
-		status = acpi_pci_osc_control_set(handle, flags);
+		status = acpi_pci_osc_control_set(handle, &flags);
 		if (ACPI_SUCCESS(status))
 			goto got_one;
 		if (status == AE_SUPPORT)
drivers/pci/pcie/portdrv_acpi.c +10 -13
index a07a70e..764d0b3 100644
@@ -55,20 +55,17 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
 			flags |= OSC_PCI_EXPRESS_AER_CONTROL;
 	}
 
-	status = acpi_pci_osc_control_query(handle, &flags);
-	if (ACPI_FAILURE(status)) {
-		dev_dbg(&port->dev, "ACPI _OSC query failed (code %d)\n",
-			status);
-		return -ENODEV;
+retry:
+	status = acpi_pci_osc_control_set(handle, &flags);
+	if (status == AE_SUPPORT) {
+		if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
+			dev_dbg(&port->dev, "BIOS refuses to grant control of "
+				"PCIe Capability Structure\n");
+			return -EACCES;
+		}
+		if (flags & ~OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+			goto retry;
 	}
-
-	if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
-		dev_dbg(&port->dev, "BIOS refuses to grant control of PCIe "
-			"Capability Structure\n");
-		return -EACCES;
-	}
-
-	status = acpi_pci_osc_control_set(handle, flags);
 	if (ACPI_FAILURE(status)) {
 		dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
 			status);
include/linux/acpi.h +1 -2
index a9afe9c..1b5aac6 100644
@@ -305,8 +305,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 				OSC_PCI_EXPRESS_AER_CONTROL |		\
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
-extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
-extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags);
 extern void acpi_early_init(void);
 
 #else	/* !CONFIG_ACPI */
Signature · 1 line
1.7.2
#77 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki
Quoted 24 lines · Rafael J. Wysocki
Quoted 23 lines · Rafael J. Wysocki
Quoted 22 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
       if ((root->osc_control_set&   control_req) == control_req)
           goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&   control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

So the code needs to be

     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

Sorry, that should have been

	query = control_req;
	status = acpi_pci_query_osc(root, root->osc_support_set, &query);
	if (ACPI_FAILURE(status))
		goto out;
	if ((query & control_req) != control_req) {
		printk_(KERN_DEBUG
			"Firmware did not grant requested _OSC control\n");
		status = AE_SUPPORT;
		goto out;
	}

I know current pcie_port_acpi_setup() queries the requesting controls before acpi_pci_osc_control_set() and only one control is requested in the other code. However, I think acpi_pci_osc_control_set() still need to query the requested controls to ensure all the requested controls, in case someone calls this function without querying the requesting controls. In other words, I think it must be ensured that any controls are never granted to OS when acpi_pci_osc_control_set() returns error.

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
     status = acpi_pci_query_osc(root, root->osc_support_set,&control_req);
     if (ACPI_FAILURE(status))
         goto out;

By the way, I think it is getting confusing regarding who query the controls. IMO, querying controls to ensure all the requested controls are granted to OS should be done in acpi_pci_osc_control_set(), as I said above. On the other hand, PCIe port driver need to query controls for other reason... Now I think it might be better to change acpi_pci_osc_control_set() like below instead of introducing acpi_pci_osc_control_query().

acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *flags)

{
	...
	query = control_req;
	status = acpi_pci_query_osc(root, root->osc_support_set, &query);
	if (ACPI_FAILURE(status))
		goto out;
	if ((query & control_req) != control_req) {
		printk_(KERN_DEBUG
			"Firmware did not grant requested _OSC control\n");
		status = AE_SUPPORT;
		*flags = (query & control_req);
		goto out;
	}
	...
}

And do as follows in pcie_port_acpi_setup()

	status = acpi_pci_osc_control_set(handle, &flags);
	if (status == AE_SUPPORT)  {
		/* 2nd try */
		status = acpi_pci_osc_control_set(handle, &flags);
	}
	if (ACPI_FAILURE(status)) {
	...

What do you think about this?

Thanks,
Kenji Kaneshige

#78 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki
Quoted 58 lines · Rafael J. Wysocki
Quoted 57 lines · Hidetoshi Seto
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
(quoted diff) +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
      if ((root->osc_control_set&  control_req) == control_req)
          goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

Review acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
(quoted diff) +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&  control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 5 lines

So the code needs to be

    status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
    if (ACPI_FAILURE(status))
        goto out;

Hum, since acpi_status acpi_pci_osc_control_set() is an exported function, we cannot be too careful here.

OTOH, I think this second query should be done in caller too, i.e. pcie_port_acpi_setup() in patch [4/8].

Now:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    acpi_pci_osc_control_query(handle, &flags);
    /* note: flags might be changed after query */
    acpi_pci_osc_control_set(handle, flags);

}

Strictly, it could be like:

New:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    do {
      pre_flags = flags;
      acpi_pci_osc_control_query(handle, &flags);
    } while (flags && pre_flags != flags);
    if (flags)
      acpi_pci_osc_control_set(handle, flags);

}

Quoted 8 lines
Quoted 2 lines

IMHO these checks are kind of preventive guard for corner cases, and I suppose it can be implemented by an incremental patch later.

OK

The assumption here is that the BIOS would only mask the bits it's not going to grant control of and will do it in a consistent way. So, I guess the purpose of the change above would be to protect us from buggy BIOSes.

What about the appended patch (on top of 4/8)?

Rafael

---
 drivers/pci/pcie/portdrv_acpi.c |   15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/pci/pcie/portdrv_acpi.c +9 -6
Index: linux-2.6/drivers/pci/pcie/portdrv_acpi.c
===================================================================
@@ -35,7 +35,7 @@ int pcie_port_acpi_setup(struct pci_dev 
 {
 	acpi_status status;
 	acpi_handle handle;
-	u32 flags;
+	u32 flags, prev_flags = 0;
 
 	if (acpi_pci_disabled)
 		return 0;
@@ -55,11 +55,14 @@ int pcie_port_acpi_setup(struct pci_dev 
 			flags |= OSC_PCI_EXPRESS_AER_CONTROL;
 	}
 
-	status = acpi_pci_osc_control_query(handle, &flags);
-	if (ACPI_FAILURE(status)) {
-		dev_dbg(&port->dev, "ACPI _OSC query failed (code %d)\n",
-			status);
-		return -ENODEV;
+	while (flags != prev_flags) {
+		prev_flags = flags;
+		status = acpi_pci_osc_control_query(handle, &flags);
+		if (ACPI_FAILURE(status)) {
+			dev_dbg(&port->dev,
+				"ACPI _OSC query failed (code %d)\n", status);
+			return -ENODEV;
+		}
 	}
 
 	if (!(flags & OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)) {
#79 lore raw

Re: [PATCH 7/8] ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Kenji Kaneshige
Quoted 21 lines · Kenji Kaneshige
Quoted 6 lines · Rafael J. Wysocki
drivers/acpi/pci_root.c +0 -2
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
      if ((root->osc_control_set&  control_req) == control_req)
          goto out;
 
-    /* Need to query controls first before requesting them */
-    if (!root->osc_queried) {

drivers/acpi/pci_root.c acpi_status acpi_pci_osc_control_set(acp · line 448

Quoted 10 lines
drivers/acpi/pci_root.c +0 -10
-        status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-        if (ACPI_FAILURE(status))
-            goto out;
-    }
-    if ((root->osc_control_qry&  control_req) != control_req) {
-        printk(KERN_DEBUG
-               "Firmware did not grant requested _OSC control\n");
-        status = AE_SUPPORT;
-        goto out;
-    }

I think acpi_pci_osc_control_set() still need to query before commit to ensure all the requested controls are granted to OS.

Quoted 5 lines

So the code needs to be

    status = acpi_pci_query_osc(root, root->osc_support_set, &control_req);
    if (ACPI_FAILURE(status))
        goto out;

Hum, since acpi_status acpi_pci_osc_control_set() is an exported function, we cannot be too careful here.

OTOH, I think this second query should be done in caller too, i.e. pcie_port_acpi_setup() in patch [4/8].

Now:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    acpi_pci_osc_control_query(handle, &flags);
    /* note: flags might be changed after query */
    acpi_pci_osc_control_set(handle, flags);

}

Strictly, it could be like:

New:
pcie_port_acpi_setup()

  {
    flags = A|B|C|D;
    do {
      pre_flags = flags;
      acpi_pci_osc_control_query(handle, &flags);
    } while (flags && pre_flags != flags);
    if (flags)
      acpi_pci_osc_control_set(handle, flags);

}

IMHO these checks are kind of preventive guard for corner cases, and I suppose it can be implemented by an incremental patch later.

Thanks,
H.Seto

#80 lore raw

PATCH 7/8 ACPI / PCI: Do not preserve _OSC control bits returned by a query (v2)

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

All of the remaining callers of acpi_pci_osc_control_set() either use acpi_pci_root_osc_query() right before it, like pcie_port_acpi_setup(), or ask for control of one feature only, like acpi_get_hp_hw_control_from_firmware(). Thus there is no reason to preserve the _OSC control bits returned by an _OSC query and the osc_control_qry and osc_queried fields of struct acpi_pci_root are not necessary any more. Remove them and modify the code that uses them accordingly.

---
 drivers/acpi/pci_root.c |   15 ---------------
 include/acpi/acpi_bus.h |    3 ---
 2 files changed, 18 deletions(-)
drivers/acpi/pci_root.c +0 -15
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -248,10 +248,8 @@ static acpi_status acpi_pci_query_osc(st
 	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
 	if (ACPI_SUCCESS(status)) {
 		root->osc_support_set = support;
-		root->osc_control_qry = result;
 		if (control)
 			*control = result;
-		root->osc_queried = 1;
 	}
 	return status;
 }
@@ -434,19 +432,6 @@ acpi_status acpi_pci_osc_control_set(acp
 	if ((root->osc_control_set & control_req) == control_req)
 		goto out;
 
-	/* Need to query controls first before requesting them */
-	if (!root->osc_queried) {
-		status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
-		if (ACPI_FAILURE(status))
-			goto out;
-	}
-	if ((root->osc_control_qry & control_req) != control_req) {
-		printk(KERN_DEBUG
-		       "Firmware did not grant requested _OSC control\n");
-		status = AE_SUPPORT;
-		goto out;
-	}
-
 	capbuf[OSC_QUERY_TYPE] = 0;
 	capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
 	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
include/acpi/acpi_bus.h +0 -3
Index: linux-2.6/include/acpi/acpi_bus.h
===================================================================
@@ -377,9 +377,6 @@ struct acpi_pci_root {
 
 	u32 osc_support_set;	/* _OSC state of support bits */
 	u32 osc_control_set;	/* _OSC state of control bits */
-	u32 osc_control_qry;	/* the latest _OSC query result */
-
-	u32 osc_queried:1;	/* has _OSC control been queried? */
 };
 
 /* helper */
#81 lore raw

PATCH 8/8 ACPI / PCI: Reorder checks in acpi_pci_osc_control_set()

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Make acpi_pci_osc_control_set() attempt to find the handle of the _OSC object under the given PCI root bridge object after verifying that its second argument is correct and that there is a struct acpi_pci_root object for the given root bridge handle. This is more logical than the old code and it matches the code ordering in acpi_pci_osc_control_query().

---
 drivers/acpi/pci_root.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/acpi/pci_root.c +4 -4
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -415,10 +415,6 @@ acpi_status acpi_pci_osc_control_set(acp
 	acpi_handle tmp;
 	struct acpi_pci_root *root;
 
-	status = acpi_get_handle(handle, "_OSC", &tmp);
-	if (ACPI_FAILURE(status))
-		return status;
-
 	control_req = (flags & OSC_PCI_CONTROL_MASKS);
 	if (!control_req)
 		return AE_TYPE;
@@ -427,6 +423,10 @@ acpi_status acpi_pci_osc_control_set(acp
 	if (!root)
 		return AE_NOT_EXIST;
 
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
 	mutex_lock(&osc_lock);
 	/* No need to evaluate _OSC if the control was already granted. */
 	if ((root->osc_control_set & control_req) == control_req)
#82 lore raw

PATCH 8/8 ACPI / PCI: Reorder checks in acpi_pci_osc_control_set()

In reply to Rafael J. Wysocki

From: Rafael J. Wysocki <[email protected]>

Make acpi_pci_osc_control_set() attempt to find the handle of the _OSC object under the given PCI root bridge object after verifying that its second argument is correct and that there is a struct acpi_pci_root object for the given root bridge handle. This is more logical than the old code and it matches the code ordering in acpi_pci_osc_control_query().

---
 drivers/acpi/pci_root.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/acpi/pci_root.c +4 -4
Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
@@ -415,10 +415,6 @@ acpi_status acpi_pci_osc_control_set(acp
 	acpi_handle tmp;
 	struct acpi_pci_root *root;
 
-	status = acpi_get_handle(handle, "_OSC", &tmp);
-	if (ACPI_FAILURE(status))
-		return status;
-
 	control_req = (flags & OSC_PCI_CONTROL_MASKS);
 	if (!control_req)
 		return AE_TYPE;
@@ -427,6 +423,10 @@ acpi_status acpi_pci_osc_control_set(acp
 	if (!root)
 		return AE_NOT_EXIST;
 
+	status = acpi_get_handle(handle, "_OSC", &tmp);
+	if (ACPI_FAILURE(status))
+		return status;
+
 	mutex_lock(&osc_lock);
 	/* No need to evaluate _OSC if the control was already granted. */
 	if ((root->osc_control_set & control_req) == control_req)
#83 lore raw
In reply to Rafael J. Wysocki
Quoted 21 lines · Rafael J. Wysocki

Hi,

This is the second iteration of the patchset based on
https://patchwork.kernel.org/patch/114917/ and the comments I received on that patch. Hopefully, I took all of the comments into account this time.

[1/8] - Introduce acpi_pci_osc_control_query() allowing the caller to get a
mask of _OSC control bits the BIOS allows the kernel to control for a given PCI root bridge.

[2/8] - Introduce pci_aer_available() allowing the caller to check if the
AER service driver should be enabled.

[3/8] - Introduce kernel command line switch pcie_ports=.

[4/8] - Rework the PCIe port driver to request _OSC control for all serives at
once.

[5/8] - Disable PCIe port services (that might be enabled by the BIOS) during
initialization.

Quoted 8 lines

[6/8] - Remove the PCIe port driver modules exit function.

[7/8] - Rework acpi_pci_osc_control_set() so that it doesn't use cached
result of a query and remove the fields of struct acpi_pci_root that
aren't used any more.

[8/8] - Reorder checks in acpi_pci_osc_control_set()

Hi Rafael,

I'm sorry for delayed responding.

Your latest patchset looks much clearer than mine.
I have comments on [1/8] and [7/8]. I'll send comment for each patch.

Thanks,
Kenji Kaneshige

#84 lore raw
In reply to Rafael J. Wysocki
Quoted 21 lines · Rafael J. Wysocki

Hi,

This is the second iteration of the patchset based on
https://patchwork.kernel.org/patch/114917/ and the comments I received on that patch. Hopefully, I took all of the comments into account this time.

[1/8] - Introduce acpi_pci_osc_control_query() allowing the caller to get a
mask of _OSC control bits the BIOS allows the kernel to control for a given PCI root bridge.

[2/8] - Introduce pci_aer_available() allowing the caller to check if the
AER service driver should be enabled.

[3/8] - Introduce kernel command line switch pcie_ports=.

[4/8] - Rework the PCIe port driver to request _OSC control for all serives at
once.

[5/8] - Disable PCIe port services (that might be enabled by the BIOS) during
initialization.

Quoted 8 lines

[6/8] - Remove the PCIe port driver modules exit function.

[7/8] - Rework acpi_pci_osc_control_set() so that it doesn't use cached
result of a query and remove the fields of struct acpi_pci_root that
aren't used any more.

[8/8] - Reorder checks in acpi_pci_osc_control_set()

Hi Rafael,

I'm sorry for delayed responding.

Your latest patchset looks much clearer than mine.
I have comments on [1/8] and [7/8]. I'll send comment for each patch.

Thanks,
Kenji Kaneshige