linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support
@ 2016-06-14 14:48 Sudeep Holla
  2016-06-14 14:48 ` [PATCH v6 1/5] ACPI / processor_idle: introduce ACPI_PROCESSOR_CSTATE Sudeep Holla
                   ` (5 more replies)
  0 siblings, 6 replies; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 14:48 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel

ACPI 6.0 introduced LPI(Low Power Idle) states that provides an alternate
method to describe processor idle states. It extends the specification
to allow the expression of idle states like C-states selectable by the
OSPM when a processor goes idle, but may affect more than one processor,
and may affect other system components.

LPI extensions leverages the processor container device(again introduced
in ACPI 6.0) allowing to express which parts of the system are affected
by a given LPI state. It defines the local power states for each node
in a hierarchical processor topology. The OSPM can use _LPI object to
select a local power state for each level of processor hierarchy in the
system. They used to produce a composite power state request that is
presented to the platform by the OSPM.

Since multiple processors affect the idle state for any non-leaf hierarchy
node, coordination of idle state requests between the processors is
required. ACPI supports two different coordination schemes: Platform
coordinated and  OS initiated.

This series aims at providing basic and initial support for platform
coordinated LPI states.

v5[5]->v6:
	- Added support for autopromotable state by not flattening them
	- Moved arm_enter_idle_state to cpuidle-arm.h as it can be reused
	  in ARM64 backend for ACPI LPI
	- Other review comments(mainly for ARM64 from Lorenzo)
	- Dropped support for skipping PM notifier as it needs to be fixed
	  in GICv3 code(will be done separately)

v4[4]->v5:
	- Addressed all the comments from Rafael
	- Added support for retention mode(Prashant)
	- Handled acpi_processor_get_power_info return value correctly(Vikas)
	- Dropped __init from arm_cpuidle_init
	- Merged psci prepartory patch into arm64 lpi support

v3[3]->v4:
	- Dropped the preparatory patches that are merged already
	- Added ARM64 arch specific callback implementations
	- Addressed most of the review comments from Rafael

v2[2]->v3:
        - rebased against v4.4-rc3
        - fixed couple of issues reported by Prashanth and review comments
          from Ashwin

v1[1]->v2[2]:
        - Fixed support for ACPI0010 processor container
        - moved sleep state code out of processor_idle

Code is also available @[5]

Regards,
Sudeep

[1] http://marc.info/?l=linux-acpi&m=143871041601132&w=2
[2] http://marc.info/?l=linux-acpi&m=144241209800788&w=2
[3] http://marc.info/?l=linux-acpi&m=144906557814813&w=2
[4] http://marc.info/?l=linux-acpi&m=146106902731359&w=2
[5] http://marc.info/?l=linux-acpi&m=146298107608349&w=2
[6] git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git for_review/arm64_lpi

Sudeep Holla (5):
  ACPI / processor_idle: introduce ACPI_PROCESSOR_CSTATE
  ACPI / processor_idle: Add support for Low Power Idle(LPI) states
  arm64: cpuidle: drop __init section marker to arm_cpuidle_init
  arm64: add support for ACPI Low Power Idle(LPI)
  ACPI : enable ACPI_PROCESSOR_IDLE on ARM64

 arch/arm64/kernel/cpuidle.c     |  19 +-
 drivers/acpi/Kconfig            |   6 +-
 drivers/acpi/bus.c              |  14 +-
 drivers/acpi/processor_driver.c |   2 +-
 drivers/acpi/processor_idle.c   | 545 ++++++++++++++++++++++++++++++++++------
 drivers/cpuidle/cpuidle-arm.c   |  23 +-
 drivers/firmware/psci.c         |  56 +++++
 include/acpi/processor.h        |  26 +-
 include/linux/acpi.h            |   4 +
 include/linux/cpuidle-arm.h     |  30 +++
 10 files changed, 616 insertions(+), 109 deletions(-)
 create mode 100644 include/linux/cpuidle-arm.h

-- 
2.7.4

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

* [PATCH v6 1/5] ACPI / processor_idle: introduce ACPI_PROCESSOR_CSTATE
  2016-06-14 14:48 [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
@ 2016-06-14 14:48 ` Sudeep Holla
  2016-06-14 14:48 ` [PATCH v6 2/5] ACPI / processor_idle: Add support for Low Power Idle(LPI) states Sudeep Holla
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 14:48 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel

ACPI 6.0 adds a new method to specify the CPU idle states(C-states)
called Low Power Idle(LPI) states. Since new architectures like ARM64
use only LPIs, introduce ACPI_PROCESSOR_CSTATE to encapsulate all the
code supporting the old style C-states(_CST).

This patch will help to extend the processor_idle module to support
LPI.

Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 drivers/acpi/Kconfig          |  4 +++
 drivers/acpi/processor_idle.c | 80 ++++++++++++++++++++++++++++---------------
 include/acpi/processor.h      |  2 +-
 3 files changed, 58 insertions(+), 28 deletions(-)

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b7e2e776397d..1358fb7d7a68 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -213,6 +213,10 @@ config ACPI_CPU_FREQ_PSS
 	bool
 	select THERMAL
 
+config ACPI_PROCESSOR_CSTATE
+	def_bool y
+	depends on IA64 || X86
+
 config ACPI_PROCESSOR_IDLE
 	bool
 	select CPU_IDLE
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 444e3745c8b3..ca0de35d1c3a 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -59,6 +59,12 @@ module_param(latency_factor, uint, 0644);
 
 static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device);
 
+struct cpuidle_driver acpi_idle_driver = {
+	.name =		"acpi_idle",
+	.owner =	THIS_MODULE,
+};
+
+#ifdef CONFIG_ACPI_PROCESSOR_CSTATE
 static
 DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX], acpi_cstate);
 
@@ -804,11 +810,6 @@ static void acpi_idle_enter_freeze(struct cpuidle_device *dev,
 	acpi_idle_do_entry(cx);
 }
 
-struct cpuidle_driver acpi_idle_driver = {
-	.name =		"acpi_idle",
-	.owner =	THIS_MODULE,
-};
-
 /**
  * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE
  * device i.e. per-cpu data
@@ -925,6 +926,50 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
 	return 0;
 }
 
+static inline void acpi_processor_cstate_first_run_checks(void)
+{
+	acpi_status status;
+	static int first_run;
+
+	if (first_run)
+		return;
+	dmi_check_system(processor_power_dmi_table);
+	max_cstate = acpi_processor_cstate_check(max_cstate);
+	if (max_cstate < ACPI_C_STATES_MAX)
+		pr_notice("ACPI: processor limited to max C-state %d\n",
+			  max_cstate);
+	first_run++;
+
+	if (acpi_gbl_FADT.cst_control && !nocst) {
+		status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+					    acpi_gbl_FADT.cst_control, 8);
+		if (ACPI_FAILURE(status))
+			ACPI_EXCEPTION((AE_INFO, status,
+					"Notifying BIOS of _CST ability failed"));
+	}
+}
+#else
+
+static inline int disabled_by_idle_boot_param(void) { return 0; }
+static inline void acpi_processor_cstate_first_run_checks(void) { }
+static int acpi_processor_get_power_info(struct acpi_processor *pr)
+{
+	return -ENODEV;
+}
+
+static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
+					   struct cpuidle_device *dev)
+{
+	return -EINVAL;
+}
+
+static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+{
+	return -EINVAL;
+}
+
+#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
+
 int acpi_processor_hotplug(struct acpi_processor *pr)
 {
 	int ret = 0;
@@ -1015,35 +1060,16 @@ static int acpi_processor_registered;
 
 int acpi_processor_power_init(struct acpi_processor *pr)
 {
-	acpi_status status;
 	int retval;
 	struct cpuidle_device *dev;
-	static int first_run;
 
 	if (disabled_by_idle_boot_param())
 		return 0;
 
-	if (!first_run) {
-		dmi_check_system(processor_power_dmi_table);
-		max_cstate = acpi_processor_cstate_check(max_cstate);
-		if (max_cstate < ACPI_C_STATES_MAX)
-			printk(KERN_NOTICE
-			       "ACPI: processor limited to max C-state %d\n",
-			       max_cstate);
-		first_run++;
-	}
+	acpi_processor_cstate_first_run_checks();
 
-	if (acpi_gbl_FADT.cst_control && !nocst) {
-		status =
-		    acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8);
-		if (ACPI_FAILURE(status)) {
-			ACPI_EXCEPTION((AE_INFO, status,
-					"Notifying BIOS of _CST ability failed"));
-		}
-	}
-
-	acpi_processor_get_power_info(pr);
-	pr->flags.power_setup_done = 1;
+	if (!acpi_processor_get_power_info(pr))
+		pr->flags.power_setup_done = 1;
 
 	/*
 	 * Install the idle handler if processor power management is supported.
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 6f1805dd5d3c..48779d678122 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -242,7 +242,7 @@ extern int acpi_processor_get_performance_info(struct acpi_processor *pr);
 DECLARE_PER_CPU(struct acpi_processor *, processors);
 extern struct acpi_processor_errata errata;
 
-#ifdef ARCH_HAS_POWER_INIT
+#if defined(ARCH_HAS_POWER_INIT) && defined(CONFIG_ACPI_PROCESSOR_CSTATE)
 void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
 					unsigned int cpu);
 int acpi_processor_ffh_cstate_probe(unsigned int cpu,
-- 
2.7.4

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

* [PATCH v6 2/5] ACPI / processor_idle: Add support for Low Power Idle(LPI) states
  2016-06-14 14:48 [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
  2016-06-14 14:48 ` [PATCH v6 1/5] ACPI / processor_idle: introduce ACPI_PROCESSOR_CSTATE Sudeep Holla
@ 2016-06-14 14:48 ` Sudeep Holla
  2016-06-14 16:47   ` Sudeep Holla
  2016-06-14 16:54   ` [PATCH v6 2/5][UPDATED] " Sudeep Holla
  2016-06-14 14:48 ` [PATCH v6 3/5] arm64: cpuidle: drop __init section marker to arm_cpuidle_init Sudeep Holla
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 14:48 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel

ACPI 6.0 introduced an optional object _LPI that provides an alternate
method to describe Low Power Idle states. It defines the local power
states for each node in a hierarchical processor topology. The OSPM can
use _LPI object to select a local power state for each level of processor
hierarchy in the system. They used to produce a composite power state
request that is presented to the platform by the OSPM.

Since multiple processors affect the idle state for any non-leaf hierarchy
node, coordination of idle state requests between the processors is
required. ACPI supports two different coordination schemes: Platform
coordinated and  OS initiated.

This patch adds initial support for Platform coordination scheme of LPI.

Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 drivers/acpi/bus.c              |  14 +-
 drivers/acpi/processor_driver.c |   2 +-
 drivers/acpi/processor_idle.c   | 469 +++++++++++++++++++++++++++++++++++-----
 include/acpi/processor.h        |  24 +-
 include/linux/acpi.h            |   4 +
 5 files changed, 453 insertions(+), 60 deletions(-)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 262ca31b86d9..80ebb05e387c 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -302,6 +302,14 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
 EXPORT_SYMBOL(acpi_run_osc);
 
 bool osc_sb_apei_support_acked;
+
+/*
+ * ACPI 6.0 Section 8.4.4.2 Idle State Coordination
+ * OSPM supports platform coordinated low power idle(LPI) states
+ */
+bool osc_pc_lpi_support_confirmed;
+EXPORT_SYMBOL_GPL(osc_pc_lpi_support_confirmed);
+
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_support(void)
 {
@@ -322,6 +330,7 @@ static void acpi_bus_osc_support(void)
 		capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT;
 
 	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
+	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT;
 
 	if (!ghes_disable)
 		capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
@@ -329,9 +338,12 @@ static void acpi_bus_osc_support(void)
 		return;
 	if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) {
 		u32 *capbuf_ret = context.ret.pointer;
-		if (context.ret.length > OSC_SUPPORT_DWORD)
+		if (context.ret.length > OSC_SUPPORT_DWORD) {
 			osc_sb_apei_support_acked =
 				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
+			osc_pc_lpi_support_confirmed =
+				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT;
+		}
 		kfree(context.ret.pointer);
 	}
 	/* do we need to check other returned cap? Sounds no */
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index d2fa8cb82d2b..0ca14ac7bb28 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -90,7 +90,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
 						  pr->performance_platform_limit);
 		break;
 	case ACPI_PROCESSOR_NOTIFY_POWER:
-		acpi_processor_cst_has_changed(pr);
+		acpi_processor_power_state_has_changed(pr);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index ca0de35d1c3a..cbc99a3b65c7 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -303,7 +303,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *cst;
 
-
 	if (nocst)
 		return -ENODEV;
 
@@ -576,7 +575,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
 	return (working);
 }
 
-static int acpi_processor_get_power_info(struct acpi_processor *pr)
+static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
 {
 	unsigned int i;
 	int result;
@@ -810,31 +809,12 @@ static void acpi_idle_enter_freeze(struct cpuidle_device *dev,
 	acpi_idle_do_entry(cx);
 }
 
-/**
- * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE
- * device i.e. per-cpu data
- *
- * @pr: the ACPI processor
- * @dev : the cpuidle device
- */
 static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 					   struct cpuidle_device *dev)
 {
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
 
-	if (!pr->flags.power_setup_done)
-		return -EINVAL;
-
-	if (pr->flags.power == 0) {
-		return -EINVAL;
-	}
-
-	if (!dev)
-		return -EINVAL;
-
-	dev->cpu = pr->id;
-
 	if (max_cstate == 0)
 		max_cstate = 1;
 
@@ -857,31 +837,13 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 	return 0;
 }
 
-/**
- * acpi_processor_setup_cpuidle states- prepares and configures cpuidle
- * global state data i.e. idle routines
- *
- * @pr: the ACPI processor
- */
-static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+static int acpi_processor_setup_cstates(struct acpi_processor *pr)
 {
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
 	struct cpuidle_state *state;
 	struct cpuidle_driver *drv = &acpi_idle_driver;
 
-	if (!pr->flags.power_setup_done)
-		return -EINVAL;
-
-	if (pr->flags.power == 0)
-		return -EINVAL;
-
-	drv->safe_state_index = -1;
-	for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) {
-		drv->states[i].name[0] = '\0';
-		drv->states[i].desc[0] = '\0';
-	}
-
 	if (max_cstate == 0)
 		max_cstate = 1;
 
@@ -893,7 +855,7 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
 
 		state = &drv->states[count];
 		snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
-		strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
+		strlcpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
 		state->exit_latency = cx->latency;
 		state->target_residency = cx->latency * latency_factor;
 		state->enter = acpi_idle_enter;
@@ -952,7 +914,7 @@ static inline void acpi_processor_cstate_first_run_checks(void)
 
 static inline int disabled_by_idle_boot_param(void) { return 0; }
 static inline void acpi_processor_cstate_first_run_checks(void) { }
-static int acpi_processor_get_power_info(struct acpi_processor *pr)
+static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
 {
 	return -ENODEV;
 }
@@ -963,13 +925,416 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 	return -EINVAL;
 }
 
-static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+static int acpi_processor_setup_cstates(struct acpi_processor *pr)
 {
 	return -EINVAL;
 }
 
 #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
 
