Cliff Huang has uploaded this change for review.

View Change

soc/intel/common/block/pcie/rtd3: Add optional _OFF and _ON skip control

- Optional feature to provide mechanism to skip _OFF and _On execution.
- It is used for the device to skip _OFF and _ON during device driver
reload.
- _OFS is used to skip _OFF Method at the end of device driver removal.
- _ONS is used to skip _ON Method at the beginning of driver loading.
- General flow use case:
1. Device driver is removed by 'rmmod' command.
2. Device _RST is called. _RST perform reset.
3. Device sets _OFS in _RST to skip the following _OFF invoked by OSPM.
4. OSPM invokes _OFF at the end of driver removal.
5. _OFF sees _OFS and skips current execution and clears _OFS so that
_OFF will be executed normally next time.
6. _OFF sets _ONS to skip the following _ON invoked by OSPM.
7. Device driver is reloading by 'insmod/modprobe' command.
8. OSPM invokes _ON at the beginning of driver loading.
9. _ON sees _ONS and skip current execution and clears _ONS so that
_ON will be executed normally next time.

- In normal case:
When supspend, OSPM invokes _OFF and _OFS is not set, so the device
go to deeper state as expected.

When resume, OSPM invokes _ON and _ONS is not set, so the device go
to active state as expected.

- Generated changes:

PowerResource (RTD3, 0x00, 0x0000)
Name (_ONS, Zero)
Name (_OFS, Zero)
...

Method (_ON, 0, Serialized) // _ON_: Power On
{
If ((_ONS == Zero))
{
...
}
ElseIf ((_ONS == One))
{
_ONS = Zero
}
}

Method (_OFF, 0, Serialized) // _OFF: Power Off
{
If ((_OFS == Zero))
{
...
}
ElseIf ((_OFS == One))
{
_OFS = Zero
_ONS = One
}
}

Test:
Enable and verify _OFS and _ONS Name objects and the if-condition logic
inside _OFF and _ON metheds is added.

Signed-off-by: Cliff Huang <cliff.huang@intel.com>
Change-Id: Ic32d151d65107bfc220258c383a575e40a496b6f
---
M src/soc/intel/common/block/pcie/rtd3/chip.h
M src/soc/intel/common/block/pcie/rtd3/rtd3.c
2 files changed, 58 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/53/61353/1
diff --git a/src/soc/intel/common/block/pcie/rtd3/chip.h b/src/soc/intel/common/block/pcie/rtd3/chip.h
index c2bad63..10470fe 100644
--- a/src/soc/intel/common/block/pcie/rtd3/chip.h
+++ b/src/soc/intel/common/block/pcie/rtd3/chip.h
@@ -51,6 +51,12 @@
* connected root port, mainly used in the device ACPI methods such as reset.
*/
bool ext_pm_support;
+
+ /*
+ * Add support to skip _OFF and _ON execution when needed, such as reloading
+ * the device driver.
+ */
+ bool skip_on_off_support;
};

#endif /* __SOC_INTEL_COMMON_BLOCK_PCIE_RTD3_CHIP_H__ */
diff --git a/src/soc/intel/common/block/pcie/rtd3/rtd3.c b/src/soc/intel/common/block/pcie/rtd3/rtd3.c
index a9df72a..0a96574 100644
--- a/src/soc/intel/common/block/pcie/rtd3/rtd3.c
+++ b/src/soc/intel/common/block/pcie/rtd3/rtd3.c
@@ -151,6 +151,13 @@
{
acpigen_write_method_serialized("_ON", 0);

+ /* When this feature is enabled, _ONS indicates if the previous _OFF was
+ * skipped. If so, since the device was not in Off state, and the current
+ * _ON can be skipped as well.
+ */
+ if (config->skip_on_off_support)
+ acpigen_write_if_lequal_namestr_int("_ONS", 0);
+
/* Disable modPHY power gating for PCH RPs. */
if (rp_type == PCIE_RP_PCH)
pcie_rtd3_enable_modphy_pg(pcie_rp, PG_DISABLE);
@@ -177,6 +184,17 @@
if (!config->disable_l23)
pcie_rtd3_acpi_l23_exit();

+ if (config->skip_on_off_support) {
+ /* If current _ON is skipped, _ONS is clear so that _ON will be
+ * executed normally until _OFF is skipped again.
+ */
+ acpigen_write_else();
+ acpigen_write_if_lequal_namestr_int("_ONS", 1);
+ acpigen_write_store_int_to_namestr(0, "_ONS");
+
+ acpigen_pop_len(); /* If */
+ acpigen_pop_len(); /* Else */
+ }
acpigen_pop_len(); /* Method */
}

@@ -187,6 +205,14 @@
{
acpigen_write_method_serialized("_OFF", 0);

+ /* When this feature is enabled, _ONS is checked to see if the device
+ * wants _OFF to be skipped for once. _ONS is normally set in the device
+ * method, such as reset _RST, which is invoked during driver reload. In
+ * such case, _OFF needs to be avoided at the end of driver removal.
+ */
+ if (config->skip_on_off_support)
+ acpigen_write_if_lequal_namestr_int("_OFS", 0);
+
/* Trigger L23 ready entry flow unless disabled by config. */
if (!config->disable_l23)
pcie_rtd3_acpi_l23_entry();
@@ -213,6 +239,18 @@
acpigen_write_sleep(config->enable_off_delay_ms);
}

+ if (config->skip_on_off_support) {
+ /* If current _OFF is skipped, _ONS is set so that the following _ON
+ * will also be skipped. In addition, _OFS is clear so that next _OFF
+ * will be executed normally until the device method sets _OFS again.
+ */
+ acpigen_write_else();
+ acpigen_write_if_lequal_namestr_int("_OFS", 1);
+ acpigen_write_store_int_to_namestr(0, "_OFS");
+ acpigen_write_store_int_to_namestr(1, "_ONS");
+ acpigen_pop_len(); /* If */
+ acpigen_pop_len(); /* Else */
+ }
acpigen_pop_len(); /* Method */
}

@@ -377,6 +415,20 @@

/* ACPI Power Resource for controlling the attached device power. */
acpigen_write_power_res("RTD3", 0, 0, power_res_states, ARRAY_SIZE(power_res_states));
+
+ if (config->skip_on_off_support) {
+ /* _OFS: 0 = _OFF Method will be executed normally when called;
+ * 1 = _OFF will be skipped once.
+ * _OFF Method to clear _OFS and set _ONS if the current execution
+ * is skipped.
+ * _ONS: 0 = _ON Method will be executed normally when called;
+ * 1 = _ONF will be skipped once.
+ * _ON Method to clear _ONS if the current execution is skipped.
+ */
+ acpigen_write_name_integer("_ONS", 0);
+ acpigen_write_name_integer("_OFS", 0);
+ }
+
pcie_rtd3_acpi_method_status(config);
pcie_rtd3_acpi_method_on(pcie_rp, config, rp_type);
pcie_rtd3_acpi_method_off(pcie_rp, config, rp_type);

To view, visit change 61353. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ic32d151d65107bfc220258c383a575e40a496b6f
Gerrit-Change-Number: 61353
Gerrit-PatchSet: 1
Gerrit-Owner: Cliff Huang <cliff.huang@intel.com>
Gerrit-MessageType: newchange