+struct acpi_lpi_states_array {
+	unsigned int size;
+	struct acpi_lpi_state *entries;
+};
+
+static int obj_get_integer(union acpi_object *obj, u32 *value)
+{
+	if (obj->type != ACPI_TYPE_INTEGER)
+		return -EINVAL;
+
+	*value = obj->integer.value;
+	return 0;
+}
+
+static int acpi_processor_evaluate_lpi(acpi_handle handle,
+				       struct acpi_lpi_states_array *info)
+{
+	acpi_status status;
+	int ret = 0;
+	int pkg_count, state_idx = 1, loop;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *lpi_data;
+	struct acpi_lpi_state *lpi_state;
+
+	status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _LPI, giving up\n"));
+		return -ENODEV;
+	}
+
+	lpi_data = buffer.pointer;
+
+	/* There must be at least 4 elements = 3 elements + 1 package */
+	if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
+	    lpi_data->package.count < 4) {
+		pr_debug("not enough elements in _LPI\n");
+		ret = -ENODATA;
+		goto end;
+	}
+
+	pkg_count = lpi_data->package.elements[2].integer.value;
+
+	/* Validate number of power states. */
+	if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) {
+		pr_debug("count given by _LPI is not valid\n");
+		ret = -ENODATA;
+		goto end;
+	}
+
+	lpi_state = kcalloc(pkg_count, sizeof(*lpi_state), GFP_KERNEL);
+	if (!lpi_state) {
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	info->size = pkg_count;
+	info->entries = lpi_state;
+
+	/* LPI States start at index 3 */
+	for (loop = 3; state_idx <= pkg_count;
+	     loop++, state_idx++, lpi_state++) {
+		union acpi_object *element, *pkg_elem, *obj;
+
+		element = &lpi_data->package.elements[loop];
+		if (element->type != ACPI_TYPE_PACKAGE)
+			continue;
+
+		if (element->package.count < 7)
+			continue;
+
+		pkg_elem = element->package.elements;
+
+		obj = pkg_elem + 6;
+		if (obj->type == ACPI_TYPE_BUFFER) {
+			struct acpi_power_register *reg;
+
+			reg = (struct acpi_power_register *)obj->buffer.pointer;
+			if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&
+			    (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
+				continue;
+
+			lpi_state->address = reg->address;
+
+			if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
+				lpi_state->entry_method = ACPI_CSTATE_FFH;
+			else
+				lpi_state->entry_method = ACPI_CSTATE_SYSTEMIO;
+		} else if (obj->type == ACPI_TYPE_INTEGER) {
+			lpi_state->entry_method = ACPI_CSTATE_INTEGER;
+			lpi_state->address = obj->integer.value;
+		} else {
+			continue;
+		}
+
+		/* elements[7,8] skipped for now i.e. Residency/Usage counter*/
+
+		obj = pkg_elem + 9;
+		if (obj->type == ACPI_TYPE_STRING)
+			strlcpy(lpi_state->desc, obj->string.pointer,
+				ACPI_CX_DESC_LEN);
+
+		lpi_state->index = state_idx;
+		if (obj_get_integer(pkg_elem + 0, &lpi_state->min_residency)) {
+			pr_debug("No min. residency found, assuming 10 us\n");
+			lpi_state->min_residency = 10;
+		}
+
+		if (obj_get_integer(pkg_elem + 1, &lpi_state->wake_latency)) {
+			pr_debug("No wakeup residency found, assuming 10 us\n");
+			lpi_state->wake_latency = 10;
+		}
+
+		if (obj_get_integer(pkg_elem + 2, &lpi_state->flags))
+			lpi_state->flags = 0;
+
+		if (obj_get_integer(pkg_elem + 3, &lpi_state->arch_flags))
+			lpi_state->arch_flags = 0;
+
+		if (obj_get_integer(pkg_elem + 4, &lpi_state->res_cnt_freq))
+			lpi_state->res_cnt_freq = 1;
+
+		if (obj_get_integer(pkg_elem + 5, &lpi_state->enable_parent_state))
+			lpi_state->enable_parent_state = 0;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n",
+			  state_idx));
+end:
+	kfree(buffer.pointer);
+	return ret;
+}
+
+/*
+ * max_leaf_depth - holds the depth of the processor hierarchy/tree
+ * flat_state_cnt - the number of composite LPI states after the process of flattening
+ */
+static int max_leaf_depth, flat_state_cnt;
+
+/**
+ * combine_lpi_states - combine local and parent LPI states to form a composite LPI state
+ *
+ * @local: local LPI state
+ * @parent: parent LPI state
+ * @result: composite LPI state
+ */
+static bool combine_lpi_states(struct acpi_lpi_state *local,
+			       struct acpi_lpi_state *parent,
+			       struct acpi_lpi_state *result)
+{
+	if (parent->entry_method == ACPI_CSTATE_INTEGER) {
+		if (!parent->address) /* 0 means autopromotable */
+			return false;
+		result->address = local->address + parent->address;
+	} else {
+		result->address = parent->address;
+	}
+
+	result->min_residency = max(local->min_residency, parent->min_residency);
+	result->wake_latency = local->wake_latency + parent->wake_latency;
+	result->enable_parent_state = parent->enable_parent_state;
+	result->entry_method = local->entry_method;
+
+	result->flags = parent->flags;
+	result->arch_flags = parent->arch_flags;
+
+	strlcpy(result->desc, local->desc, ACPI_CX_DESC_LEN);
+	strlcat(result->desc, "+", ACPI_CX_DESC_LEN);
+	strlcat(result->desc, parent->desc, ACPI_CX_DESC_LEN);
+	return true;
+}
+
+#define ACPI_LPI_STATE_FLAGS_ENABLED			BIT(0)
+
+static int flatten_lpi_states(struct acpi_processor *pr,
+			      struct acpi_lpi_states_array *info,
+			      struct acpi_lpi_state *lpi,
+			      uint32_t depth)
+{
+	int j, state_count = info[depth].size;
+	struct acpi_lpi_state *t = info[depth].entries;
+
+	for (j = 0; j < state_count; j++, t++) {
+		struct acpi_lpi_state *flpi;
+		bool valid = false;
+
+		if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED))
+			continue;
+
+		flpi = &pr->power.lpi_states[flat_state_cnt];
+		flpi->index = flat_state_cnt;
+
+		if (depth == max_leaf_depth) { /* leaf/processor node */
+			memcpy(flpi, t, sizeof(*t));
+			flat_state_cnt++;
+			valid = true;
+		} else if (lpi && t->index <= lpi->enable_parent_state) {
+			if (combine_lpi_states(lpi, t, flpi)) {
+				flat_state_cnt++;
+				valid = true;
+			}
+		}
+
+		/*
+		 * flatten recursively from leaf until the highest level
+		 * (e.g. system) is reached
+		 */
+		if (valid && depth)
+			flatten_lpi_states(pr, info, flpi, depth - 1);
+	}
+	return 0;
+}
+
+static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
+{
+	int ret, i;
+	struct acpi_lpi_states_array *info;
+	struct acpi_device *d = NULL;
+	acpi_handle handle = pr->handle, pr_ahandle;
+	acpi_status status;
+
+	if (!osc_pc_lpi_support_confirmed)
+		return -EOPNOTSUPP;
+
+	max_leaf_depth = 0;
+	if (!acpi_has_method(handle, "_LPI"))
+		return -EINVAL;
+	flat_state_cnt = 0;
+
+	while (ACPI_SUCCESS(status = acpi_get_parent(handle, &pr_ahandle))) {
+		acpi_bus_get_device(pr_ahandle, &d);
+		handle = pr_ahandle;
+
+		if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
+			break;
+
+		if (!acpi_has_method(pr_ahandle, "_LPI"))
+			break;
+
+		max_leaf_depth++;
+	}
+
+	info = kcalloc(max_leaf_depth + 1, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	pr_ahandle = pr->handle;
+	for (i = max_leaf_depth; i >= 0 && ACPI_SUCCESS(status); i--) {
+		handle = pr_ahandle;
+		ret = acpi_processor_evaluate_lpi(handle, info + i);
+		if (ret)
+			break;
+
+		status = acpi_get_parent(handle, &pr_ahandle);
+	}
+
+	/* flatten all the LPI states in the entire hierarchy */
+	flatten_lpi_states(pr, info, NULL, max_leaf_depth);
+
+	pr->power.count = flat_state_cnt;
+
+	for (i = 0; i <= max_leaf_depth; i++)
+		kfree(info[i].entries);
+
+	kfree(info);
+
+	/* Tell driver that _LPI is supported. */
+	pr->flags.has_lpi = 1;
+	pr->flags.power = 1;
+
+	return 0;
+}
+
+int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
+{
+	return -ENODEV;
+}
+
+int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi, int idx)
+{
+	return -ENODEV;
+}
+
+/**
+ * acpi_idle_lpi_enter - enters an ACPI any LPI state
+ * @dev: the target CPU
+ * @drv: cpuidle driver containing cpuidle state info
+ * @index: index of target state
+ *
+ * Return: 0 for success or negative value for error
+ */
+static int acpi_idle_lpi_enter(struct cpuidle_device *dev,
+			       struct cpuidle_driver *drv, int index)
+{
+	struct acpi_processor *pr;
+	struct acpi_lpi_state *lpi;
+
+	pr = __this_cpu_read(processors);
+
+	if (unlikely(!pr))
+		return -EINVAL;
+
+	lpi = &pr->power.lpi_states[index];
+	if (lpi->entry_method == ACPI_CSTATE_FFH)
+		return acpi_processor_ffh_lpi_enter(lpi, index);
+
+	return -EINVAL;
+}
+
+static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
+{
+	int i;
+	struct acpi_lpi_state *lpi;
+	struct cpuidle_state *state;
+	struct cpuidle_driver *drv = &acpi_idle_driver;
+
+	if (!pr->flags.has_lpi)
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < flat_state_cnt && i < CPUIDLE_STATE_MAX; i++) {
+		lpi = &pr->power.lpi_states[i];
+
+		state = &drv->states[i];
+		snprintf(state->name, CPUIDLE_NAME_LEN, "LPI-%d", i);
+		strlcpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN);
+		state->exit_latency = lpi->wake_latency;
+		state->target_residency = lpi->min_residency;
+		if (lpi->arch_flags)
+			state->flags |= CPUIDLE_FLAG_TIMER_STOP;
+		state->enter = acpi_idle_lpi_enter;
+		drv->safe_state_index = i;
+	}
+
+	drv->state_count = i;
+
+	return 0;
+}
+
+/**
+ * acpi_processor_setup_cpuidle_states- prepares and configures cpuidle
+ * global state data i.e. idle routines
+ *
+ * @pr: the ACPI processor
+ */
+static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+{
+	int i;
+	struct cpuidle_driver *drv = &acpi_idle_driver;
+
+	if (!pr->flags.power_setup_done)
+		return -EINVAL;
+
+	if (pr->flags.power == 0)
+		return -EINVAL;
+
+	drv->safe_state_index = -1;
+	for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) {
+		drv->states[i].name[0] = '\0';
+		drv->states[i].desc[0] = '\0';
+	}
+
+	if (pr->flags.has_lpi)
+		return acpi_processor_setup_lpi_states(pr);
+
+	return acpi_processor_setup_cstates(pr);
+}
+
+/**
+ * acpi_processor_setup_cpuidle_dev - prepares and configures CPUIDLE
+ * device i.e. per-cpu data
+ *
+ * @pr: the ACPI processor
+ * @dev : the cpuidle device
+ */
+static int acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr,
+					    struct cpuidle_device *dev)
+{
+	if (!pr->flags.power_setup_done)
+		return -EINVAL;
+
+	if (pr->flags.power == 0)
+		return -EINVAL;
+
+	if (!dev)
+		return -EINVAL;
+
+	dev->cpu = pr->id;
+	if (pr->flags.has_lpi)
+		return acpi_processor_ffh_lpi_probe(pr->id);
+
+	return acpi_processor_setup_cpuidle_cx(pr, dev);
+}
+
+static int acpi_processor_get_power_info(struct acpi_processor *pr)
+{
+	int ret;
+
+	ret = acpi_processor_get_lpi_info(pr);
+	if (ret)
+		ret = acpi_processor_get_cstate_info(pr);
+
+	return ret;
+}
+
 int acpi_processor_hotplug(struct acpi_processor *pr)
 {
 	int ret = 0;
@@ -978,18 +1343,15 @@ int acpi_processor_hotplug(struct acpi_processor *pr)
 	if (disabled_by_idle_boot_param())
 		return 0;
 
-	if (nocst)
-		return -ENODEV;
-
 	if (!pr->flags.power_setup_done)
 		return -ENODEV;
 
 	dev = per_cpu(acpi_cpuidle_device, pr->id);
 	cpuidle_pause_and_lock();
 	cpuidle_disable_device(dev);
-	acpi_processor_get_power_info(pr);
-	if (pr->flags.power) {
-		acpi_processor_setup_cpuidle_cx(pr, dev);
+	ret = acpi_processor_get_power_info(pr);
+	if (!ret && pr->flags.power) {
+		acpi_processor_setup_cpuidle_dev(pr, dev);
 		ret = cpuidle_enable_device(dev);
 	}
 	cpuidle_resume_and_unlock();
@@ -997,7 +1359,7 @@ int acpi_processor_hotplug(struct acpi_processor *pr)
 	return ret;
 }
 
-int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
 {
 	int cpu;
 	struct acpi_processor *_pr;
@@ -1006,9 +1368,6 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
 	if (disabled_by_idle_boot_param())
 		return 0;
 
-	if (nocst)
-		return -ENODEV;
-
 	if (!pr->flags.power_setup_done)
 		return -ENODEV;
 
@@ -1045,7 +1404,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
 			acpi_processor_get_power_info(_pr);
 			if (_pr->flags.power) {
 				dev = per_cpu(acpi_cpuidle_device, cpu);
-				acpi_processor_setup_cpuidle_cx(_pr, dev);
+				acpi_processor_setup_cpuidle_dev(_pr, dev);
 				cpuidle_enable_device(dev);
 			}
 		}
@@ -1092,7 +1451,7 @@ int acpi_processor_power_init(struct acpi_processor *pr)
 			return -ENOMEM;
 		per_cpu(acpi_cpuidle_device, pr->id) = dev;
 
-		acpi_processor_setup_cpuidle_cx(pr, dev);
+		acpi_processor_setup_cpuidle_dev(pr, dev);
 
 		/* Register per-cpu cpuidle_device. Cpuidle driver
 		 * must already be registered before registering device
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 48779d678122..e2dcb0c51554 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -39,6 +39,7 @@
 #define ACPI_CSTATE_SYSTEMIO	0
 #define ACPI_CSTATE_FFH		1
 #define ACPI_CSTATE_HALT	2
+#define ACPI_CSTATE_INTEGER	3
 
 #define ACPI_CX_DESC_LEN	32
 
@@ -67,9 +68,25 @@ struct acpi_processor_cx {
 	char desc[ACPI_CX_DESC_LEN];
 };
 
+struct acpi_lpi_state {
+	u32 min_residency;
+	u32 wake_latency; /* worst case */
+	u32 flags;
+	u32 arch_flags;
+	u32 res_cnt_freq;
+	u32 enable_parent_state;
+	u64 address;
+	u8 index;
+	u8 entry_method;
+	char desc[ACPI_CX_DESC_LEN];
+};
+
 struct acpi_processor_power {
 	int count;
-	struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
+	union {
+		struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
+		struct acpi_lpi_state lpi_states[ACPI_PROCESSOR_MAX_POWER];
+	};
 	int timer_broadcast_on_state;
 };
 
@@ -189,6 +206,7 @@ struct acpi_processor_flags {
 	u8 bm_control:1;
 	u8 bm_check:1;
 	u8 has_cst:1;
+	u8 has_lpi:1;
 	u8 power_setup_done:1;
 	u8 bm_rld_set:1;
 	u8 need_hotplug_init:1;
@@ -371,7 +389,7 @@ extern struct cpuidle_driver acpi_idle_driver;
 #ifdef CONFIG_ACPI_PROCESSOR_IDLE
 int acpi_processor_power_init(struct acpi_processor *pr);
 int acpi_processor_power_exit(struct acpi_processor *pr);
-int acpi_processor_cst_has_changed(struct acpi_processor *pr);
+int acpi_processor_power_state_has_changed(struct acpi_processor *pr);
 int acpi_processor_hotplug(struct acpi_processor *pr);
 #else
 static inline int acpi_processor_power_init(struct acpi_processor *pr)
@@ -384,7 +402,7 @@ static inline int acpi_processor_power_exit(struct acpi_processor *pr)
 	return -ENODEV;
 }
 
-static inline int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+static inline int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
 {
 	return -ENODEV;
 }
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 288fac5294f5..65754566ae17 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -444,8 +444,12 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 #define OSC_SB_HOTPLUG_OST_SUPPORT		0x00000008
 #define OSC_SB_APEI_SUPPORT			0x00000010
 #define OSC_SB_CPC_SUPPORT			0x00000020
+#define OSC_SB_CPCV2_SUPPORT			0x00000040
+#define OSC_SB_PCLPI_SUPPORT			0x00000080
+#define OSC_SB_OSLPI_SUPPORT			0x00000100
 
 extern bool osc_sb_apei_support_acked;
+extern bool osc_pc_lpi_support_confirmed;
 
 /* PCI Host Bridge _OSC: Capabilities DWORD 2: Support Field */
 #define OSC_PCI_EXT_CONFIG_SUPPORT		0x00000001
-- 
2.7.4

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

* [PATCH v6 3/5] arm64: cpuidle: drop __init section marker to arm_cpuidle_init
  2016-06-14 14:48 [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
  2016-06-14 14:48 ` [PATCH v6 1/5] ACPI / processor_idle: introduce ACPI_PROCESSOR_CSTATE Sudeep Holla
  2016-06-14 14:48 ` [PATCH v6 2/5] ACPI / processor_idle: Add support for Low Power Idle(LPI) states Sudeep Holla
@ 2016-06-14 14:48 ` Sudeep Holla
  2016-06-22 16:09   ` Lorenzo Pieralisi
  2016-06-14 14:48 ` [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI) Sudeep Holla
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 14:48 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, linux-arm-kernel

Commit ea389daa7fd9 ("arm64: cpuidle: add __init section marker to
arm_cpuidle_init") added the __init annotation to arm_cpuidle_init
as it was not needed after booting which was correct at that time.

However with the introduction of ACPI LPI support, this will be used
from cpuhotplug path in ACPI processor driver.

This patch drops the __init annotation from arm_cpuidle_init to avoid
the following warning:

WARNING: vmlinux.o(.text+0x113c8): Section mismatch in reference from the
	function acpi_processor_ffh_lpi_probe() to the function
	.init.text:arm_cpuidle_init()
The function acpi_processor_ffh_lpi_probe() references
the function __init arm_cpuidle_init().
This is often because acpi_processor_ffh_lpi_probe lacks a __init
annotation or the annotation of arm_cpuidle_init is wrong.

Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 arch/arm64/kernel/cpuidle.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c
index e11857fce05f..06786fdaadeb 100644
--- a/arch/arm64/kernel/cpuidle.c
+++ b/arch/arm64/kernel/cpuidle.c
@@ -15,7 +15,7 @@
 #include <asm/cpuidle.h>
 #include <asm/cpu_ops.h>
 
-int __init arm_cpuidle_init(unsigned int cpu)
+int arm_cpuidle_init(unsigned int cpu)
 {
 	int ret = -EOPNOTSUPP;
 
-- 
2.7.4

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

* [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-14 14:48 [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
                   ` (2 preceding siblings ...)
  2016-06-14 14:48 ` [PATCH v6 3/5] arm64: cpuidle: drop __init section marker to arm_cpuidle_init Sudeep Holla
@ 2016-06-14 14:48 ` Sudeep Holla
  2016-06-22 14:17   ` Lorenzo Pieralisi
  2016-06-14 14:48 ` [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64 Sudeep Holla
  2016-06-22 17:45 ` [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
  5 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 14:48 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, Daniel Lezcano, linux-arm-kernel

This patch adds appropriate callbacks to support ACPI Low Power Idle
(LPI) on ARM64.

Now that arm_enter_idle_state is exactly same in both generic ARM{32,64}
CPUIdle driver and ARM64 backend for ACPI processor idle driver, we can
unify it and move to cpuidle-arm.h header.

Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 arch/arm64/kernel/cpuidle.c   | 17 +++++++++++++
 drivers/cpuidle/cpuidle-arm.c | 23 ++----------------
 drivers/firmware/psci.c       | 56 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/cpuidle-arm.h   | 30 +++++++++++++++++++++++
 4 files changed, 105 insertions(+), 21 deletions(-)
 create mode 100644 include/linux/cpuidle-arm.h

diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c
index 06786fdaadeb..6874d01531ae 100644
--- a/arch/arm64/kernel/cpuidle.c
+++ b/arch/arm64/kernel/cpuidle.c
@@ -9,6 +9,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/acpi.h>
+#include <linux/cpuidle-arm.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 
@@ -39,3 +41,18 @@ int arm_cpuidle_suspend(int index)
 
 	return cpu_ops[cpu]->cpu_suspend(index);
 }
+
+#ifdef CONFIG_ACPI
+
+#include <acpi/processor.h>
+
+int acpi_processor_ffh_lpi_probe(unsigned int cpu)
+{
+	return arm_cpuidle_init(cpu);
+}
+
+int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
+{
+	return arm_generic_enter_idle_state(lpi->index);
+}
+#endif
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index e342565e8715..75178ba4a1b2 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -12,8 +12,8 @@
 #define pr_fmt(fmt) "CPUidle arm: " fmt
 
 #include <linux/cpuidle.h>
+#include <linux/cpuidle-arm.h>
 #include <linux/cpumask.h>
-#include <linux/cpu_pm.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -36,26 +36,7 @@
 static int arm_enter_idle_state(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv, int idx)
 {
-	int ret;
-
-	if (!idx) {
-		cpu_do_idle();
-		return idx;
-	}
-
-	ret = cpu_pm_enter();
-	if (!ret) {
-		/*
-		 * Pass idle state index to cpu_suspend which in turn will
-		 * call the CPU ops suspend protocol with idle index as a
-		 * parameter.
-		 */
-		ret = arm_cpuidle_suspend(idx);
-
-		cpu_pm_exit();
-	}
-
-	return ret ? -1 : idx;
+	return arm_generic_enter_idle_state(idx);
 }
 
 static struct cpuidle_driver arm_idle_driver = {
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 03e04582791c..c6caa863d156 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -13,6 +13,7 @@
 
 #define pr_fmt(fmt) "psci: " fmt
 
+#include <linux/acpi.h>
 #include <linux/arm-smccc.h>
 #include <linux/cpuidle.h>
 #include <linux/errno.h>
@@ -310,11 +311,66 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
 	return ret;
 }
 
+#ifdef CONFIG_ACPI
+#include <acpi/processor.h>
+
+static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
+{
+	int i, count;
+	u32 *psci_states;
+	struct acpi_processor *pr;
+	struct acpi_lpi_state *lpi;
+
+	pr = per_cpu(processors, cpu);
+	if (unlikely(!pr || !pr->flags.has_lpi))
+		return -EINVAL;
+
+	/*
+	 * If the PSCI cpu_suspend function hook has not been initialized
+	 * idle states must not be enabled, so bail out
+	 */
+	if (!psci_ops.cpu_suspend)
+		return -EOPNOTSUPP;
+
+	count = pr->power.count - 1;
+	if (count <= 0)
+		return -ENODEV;
+
+	psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
+	if (!psci_states)
+		return -ENOMEM;
+
+	for (i = 0; i < count; i++) {
+		u32 state;
+
+		lpi = &pr->power.lpi_states[i + 1];
+		state = lpi->address & 0xFFFFFFFF;
+		if (!psci_power_state_is_valid(state)) {
+			pr_warn("Invalid PSCI power state %#x\n", state);
+			kfree(psci_states);
+			return -EINVAL;
+		}
+		psci_states[i] = state;
+	}
+	/* Idle states parsed correctly, initialize per-cpu pointer */
+	per_cpu(psci_power_state, cpu) = psci_states;
+	return 0;
+}
+#else
+static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
+{
+	return -EINVAL;
+}
+#endif
+
 int psci_cpu_init_idle(unsigned int cpu)
 {
 	struct device_node *cpu_node;
 	int ret;
 
+	if (!acpi_disabled)
+		return psci_acpi_cpu_init_idle(cpu);
+
 	cpu_node = of_get_cpu_node(cpu, NULL);
 	if (!cpu_node)
 		return -ENODEV;
diff --git a/include/linux/cpuidle-arm.h b/include/linux/cpuidle-arm.h
new file mode 100644
index 000000000000..b99bcb3f43dd
--- /dev/null
+++ b/include/linux/cpuidle-arm.h
@@ -0,0 +1,30 @@
+#include <linux/cpu_pm.h>
+
+#include <asm/cpuidle.h>
+
+/*
+ * arm_enter_idle_state - Programs CPU to enter the specified state
+ */
+static int arm_generic_enter_idle_state(int idx)
+{
+	int ret;
+
+	if (!idx) {
+		cpu_do_idle();
+		return idx;
+	}
+
+	ret = cpu_pm_enter();
+	if (!ret) {
+		/*
+		 * Pass idle state index to cpu_suspend which in turn will
+		 * call the CPU ops suspend protocol with idle index as a
+		 * parameter.
+		 */
+		ret = arm_cpuidle_suspend(idx);
+
+		cpu_pm_exit();
+	}
+
+	return ret ? -1 : idx;
+}
-- 
2.7.4

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

* [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-14 14:48 [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
                   ` (3 preceding siblings ...)
  2016-06-14 14:48 ` [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI) Sudeep Holla
@ 2016-06-14 14:48 ` Sudeep Holla
  2016-06-27 14:33   ` Daniel Lezcano
  2016-06-22 17:45 ` [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
  5 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 14:48 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	linux-arm-kernel

Now that ACPI processor idle driver supports LPI(Low Power Idle), lets
enable ACPI_PROCESSOR_IDLE for ARM64 too.

This patch just removes the IA64 and X86 dependency on ACPI_PROCESSOR_IDLE

Cc: linux-arm-kernel@lists.infradead.org
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 drivers/acpi/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 1358fb7d7a68..d74275c0f374 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -238,7 +238,7 @@ config ACPI_CPPC_LIB
 config ACPI_PROCESSOR
 	tristate "Processor"
 	depends on X86 || IA64 || ARM64
-	select ACPI_PROCESSOR_IDLE if X86 || IA64
+	select ACPI_PROCESSOR_IDLE
 	select ACPI_CPU_FREQ_PSS if X86 || IA64
 	default y
 	help
-- 
2.7.4

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

* Re: [PATCH v6 2/5] ACPI / processor_idle: Add support for Low Power Idle(LPI) states
  2016-06-14 14:48 ` [PATCH v6 2/5] ACPI / processor_idle: Add support for Low Power Idle(LPI) states Sudeep Holla
@ 2016-06-14 16:47   ` Sudeep Holla
  2016-06-14 16:54   ` [PATCH v6 2/5][UPDATED] " Sudeep Holla
  1 sibling, 0 replies; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 16:47 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel



On 14/06/16 15:48, Sudeep Holla wrote:
> ACPI 6.0 introduced an optional object _LPI that provides an alternate
> method to describe Low Power Idle states. It defines the local power
> states for each node in a hierarchical processor topology. The OSPM can
> use _LPI object to select a local power state for each level of processor
> hierarchy in the system. They used to produce a composite power state
> request that is presented to the platform by the OSPM.
>
> Since multiple processors affect the idle state for any non-leaf hierarchy
> node, coordination of idle state requests between the processors is
> required. ACPI supports two different coordination schemes: Platform
> coordinated and  OS initiated.
>
> This patch adds initial support for Platform coordination scheme of LPI.
>

I seem to have sent a stale version of this patch, will send an updated
version of this patch alone. Please ignore this one.

-- 
Regards,
Sudeep

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

* [PATCH v6 2/5][UPDATED] ACPI / processor_idle: Add support for Low Power Idle(LPI) states
  2016-06-14 14:48 ` [PATCH v6 2/5] ACPI / processor_idle: Add support for Low Power Idle(LPI) states Sudeep Holla
  2016-06-14 16:47   ` Sudeep Holla
@ 2016-06-14 16:54   ` Sudeep Holla
  1 sibling, 0 replies; 27+ messages in thread
From: Sudeep Holla @ 2016-06-14 16:54 UTC (permalink / raw)
  To: Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel

ACPI 6.0 introduced an optional object _LPI that provides an alternate
method to describe Low Power Idle states. It defines the local power
states for each node in a hierarchical processor topology. The OSPM can
use _LPI object to select a local power state for each level of processor
hierarchy in the system. They used to produce a composite power state
request that is presented to the platform by the OSPM.

Since multiple processors affect the idle state for any non-leaf hierarchy
node, coordination of idle state requests between the processors is
required. ACPI supports two different coordination schemes: Platform
coordinated and  OS initiated.

This patch adds initial support for Platform coordination scheme of LPI.

Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 drivers/acpi/bus.c              |  14 +-
 drivers/acpi/processor_driver.c |   2 +-
 drivers/acpi/processor_idle.c   | 468 +++++++++++++++++++++++++++++++++++-----
 include/acpi/processor.h        |  24 ++-
 include/linux/acpi.h            |   4 +
 5 files changed, 452 insertions(+), 60 deletions(-)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 262ca31b86d9..80ebb05e387c 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -302,6 +302,14 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
 EXPORT_SYMBOL(acpi_run_osc);
 
 bool osc_sb_apei_support_acked;
+
+/*
+ * ACPI 6.0 Section 8.4.4.2 Idle State Coordination
+ * OSPM supports platform coordinated low power idle(LPI) states
+ */
+bool osc_pc_lpi_support_confirmed;
+EXPORT_SYMBOL_GPL(osc_pc_lpi_support_confirmed);
+
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_support(void)
 {
@@ -322,6 +330,7 @@ static void acpi_bus_osc_support(void)
 		capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT;
 
 	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
+	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT;
 
 	if (!ghes_disable)
 		capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
@@ -329,9 +338,12 @@ static void acpi_bus_osc_support(void)
 		return;
 	if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) {
 		u32 *capbuf_ret = context.ret.pointer;
-		if (context.ret.length > OSC_SUPPORT_DWORD)
+		if (context.ret.length > OSC_SUPPORT_DWORD) {
 			osc_sb_apei_support_acked =
 				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
+			osc_pc_lpi_support_confirmed =
+				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT;
+		}
 		kfree(context.ret.pointer);
 	}
 	/* do we need to check other returned cap? Sounds no */
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index d2fa8cb82d2b..0ca14ac7bb28 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -90,7 +90,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
 						  pr->performance_platform_limit);
 		break;
 	case ACPI_PROCESSOR_NOTIFY_POWER:
-		acpi_processor_cst_has_changed(pr);
+		acpi_processor_power_state_has_changed(pr);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index ca0de35d1c3a..98e8c62a961c 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -303,7 +303,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *cst;
 
-
 	if (nocst)
 		return -ENODEV;
 
@@ -576,7 +575,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
 	return (working);
 }
 
-static int acpi_processor_get_power_info(struct acpi_processor *pr)
+static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
 {
 	unsigned int i;
 	int result;
@@ -810,31 +809,12 @@ static void acpi_idle_enter_freeze(struct cpuidle_device *dev,
 	acpi_idle_do_entry(cx);
 }
 
-/**
- * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE
- * device i.e. per-cpu data
- *
- * @pr: the ACPI processor
- * @dev : the cpuidle device
- */
 static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 					   struct cpuidle_device *dev)
 {
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
 
-	if (!pr->flags.power_setup_done)
-		return -EINVAL;
-
-	if (pr->flags.power == 0) {
-		return -EINVAL;
-	}
-
-	if (!dev)
-		return -EINVAL;
-
-	dev->cpu = pr->id;
-
 	if (max_cstate == 0)
 		max_cstate = 1;
 
@@ -857,31 +837,13 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 	return 0;
 }
 
-/**
- * acpi_processor_setup_cpuidle states- prepares and configures cpuidle
- * global state data i.e. idle routines
- *
- * @pr: the ACPI processor
- */
-static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+static int acpi_processor_setup_cstates(struct acpi_processor *pr)
 {
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
 	struct cpuidle_state *state;
 	struct cpuidle_driver *drv = &acpi_idle_driver;
 
-	if (!pr->flags.power_setup_done)
-		return -EINVAL;
-
-	if (pr->flags.power == 0)
-		return -EINVAL;
-
-	drv->safe_state_index = -1;
-	for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) {
-		drv->states[i].name[0] = '\0';
-		drv->states[i].desc[0] = '\0';
-	}
-
 	if (max_cstate == 0)
 		max_cstate = 1;
 
@@ -893,7 +855,7 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
 
 		state = &drv->states[count];
 		snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
-		strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
+		strlcpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
 		state->exit_latency = cx->latency;
 		state->target_residency = cx->latency * latency_factor;
 		state->enter = acpi_idle_enter;
@@ -952,7 +914,7 @@ static inline void acpi_processor_cstate_first_run_checks(void)
 
 static inline int disabled_by_idle_boot_param(void) { return 0; }
 static inline void acpi_processor_cstate_first_run_checks(void) { }
-static int acpi_processor_get_power_info(struct acpi_processor *pr)
+static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
 {
 	return -ENODEV;
 }
@@ -963,13 +925,415 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 	return -EINVAL;
 }
 
-static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+static int acpi_processor_setup_cstates(struct acpi_processor *pr)
 {
 	return -EINVAL;
 }
 
 #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
 
+struct acpi_lpi_states_array {
+	unsigned int size;
+	struct acpi_lpi_state *entries;
+};
+
+static int obj_get_integer(union acpi_object *obj, u32 *value)
+{
+	if (obj->type != ACPI_TYPE_INTEGER)
+		return -EINVAL;
+
+	*value = obj->integer.value;
+	return 0;
+}
+
+static int acpi_processor_evaluate_lpi(acpi_handle handle,
+				       struct acpi_lpi_states_array *info)
+{
+	acpi_status status;
+	int ret = 0;
+	int pkg_count, state_idx = 1, loop;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *lpi_data;
+	struct acpi_lpi_state *lpi_state;
+
+	status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _LPI, giving up\n"));
+		return -ENODEV;
+	}
+
+	lpi_data = buffer.pointer;
+
+	/* There must be at least 4 elements = 3 elements + 1 package */
+	if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
+	    lpi_data->package.count < 4) {
+		pr_debug("not enough elements in _LPI\n");
+		ret = -ENODATA;
+		goto end;
+	}
+
+	pkg_count = lpi_data->package.elements[2].integer.value;
+
+	/* Validate number of power states. */
+	if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) {
+		pr_debug("count given by _LPI is not valid\n");
+		ret = -ENODATA;
+		goto end;
+	}
+
+	lpi_state = kcalloc(pkg_count, sizeof(*lpi_state), GFP_KERNEL);
+	if (!lpi_state) {
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	info->size = pkg_count;
+	info->entries = lpi_state;
+
+	/* LPI States start at index 3 */
+	for (loop = 3; state_idx <= pkg_count;
+	     loop++, state_idx++, lpi_state++) {
+		union acpi_object *element, *pkg_elem, *obj;
+
+		element = &lpi_data->package.elements[loop];
+		if (element->type != ACPI_TYPE_PACKAGE)
+			continue;
+
+		if (element->package.count < 7)
+			continue;
+
+		pkg_elem = element->package.elements;
+
+		obj = pkg_elem + 6;
+		if (obj->type == ACPI_TYPE_BUFFER) {
+			struct acpi_power_register *reg;
+
+			reg = (struct acpi_power_register *)obj->buffer.pointer;
+			if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&
+			    (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
+				continue;
+
+			lpi_state->address = reg->address;
+
+			if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
+				lpi_state->entry_method = ACPI_CSTATE_FFH;
+			else
+				lpi_state->entry_method = ACPI_CSTATE_SYSTEMIO;
+		} else if (obj->type == ACPI_TYPE_INTEGER) {
+			lpi_state->entry_method = ACPI_CSTATE_INTEGER;
+			lpi_state->address = obj->integer.value;
+		} else {
+			continue;
+		}
+
+		/* elements[7,8] skipped for now i.e. Residency/Usage counter*/
+
+		obj = pkg_elem + 9;
+		if (obj->type == ACPI_TYPE_STRING)
+			strlcpy(lpi_state->desc, obj->string.pointer,
+				ACPI_CX_DESC_LEN);
+
+		lpi_state->index = state_idx;
+		if (obj_get_integer(pkg_elem + 0, &lpi_state->min_residency)) {
+			pr_debug("No min. residency found, assuming 10 us\n");
+			lpi_state->min_residency = 10;
+		}
+
+		if (obj_get_integer(pkg_elem + 1, &lpi_state->wake_latency)) {
+			pr_debug("No wakeup residency found, assuming 10 us\n");
+			lpi_state->wake_latency = 10;
+		}
+
+		if (obj_get_integer(pkg_elem + 2, &lpi_state->flags))
+			lpi_state->flags = 0;
+
+		if (obj_get_integer(pkg_elem + 3, &lpi_state->arch_flags))
+			lpi_state->arch_flags = 0;
+
+		if (obj_get_integer(pkg_elem + 4, &lpi_state->res_cnt_freq))
+			lpi_state->res_cnt_freq = 1;
+
+		if (obj_get_integer(pkg_elem + 5, &lpi_state->enable_parent_state))
+			lpi_state->enable_parent_state = 0;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n",
+			  state_idx));
+end:
+	kfree(buffer.pointer);
+	return ret;
+}
+
+/*
+ * max_leaf_depth - holds the depth of the processor hierarchy/tree
+ * flat_state_cnt - the number of composite LPI states after the process of flattening
+ */
+static int max_leaf_depth, flat_state_cnt;
+
+/**
+ * combine_lpi_states - combine local and parent LPI states to form a composite LPI state
+ *
+ * @local: local LPI state
+ * @parent: parent LPI state
+ * @result: composite LPI state
+ */
+static bool combine_lpi_states(struct acpi_lpi_state *local,
+			       struct acpi_lpi_state *parent,
+			       struct acpi_lpi_state *result)
+{
+	if (parent->entry_method == ACPI_CSTATE_INTEGER) {
+		if (!parent->address) /* 0 means autopromotable */
+			return false;
+		result->address = local->address + parent->address;
+	} else {
+		result->address = parent->address;
+	}
+
+	result->min_residency = max(local->min_residency, parent->min_residency);
+	result->wake_latency = local->wake_latency + parent->wake_latency;
+	result->enable_parent_state = parent->enable_parent_state;
+	result->entry_method = local->entry_method;
+
+	result->flags = parent->flags;
+	result->arch_flags = parent->arch_flags;
+
+	strlcpy(result->desc, local->desc, ACPI_CX_DESC_LEN);
+	strlcat(result->desc, "+", ACPI_CX_DESC_LEN);
+	strlcat(result->desc, parent->desc, ACPI_CX_DESC_LEN);
+	return true;
+}
+
+#define ACPI_LPI_STATE_FLAGS_ENABLED			BIT(0)
+
+static int flatten_lpi_states(struct acpi_processor *pr,
+			      struct acpi_lpi_states_array *info,
+			      struct acpi_lpi_state *lpi,
+			      uint32_t depth)
+{
+	int j, state_count = info[depth].size;
+	struct acpi_lpi_state *t = info[depth].entries;
+
+	for (j = 0; j < state_count; j++, t++) {
+		struct acpi_lpi_state *flpi;
+		bool valid = false;
+
+		if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED))
+			continue;
+
+		flpi = &pr->power.lpi_states[flat_state_cnt];
+
+		if (depth == max_leaf_depth) { /* leaf/processor node */
+			memcpy(flpi, t, sizeof(*t));
+			flpi->index = flat_state_cnt++;
+			valid = true;
+		} else if (lpi && t->index <= lpi->enable_parent_state) {
+			if (combine_lpi_states(lpi, t, flpi)) {
+				flpi->index = flat_state_cnt++;
+				valid = true;
+			}
+		}
+
+		/*
+		 * flatten recursively from leaf until the highest level
+		 * (e.g. system) is reached
+		 */
+		if (valid && depth)
+			flatten_lpi_states(pr, info, flpi, depth - 1);
+	}
+	return 0;
+}
+
+static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
+{
+	int ret, i;
+	struct acpi_lpi_states_array *info;
+	struct acpi_device *d = NULL;
+	acpi_handle handle = pr->handle, pr_ahandle;
+	acpi_status status;
+
+	if (!osc_pc_lpi_support_confirmed)
+		return -EOPNOTSUPP;
+
+	max_leaf_depth = 0;
+	if (!acpi_has_method(handle, "_LPI"))
+		return -EINVAL;
+	flat_state_cnt = 0;
+
+	while (ACPI_SUCCESS(status = acpi_get_parent(handle, &pr_ahandle))) {
+		acpi_bus_get_device(pr_ahandle, &d);
+		handle = pr_ahandle;
+
+		if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
+			break;
+
+		if (!acpi_has_method(pr_ahandle, "_LPI"))
+			break;
+
+		max_leaf_depth++;
+	}
+
+	info = kcalloc(max_leaf_depth + 1, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	pr_ahandle = pr->handle;
+	for (i = max_leaf_depth; i >= 0 && ACPI_SUCCESS(status); i--) {
+		handle = pr_ahandle;
+		ret = acpi_processor_evaluate_lpi(handle, info + i);
+		if (ret)
+			break;
+
+		status = acpi_get_parent(handle, &pr_ahandle);
+	}
+
+	/* flatten all the LPI states in the entire hierarchy */
+	flatten_lpi_states(pr, info, NULL, max_leaf_depth);
+
+	pr->power.count = flat_state_cnt;
+
+	for (i = 0; i <= max_leaf_depth; i++)
+		kfree(info[i].entries);
+
+	kfree(info);
+
+	/* Tell driver that _LPI is supported. */
+	pr->flags.has_lpi = 1;
+	pr->flags.power = 1;
+
+	return 0;
+}
+
+int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
+{
+	return -ENODEV;
+}
+
+int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
+{
+	return -ENODEV;
+}
+
+/**
+ * acpi_idle_lpi_enter - enters an ACPI any LPI state
+ * @dev: the target CPU
+ * @drv: cpuidle driver containing cpuidle state info
+ * @index: index of target state
+ *
+ * Return: 0 for success or negative value for error
+ */
+static int acpi_idle_lpi_enter(struct cpuidle_device *dev,
+			       struct cpuidle_driver *drv, int index)
+{
+	struct acpi_processor *pr;
+	struct acpi_lpi_state *lpi;
+
+	pr = __this_cpu_read(processors);
+
+	if (unlikely(!pr))
+		return -EINVAL;
+
+	lpi = &pr->power.lpi_states[index];
+	if (lpi->entry_method == ACPI_CSTATE_FFH)
+		return acpi_processor_ffh_lpi_enter(lpi);
+
+	return -EINVAL;
+}
+
+static int acpi_processor_setup_lpi_states(struct acpi_processor *pr)
+{
+	int i;
+	struct acpi_lpi_state *lpi;
+	struct cpuidle_state *state;
+	struct cpuidle_driver *drv = &acpi_idle_driver;
+
+	if (!pr->flags.has_lpi)
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < flat_state_cnt && i < CPUIDLE_STATE_MAX; i++) {
+		lpi = &pr->power.lpi_states[i];
+
+		state = &drv->states[i];
+		snprintf(state->name, CPUIDLE_NAME_LEN, "LPI-%d", i);
+		strlcpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN);
+		state->exit_latency = lpi->wake_latency;
+		state->target_residency = lpi->min_residency;
+		if (lpi->arch_flags)
+			state->flags |= CPUIDLE_FLAG_TIMER_STOP;
+		state->enter = acpi_idle_lpi_enter;
+		drv->safe_state_index = i;
+	}
+
+	drv->state_count = i;
+
+	return 0;
+}
+
+/**
+ * acpi_processor_setup_cpuidle_states- prepares and configures cpuidle
+ * global state data i.e. idle routines
+ *
+ * @pr: the ACPI processor
+ */
+static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+{
+	int i;
+	struct cpuidle_driver *drv = &acpi_idle_driver;
+
+	if (!pr->flags.power_setup_done)
+		return -EINVAL;
+
+	if (pr->flags.power == 0)
+		return -EINVAL;
+
+	drv->safe_state_index = -1;
+	for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) {
+		drv->states[i].name[0] = '\0';
+		drv->states[i].desc[0] = '\0';
+	}
+
+	if (pr->flags.has_lpi)
+		return acpi_processor_setup_lpi_states(pr);
+
+	return acpi_processor_setup_cstates(pr);
+}
+
+/**
+ * acpi_processor_setup_cpuidle_dev - prepares and configures CPUIDLE
+ * device i.e. per-cpu data
+ *
+ * @pr: the ACPI processor
+ * @dev : the cpuidle device
+ */
+static int acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr,
+					    struct cpuidle_device *dev)
+{
+	if (!pr->flags.power_setup_done)
+		return -EINVAL;
+
+	if (pr->flags.power == 0)
+		return -EINVAL;
+
+	if (!dev)
+		return -EINVAL;
+
+	dev->cpu = pr->id;
+	if (pr->flags.has_lpi)
+		return acpi_processor_ffh_lpi_probe(pr->id);
+
+	return acpi_processor_setup_cpuidle_cx(pr, dev);
+}
+
+static int acpi_processor_get_power_info(struct acpi_processor *pr)
+{
+	int ret;
+
+	ret = acpi_processor_get_lpi_info(pr);
+	if (ret)
+		ret = acpi_processor_get_cstate_info(pr);
+
+	return ret;
+}
+
 int acpi_processor_hotplug(struct acpi_processor *pr)
 {
 	int ret = 0;
@@ -978,18 +1342,15 @@ int acpi_processor_hotplug(struct acpi_processor *pr)
 	if (disabled_by_idle_boot_param())
 		return 0;
 
-	if (nocst)
-		return -ENODEV;
-
 	if (!pr->flags.power_setup_done)
 		return -ENODEV;
 
 	dev = per_cpu(acpi_cpuidle_device, pr->id);
 	cpuidle_pause_and_lock();
 	cpuidle_disable_device(dev);
-	acpi_processor_get_power_info(pr);
-	if (pr->flags.power) {
-		acpi_processor_setup_cpuidle_cx(pr, dev);
+	ret = acpi_processor_get_power_info(pr);
+	if (!ret && pr->flags.power) {
+		acpi_processor_setup_cpuidle_dev(pr, dev);
 		ret = cpuidle_enable_device(dev);
 	}
 	cpuidle_resume_and_unlock();
@@ -997,7 +1358,7 @@ int acpi_processor_hotplug(struct acpi_processor *pr)
 	return ret;
 }
 
-int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
 {
 	int cpu;
 	struct acpi_processor *_pr;
@@ -1006,9 +1367,6 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
 	if (disabled_by_idle_boot_param())
 		return 0;
 
-	if (nocst)
-		return -ENODEV;
-
 	if (!pr->flags.power_setup_done)
 		return -ENODEV;
 
@@ -1045,7 +1403,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
 			acpi_processor_get_power_info(_pr);
 			if (_pr->flags.power) {
 				dev = per_cpu(acpi_cpuidle_device, cpu);
-				acpi_processor_setup_cpuidle_cx(_pr, dev);
+				acpi_processor_setup_cpuidle_dev(_pr, dev);
 				cpuidle_enable_device(dev);
 			}
 		}
@@ -1092,7 +1450,7 @@ int acpi_processor_power_init(struct acpi_processor *pr)
 			return -ENOMEM;
 		per_cpu(acpi_cpuidle_device, pr->id) = dev;
 
-		acpi_processor_setup_cpuidle_cx(pr, dev);
+		acpi_processor_setup_cpuidle_dev(pr, dev);
 
 		/* Register per-cpu cpuidle_device. Cpuidle driver
 		 * must already be registered before registering device
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 48779d678122..e2dcb0c51554 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -39,6 +39,7 @@
 #define ACPI_CSTATE_SYSTEMIO	0
 #define ACPI_CSTATE_FFH		1
 #define ACPI_CSTATE_HALT	2
+#define ACPI_CSTATE_INTEGER	3
 
 #define ACPI_CX_DESC_LEN	32
 
@@ -67,9 +68,25 @@ struct acpi_processor_cx {
 	char desc[ACPI_CX_DESC_LEN];
 };
 
+struct acpi_lpi_state {
+	u32 min_residency;
+	u32 wake_latency; /* worst case */
+	u32 flags;
+	u32 arch_flags;
+	u32 res_cnt_freq;
+	u32 enable_parent_state;
+	u64 address;
+	u8 index;
+	u8 entry_method;
+	char desc[ACPI_CX_DESC_LEN];
+};
+
 struct acpi_processor_power {
 	int count;
-	struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
+	union {
+		struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
+		struct acpi_lpi_state lpi_states[ACPI_PROCESSOR_MAX_POWER];
+	};
 	int timer_broadcast_on_state;
 };
 
@@ -189,6 +206,7 @@ struct acpi_processor_flags {
 	u8 bm_control:1;
 	u8 bm_check:1;
 	u8 has_cst:1;
+	u8 has_lpi:1;
 	u8 power_setup_done:1;
 	u8 bm_rld_set:1;
 	u8 need_hotplug_init:1;
@@ -371,7 +389,7 @@ extern struct cpuidle_driver acpi_idle_driver;
 #ifdef CONFIG_ACPI_PROCESSOR_IDLE
 int acpi_processor_power_init(struct acpi_processor *pr);
 int acpi_processor_power_exit(struct acpi_processor *pr);
-int acpi_processor_cst_has_changed(struct acpi_processor *pr);
+int acpi_processor_power_state_has_changed(struct acpi_processor *pr);
 int acpi_processor_hotplug(struct acpi_processor *pr);
 #else
 static inline int acpi_processor_power_init(struct acpi_processor *pr)
@@ -384,7 +402,7 @@ static inline int acpi_processor_power_exit(struct acpi_processor *pr)
 	return -ENODEV;
 }
 
-static inline int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+static inline int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
 {
 	return -ENODEV;
 }
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 288fac5294f5..65754566ae17 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -444,8 +444,12 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 #define OSC_SB_HOTPLUG_OST_SUPPORT		0x00000008
 #define OSC_SB_APEI_SUPPORT			0x00000010
 #define OSC_SB_CPC_SUPPORT			0x00000020
+#define OSC_SB_CPCV2_SUPPORT			0x00000040
+#define OSC_SB_PCLPI_SUPPORT			0x00000080
+#define OSC_SB_OSLPI_SUPPORT			0x00000100
 
 extern bool osc_sb_apei_support_acked;
+extern bool osc_pc_lpi_support_confirmed;
 
 /* PCI Host Bridge _OSC: Capabilities DWORD 2: Support Field */
 #define OSC_PCI_EXT_CONFIG_SUPPORT		0x00000001
-- 
2.7.4

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-14 14:48 ` [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI) Sudeep Holla
@ 2016-06-22 14:17   ` Lorenzo Pieralisi
  2016-06-24 21:04     ` Daniel Lezcano
  2016-06-27 16:29     ` Daniel Lezcano
  0 siblings, 2 replies; 27+ messages in thread
From: Lorenzo Pieralisi @ 2016-06-22 14:17 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Rafael J . Wysocki, linux-acpi, Vikas Sajjan, Sunil,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, Daniel Lezcano, linux-arm-kernel

Hi Sudeep,

On Tue, Jun 14, 2016 at 03:48:38PM +0100, Sudeep Holla wrote:
> This patch adds appropriate callbacks to support ACPI Low Power Idle
> (LPI) on ARM64.
> 
> Now that arm_enter_idle_state is exactly same in both generic ARM{32,64}
> CPUIdle driver and ARM64 backend for ACPI processor idle driver, we can
> unify it and move to cpuidle-arm.h header.
> 
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> Cc: linux-arm-kernel@lists.infradead.org
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> ---
>  arch/arm64/kernel/cpuidle.c   | 17 +++++++++++++
>  drivers/cpuidle/cpuidle-arm.c | 23 ++----------------
>  drivers/firmware/psci.c       | 56 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/cpuidle-arm.h   | 30 +++++++++++++++++++++++
>  4 files changed, 105 insertions(+), 21 deletions(-)
>  create mode 100644 include/linux/cpuidle-arm.h

This patch seems fine by me, it would be good if Daniel can have
a look too.

Some minor comments below.

[...]

> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> index 03e04582791c..c6caa863d156 100644
> --- a/drivers/firmware/psci.c
> +++ b/drivers/firmware/psci.c
> @@ -13,6 +13,7 @@
>  
>  #define pr_fmt(fmt) "psci: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/arm-smccc.h>
>  #include <linux/cpuidle.h>
>  #include <linux/errno.h>
> @@ -310,11 +311,66 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
>  	return ret;
>  }
>  
> +#ifdef CONFIG_ACPI
> +#include <acpi/processor.h>
> +
> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
> +{
> +	int i, count;
> +	u32 *psci_states;
> +	struct acpi_processor *pr;
> +	struct acpi_lpi_state *lpi;
> +
> +	pr = per_cpu(processors, cpu);
> +	if (unlikely(!pr || !pr->flags.has_lpi))
> +		return -EINVAL;
> +
> +	/*
> +	 * If the PSCI cpu_suspend function hook has not been initialized
> +	 * idle states must not be enabled, so bail out
> +	 */
> +	if (!psci_ops.cpu_suspend)
> +		return -EOPNOTSUPP;
> +
> +	count = pr->power.count - 1;
> +	if (count <= 0)
> +		return -ENODEV;
> +
> +	psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
> +	if (!psci_states)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < count; i++) {
> +		u32 state;
> +
> +		lpi = &pr->power.lpi_states[i + 1];
> +		state = lpi->address & 0xFFFFFFFF;
> +		if (!psci_power_state_is_valid(state)) {
> +			pr_warn("Invalid PSCI power state %#x\n", state);
> +			kfree(psci_states);
> +			return -EINVAL;
> +		}
> +		psci_states[i] = state;
> +	}
> +	/* Idle states parsed correctly, initialize per-cpu pointer */
> +	per_cpu(psci_power_state, cpu) = psci_states;
> +	return 0;

Most of the code in this function is FW independent, it would be nice
to factor it out and add the respective ACPI/DT helper functions to
retrieve idle states count and parameters, we can update it later
anyway it is fine by me to leave it as it is.

> +}
> +#else
> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
> +{
> +	return -EINVAL;
> +}
> +#endif
> +
>  int psci_cpu_init_idle(unsigned int cpu)
>  {
>  	struct device_node *cpu_node;
>  	int ret;
>  
> +	if (!acpi_disabled)
> +		return psci_acpi_cpu_init_idle(cpu);
> +
>  	cpu_node = of_get_cpu_node(cpu, NULL);
>  	if (!cpu_node)
>  		return -ENODEV;
> diff --git a/include/linux/cpuidle-arm.h b/include/linux/cpuidle-arm.h
> new file mode 100644
> index 000000000000..b99bcb3f43dd
> --- /dev/null
> +++ b/include/linux/cpuidle-arm.h

arm-cpuidle.h for consistency with other (ARM) include/linux files ?

> @@ -0,0 +1,30 @@
> +#include <linux/cpu_pm.h>
> +
> +#include <asm/cpuidle.h>
> +
> +/*
> + * arm_enter_idle_state - Programs CPU to enter the specified state
> + */
> +static int arm_generic_enter_idle_state(int idx)
> +{
> +	int ret;
> +
> +	if (!idx) {
> +		cpu_do_idle();
> +		return idx;
> +	}
> +
> +	ret = cpu_pm_enter();
> +	if (!ret) {
> +		/*
> +		 * Pass idle state index to cpu_suspend which in turn will
> +		 * call the CPU ops suspend protocol with idle index as a
> +		 * parameter.
> +		 */
> +		ret = arm_cpuidle_suspend(idx);
> +
> +		cpu_pm_exit();
> +	}
> +
> +	return ret ? -1 : idx;
> +}

Either you do this, or we have to add it somehow somewhere in
drivers/cpuidle to avoid duplicating it.

@Daniel: do you have an opinion on this please ?

Thanks,
Lorenzo

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

* Re: [PATCH v6 3/5] arm64: cpuidle: drop __init section marker to arm_cpuidle_init
  2016-06-14 14:48 ` [PATCH v6 3/5] arm64: cpuidle: drop __init section marker to arm_cpuidle_init Sudeep Holla
@ 2016-06-22 16:09   ` Lorenzo Pieralisi
  0 siblings, 0 replies; 27+ messages in thread
From: Lorenzo Pieralisi @ 2016-06-22 16:09 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Rafael J . Wysocki, linux-acpi, Vikas Sajjan, Sunil,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, linux-arm-kernel

On Tue, Jun 14, 2016 at 03:48:37PM +0100, Sudeep Holla wrote:
> Commit ea389daa7fd9 ("arm64: cpuidle: add __init section marker to
> arm_cpuidle_init") added the __init annotation to arm_cpuidle_init
> as it was not needed after booting which was correct at that time.
> 
> However with the introduction of ACPI LPI support, this will be used
> from cpuhotplug path in ACPI processor driver.
> 
> This patch drops the __init annotation from arm_cpuidle_init to avoid
> the following warning:
> 
> WARNING: vmlinux.o(.text+0x113c8): Section mismatch in reference from the
> 	function acpi_processor_ffh_lpi_probe() to the function
> 	.init.text:arm_cpuidle_init()
> The function acpi_processor_ffh_lpi_probe() references
> the function __init arm_cpuidle_init().
> This is often because acpi_processor_ffh_lpi_probe lacks a __init
> annotation or the annotation of arm_cpuidle_init is wrong.
> 
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: linux-arm-kernel@lists.infradead.org
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

Depending on acceptance of other patches in this series:

Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

> ---
>  arch/arm64/kernel/cpuidle.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c
> index e11857fce05f..06786fdaadeb 100644
> --- a/arch/arm64/kernel/cpuidle.c
> +++ b/arch/arm64/kernel/cpuidle.c
> @@ -15,7 +15,7 @@
>  #include <asm/cpuidle.h>
>  #include <asm/cpu_ops.h>
>  
> -int __init arm_cpuidle_init(unsigned int cpu)
> +int arm_cpuidle_init(unsigned int cpu)
>  {
>  	int ret = -EOPNOTSUPP;
>  
> -- 
> 2.7.4
> 

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

* Re: [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support
  2016-06-14 14:48 [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
                   ` (4 preceding siblings ...)
  2016-06-14 14:48 ` [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64 Sudeep Holla
@ 2016-06-22 17:45 ` Sudeep Holla
  2016-06-23  0:42   ` Rafael J. Wysocki
  5 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-22 17:45 UTC (permalink / raw)
  To: Rafael J . Wysocki
  Cc: linux-acpi, Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel

Hi Rafael,

On 14/06/16 15:48, Sudeep Holla wrote:
> ACPI 6.0 introduced LPI(Low Power Idle) states that provides an alternate
> method to describe processor idle states. It extends the specification
> to allow the expression of idle states like C-states selectable by the
> OSPM when a processor goes idle, but may affect more than one processor,
> and may affect other system components.
>
> LPI extensions leverages the processor container device(again introduced
> in ACPI 6.0) allowing to express which parts of the system are affected
> by a given LPI state. It defines the local power states for each node
> in a hierarchical processor topology. The OSPM can use _LPI object to
> select a local power state for each level of processor hierarchy in the
> system. They used to produce a composite power state request that is
> presented to the platform by the OSPM.
>
> Since multiple processors affect the idle state for any non-leaf hierarchy
> node, coordination of idle state requests between the processors is
> required. ACPI supports two different coordination schemes: Platform
> coordinated and  OS initiated.
>
> This series aims at providing basic and initial support for platform
> coordinated LPI states.
>

Gentle ping, was hoping to target this series for v4.8

-- 
Regards,
Sudeep

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

* Re: [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support
  2016-06-22 17:45 ` [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
@ 2016-06-23  0:42   ` Rafael J. Wysocki
  2016-06-25  0:23     ` Rafael J. Wysocki
  0 siblings, 1 reply; 27+ messages in thread
From: Rafael J. Wysocki @ 2016-06-23  0:42 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-acpi, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel

On Wednesday, June 22, 2016 06:45:15 PM Sudeep Holla wrote:
> Hi Rafael,
> 
> On 14/06/16 15:48, Sudeep Holla wrote:
> > ACPI 6.0 introduced LPI(Low Power Idle) states that provides an alternate
> > method to describe processor idle states. It extends the specification
> > to allow the expression of idle states like C-states selectable by the
> > OSPM when a processor goes idle, but may affect more than one processor,
> > and may affect other system components.
> >
> > LPI extensions leverages the processor container device(again introduced
> > in ACPI 6.0) allowing to express which parts of the system are affected
> > by a given LPI state. It defines the local power states for each node
> > in a hierarchical processor topology. The OSPM can use _LPI object to
> > select a local power state for each level of processor hierarchy in the
> > system. They used to produce a composite power state request that is
> > presented to the platform by the OSPM.
> >
> > Since multiple processors affect the idle state for any non-leaf hierarchy
> > node, coordination of idle state requests between the processors is
> > required. ACPI supports two different coordination schemes: Platform
> > coordinated and  OS initiated.
> >
> > This series aims at providing basic and initial support for platform
> > coordinated LPI states.
> >
> 
> Gentle ping, was hoping to target this series for v4.8

On my list of things to take care of this week.  But this is a long list ...

Thanks,
Rafael

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-22 14:17   ` Lorenzo Pieralisi
@ 2016-06-24 21:04     ` Daniel Lezcano
  2016-06-24 22:47       ` Rafael J. Wysocki
  2016-06-27  9:50       ` Sudeep Holla
  2016-06-27 16:29     ` Daniel Lezcano
  1 sibling, 2 replies; 27+ messages in thread
From: Daniel Lezcano @ 2016-06-24 21:04 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Sudeep Holla
  Cc: Rafael J . Wysocki, linux-acpi, Vikas Sajjan, Sunil,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, linux-arm-kernel

On 06/22/2016 04:17 PM, Lorenzo Pieralisi wrote:
> Hi Sudeep,
>
> On Tue, Jun 14, 2016 at 03:48:38PM +0100, Sudeep Holla wrote:
>> This patch adds appropriate callbacks to support ACPI Low Power Idle
>> (LPI) on ARM64.
>>
>> Now that arm_enter_idle_state is exactly same in both generic ARM{32,64}
>> CPUIdle driver and ARM64 backend for ACPI processor idle driver, we can
>> unify it and move to cpuidle-arm.h header.
>>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>> Cc: linux-arm-kernel@lists.infradead.org
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> ---
>>   arch/arm64/kernel/cpuidle.c   | 17 +++++++++++++
>>   drivers/cpuidle/cpuidle-arm.c | 23 ++----------------
>>   drivers/firmware/psci.c       | 56 +++++++++++++++++++++++++++++++++++++++++++
>>   include/linux/cpuidle-arm.h   | 30 +++++++++++++++++++++++
>>   4 files changed, 105 insertions(+), 21 deletions(-)
>>   create mode 100644 include/linux/cpuidle-arm.h
>
> This patch seems fine by me, it would be good if Daniel can have
> a look too.
>
> Some minor comments below.
>
> [...]
>
>> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
>> index 03e04582791c..c6caa863d156 100644
>> --- a/drivers/firmware/psci.c
>> +++ b/drivers/firmware/psci.c
>> @@ -13,6 +13,7 @@
>>
>>   #define pr_fmt(fmt) "psci: " fmt
>>
>> +#include <linux/acpi.h>
>>   #include <linux/arm-smccc.h>
>>   #include <linux/cpuidle.h>
>>   #include <linux/errno.h>
>> @@ -310,11 +311,66 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
>>   	return ret;
>>   }
>>
>> +#ifdef CONFIG_ACPI
>> +#include <acpi/processor.h>
>> +
>> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
>> +{
>> +	int i, count;
>> +	u32 *psci_states;
>> +	struct acpi_processor *pr;
>> +	struct acpi_lpi_state *lpi;
>> +
>> +	pr = per_cpu(processors, cpu);
>> +	if (unlikely(!pr || !pr->flags.has_lpi))
>> +		return -EINVAL;
>> +
>> +	/*
>> +	 * If the PSCI cpu_suspend function hook has not been initialized
>> +	 * idle states must not be enabled, so bail out
>> +	 */
>> +	if (!psci_ops.cpu_suspend)
>> +		return -EOPNOTSUPP;
>> +
>> +	count = pr->power.count - 1;
>> +	if (count <= 0)
>> +		return -ENODEV;
>> +
>> +	psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
>> +	if (!psci_states)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < count; i++) {
>> +		u32 state;
>> +
>> +		lpi = &pr->power.lpi_states[i + 1];
>> +		state = lpi->address & 0xFFFFFFFF;

Why is needed to mask 'address' ?

>> +		if (!psci_power_state_is_valid(state)) {
>> +			pr_warn("Invalid PSCI power state %#x\n", state);
>> +			kfree(psci_states);
>> +			return -EINVAL;
>> +		}
>> +		psci_states[i] = state;
>> +	}
>> +	/* Idle states parsed correctly, initialize per-cpu pointer */
>> +	per_cpu(psci_power_state, cpu) = psci_states;
>> +	return 0;
>
> Most of the code in this function is FW independent, it would be nice
> to factor it out and add the respective ACPI/DT helper functions to
> retrieve idle states count and parameters, we can update it later
> anyway it is fine by me to leave it as it is.
>
>> +}
>> +#else
>> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
>> +{
>> +	return -EINVAL;
>> +}
>> +#endif
>> +
>>   int psci_cpu_init_idle(unsigned int cpu)
>>   {
>>   	struct device_node *cpu_node;
>>   	int ret;
>>
>> +	if (!acpi_disabled)
>> +		return psci_acpi_cpu_init_idle(cpu);

Is it possible the case where there is information in both the DT and in 
ACPI ? So ACPI is enabled without idle information which is in the DT ?

>>   	cpu_node = of_get_cpu_node(cpu, NULL);
>>   	if (!cpu_node)
>>   		return -ENODEV;
>> diff --git a/include/linux/cpuidle-arm.h b/include/linux/cpuidle-arm.h
>> new file mode 100644
>> index 000000000000..b99bcb3f43dd
>> --- /dev/null
>> +++ b/include/linux/cpuidle-arm.h
>
> arm-cpuidle.h for consistency with other (ARM) include/linux files ?
>
>> @@ -0,0 +1,30 @@
>> +#include <linux/cpu_pm.h>
>> +
>> +#include <asm/cpuidle.h>
>> +
>> +/*
>> + * arm_enter_idle_state - Programs CPU to enter the specified state
>> + */
>> +static int arm_generic_enter_idle_state(int idx)
>> +{
>> +	int ret;
>> +
>> +	if (!idx) {
>> +		cpu_do_idle();
>> +		return idx;
>> +	}
>> +
>> +	ret = cpu_pm_enter();
>> +	if (!ret) {
>> +		/*
>> +		 * Pass idle state index to cpu_suspend which in turn will
>> +		 * call the CPU ops suspend protocol with idle index as a
>> +		 * parameter.
>> +		 */
>> +		ret = arm_cpuidle_suspend(idx);
>> +
>> +		cpu_pm_exit();
>> +	}
>> +
>> +	return ret ? -1 : idx;
>> +}
>
> Either you do this, or we have to add it somehow somewhere in
> drivers/cpuidle to avoid duplicating it.
>
> @Daniel: do you have an opinion on this please ?

Yes, this function should be added to avoid duplication.

  -- Daniel


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-24 21:04     ` Daniel Lezcano
@ 2016-06-24 22:47       ` Rafael J. Wysocki
  2016-06-25  8:05         ` Daniel Lezcano
  2016-06-27  9:50       ` Sudeep Holla
  1 sibling, 1 reply; 27+ messages in thread
From: Rafael J. Wysocki @ 2016-06-24 22:47 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Lorenzo Pieralisi, Sudeep Holla, linux-acpi, Vikas Sajjan, Sunil,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, linux-arm-kernel

On Friday, June 24, 2016 11:04:07 PM Daniel Lezcano wrote:
> On 06/22/2016 04:17 PM, Lorenzo Pieralisi wrote:
> > Hi Sudeep,
> >
> > On Tue, Jun 14, 2016 at 03:48:38PM +0100, Sudeep Holla wrote:
> >> This patch adds appropriate callbacks to support ACPI Low Power Idle
> >> (LPI) on ARM64.
> >>
> >> Now that arm_enter_idle_state is exactly same in both generic ARM{32,64}
> >> CPUIdle driver and ARM64 backend for ACPI processor idle driver, we can
> >> unify it and move to cpuidle-arm.h header.
> >>
> >> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> >> Cc: Mark Rutland <mark.rutland@arm.com>
> >> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> >> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> >> Cc: linux-arm-kernel@lists.infradead.org
> >> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> >> ---
> >>   arch/arm64/kernel/cpuidle.c   | 17 +++++++++++++
> >>   drivers/cpuidle/cpuidle-arm.c | 23 ++----------------
> >>   drivers/firmware/psci.c       | 56 +++++++++++++++++++++++++++++++++++++++++++
> >>   include/linux/cpuidle-arm.h   | 30 +++++++++++++++++++++++
> >>   4 files changed, 105 insertions(+), 21 deletions(-)
> >>   create mode 100644 include/linux/cpuidle-arm.h
> >
> > This patch seems fine by me, it would be good if Daniel can have
> > a look too.
> >
> > Some minor comments below.
> >
> > [...]
> >
> >> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> >> index 03e04582791c..c6caa863d156 100644
> >> --- a/drivers/firmware/psci.c
> >> +++ b/drivers/firmware/psci.c
> >> @@ -13,6 +13,7 @@
> >>
> >>   #define pr_fmt(fmt) "psci: " fmt
> >>
> >> +#include <linux/acpi.h>
> >>   #include <linux/arm-smccc.h>
> >>   #include <linux/cpuidle.h>
> >>   #include <linux/errno.h>
> >> @@ -310,11 +311,66 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
> >>   	return ret;
> >>   }
> >>
> >> +#ifdef CONFIG_ACPI
> >> +#include <acpi/processor.h>
> >> +
> >> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
> >> +{
> >> +	int i, count;
> >> +	u32 *psci_states;
> >> +	struct acpi_processor *pr;
> >> +	struct acpi_lpi_state *lpi;
> >> +
> >> +	pr = per_cpu(processors, cpu);
> >> +	if (unlikely(!pr || !pr->flags.has_lpi))
> >> +		return -EINVAL;
> >> +
> >> +	/*
> >> +	 * If the PSCI cpu_suspend function hook has not been initialized
> >> +	 * idle states must not be enabled, so bail out
> >> +	 */
> >> +	if (!psci_ops.cpu_suspend)
> >> +		return -EOPNOTSUPP;
> >> +
> >> +	count = pr->power.count - 1;
> >> +	if (count <= 0)
> >> +		return -ENODEV;
> >> +
> >> +	psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
> >> +	if (!psci_states)
> >> +		return -ENOMEM;
> >> +
> >> +	for (i = 0; i < count; i++) {
> >> +		u32 state;
> >> +
> >> +		lpi = &pr->power.lpi_states[i + 1];
> >> +		state = lpi->address & 0xFFFFFFFF;
> 
> Why is needed to mask 'address' ?
> 
> >> +		if (!psci_power_state_is_valid(state)) {
> >> +			pr_warn("Invalid PSCI power state %#x\n", state);
> >> +			kfree(psci_states);
> >> +			return -EINVAL;
> >> +		}
> >> +		psci_states[i] = state;
> >> +	}
> >> +	/* Idle states parsed correctly, initialize per-cpu pointer */
> >> +	per_cpu(psci_power_state, cpu) = psci_states;
> >> +	return 0;
> >
> > Most of the code in this function is FW independent, it would be nice
> > to factor it out and add the respective ACPI/DT helper functions to
> > retrieve idle states count and parameters, we can update it later
> > anyway it is fine by me to leave it as it is.
> >
> >> +}
> >> +#else
> >> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
> >> +{
> >> +	return -EINVAL;
> >> +}
> >> +#endif
> >> +
> >>   int psci_cpu_init_idle(unsigned int cpu)
> >>   {
> >>   	struct device_node *cpu_node;
> >>   	int ret;
> >>
> >> +	if (!acpi_disabled)
> >> +		return psci_acpi_cpu_init_idle(cpu);
> 
> Is it possible the case where there is information in both the DT and in 
> ACPI ?

No, it isn't.

It is either-or, never both at the same time.

Thanks,
Rafael

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

* Re: [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support
  2016-06-23  0:42   ` Rafael J. Wysocki
@ 2016-06-25  0:23     ` Rafael J. Wysocki
  0 siblings, 0 replies; 27+ messages in thread
From: Rafael J. Wysocki @ 2016-06-25  0:23 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: linux-acpi, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel

On Thursday, June 23, 2016 02:42:57 AM Rafael J. Wysocki wrote:
> On Wednesday, June 22, 2016 06:45:15 PM Sudeep Holla wrote:
> > Hi Rafael,
> > 
> > On 14/06/16 15:48, Sudeep Holla wrote:
> > > ACPI 6.0 introduced LPI(Low Power Idle) states that provides an alternate
> > > method to describe processor idle states. It extends the specification
> > > to allow the expression of idle states like C-states selectable by the
> > > OSPM when a processor goes idle, but may affect more than one processor,
> > > and may affect other system components.
> > >
> > > LPI extensions leverages the processor container device(again introduced
> > > in ACPI 6.0) allowing to express which parts of the system are affected
> > > by a given LPI state. It defines the local power states for each node
> > > in a hierarchical processor topology. The OSPM can use _LPI object to
> > > select a local power state for each level of processor hierarchy in the
> > > system. They used to produce a composite power state request that is
> > > presented to the platform by the OSPM.
> > >
> > > Since multiple processors affect the idle state for any non-leaf hierarchy
> > > node, coordination of idle state requests between the processors is
> > > required. ACPI supports two different coordination schemes: Platform
> > > coordinated and  OS initiated.
> > >
> > > This series aims at providing basic and initial support for platform
> > > coordinated LPI states.
> > >
> > 
> > Gentle ping, was hoping to target this series for v4.8
> 
> On my list of things to take care of this week.  But this is a long list ...

Well, there are comments from Lorenzo and Daniel that need addressing,
so can you please do that and resend?

Thanks,
Rafael

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-24 22:47       ` Rafael J. Wysocki
@ 2016-06-25  8:05         ` Daniel Lezcano
  0 siblings, 0 replies; 27+ messages in thread
From: Daniel Lezcano @ 2016-06-25  8:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Lorenzo Pieralisi, Sudeep Holla, linux-acpi, Vikas Sajjan, Sunil,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, linux-arm-kernel

On 06/25/2016 12:47 AM, Rafael J. Wysocki wrote:

[ ... ]

>>>> +	if (!acpi_disabled)
>>>> +		return psci_acpi_cpu_init_idle(cpu);
>>
>> Is it possible the case where there is information in both the DT and in
>> ACPI ?
>
> No, it isn't.
>
> It is either-or, never both at the same time.

Ok, thanks for the clarification.

   -- Daniel


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-24 21:04     ` Daniel Lezcano
  2016-06-24 22:47       ` Rafael J. Wysocki
@ 2016-06-27  9:50       ` Sudeep Holla
  1 sibling, 0 replies; 27+ messages in thread
From: Sudeep Holla @ 2016-06-27  9:50 UTC (permalink / raw)
  To: Daniel Lezcano, Lorenzo Pieralisi
  Cc: Sudeep Holla, Rafael J . Wysocki, linux-acpi, Vikas Sajjan,
	Sunil, Prashanth Prakash, Al Stone, Ashwin Chaugule,
	linux-kernel, Mark Rutland, linux-arm-kernel

Hi, Daniel,

On 24/06/16 22:04, Daniel Lezcano wrote:

[...]

>>> +
>>> +    psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
>>> +    if (!psci_states)
>>> +        return -ENOMEM;
>>> +
>>> +    for (i = 0; i < count; i++) {
>>> +        u32 state;
>>> +
>>> +        lpi = &pr->power.lpi_states[i + 1];
>>> +        state = lpi->address & 0xFFFFFFFF;
>
> Why is needed to mask 'address' ?
>

This is as per Section 3.1.1 FFH Usage in LPI state entry methods in [1]

[...]

>>>   int psci_cpu_init_idle(unsigned int cpu)
>>>   {
>>>       struct device_node *cpu_node;
>>>       int ret;
>>>
>>> +    if (!acpi_disabled)
>>> +        return psci_acpi_cpu_init_idle(cpu);
>
> Is it possible the case where there is information in both the DT and in
> ACPI ? So ACPI is enabled without idle information which is in the DT ?
>

No, as Rafael mentioned aready.

>>
>> Either you do this, or we have to add it somehow somewhere in
>> drivers/cpuidle to avoid duplicating it.
>>
>> @Daniel: do you have an opinion on this please ?
>
> Yes, this function should be added to avoid duplication.
>

So, I assume you are happy with the way it's handled in this patch ?
(I will rename the file as suggested by Lorenzo)

-- 
Regards,
Sudeep

[1] 
http://infocenter.arm.com/help/topic/com.arm.doc.den0048a/DEN0048A_ARM_FFH_Specification.pdf

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

* Re: [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-14 14:48 ` [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64 Sudeep Holla
@ 2016-06-27 14:33   ` Daniel Lezcano
  2016-06-27 15:03     ` Sudeep Holla
  0 siblings, 1 reply; 27+ messages in thread
From: Daniel Lezcano @ 2016-06-27 14:33 UTC (permalink / raw)
  To: Sudeep Holla, Rafael J . Wysocki, linux-acpi
  Cc: Vikas Sajjan, Sunil, Lorenzo Pieralisi, Prashanth Prakash,
	Al Stone, Ashwin Chaugule, linux-kernel, linux-arm-kernel

On 06/14/2016 04:48 PM, Sudeep Holla wrote:
> Now that ACPI processor idle driver supports LPI(Low Power Idle), lets
> enable ACPI_PROCESSOR_IDLE for ARM64 too.
>
> This patch just removes the IA64 and X86 dependency on ACPI_PROCESSOR_IDLE
>
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> ---

Hi Sudeep,

now that ACPI processor supports ARM64 did you check the 
CPUIDLE_DRIVER_STATE_START trick in the code and its derivative ?

I deleted the patch 2/5 but there is a place where:

if (max_cstate=0)
	max_cstate=1;

Probably this is because the POLL state is inserted, so there is always 
an idle state. But for ARM, that is not the case.

Also, there are some places where the idle state index begins to 1. I 
think it should be 0 for ARM.

>   drivers/acpi/Kconfig | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 1358fb7d7a68..d74275c0f374 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -238,7 +238,7 @@ config ACPI_CPPC_LIB
>   config ACPI_PROCESSOR
>   	tristate "Processor"
>   	depends on X86 || IA64 || ARM64
> -	select ACPI_PROCESSOR_IDLE if X86 || IA64
> +	select ACPI_PROCESSOR_IDLE
>   	select ACPI_CPU_FREQ_PSS if X86 || IA64
>   	default y
>   	help
>


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-27 14:33   ` Daniel Lezcano
@ 2016-06-27 15:03     ` Sudeep Holla
  2016-06-27 15:05       ` Daniel Lezcano
  0 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-27 15:03 UTC (permalink / raw)
  To: Daniel Lezcano, Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	linux-arm-kernel

Hi Daniel,

On 27/06/16 15:33, Daniel Lezcano wrote:
> On 06/14/2016 04:48 PM, Sudeep Holla wrote:
>> Now that ACPI processor idle driver supports LPI(Low Power Idle), lets
>> enable ACPI_PROCESSOR_IDLE for ARM64 too.
>>
>> This patch just removes the IA64 and X86 dependency on
>> ACPI_PROCESSOR_IDLE
>>
>> Cc: linux-arm-kernel@lists.infradead.org
>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> ---
>
> Hi Sudeep,
>
> now that ACPI processor supports ARM64 did you check the
> CPUIDLE_DRIVER_STATE_START trick in the code and its derivative ?
>

No, that is used only for C-State and ARM64 doesn't support it.
Patch 1/5 puts all the C-State code under #ifdef so that it's not
compiled on ARM64.

> I deleted the patch 2/5 but there is a place where:
>

Sorry, I don't follow what you mean by that.

> if (max_cstate=0)
>      max_cstate=1;
>
> Probably this is because the POLL state is inserted, so there is always
> an idle state. But for ARM, that is not the case.
>

Yes

> Also, there are some places where the idle state index begins to 1. I
> think it should be 0 for ARM.
>

Yes for LPI, it does start from 0.

-- 
Regards,
Sudeep

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

* Re: [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-27 15:03     ` Sudeep Holla
@ 2016-06-27 15:05       ` Daniel Lezcano
  2016-06-27 15:06         ` Sudeep Holla
  0 siblings, 1 reply; 27+ messages in thread
From: Daniel Lezcano @ 2016-06-27 15:05 UTC (permalink / raw)
  To: Sudeep Holla, Rafael J . Wysocki, linux-acpi
  Cc: Vikas Sajjan, Sunil, Lorenzo Pieralisi, Prashanth Prakash,
	Al Stone, Ashwin Chaugule, linux-kernel, linux-arm-kernel

On 06/27/2016 05:03 PM, Sudeep Holla wrote:
> Hi Daniel,
>
> On 27/06/16 15:33, Daniel Lezcano wrote:
>> On 06/14/2016 04:48 PM, Sudeep Holla wrote:
>>> Now that ACPI processor idle driver supports LPI(Low Power Idle), lets
>>> enable ACPI_PROCESSOR_IDLE for ARM64 too.
>>>
>>> This patch just removes the IA64 and X86 dependency on
>>> ACPI_PROCESSOR_IDLE
>>>
>>> Cc: linux-arm-kernel@lists.infradead.org
>>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>>> ---
>>
>> Hi Sudeep,
>>
>> now that ACPI processor supports ARM64 did you check the
>> CPUIDLE_DRIVER_STATE_START trick in the code and its derivative ?
>>
>
> No, that is used only for C-State and ARM64 doesn't support it.
> Patch 1/5 puts all the C-State code under #ifdef so that it's not
> compiled on ARM64.
>
>> I deleted the patch 2/5 but there is a place where:
>>
>
> Sorry, I don't follow what you mean by that.

I meant I just deleted from my mailbox the patch 2/5, so I can't do 
inline comment.

>> if (max_cstate=0)
>>      max_cstate=1;
>>
>> Probably this is because the POLL state is inserted, so there is always
>> an idle state. But for ARM, that is not the case.
>>
>
> Yes
>
>> Also, there are some places where the idle state index begins to 1. I
>> think it should be 0 for ARM.
>>
>
> Yes for LPI, it does start from 0.
>


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-27 15:05       ` Daniel Lezcano
@ 2016-06-27 15:06         ` Sudeep Holla
  2016-06-27 15:08           ` Daniel Lezcano
  0 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-27 15:06 UTC (permalink / raw)
  To: Daniel Lezcano, Rafael J . Wysocki, linux-acpi
  Cc: Sudeep Holla, Vikas Sajjan, Sunil, Lorenzo Pieralisi,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	linux-arm-kernel



On 27/06/16 16:05, Daniel Lezcano wrote:
> On 06/27/2016 05:03 PM, Sudeep Holla wrote:
>> Hi Daniel,
>>
>> On 27/06/16 15:33, Daniel Lezcano wrote:
>>> On 06/14/2016 04:48 PM, Sudeep Holla wrote:
>>>> Now that ACPI processor idle driver supports LPI(Low Power Idle), lets
>>>> enable ACPI_PROCESSOR_IDLE for ARM64 too.
>>>>
>>>> This patch just removes the IA64 and X86 dependency on
>>>> ACPI_PROCESSOR_IDLE
>>>>
>>>> Cc: linux-arm-kernel@lists.infradead.org
>>>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>>>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>>>> ---
>>>
>>> Hi Sudeep,
>>>
>>> now that ACPI processor supports ARM64 did you check the
>>> CPUIDLE_DRIVER_STATE_START trick in the code and its derivative ?
>>>
>>
>> No, that is used only for C-State and ARM64 doesn't support it.
>> Patch 1/5 puts all the C-State code under #ifdef so that it's not
>> compiled on ARM64.
>>
>>> I deleted the patch 2/5 but there is a place where:
>>>
>>
>> Sorry, I don't follow what you mean by that.
>
> I meant I just deleted from my mailbox the patch 2/5, so I can't do
> inline comment.
>

Ah ok, anyways LPI always starts from index 0. IIUC that was your main
concern.

-- 
Regards,
Sudeep

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

* Re: [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-27 15:06         ` Sudeep Holla
@ 2016-06-27 15:08           ` Daniel Lezcano
  2016-06-27 15:11             ` Sudeep Holla
  0 siblings, 1 reply; 27+ messages in thread
From: Daniel Lezcano @ 2016-06-27 15:08 UTC (permalink / raw)
  To: Sudeep Holla, Rafael J . Wysocki, linux-acpi
  Cc: Vikas Sajjan, Sunil, Lorenzo Pieralisi, Prashanth Prakash,
	Al Stone, Ashwin Chaugule, linux-kernel, linux-arm-kernel

On 06/27/2016 05:06 PM, Sudeep Holla wrote:
>
>
> On 27/06/16 16:05, Daniel Lezcano wrote:
>> On 06/27/2016 05:03 PM, Sudeep Holla wrote:
>>> Hi Daniel,
>>>
>>> On 27/06/16 15:33, Daniel Lezcano wrote:
>>>> On 06/14/2016 04:48 PM, Sudeep Holla wrote:
>>>>> Now that ACPI processor idle driver supports LPI(Low Power Idle), lets
>>>>> enable ACPI_PROCESSOR_IDLE for ARM64 too.
>>>>>
>>>>> This patch just removes the IA64 and X86 dependency on
>>>>> ACPI_PROCESSOR_IDLE
>>>>>
>>>>> Cc: linux-arm-kernel@lists.infradead.org
>>>>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>>>>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>>>>> ---
>>>>
>>>> Hi Sudeep,
>>>>
>>>> now that ACPI processor supports ARM64 did you check the
>>>> CPUIDLE_DRIVER_STATE_START trick in the code and its derivative ?
>>>>
>>>
>>> No, that is used only for C-State and ARM64 doesn't support it.
>>> Patch 1/5 puts all the C-State code under #ifdef so that it's not
>>> compiled on ARM64.
>>>
>>>> I deleted the patch 2/5 but there is a place where:
>>>>
>>>
>>> Sorry, I don't follow what you mean by that.
>>
>> I meant I just deleted from my mailbox the patch 2/5, so I can't do
>> inline comment.
>>
>
> Ah ok, anyways LPI always starts from index 0. IIUC that was your main
> concern.

Do you have a repo where I can see the code ?

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

* Re: [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-27 15:08           ` Daniel Lezcano
@ 2016-06-27 15:11             ` Sudeep Holla
  2016-06-27 15:12               ` Daniel Lezcano
  0 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-27 15:11 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Rafael J . Wysocki, linux-acpi, Sudeep Holla, Vikas Sajjan,
	Sunil, Lorenzo Pieralisi, Prashanth Prakash, Al Stone,
	Ashwin Chaugule, linux-kernel, linux-arm-kernel



On 27/06/16 16:08, Daniel Lezcano wrote:
> On 06/27/2016 05:06 PM, Sudeep Holla wrote:

[...]

>> Ah ok, anyways LPI always starts from index 0. IIUC that was your main
>> concern.
>
> Do you have a repo where I can see the code ?
>

Yes, you can get it from [1]

--
Regards,
Sudeep

[1] http://git.kernel.org/sudeep.holla/linux/h/for_review/arm64_lpi

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

* Re: [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64
  2016-06-27 15:11             ` Sudeep Holla
@ 2016-06-27 15:12               ` Daniel Lezcano
  0 siblings, 0 replies; 27+ messages in thread
From: Daniel Lezcano @ 2016-06-27 15:12 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Rafael J . Wysocki, linux-acpi, Vikas Sajjan, Sunil,
	Lorenzo Pieralisi, Prashanth Prakash, Al Stone, Ashwin Chaugule,
	linux-kernel, linux-arm-kernel

On 06/27/2016 05:11 PM, Sudeep Holla wrote:
>
>
> On 27/06/16 16:08, Daniel Lezcano wrote:
>> On 06/27/2016 05:06 PM, Sudeep Holla wrote:
>
> [...]
>
>>> Ah ok, anyways LPI always starts from index 0. IIUC that was your main
>>> concern.
>>
>> Do you have a repo where I can see the code ?
>>
>
> Yes, you can get it from [1]

Great. Thanks Sudeep !

> Regards,
> Sudeep
>
> [1] http://git.kernel.org/sudeep.holla/linux/h/for_review/arm64_lpi


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-22 14:17   ` Lorenzo Pieralisi
  2016-06-24 21:04     ` Daniel Lezcano
@ 2016-06-27 16:29     ` Daniel Lezcano
  2016-06-27 17:07       ` Sudeep Holla
  1 sibling, 1 reply; 27+ messages in thread
From: Daniel Lezcano @ 2016-06-27 16:29 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Sudeep Holla
  Cc: Rafael J . Wysocki, linux-acpi, Vikas Sajjan, Sunil,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, linux-arm-kernel

On 06/22/2016 04:17 PM, Lorenzo Pieralisi wrote:
> Hi Sudeep,
>
> On Tue, Jun 14, 2016 at 03:48:38PM +0100, Sudeep Holla wrote:
>> This patch adds appropriate callbacks to support ACPI Low Power Idle
>> (LPI) on ARM64.
>>
>> Now that arm_enter_idle_state is exactly same in both generic ARM{32,64}
>> CPUIdle driver and ARM64 backend for ACPI processor idle driver, we can
>> unify it and move to cpuidle-arm.h header.
>>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>> Cc: linux-arm-kernel@lists.infradead.org
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> ---
>>   arch/arm64/kernel/cpuidle.c   | 17 +++++++++++++
>>   drivers/cpuidle/cpuidle-arm.c | 23 ++----------------
>>   drivers/firmware/psci.c       | 56 +++++++++++++++++++++++++++++++++++++++++++
>>   include/linux/cpuidle-arm.h   | 30 +++++++++++++++++++++++
>>   4 files changed, 105 insertions(+), 21 deletions(-)
>>   create mode 100644 include/linux/cpuidle-arm.h
>
> This patch seems fine by me, it would be good if Daniel can have
> a look too.
>
> Some minor comments below.
>
> [...]
>
>> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
>> index 03e04582791c..c6caa863d156 100644
>> --- a/drivers/firmware/psci.c
>> +++ b/drivers/firmware/psci.c
>> @@ -13,6 +13,7 @@
>>
>>   #define pr_fmt(fmt) "psci: " fmt
>>
>> +#include <linux/acpi.h>
>>   #include <linux/arm-smccc.h>
>>   #include <linux/cpuidle.h>
>>   #include <linux/errno.h>
>> @@ -310,11 +311,66 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
>>   	return ret;
>>   }
>>
>> +#ifdef CONFIG_ACPI
>> +#include <acpi/processor.h>
>> +
>> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
>> +{
>> +	int i, count;
>> +	u32 *psci_states;
>> +	struct acpi_processor *pr;
>> +	struct acpi_lpi_state *lpi;
>> +
>> +	pr = per_cpu(processors, cpu);
>> +	if (unlikely(!pr || !pr->flags.has_lpi))
>> +		return -EINVAL;
>> +
>> +	/*
>> +	 * If the PSCI cpu_suspend function hook has not been initialized
>> +	 * idle states must not be enabled, so bail out
>> +	 */
>> +	if (!psci_ops.cpu_suspend)
>> +		return -EOPNOTSUPP;
>> +
>> +	count = pr->power.count - 1;
>> +	if (count <= 0)
>> +		return -ENODEV;
>> +
>> +	psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
>> +	if (!psci_states)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < count; i++) {
>> +		u32 state;
>> +
>> +		lpi = &pr->power.lpi_states[i + 1];
>> +		state = lpi->address & 0xFFFFFFFF;

Why mask 'address' if 'state' is u32 ?

>> +		if (!psci_power_state_is_valid(state)) {
>> +			pr_warn("Invalid PSCI power state %#x\n", state);
>> +			kfree(psci_states);
>> +			return -EINVAL;
>> +		}
>> +		psci_states[i] = state;
>> +	}
>> +	/* Idle states parsed correctly, initialize per-cpu pointer */
>> +	per_cpu(psci_power_state, cpu) = psci_states;
>> +	return 0;

The ACPI and the PSCI code are not self contained here.

It would be nice to move this function to the ACPI code.

>> +}
>> +#else
>> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
>> +{
>> +	return -EINVAL;
>> +}
>> +#endif
>> +
>>   int psci_cpu_init_idle(unsigned int cpu)
>>   {
>>   	struct device_node *cpu_node;
>>   	int ret;
>>
>> +	if (!acpi_disabled)
>> +		return psci_acpi_cpu_init_idle(cpu);
>> +

acpi_disabled - acpi_disabled - acpi_disabled everywhere :/

The enable-method approach is not straightforward and now it is polluted 
by acpi-disabled.

So IIUC,

smp_init_cpus (contains acpi_disabled)
   smp_cpu_setup
     cpu_read_ops
       cpu_read_enable_method (contains acpi_disabled)
         acpi_get_enable_method (returns 'psci' after checking 
psci_is_present)

Then psci_cpu_init_idle is called... and check again acpi_disabled.

IMO, the circumlocution with the psci vs acpi vs acpi_disabled is 
getting unnecessary too complex, is prone to error and will lead to 
unmaintainable code very soon.

I suggest to sort out encapsulation and self-contained code before 
adding more feature in this area.


>>   	cpu_node = of_get_cpu_node(cpu, NULL);
>>   	if (!cpu_node)
>>   		return -ENODEV;
>> diff --git a/include/linux/cpuidle-arm.h b/include/linux/cpuidle-arm.h
>> new file mode 100644
>> index 000000000000..b99bcb3f43dd
>> --- /dev/null
>> +++ b/include/linux/cpuidle-arm.h
>
> arm-cpuidle.h for consistency with other (ARM) include/linux files ?
>
>> @@ -0,0 +1,30 @@
>> +#include <linux/cpu_pm.h>
>> +
>> +#include <asm/cpuidle.h>
>> +
>> +/*
>> + * arm_enter_idle_state - Programs CPU to enter the specified state
>> + */
>> +static int arm_generic_enter_idle_state(int idx)
>> +{
>> +	int ret;
>> +
>> +	if (!idx) {
>> +		cpu_do_idle();
>> +		return idx;
>> +	}
>> +
>> +	ret = cpu_pm_enter();
>> +	if (!ret) {
>> +		/*
>> +		 * Pass idle state index to cpu_suspend which in turn will
>> +		 * call the CPU ops suspend protocol with idle index as a
>> +		 * parameter.
>> +		 */
>> +		ret = arm_cpuidle_suspend(idx);
>> +
>> +		cpu_pm_exit();
>> +	}
>> +
>> +	return ret ? -1 : idx;
>> +}
>
> Either you do this, or we have to add it somehow somewhere in
> drivers/cpuidle to avoid duplicating it.
>
> @Daniel: do you have an opinion on this please ?

I don't like the idea to add an ARM arch specific header in 
include/linux. I thought this directory was supposed to contain as much 
as possible arch agnostic headers.

May be the name can be changed to something more generic:

eg.

int cpuidle_generic_enter(int idx);

and then add an option:

HAVE_CPUIDLE_GENERIC_ENTER

, then in the generic header:

#ifdef HAVE_CPUIDLE_GENERIC_ENTER
int cpuidle_generic_enter(int idx);
#endif

, change the function name in cpuidle-arm .c

and finally add in the ARM and ARM64 Kconfig's option 
HAVE_CPUIDLE_GENERIC_ENTER.


   -- Daniel

-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-27 16:29     ` Daniel Lezcano
@ 2016-06-27 17:07       ` Sudeep Holla
  2016-06-27 17:58         ` Sudeep Holla
  0 siblings, 1 reply; 27+ messages in thread
From: Sudeep Holla @ 2016-06-27 17:07 UTC (permalink / raw)
  To: Daniel Lezcano, Lorenzo Pieralisi
  Cc: Sudeep Holla, Rafael J . Wysocki, linux-acpi, Vikas Sajjan,
	Sunil, Prashanth Prakash, Al Stone, Ashwin Chaugule,
	linux-kernel, Mark Rutland, linux-arm-kernel



On 27/06/16 17:29, Daniel Lezcano wrote:
> On 06/22/2016 04:17 PM, Lorenzo Pieralisi wrote:
>> Hi Sudeep,
>>
>> On Tue, Jun 14, 2016 at 03:48:38PM +0100, Sudeep Holla wrote:
>>> This patch adds appropriate callbacks to support ACPI Low Power Idle
>>> (LPI) on ARM64.
>>>
>>> Now that arm_enter_idle_state is exactly same in both generic ARM{32,64}
>>> CPUIdle driver and ARM64 backend for ACPI processor idle driver, we can
>>> unify it and move to cpuidle-arm.h header.
>>>
>>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>>> Cc: Mark Rutland <mark.rutland@arm.com>
>>> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
>>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>>> Cc: linux-arm-kernel@lists.infradead.org
>>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>>> ---
>>>   arch/arm64/kernel/cpuidle.c   | 17 +++++++++++++
>>>   drivers/cpuidle/cpuidle-arm.c | 23 ++----------------
>>>   drivers/firmware/psci.c       | 56
>>> +++++++++++++++++++++++++++++++++++++++++++
>>>   include/linux/cpuidle-arm.h   | 30 +++++++++++++++++++++++
>>>   4 files changed, 105 insertions(+), 21 deletions(-)
>>>   create mode 100644 include/linux/cpuidle-arm.h
>>
>> This patch seems fine by me, it would be good if Daniel can have
>> a look too.
>>
>> Some minor comments below.
>>
>> [...]
>>
>>> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
>>> index 03e04582791c..c6caa863d156 100644
>>> --- a/drivers/firmware/psci.c
>>> +++ b/drivers/firmware/psci.c
>>> @@ -13,6 +13,7 @@
>>>
>>>   #define pr_fmt(fmt) "psci: " fmt
>>>
>>> +#include <linux/acpi.h>
>>>   #include <linux/arm-smccc.h>
>>>   #include <linux/cpuidle.h>
>>>   #include <linux/errno.h>
>>> @@ -310,11 +311,66 @@ static int psci_dt_cpu_init_idle(struct
>>> device_node *cpu_node, int cpu)
>>>       return ret;
>>>   }
>>>
>>> +#ifdef CONFIG_ACPI
>>> +#include <acpi/processor.h>
>>> +
>>> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
>>> +{
>>> +    int i, count;
>>> +    u32 *psci_states;
>>> +    struct acpi_processor *pr;
>>> +    struct acpi_lpi_state *lpi;
>>> +
>>> +    pr = per_cpu(processors, cpu);
>>> +    if (unlikely(!pr || !pr->flags.has_lpi))
>>> +        return -EINVAL;
>>> +
>>> +    /*
>>> +     * If the PSCI cpu_suspend function hook has not been initialized
>>> +     * idle states must not be enabled, so bail out
>>> +     */
>>> +    if (!psci_ops.cpu_suspend)
>>> +        return -EOPNOTSUPP;
>>> +
>>> +    count = pr->power.count - 1;
>>> +    if (count <= 0)
>>> +        return -ENODEV;
>>> +
>>> +    psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
>>> +    if (!psci_states)
>>> +        return -ENOMEM;
>>> +
>>> +    for (i = 0; i < count; i++) {
>>> +        u32 state;
>>> +
>>> +        lpi = &pr->power.lpi_states[i + 1];
>>> +        state = lpi->address & 0xFFFFFFFF;
>
> Why mask 'address' if 'state' is u32 ?
>

Agreed, I overlooked it.

>>> +        if (!psci_power_state_is_valid(state)) {
>>> +            pr_warn("Invalid PSCI power state %#x\n", state);
>>> +            kfree(psci_states);
>>> +            return -EINVAL;
>>> +        }
>>> +        psci_states[i] = state;
>>> +    }
>>> +    /* Idle states parsed correctly, initialize per-cpu pointer */
>>> +    per_cpu(psci_power_state, cpu) = psci_states;
>>> +    return 0;
>
> The ACPI and the PSCI code are not self contained here.
>
> It would be nice to move this function to the ACPI code.
>
>>> +}
>>> +#else
>>> +static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
>>> +{
>>> +    return -EINVAL;
>>> +}
>>> +#endif
>>> +
>>>   int psci_cpu_init_idle(unsigned int cpu)
>>>   {
>>>       struct device_node *cpu_node;
>>>       int ret;
>>>
>>> +    if (!acpi_disabled)
>>> +        return psci_acpi_cpu_init_idle(cpu);
>>> +
>
> acpi_disabled - acpi_disabled - acpi_disabled everywhere :/
>
> The enable-method approach is not straightforward and now it is polluted
> by acpi-disabled.
>
> So IIUC,
>
> smp_init_cpus (contains acpi_disabled)
>    smp_cpu_setup
>      cpu_read_ops
>        cpu_read_enable_method (contains acpi_disabled)
>          acpi_get_enable_method (returns 'psci' after checking
> psci_is_present)
>
> Then psci_cpu_init_idle is called... and check again acpi_disabled.
>
> IMO, the circumlocution with the psci vs acpi vs acpi_disabled is
> getting unnecessary too complex, is prone to error and will lead to
> unmaintainable code very soon.
>
> I suggest to sort out encapsulation and self-contained code before
> adding more feature in this area.
>

I understand your concern but I have no idea on how to clean up. Lorenzo
asked to factor our common code between psci_{dt,acpi}_cpu_init_idle and
I think you might not like the refactoring[1]. I didn't want to change
cpuidle_ops and hence psci_dt_cpu_init_idle parameters. I will see if
changing that simplifies things.

>>>       cpu_node = of_get_cpu_node(cpu, NULL);
>>>       if (!cpu_node)
>>>           return -ENODEV;
>>> diff --git a/include/linux/cpuidle-arm.h b/include/linux/cpuidle-arm.h
>>> new file mode 100644
>>> index 000000000000..b99bcb3f43dd
>>> --- /dev/null
>>> +++ b/include/linux/cpuidle-arm.h
>>
>> arm-cpuidle.h for consistency with other (ARM) include/linux files ?
>>
>>> @@ -0,0 +1,30 @@
>>> +#include <linux/cpu_pm.h>
>>> +
>>> +#include <asm/cpuidle.h>
>>> +
>>> +/*
>>> + * arm_enter_idle_state - Programs CPU to enter the specified state
>>> + */
>>> +static int arm_generic_enter_idle_state(int idx)
>>> +{
>>> +    int ret;
>>> +
>>> +    if (!idx) {
>>> +        cpu_do_idle();
>>> +        return idx;
>>> +    }
>>> +
>>> +    ret = cpu_pm_enter();
>>> +    if (!ret) {
>>> +        /*
>>> +         * Pass idle state index to cpu_suspend which in turn will
>>> +         * call the CPU ops suspend protocol with idle index as a
>>> +         * parameter.
>>> +         */
>>> +        ret = arm_cpuidle_suspend(idx);
>>> +
>>> +        cpu_pm_exit();
>>> +    }
>>> +
>>> +    return ret ? -1 : idx;
>>> +}
>>
>> Either you do this, or we have to add it somehow somewhere in
>> drivers/cpuidle to avoid duplicating it.
>>
>> @Daniel: do you have an opinion on this please ?
>
> I don't like the idea to add an ARM arch specific header in
> include/linux. I thought this directory was supposed to contain as much
> as possible arch agnostic headers.
>

While I agree, but what we have is ARM specific code here and calling it
generic might not make it any usable on other architecture unless they 
have the same semantics. I am fine if you and Rafael are OK with that.

> May be the name can be changed to something more generic:
>
> eg.
>
> int cpuidle_generic_enter(int idx);
>
> and then add an option:
>
> HAVE_CPUIDLE_GENERIC_ENTER
>
> , then in the generic header:
>
> #ifdef HAVE_CPUIDLE_GENERIC_ENTER
> int cpuidle_generic_enter(int idx);
> #endif
>
> , change the function name in cpuidle-arm .c
>
> and finally add in the ARM and ARM64 Kconfig's option
> HAVE_CPUIDLE_GENERIC_ENTER.
>
>
>    -- Daniel
>

[1] 
http://git.kernel.org/cgit/linux/kernel/git/sudeep.holla/linux.git/commit/?h=for_review/arm64_lpi&id=9b516ad4442b4168e962ba4ca87bd568d605053b
-- 
Regards,
Sudeep

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

* Re: [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI)
  2016-06-27 17:07       ` Sudeep Holla
@ 2016-06-27 17:58         ` Sudeep Holla
  0 siblings, 0 replies; 27+ messages in thread
From: Sudeep Holla @ 2016-06-27 17:58 UTC (permalink / raw)
  To: Daniel Lezcano, Rafael J . Wysocki
  Cc: Lorenzo Pieralisi, Sudeep Holla, linux-acpi, Vikas Sajjan, Sunil,
	Prashanth Prakash, Al Stone, Ashwin Chaugule, linux-kernel,
	Mark Rutland, linux-arm-kernel



On 27/06/16 18:07, Sudeep Holla wrote:
>
>
> On 27/06/16 17:29, Daniel Lezcano wrote:

[...]

>>
>> acpi_disabled - acpi_disabled - acpi_disabled everywhere :/
>>
>> The enable-method approach is not straightforward and now it is polluted
>> by acpi-disabled.
>>
>> So IIUC,
>>
>> smp_init_cpus (contains acpi_disabled)
>>    smp_cpu_setup
>>      cpu_read_ops
>>        cpu_read_enable_method (contains acpi_disabled)
>>          acpi_get_enable_method (returns 'psci' after checking
>> psci_is_present)
>>
>> Then psci_cpu_init_idle is called... and check again acpi_disabled.
>>
>> IMO, the circumlocution with the psci vs acpi vs acpi_disabled is
>> getting unnecessary too complex, is prone to error and will lead to
>> unmaintainable code very soon.
>>
>> I suggest to sort out encapsulation and self-contained code before
>> adding more feature in this area.
>>
>
> I understand your concern but I have no idea on how to clean up. Lorenzo
> asked to factor our common code between psci_{dt,acpi}_cpu_init_idle and
> I think you might not like the refactoring[1]. I didn't want to change
> cpuidle_ops and hence psci_dt_cpu_init_idle parameters. I will see if
> changing that simplifies things.
>

One of the reasons for adding acpi_disabled check is to keep the other
logic at the same place. Otherwise we end up duplicating that code which
is what I have done in psci_{dt,acpi}_cpu_init_idle at the first place.

-- 
Regards,
Sudeep

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

end of thread, other threads:[~2016-06-27 17:59 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-14 14:48 [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
2016-06-14 14:48 ` [PATCH v6 1/5] ACPI / processor_idle: introduce ACPI_PROCESSOR_CSTATE Sudeep Holla
2016-06-14 14:48 ` [PATCH v6 2/5] ACPI / processor_idle: Add support for Low Power Idle(LPI) states Sudeep Holla
2016-06-14 16:47   ` Sudeep Holla
2016-06-14 16:54   ` [PATCH v6 2/5][UPDATED] " Sudeep Holla
2016-06-14 14:48 ` [PATCH v6 3/5] arm64: cpuidle: drop __init section marker to arm_cpuidle_init Sudeep Holla
2016-06-22 16:09   ` Lorenzo Pieralisi
2016-06-14 14:48 ` [PATCH v6 4/5] arm64: add support for ACPI Low Power Idle(LPI) Sudeep Holla
2016-06-22 14:17   ` Lorenzo Pieralisi
2016-06-24 21:04     ` Daniel Lezcano
2016-06-24 22:47       ` Rafael J. Wysocki
2016-06-25  8:05         ` Daniel Lezcano
2016-06-27  9:50       ` Sudeep Holla
2016-06-27 16:29     ` Daniel Lezcano
2016-06-27 17:07       ` Sudeep Holla
2016-06-27 17:58         ` Sudeep Holla
2016-06-14 14:48 ` [PATCH v6 5/5] ACPI : enable ACPI_PROCESSOR_IDLE on ARM64 Sudeep Holla
2016-06-27 14:33   ` Daniel Lezcano
2016-06-27 15:03     ` Sudeep Holla
2016-06-27 15:05       ` Daniel Lezcano
2016-06-27 15:06         ` Sudeep Holla
2016-06-27 15:08           ` Daniel Lezcano
2016-06-27 15:11             ` Sudeep Holla
2016-06-27 15:12               ` Daniel Lezcano
2016-06-22 17:45 ` [PATCH v6 0/5] ACPI / processor_idle: Add ACPI v6.0 LPI support Sudeep Holla
2016-06-23  0:42   ` Rafael J. Wysocki
2016-06-25  0:23     ` Rafael J. Wysocki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).