LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Enable powernv based platform sensors
From: Neelesh Gupta @ 2014-03-07  5:33 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: sbhat

This patchset contains the enablement code to expose platform sensor data
on powernv platform. First patch fetches the sensor data from the firmware
and second patch being an hwmon driver, enables the sysfs interfaces.

---

Neelesh Gupta (1):
      powerpc/powernv: Enable fetching of platform sensor data

Shivaprasad G Bhat (1):
      powerpc/powernv: hwmon driver for power values, fan rpm and temperature


 arch/powerpc/include/asm/opal.h                |    4 
 arch/powerpc/platforms/powernv/Makefile        |    2 
 arch/powerpc/platforms/powernv/opal-sensor.c   |   64 +++
 arch/powerpc/platforms/powernv/opal-wrappers.S |    1 
 drivers/hwmon/Kconfig                          |    8 
 drivers/hwmon/Makefile                         |    1 
 drivers/hwmon/ibmpowernv.c                     |  529 ++++++++++++++++++++++++
 7 files changed, 608 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-sensor.c
 create mode 100644 drivers/hwmon/ibmpowernv.c

-- 
Signature

^ permalink raw reply

* [PATCH] powerpc/powernv: Enable reading and updating of system parameters
From: Neelesh Gupta @ 2014-03-07  5:32 UTC (permalink / raw)
  To: linuxppc-dev

This patch enables reading and updating of system parameters through
OPAL call.

Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/opal.h                |   14 +
 arch/powerpc/platforms/powernv/Makefile        |    2 
 arch/powerpc/platforms/powernv/opal-sysparam.c |  290 ++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |    2 
 arch/powerpc/platforms/powernv/opal.c          |    2 
 5 files changed, 309 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-sysparam.c

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 90fad59..60b3edc 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -159,6 +159,8 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_GET_MSG				85
 #define OPAL_CHECK_ASYNC_COMPLETION		86
 #define OPAL_SYNC_HOST_REBOOT			87
+#define OPAL_GET_PARAM				89
+#define OPAL_SET_PARAM				90
 
 #ifndef __ASSEMBLY__
 
@@ -398,6 +400,13 @@ enum OpalLPCAddressType {
 	OPAL_LPC_FW	= 2,
 };
 
+/* System parameter permission */
+enum OpalSysparamPerm {
+	OPAL_SYSPARAM_READ      = 0x1,
+	OPAL_SYSPARAM_WRITE     = 0x2,
+	OPAL_SYSPARAM_RW        = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE),
+};
+
 struct opal_msg {
 	uint32_t msg_type;
 	uint32_t reserved;
@@ -834,6 +843,10 @@ int64_t opal_update_flash(uint64_t blk_list);
 int64_t opal_get_msg(uint64_t buffer, size_t size);
 int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
 int64_t opal_sync_host_reboot(void);
+int64_t opal_get_param(uint64_t token, uint32_t param_id, uint64_t buffer,
+		size_t length);
+int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
+		size_t length);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
@@ -871,6 +884,7 @@ extern void opal_get_rtc_time(struct rtc_time *tm);
 extern unsigned long opal_get_boot_time(void);
 extern void opal_nvram_init(void);
 extern void opal_flash_init(void);
+extern void opal_sys_param_init(void);
 
 extern int opal_machine_check(struct pt_regs *regs);
 
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index c0f85ea..e6166d3 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,5 +1,5 @@
 obj-y			+= setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
-obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
+obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o opal-sysparam.o
 obj-y			+= rng.o
 
 obj-$(CONFIG_SMP)	+= smp.o
diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c
new file mode 100644
index 0000000..0bd249a
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-sysparam.c
@@ -0,0 +1,290 @@
+/*
+ * PowerNV system parameter code
+ *
+ * Copyright (C) 2013 IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kobject.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/gfp.h>
+#include <linux/stat.h>
+#include <asm/opal.h>
+
+#define MAX_PARAM_DATA_LEN	64
+
+static DEFINE_MUTEX(opal_sysparam_mutex);
+static struct kobject *sysparam_kobj;
+static void *param_data_buf;
+
+struct param_attr {
+	struct list_head list;
+	u32 param_id;
+	u32 param_size;
+	struct kobj_attribute kobj_attr;
+};
+
+static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
+{
+	struct opal_msg msg;
+	int ret, token;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		if (token != -ERESTARTSYS)
+			pr_err("%s: Couldn't get the token, returning\n",
+					__func__);
+		ret = token;
+		goto out;
+	}
+
+	ret = opal_get_param(token, param_id, (u64)buffer, length);
+	if (ret != OPAL_ASYNC_COMPLETION)
+		goto out_token;
+
+	ret = opal_async_wait_response(token, &msg);
+	if (ret) {
+		pr_err("%s: Failed to wait for the async response, %d\n",
+				__func__, ret);
+		goto out_token;
+	}
+
+	ret = msg.params[1];
+
+out_token:
+	opal_async_release_token(token);
+out:
+	return ret;
+}
+
+static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
+{
+	struct opal_msg msg;
+	int ret, token;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		if (token != -ERESTARTSYS)
+			pr_err("%s: Couldn't get the token, returning\n",
+					__func__);
+		ret = token;
+		goto out;
+	}
+
+	ret = opal_set_param(token, param_id, (u64)buffer, length);
+
+	if (ret != OPAL_ASYNC_COMPLETION)
+		goto out_token;
+
+	ret = opal_async_wait_response(token, &msg);
+	if (ret) {
+		pr_err("%s: Failed to wait for the async response, %d\n",
+				__func__, ret);
+		goto out_token;
+	}
+
+	ret = msg.params[1];
+
+out_token:
+	opal_async_release_token(token);
+out:
+	return ret;
+}
+
+static ssize_t sys_param_show(struct kobject *kobj,
+		struct kobj_attribute *kobj_attr, char *buf)
+{
+	struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+			kobj_attr);
+	int ret;
+
+	mutex_lock(&opal_sysparam_mutex);
+	ret = opal_get_sys_param(attr->param_id, attr->param_size,
+			param_data_buf);
+	if (ret)
+		goto out;
+
+	memcpy(buf, param_data_buf, attr->param_size);
+
+out:
+	mutex_unlock(&opal_sysparam_mutex);
+	return ret ? ret : attr->param_size;
+}
+
+static ssize_t sys_param_store(struct kobject *kobj,
+		struct kobj_attribute *kobj_attr, const char *buf, size_t count)
+{
+	struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+			kobj_attr);
+	int ret;
+
+	mutex_lock(&opal_sysparam_mutex);
+	memcpy(param_data_buf, buf, count);
+	ret = opal_set_sys_param(attr->param_id, attr->param_size,
+			param_data_buf);
+	mutex_unlock(&opal_sysparam_mutex);
+	return ret ? ret : count;
+}
+
+void __init opal_sys_param_init(void)
+{
+	struct device_node *sysparam;
+	struct param_attr *attr;
+	u32 *id, *size;
+	int count, i;
+	u8 *perm;
+
+	if (!opal_kobj) {
+		pr_warn("SYSPARAM: opal kobject is not available\n");
+		goto out;
+	}
+
+	sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
+	if (!sysparam_kobj) {
+		pr_err("SYSPARAM: Failed to create sysparam kobject\n");
+		goto out;
+	}
+
+	/* Allocate big enough buffer for any get/set transactions */
+	param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
+	if (!param_data_buf) {
+		pr_err("SYSPARAM: Failed to allocate memory for param data "
+				"buf\n");
+		goto out_kobj_put;
+	}
+
+	sysparam = of_find_node_by_path("/ibm,opal/sysparams");
+	if (!sysparam) {
+		pr_err("SYSPARAM: Opal sysparam node not found\n");
+		goto out_param_buf;
+	}
+
+	if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
+		pr_err("SYSPARAM: Opal sysparam node not compatible\n");
+		goto out_node_put;
+	}
+
+	/* Number of parameters exposed through DT */
+	count = of_property_count_strings(sysparam, "param-name");
+	if (count < 0) {
+		pr_err("SYSPARAM: No string found of property param-name in "
+				"the node %s\n", sysparam->name);
+		goto out_node_put;
+	}
+
+	id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
+	if (!id) {
+		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+				"id\n");
+		goto out_node_put;
+	}
+
+	size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
+	if (!size) {
+		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+				"size\n");
+		goto out_free_id;
+	}
+
+	perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
+	if (!perm) {
+		pr_err("SYSPARAM: Failed to allocate memory to read supported "
+				"action on the parameter");
+		goto out_free_size;
+	}
+
+	if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
+		pr_err("SYSPARAM: Missing property param-id in the DT\n");
+		goto out_free_perm;
+	}
+
+	if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
+		pr_err("SYSPARAM: Missing propery param-len in the DT\n");
+		goto out_free_perm;
+	}
+
+
+	if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
+		pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
+		goto out_free_perm;
+	}
+
+	attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
+	if (!attr) {
+		pr_err("SYSPARAM: Failed to allocate memory for parameter "
+				"attributes\n");
+		goto out_free_perm;
+	}
+
+	/* For each of the parameters, populate the parameter attributes */
+	for (i = 0; i < count; i++) {
+		sysfs_attr_init(&attr[i].kobj_attr.attr);
+		attr[i].param_id = id[i];
+		attr[i].param_size = size[i];
+		if (of_property_read_string_index(sysparam, "param-name", i,
+				&attr[i].kobj_attr.attr.name))
+			continue;
+
+		/* If the parameter is read-only or read-write */
+		switch (perm[i] & 3) {
+		case OPAL_SYSPARAM_READ:
+			attr[i].kobj_attr.attr.mode = S_IRUGO;
+			break;
+		case OPAL_SYSPARAM_WRITE:
+			attr[i].kobj_attr.attr.mode = S_IWUGO;
+			break;
+		case OPAL_SYSPARAM_RW:
+			attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUGO;
+			break;
+		default:
+			break;
+		}
+
+		attr[i].kobj_attr.show = sys_param_show;
+		attr[i].kobj_attr.store = sys_param_store;
+
+		if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
+			pr_err("SYSPARAM: Failed to create sysfs file %s\n",
+					attr[i].kobj_attr.attr.name);
+			goto out_free_attr;
+		}
+	}
+
+	kfree(perm);
+	kfree(size);
+	kfree(id);
+	of_node_put(sysparam);
+	return;
+
+out_free_attr:
+	kfree(attr);
+out_free_perm:
+	kfree(perm);
+out_free_size:
+	kfree(size);
+out_free_id:
+	kfree(id);
+out_node_put:
+	of_node_put(sysparam);
+out_param_buf:
+	kfree(param_data_buf);
+out_kobj_put:
+	kobject_put(sysparam_kobj);
+out:
+	return;
+}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 3e8829c..0afdeca 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -129,3 +129,5 @@ OPAL_CALL(opal_update_flash,			OPAL_FLASH_UPDATE);
 OPAL_CALL(opal_get_msg,				OPAL_GET_MSG);
 OPAL_CALL(opal_check_completion,		OPAL_CHECK_ASYNC_COMPLETION);
 OPAL_CALL(opal_sync_host_reboot,		OPAL_SYNC_HOST_REBOOT);
+OPAL_CALL(opal_get_param,			OPAL_GET_PARAM);
+OPAL_CALL(opal_set_param,			OPAL_SET_PARAM);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 65499ad..4fad36a 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -474,6 +474,8 @@ static int __init opal_init(void)
 	if (rc == 0) {
 		/* Setup code update interface */
 		opal_flash_init();
+		/* Setup system parameters interface */
+		opal_sys_param_init();
 	}
 
 	return 0;

^ permalink raw reply related

* [PATCH] powerpc/powernv: Infrastructure to support OPAL async completion
From: Neelesh Gupta @ 2014-03-07  5:30 UTC (permalink / raw)
  To: linuxppc-dev

This patch adds support for notifying the clients of their request
completion. Clients request for the token before making OPAL call
and then wait for the response.

This patch uses messaging infrastructure to pull the data to linux
by registering itself for the message type OPAL_MSG_ASYNC_COMP.

Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/opal.h             |   12 +-
 arch/powerpc/platforms/powernv/Makefile     |    2 
 arch/powerpc/platforms/powernv/opal-async.c |  203 +++++++++++++++++++++++++++
 3 files changed, 215 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-async.c

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ed82142..90fad59 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -83,6 +83,8 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_INTERNAL_ERROR	-11
 #define OPAL_BUSY_EVENT		-12
 #define OPAL_HARDWARE_FROZEN	-13
+#define OPAL_WRONG_STATE	-14
+#define OPAL_ASYNC_COMPLETION	-15
 
 /* API Tokens (in r0) */
 #define OPAL_CONSOLE_WRITE			1
@@ -241,7 +243,9 @@ enum OpalPendingState {
 };
 
 enum OpalMessageType {
-	OPAL_MSG_ASYNC_COMP		= 0,
+	OPAL_MSG_ASYNC_COMP = 0,	/* params[0] = token, params[1] = rc,
+					 * additional params function-specific
+					 */
 	OPAL_MSG_MEM_ERR,
 	OPAL_MSG_EPOW,
 	OPAL_MSG_SHUTDOWN,
@@ -853,6 +857,12 @@ extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
 extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
 extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
 
+extern int __opal_async_get_token(void);
+extern int opal_async_get_token_interruptible(void);
+extern int __opal_async_release_token(int token);
+extern int opal_async_release_token(int token);
+extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg);
+
 extern void hvc_opal_init_early(void);
 
 struct rtc_time;
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 8d767fd..c0f85ea 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,4 +1,4 @@
-obj-y			+= setup.o opal-takeover.o opal-wrappers.o opal.o
+obj-y			+= setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o
 
diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c
new file mode 100644
index 0000000..cd0c135
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-async.c
@@ -0,0 +1,203 @@
+/*
+ * PowerNV OPAL asynchronous completion interfaces
+ *
+ * Copyright 2013 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <asm/opal.h>
+
+#define N_ASYNC_COMPLETIONS	64
+
+static DECLARE_BITMAP(opal_async_complete_map, N_ASYNC_COMPLETIONS) = {~0UL};
+static DECLARE_BITMAP(opal_async_token_map, N_ASYNC_COMPLETIONS);
+static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait);
+static DEFINE_SPINLOCK(opal_async_comp_lock);
+static struct semaphore opal_async_sem;
+static struct opal_msg *opal_async_responses;
+static unsigned int opal_max_async_tokens;
+
+int __opal_async_get_token(void)
+{
+	unsigned long flags;
+	int token;
+
+	spin_lock_irqsave(&opal_async_comp_lock, flags);
+	token = find_first_bit(opal_async_complete_map, opal_max_async_tokens);
+	if (token >= opal_max_async_tokens) {
+		token = -EBUSY;
+		goto out;
+	}
+
+	if (__test_and_set_bit(token, opal_async_token_map)) {
+		token = -EBUSY;
+		goto out;
+	}
+
+	__clear_bit(token, opal_async_complete_map);
+
+out:
+	spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+	return token;
+}
+
+int opal_async_get_token_interruptible(void)
+{
+	int token;
+
+	/* Wait until a token is available */
+	if (down_interruptible(&opal_async_sem))
+		return -ERESTARTSYS;
+
+	token = __opal_async_get_token();
+	if (token < 0)
+		up(&opal_async_sem);
+
+	return token;
+}
+
+int __opal_async_release_token(int token)
+{
+	unsigned long flags;
+
+	if (token < 0 || token >= opal_max_async_tokens) {
+		pr_err("%s: Passed token is out of range, token %d\n",
+				__func__, token);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&opal_async_comp_lock, flags);
+	__set_bit(token, opal_async_complete_map);
+	__clear_bit(token, opal_async_token_map);
+	spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+	return 0;
+}
+
+int opal_async_release_token(int token)
+{
+	int ret;
+
+	ret = __opal_async_release_token(token);
+	if (ret)
+		return ret;
+
+	up(&opal_async_sem);
+
+	return 0;
+}
+
+int opal_async_wait_response(uint64_t token, struct opal_msg *msg)
+{
+	if (token >= opal_max_async_tokens) {
+		pr_err("%s: Invalid token passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!msg) {
+		pr_err("%s: Invalid message pointer passed\n", __func__);
+		return -EINVAL;
+	}
+
+	wait_event(opal_async_wait, test_bit(token, opal_async_complete_map));
+	memcpy(msg, &opal_async_responses[token], sizeof(*msg));
+
+	return 0;
+}
+
+static int opal_async_comp_event(struct notifier_block *nb,
+		unsigned long msg_type, void *msg)
+{
+	struct opal_msg *comp_msg = msg;
+	unsigned long flags;
+
+	if (msg_type != OPAL_MSG_ASYNC_COMP)
+		return 0;
+
+	memcpy(&opal_async_responses[comp_msg->params[0]], comp_msg,
+			sizeof(*comp_msg));
+	spin_lock_irqsave(&opal_async_comp_lock, flags);
+	__set_bit(comp_msg->params[0], opal_async_complete_map);
+	spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+	wake_up(&opal_async_wait);
+
+	return 0;
+}
+
+static struct notifier_block opal_async_comp_nb = {
+		.notifier_call	= opal_async_comp_event,
+		.next		= NULL,
+		.priority	= 0,
+};
+
+static int __init opal_async_comp_init(void)
+{
+	struct device_node *opal_node;
+	const __be32 *async;
+	int err;
+
+	opal_node = of_find_node_by_path("/ibm,opal");
+	if (!opal_node) {
+		pr_err("%s: Opal node not found\n", __func__);
+		err = -ENOENT;
+		goto out;
+	}
+
+	async = of_get_property(opal_node, "opal-msg-async-num", NULL);
+	if (!async) {
+		pr_err("%s: %s has no opal-msg-async-num\n",
+				__func__, opal_node->full_name);
+		err = -ENOENT;
+		goto out_opal_node;
+	}
+
+	opal_max_async_tokens = be32_to_cpup(async);
+	if (opal_max_async_tokens > N_ASYNC_COMPLETIONS)
+		opal_max_async_tokens = N_ASYNC_COMPLETIONS;
+
+	err = opal_message_notifier_register(OPAL_MSG_ASYNC_COMP,
+			&opal_async_comp_nb);
+	if (err) {
+		pr_err("%s: Can't register OPAL event notifier (%d)\n",
+				__func__, err);
+		goto out_opal_node;
+	}
+
+	opal_async_responses = kzalloc(
+			sizeof(*opal_async_responses) * opal_max_async_tokens,
+			GFP_KERNEL);
+	if (!opal_async_responses) {
+		pr_err("%s: Out of memory, failed to do asynchronous "
+				"completion init\n", __func__);
+		err = -ENOMEM;
+		goto out_opal_node;
+	}
+
+	/* Initialize to 1 less than the maximum tokens available, as we may
+	 * require to pop one during emergency through synchronous call to
+	 * __opal_async_get_token()
+	 */
+	sema_init(&opal_async_sem, opal_max_async_tokens - 1);
+
+out_opal_node:
+	of_node_put(opal_node);
+out:
+	return err;
+}
+subsys_initcall(opal_async_comp_init);

^ permalink raw reply related

* Re: [PATCH] kexec/powerpc: fix exporting memory limit
From: Nikita Yushchenko @ 2014-03-07  4:38 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: yadviga, lugovskoy, kexec, linux-kernel, Paul Mackerras,
	Anton Blanchard, Mahesh Salgaonkar, Hari Bathini, linuxppc-dev
In-Reply-To: <1394153258.21206.1.camel@concordia>

> On Thu, 2014-03-06 at 18:24 +0400, Nikita Yushchenko wrote:
> > When preparing dump-capturing kernel, kexec userspace tool needs to
> > know actual amount of memory used by the running kernel. This may
> > differ from extire available DRAM for a couple of reasons. To address
> > this issue, kdump kernel support code injects several attributes into
> > device tree that are later captured by userspace kexec tool via /proc
> > interface.
> >
> > One such attrubute is 'chosen/linux,memory_limit' that is used to pass
> > memory limit of the running kernel.
> >
> > This was initialized using kernel's 'memory_limit' variable, that is
> > set by early init code based on mem= kernel parameter and other
> > reasons.
> >
> > But there are cases when memory_limit variable does not contain proper
> > information. One such case is when !CONFIG_HIGHMEM kernel runs on
> > system with memory large enough not to fit into lowmem.
>
> Why doesn't the !CONFIG_HIGHMEM code update memory_limit to reflect
> reality.

I guess because memory_limit is used for ... well, memory limit, set by 
mem=. And for the rest memblock is used (and it *is* updated).

And code elsewhere does use memblock, see e.g. numa_enforce_memory_limit() 
in arch/powerpc/mm/numa.c

In MMU init (MMU_init() in arch/powerpc/mm/init_32.c -which is the point 
where final memory configuration is set) memblock, not memory_limit, is 
both used and updated.

^ permalink raw reply

* [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers
From: Chenhui Zhao @ 2014-03-07  4:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

From: Wang Dongsheng <dongsheng.wang@freescale.com>

Add booke_cpu_state_save() and booke_cpu_state_restore() functions which can be
used to save/restore CPU's registers in the case of deep sleep and hibernation.

Supported processors: E6500, E5500, E500MC, E500v2 and E500v1.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
 arch/powerpc/include/asm/booke_save_regs.h |   96 ++++++++
 arch/powerpc/kernel/Makefile               |    1 +
 arch/powerpc/kernel/booke_save_regs.S      |  361 ++++++++++++++++++++++++++++
 3 files changed, 458 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/booke_save_regs.h
 create mode 100644 arch/powerpc/kernel/booke_save_regs.S

diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
new file mode 100644
index 0000000..87c357a
--- /dev/null
+++ b/arch/powerpc/include/asm/booke_save_regs.h
@@ -0,0 +1,96 @@
+/*
+ *  Save/restore e500 series core registers
+ *
+ * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_FSL_SLEEP_H
+#define __ASM_FSL_SLEEP_H
+
+/*
+ * 8 bytes for each register, which is compatible with
+ * both 32-bit and 64-bit registers
+ *
+ * Acronyms:
+ *	dw(data width)	0x08
+ *
+ * Map:
+ * General-Purpose Registers
+ *	GPR1(sp)		0
+ *	GPR2			0x8		(dw * 1)
+ *	GPR13 - GPR31		0x10 ~ 0xa0	(dw * 2 ~ dw * 20)
+ * Foating-point registers
+ *	FPR14 - FPR31		0xa8 ~ 0x130	(dw * 21 ~ dw * 38)
+ * Registers for Branch Operations
+ *	CR			0x138		(dw * 39)
+ *	LR			0x140		(dw * 40)
+ * Processor Control Registers
+ *	MSR			0x148		(dw * 41)
+ *	EPCR			0x150		(dw * 42)
+ *
+ *	Only e500, e500v2 need to save HID0 - HID1
+ *	HID0 - HID1		0x158 ~ 0x160 (dw * 43 ~ dw * 44)
+ * Timer Registers
+ *	TCR			0x168		(dw * 45)
+ *	TB(64bit)		0x170		(dw * 46)
+ *	TBU(32bit)		0x178		(dw * 47)
+ *	TBL(32bit)		0x180		(dw * 48)
+ * Interrupt Registers
+ *	IVPR			0x188		(dw * 49)
+ *	IVOR0 - IVOR15		0x190 ~ 0x208	(dw * 50 ~ dw * 65)
+ *	IVOR32 - IVOR41		0x210 ~ 0x258	(dw * 66 ~ dw * 75)
+ * Software-Use Registers
+ *	SPRG1			0x260		(dw * 76), 64-bit need to save.
+ *	SPRG3			0x268		(dw * 77), 32-bit need to save.
+ * MMU Registers
+ *	PID0 - PID2		0x270 ~ 0x280	(dw * 78 ~ dw * 80)
+ * Debug Registers
+ *	DBCR0 - DBCR2		0x288 ~ 0x298	(dw * 81 ~ dw * 83)
+ *	IAC1 - IAC4		0x2a0 ~ 0x2b8	(dw * 84 ~ dw * 87)
+ *	DAC1 - DAC2		0x2c0 ~ 0x2c8	(dw * 88 ~ dw * 89)
+ *
+ */
+
+#define SR_GPR1			0x000
+#define SR_GPR2			0x008
+#define SR_GPR13		0x010
+#define SR_FPR14		0x0a8
+#define SR_CR			0x138
+#define SR_LR			0x140
+#define SR_MSR			0x148
+#define SR_EPCR			0x150
+#define SR_HID0			0x158
+#define SR_TCR			0x168
+#define SR_TB			0x170
+#define SR_TBU			0x178
+#define SR_TBL			0x180
+#define SR_IVPR			0x188
+#define SR_IVOR0		0x190
+#define SR_IVOR32		0x210
+#define SR_SPRG1		0x260
+#define SR_SPRG3		0x268
+#define SR_PID0			0x270
+#define SR_DBCR0		0x288
+#define SR_IAC1			0x2a0
+#define SR_DAC1			0x2c0
+#define REGS_BUFFER_SIZE	(SR_DAC1 + 0x10)
+
+/*
+ * hibernation and deepsleep save/restore different number of registers,
+ * use these flags to indicate.
+ */
+#define HIBERNATION_FLAG	1
+#define DEEPSLEEP_FLAG		2
+
+#ifndef __ASSEMBLY__
+extern void booke_cpu_state_save(void *buf, int type);
+extern void *booke_cpu_state_restore(void *buf, int type);
+#endif
+#endif
+
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index fcc9a89..64acae6 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_HIBERNATION)	+= swsusp_booke.o
 else
 obj-$(CONFIG_HIBERNATION)	+= swsusp_$(CONFIG_WORD_SIZE).o
 endif
+obj-$(CONFIG_E500)		+= booke_save_regs.o
 obj64-$(CONFIG_HIBERNATION)	+= swsusp_asm64.o
 obj-$(CONFIG_MODULES)		+= module.o module_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_44x)		+= cpu_setup_44x.o
diff --git a/arch/powerpc/kernel/booke_save_regs.S b/arch/powerpc/kernel/booke_save_regs.S
new file mode 100644
index 0000000..9ccd576
--- /dev/null
+++ b/arch/powerpc/kernel/booke_save_regs.S
@@ -0,0 +1,361 @@
+/*
+ * Freescale Power Management, Save/Restore core state
+ *
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/booke_save_regs.h>
+
+/*
+ * Supported Core List:
+ * E500v1, E500v2, E500MC, E5500, E6500.
+ */
+
+/* Save/Restore register operation define */
+#define do_save_gpr_reg(reg, addr) \
+	PPC_STL reg, addr(r10)
+
+#define do_save_fpr_reg(reg, addr) \
+	stfd	reg, addr(r10)
+
+#define do_save_spr_reg(reg, addr) \
+	mfspr	r0, SPRN_##reg ;\
+	PPC_STL r0, addr(r10)
+
+#define do_save_special_reg(special, addr) \
+	mf##special	r0 ;\
+	PPC_STL r0, addr(r10)
+
+#define do_restore_gpr_reg(reg, addr) \
+	PPC_LL reg, addr(r10)
+
+#define do_restore_fpr_reg(reg, addr) \
+	lfd	reg, addr(r10)
+
+#define do_restore_spr_reg(reg, addr) \
+	PPC_LL r0, addr(r10) ;\
+	mtspr	SPRN_##reg, r0
+
+#define do_restore_special_reg(special, addr) \
+	PPC_LL r0, addr(r10) ;\
+	mt##special	r0
+
+#define do_sr_general_gpr_regs(func) \
+	do_##func##_gpr_reg(r1, SR_GPR1) ;\
+	do_##func##_gpr_reg(r2, SR_GPR2) ;\
+	do_##func##_gpr_reg(r13, SR_GPR13 + 0x00) ;\
+	do_##func##_gpr_reg(r14, SR_GPR13 + 0x08) ;\
+	do_##func##_gpr_reg(r15, SR_GPR13 + 0x10) ;\
+	do_##func##_gpr_reg(r16, SR_GPR13 + 0x18) ;\
+	do_##func##_gpr_reg(r17, SR_GPR13 + 0x20) ;\
+	do_##func##_gpr_reg(r18, SR_GPR13 + 0x28) ;\
+	do_##func##_gpr_reg(r19, SR_GPR13 + 0x30) ;\
+	do_##func##_gpr_reg(r20, SR_GPR13 + 0x38) ;\
+	do_##func##_gpr_reg(r21, SR_GPR13 + 0x40) ;\
+	do_##func##_gpr_reg(r22, SR_GPR13 + 0x48) ;\
+	do_##func##_gpr_reg(r23, SR_GPR13 + 0x50) ;\
+	do_##func##_gpr_reg(r24, SR_GPR13 + 0x58) ;\
+	do_##func##_gpr_reg(r25, SR_GPR13 + 0x60) ;\
+	do_##func##_gpr_reg(r26, SR_GPR13 + 0x68) ;\
+	do_##func##_gpr_reg(r27, SR_GPR13 + 0x70) ;\
+	do_##func##_gpr_reg(r28, SR_GPR13 + 0x78) ;\
+	do_##func##_gpr_reg(r29, SR_GPR13 + 0x80) ;\
+	do_##func##_gpr_reg(r30, SR_GPR13 + 0x88) ;\
+	do_##func##_gpr_reg(r31, SR_GPR13 + 0x90)
+
+#define do_sr_general_pcr_regs(func) \
+	do_##func##_spr_reg(EPCR, SR_EPCR) ;\
+	do_##func##_spr_reg(HID0, SR_HID0 + 0x00)
+
+#define do_sr_e500_pcr_regs(func) \
+	do_##func##_spr_reg(HID1, SR_HID0 + 0x08)
+
+#define do_sr_save_tb_regs \
+	do_save_spr_reg(TBRU, SR_TBU) ;\
+	do_save_spr_reg(TBRL, SR_TBL)
+
+#define do_sr_restore_tb_regs \
+	do_restore_spr_reg(TBWU, SR_TBU) ;\
+	do_restore_spr_reg(TBWL, SR_TBL)
+
+#define do_sr_general_time_regs(func) \
+	do_sr_##func##_tb_regs	;\
+	do_##func##_spr_reg(TCR, SR_TCR)
+
+#define do_sr_interrupt_regs(func) \
+	do_##func##_spr_reg(IVPR, SR_IVPR) ;\
+	do_##func##_spr_reg(IVOR0, SR_IVOR0 + 0x00) ;\
+	do_##func##_spr_reg(IVOR1, SR_IVOR0 + 0x08) ;\
+	do_##func##_spr_reg(IVOR2, SR_IVOR0 + 0x10) ;\
+	do_##func##_spr_reg(IVOR3, SR_IVOR0 + 0x18) ;\
+	do_##func##_spr_reg(IVOR4, SR_IVOR0 + 0x20) ;\
+	do_##func##_spr_reg(IVOR5, SR_IVOR0 + 0x28) ;\
+	do_##func##_spr_reg(IVOR6, SR_IVOR0 + 0x30) ;\
+	do_##func##_spr_reg(IVOR7, SR_IVOR0 + 0x38) ;\
+	do_##func##_spr_reg(IVOR8, SR_IVOR0 + 0x40) ;\
+	do_##func##_spr_reg(IVOR10, SR_IVOR0 + 0x50) ;\
+	do_##func##_spr_reg(IVOR11, SR_IVOR0 + 0x58) ;\
+	do_##func##_spr_reg(IVOR12, SR_IVOR0 + 0x60) ;\
+	do_##func##_spr_reg(IVOR13, SR_IVOR0 + 0x68) ;\
+	do_##func##_spr_reg(IVOR14, SR_IVOR0 + 0x70) ;\
+	do_##func##_spr_reg(IVOR15, SR_IVOR0 + 0x78)
+
+#define do_e500_sr_interrupt_regs(func) \
+	do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
+	do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
+	do_##func##_spr_reg(IVOR34, SR_IVOR32 + 0x10)
+
+#define do_e500mc_sr_interrupt_regs(func) \
+	do_##func##_spr_reg(IVOR9, SR_IVOR0 + 0x48) ;\
+	do_##func##_spr_reg(IVOR35, SR_IVOR32 + 0x18) ;\
+	do_##func##_spr_reg(IVOR36, SR_IVOR32 + 0x20) ;\
+	do_##func##_spr_reg(IVOR37, SR_IVOR32 + 0x28) ;\
+	do_##func##_spr_reg(IVOR38, SR_IVOR32 + 0x30) ;\
+	do_##func##_spr_reg(IVOR39, SR_IVOR32 + 0x38) ;\
+	do_##func##_spr_reg(IVOR40, SR_IVOR32 + 0x40) ;\
+	do_##func##_spr_reg(IVOR41, SR_IVOR32 + 0x48)
+
+#define do_e5500_sr_interrupt_regs(func) \
+	do_e500mc_sr_interrupt_regs(func)
+
+#define do_e6500_sr_interrupt_regs(func) \
+	do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
+	do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
+	do_e5500_sr_interrupt_regs(func)
+
+#define do_sr_general_software_regs(func) \
+	do_##func##_spr_reg(SPRG1, SR_SPRG1) ;\
+	do_##func##_spr_reg(SPRG3, SR_SPRG3) ;\
+	do_##func##_spr_reg(PID0, SR_PID0)
+
+#define do_sr_e500_mmu_regs(func) \
+	do_##func##_spr_reg(PID1, SR_PID0 + 0x08) ;\
+	do_##func##_spr_reg(PID2, SR_PID0 + 0x10)
+
+#define do_sr_debug_regs(func) \
+	do_##func##_spr_reg(DBCR0, SR_DBCR0 + 0x00) ;\
+	do_##func##_spr_reg(DBCR1, SR_DBCR0 + 0x08) ;\
+	do_##func##_spr_reg(DBCR2, SR_DBCR0 + 0x10) ;\
+	do_##func##_spr_reg(IAC1, SR_IAC1 + 0x00) ;\
+	do_##func##_spr_reg(IAC2, SR_IAC1 + 0x08) ;\
+	do_##func##_spr_reg(DAC1, SR_DAC1 + 0x00) ;\
+	do_##func##_spr_reg(DAC2, SR_DAC1 + 0x08)
+
+#define do_e6500_sr_debug_regs(func) \
+	do_##func##_spr_reg(IAC3, SR_IAC1 + 0x10) ;\
+	do_##func##_spr_reg(IAC4, SR_IAC1 + 0x18)
+
+	.section .text
+	.align	5
+booke_cpu_base_save:
+	do_sr_general_gpr_regs(save)
+	do_sr_general_pcr_regs(save)
+	do_sr_general_software_regs(save)
+1:
+	mfspr	r5, SPRN_TBRU
+	do_sr_general_time_regs(save)
+	mfspr	r6, SPRN_TBRU
+	cmpw	r5, r6
+	bne	1b
+
+	blr
+
+booke_cpu_base_restore:
+	do_sr_general_gpr_regs(restore)
+	do_sr_general_pcr_regs(restore)
+	do_sr_general_software_regs(restore)
+
+	isync
+
+	/* Restore Time registers, clear tb lower to avoid wrap */
+	li	r0, 0
+	mtspr	SPRN_TBWL, r0
+	do_sr_general_time_regs(restore)
+
+	/* clear out status */
+	mfspr   r0,SPRN_TSR
+	mtspr   SPRN_TSR, r0
+
+	blr
+
+/* Base registers, e500v1, e500v2 need to do some special save/restore */
+e500_base_special_save:
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V1@l
+	cmpw	r11, r12
+	beq	1f
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V2@l
+	cmpw	r11, r12
+	bne	2f
+1:
+	do_sr_e500_pcr_regs(save)
+	do_sr_e500_mmu_regs(save)
+2:
+	blr
+
+e500_base_special_restore:
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V1@l
+	cmpw	r11, r12
+	beq	1f
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V2@l
+	cmpw	r11, r12
+	bne	2f
+1:
+	do_sr_e500_pcr_regs(save)
+	do_sr_e500_mmu_regs(save)
+2:
+	blr
+
+booke_cpu_append_save:
+	mfspr	r0, SPRN_PVR
+	rlwinm	r11, r0, 16, 16, 31
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E6500@l
+	cmpw	r11, r12
+	beq	e6500_append_save
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E5500@l
+	cmpw	r11, r12
+	beq	e5500_append_save
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500MC@l
+	cmpw	r11, r12
+	beq	e500mc_append_save
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V2@l
+	cmpw	r11, r12
+	beq	e500v2_append_save
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V1@l
+	cmpw	r11, r12
+	beq	e500v1_append_save
+	b	1f
+
+e6500_append_save:
+	do_e6500_sr_interrupt_regs(save)
+	do_e6500_sr_debug_regs(save)
+	b	1f
+
+e5500_append_save:
+	do_e5500_sr_interrupt_regs(save)
+	b	1f
+
+e500mc_append_save:
+	do_e500mc_sr_interrupt_regs(save)
+	b	1f
+
+e500v2_append_save:
+e500v1_append_save:
+	do_e500_sr_interrupt_regs(save)
+1:
+	do_sr_interrupt_regs(save)
+	do_sr_debug_regs(save)
+
+	blr
+
+booke_cpu_append_restore:
+	mfspr	r0, SPRN_PVR
+	rlwinm	r11, r0, 16, 16, 31
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E6500@l
+	cmpw	r11, r12
+	beq	e6500_append_restore
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E5500@l
+	cmpw	r11, r12
+	beq	e5500_append_restore
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500MC@l
+	cmpw	r11, r12
+	beq	e500mc_append_restore
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V2@l
+	cmpw	r11, r12
+	beq	e500v2_append_restore
+
+	lis	r12, 0
+	ori	r12, r12, PVR_VER_E500V1@l
+	cmpw	r11, r12
+	beq	e500v1_append_restore
+	b	1f
+
+e6500_append_restore:
+	do_e6500_sr_interrupt_regs(restore)
+	do_e6500_sr_debug_regs(restore)
+	b	1f
+
+e5500_append_restore:
+	do_e5500_sr_interrupt_regs(restore)
+	b	1f
+
+e500mc_append_restore:
+	do_e500mc_sr_interrupt_regs(restore)
+	b	1f
+
+e500v2_append_restore:
+e500v1_append_restore:
+	do_e500_sr_interrupt_regs(restore)
+1:
+	do_sr_interrupt_regs(restore)
+	do_sr_debug_regs(restore)
+	sync
+
+	blr
+
+/*
+ * r3 = the address of buffer
+ * r4 = type: HIBERNATION_FLAG or DEEPSLEEP_FLAG
+ */
+_GLOBAL(booke_cpu_state_save)
+	mflr	r9
+	mr	r10, r3
+
+	cmpwi	r4, HIBERNATION_FLAG
+	beq	1f
+	bl	booke_cpu_append_save
+1:
+	bl	e500_base_special_save
+	bl	booke_cpu_base_save
+
+	mtlr	r9
+	blr
+
+/*
+ * r3 = the address of buffer
+ * r4 = type: HIBERNATION_FLAG or DEEPSLEEP_FLAG
+ */
+_GLOBAL(booke_cpu_state_restore)
+	mflr	r9
+	mr	r10, r3
+
+	cmpwi	r4, HIBERNATION_FLAG
+	beq	1f
+
+	bl	booke_cpu_append_restore
+1:
+	bl	e500_base_special_restore
+	bl	booke_cpu_base_restore
+
+	mtlr	r9
+	blr
-- 
1.7.3

^ permalink raw reply related

* [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
From: Chenhui Zhao @ 2014-03-07  4:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

From: Zhao Chenhui <chenhui.zhao@freescale.com>

T1040 supports deep sleep feature, which can switch off most parts of
the SoC when it is in deep sleep mode. This way, it becomes more
energy-efficient.

The DDR controller will also be powered off in deep sleep. Therefore,
the last stage (the latter part of fsl_dp_enter_low) will run without DDR
access. This piece of code and related TLBs will be prefetched.

Due to the different initialization code between 32-bit and 64-bit, they
have seperate resume entry and precedure.

The feature supports 32-bit and 64-bit kernel mode.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/include/asm/booke_save_regs.h |    3 +
 arch/powerpc/kernel/cpu_setup_fsl_booke.S  |   17 ++
 arch/powerpc/kernel/head_fsl_booke.S       |   30 +++
 arch/powerpc/platforms/85xx/Makefile       |    2 +-
 arch/powerpc/platforms/85xx/deepsleep.c    |  201 +++++++++++++++++++
 arch/powerpc/platforms/85xx/qoriq_pm.c     |   38 ++++
 arch/powerpc/platforms/85xx/sleep.S        |  295 ++++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.h              |    7 +
 8 files changed, 592 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
 create mode 100644 arch/powerpc/platforms/85xx/sleep.S

diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
index 87c357a..37c1f6c 100644
--- a/arch/powerpc/include/asm/booke_save_regs.h
+++ b/arch/powerpc/include/asm/booke_save_regs.h
@@ -88,6 +88,9 @@
 #define HIBERNATION_FLAG	1
 #define DEEPSLEEP_FLAG		2
 
+#define CPLD_FLAG	1
+#define FPGA_FLAG	2
+
 #ifndef __ASSEMBLY__
 extern void booke_cpu_state_save(void *buf, int type);
 extern void *booke_cpu_state_restore(void *buf, int type);
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index e59d6de..ea9bc28 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -318,6 +318,23 @@ flush_backside_L2_cache:
 2:
 	blr
 
+#define CPC_CPCCSR0		0x0
+#define CPC_CPCCSR0_CPCFL	0x800
+
+/* r3 : the base address of CPC  */
+_GLOBAL(fsl_flush_cpc_cache)
+	lwz	r6, CPC_CPCCSR0(r3)
+	ori	r6, r6, CPC_CPCCSR0_CPCFL
+	stw	r6, CPC_CPCCSR0(r3)
+	sync
+
+	/* Wait until completing the flush */
+1:	lwz	r6, CPC_CPCCSR0(r3)
+	andi.	r6, r6, CPC_CPCCSR0_CPCFL
+	bne	1b
+
+	blr
+
 _GLOBAL(__flush_caches_e500v2)
 	mflr r0
 	bl	flush_dcache_L1
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 20204fe..3285752 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -162,6 +162,19 @@ _ENTRY(__early_start)
 #include "fsl_booke_entry_mapping.S"
 #undef ENTRY_MAPPING_BOOT_SETUP
 
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
+	/* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
+	LOAD_REG_ADDR(r4, deep_sleep_flag)
+	lwz	r3, 0(r4)
+	cmpwi	r3, 0
+	beq	11f
+	/* clear deep_sleep_flag */
+	li	r3, 0
+	stw	r3, 0(r4)
+	b	fsl_deepsleep_resume
+11:
+#endif
+
 set_ivor:
 	/* Establish the interrupt vector offsets */
 	SET_IVOR(0,  CriticalInput);
@@ -343,6 +356,23 @@ set_ivor:
 	lwz	r11, 0(r12);		/* Get Linux PTE */
 #endif
 
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
+_ENTRY(__entry_deep_sleep)
+/*
+ * Bootloader will jump to here when resuming from deep sleep.
+ * After executing the init code in fsl_booke_entry_mapping.S,
+ * will jump to the real resume entry.
+ */
+	li	r8, 1
+	bl	12f
+12:	mflr	r9
+	addi	r9, r9, (deep_sleep_flag - 12b)
+	stw	r8, 0(r9)
+	b __early_start
+deep_sleep_flag:
+	.long	0
+#endif
+
 /*
  * Interrupt vector entry code
  *
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 7fae817..9a4ea86 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,7 +3,7 @@
 #
 obj-$(CONFIG_SMP) += smp.o
 ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
-obj-$(CONFIG_SUSPEND)	+= qoriq_pm.o
+obj-$(CONFIG_SUSPEND)	+= qoriq_pm.o deepsleep.o sleep.o
 endif
 
 obj-y += common.o
diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c
new file mode 100644
index 0000000..ddd7185
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/deepsleep.c
@@ -0,0 +1,201 @@
+/*
+ * Support deep sleep feature
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <asm/machdep.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/booke_save_regs.h>
+
+#define SIZE_1MB	0x100000
+#define SIZE_2MB	0x200000
+
+#define CCSR_SCFG_DPSLPCR	0xfc000
+#define CCSR_SCFG_DPSLPCR_WDRR_EN	0x1
+#define CCSR_SCFG_SPARECR2	0xfc504
+#define CCSR_SCFG_SPARECR3	0xfc508
+
+#define CCSR_GPIO1_GPDIR	0x130000
+#define CCSR_GPIO1_GPODR	0x130004
+#define CCSR_GPIO1_GPDAT	0x130008
+#define CCSR_GPIO1_GPDIR_29		0x4
+
+/* 128 bytes buffer for restoring data broke by DDR training initialization */
+#define DDR_BUF_SIZE	128
+static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64);
+
+static void *dcsr_base, *ccsr_base, *pld_base;
+static int pld_flag;
+
+int fsl_dp_iomap(void)
+{
+	struct device_node *np;
+	const u32 *prop;
+	int ret = 0;
+	u64 ccsr_phy_addr, dcsr_phy_addr;
+
+	np = of_find_node_by_type(NULL, "soc");
+	if (!np) {
+		pr_err("%s: Can't find the node of \"soc\"\n", __func__);
+		ret = -EINVAL;
+		goto ccsr_err;
+	}
+	prop = of_get_property(np, "ranges", NULL);
+	if (!prop) {
+		pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
+		of_node_put(np);
+		ret = -EINVAL;
+		goto ccsr_err;
+	}
+	ccsr_phy_addr = of_translate_address(np, prop + 1);
+	ccsr_base = ioremap((phys_addr_t)ccsr_phy_addr, SIZE_2MB);
+	of_node_put(np);
+	if (!ccsr_base) {
+		ret = -ENOMEM;
+		goto ccsr_err;
+	}
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,dcsr");
+	if (!np) {
+		pr_err("%s: Can't find the node of \"fsl,dcsr\"\n", __func__);
+		ret = -EINVAL;
+		goto dcsr_err;
+	}
+	prop = of_get_property(np, "ranges", NULL);
+	if (!prop) {
+		pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
+		of_node_put(np);
+		ret = -EINVAL;
+		goto dcsr_err;
+	}
+	dcsr_phy_addr = of_translate_address(np, prop + 1);
+	dcsr_base = ioremap((phys_addr_t)dcsr_phy_addr, SIZE_1MB);
+	of_node_put(np);
+	if (!dcsr_base) {
+		ret = -ENOMEM;
+		goto dcsr_err;
+	}
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,fpga-qixis");
+	if (np) {
+		pld_flag = FPGA_FLAG;
+	} else {
+		np = of_find_compatible_node(NULL, NULL, "fsl,p104xrdb-cpld");
+		if (np) {
+			pld_flag = CPLD_FLAG;
+		} else {
+			pr_err("%s: Can't find the FPGA/CPLD node\n",
+					__func__);
+			ret = -EINVAL;
+			goto pld_err;
+		}
+	}
+	pld_base = of_iomap(np, 0);
+	of_node_put(np);
+
+	return 0;
+
+pld_err:
+	iounmap(dcsr_base);
+dcsr_err:
+	iounmap(ccsr_base);
+ccsr_err:
+	ccsr_base = NULL;
+	dcsr_base = NULL;
+	pld_base = NULL;
+	return ret;
+}
+
+void fsl_dp_iounmap(void)
+{
+	if (dcsr_base) {
+		iounmap(dcsr_base);
+		dcsr_base = NULL;
+	}
+
+	if (ccsr_base) {
+		iounmap(ccsr_base);
+		ccsr_base = NULL;
+	}
+
+	if (pld_base) {
+		iounmap(pld_base);
+		pld_base = NULL;
+	}
+}
+
+static void fsl_dp_ddr_save(void *ccsr_base)
+{
+	u32 ddr_buff_addr;
+
+	/*
+	 * DDR training initialization will break 128 bytes at the beginning
+	 * of DDR, therefore, save them so that the bootloader will restore
+	 * them. Assume that DDR is mapped to the address space started with
+	 * CONFIG_PAGE_OFFSET.
+	 */
+	memcpy(ddr_buff, (void *)CONFIG_PAGE_OFFSET, DDR_BUF_SIZE);
+
+	/* assume ddr_buff is in the physical address space of 4GB */
+	ddr_buff_addr = (u32)(__pa(ddr_buff) & 0xffffffff);
+
+	/*
+	 * the bootloader will restore the first 128 bytes of DDR from
+	 * the location indicated by the register SPARECR3
+	 */
+	out_be32(ccsr_base + CCSR_SCFG_SPARECR3, ddr_buff_addr);
+}
+
+static void fsl_dp_set_resume_pointer(void *ccsr_base)
+{
+	u32 resume_addr;
+
+	/* the bootloader will finally jump to this address to return kernel */
+#ifdef CONFIG_PPC32
+	resume_addr = (u32)(__pa(__entry_deep_sleep));
+#else
+	resume_addr = (u32)(__pa(*(u64 *)__entry_deep_sleep) & 0xffffffff);
+#endif
+
+	/* use the register SPARECR2 to save the resume address */
+	out_be32(ccsr_base + CCSR_SCFG_SPARECR2, resume_addr);
+
+}
+
+int fsl_enter_epu_deepsleep(void)
+{
+
+	fsl_dp_ddr_save(ccsr_base);
+
+	fsl_dp_set_resume_pointer(ccsr_base);
+
+	/*  enable Warm Device Reset request. */
+	setbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+	/* set GPIO1_29 as an output pin (not open-drain), and output 0 */
+	clrbits32(ccsr_base + CCSR_GPIO1_GPDAT, CCSR_GPIO1_GPDIR_29);
+	clrbits32(ccsr_base + CCSR_GPIO1_GPODR, CCSR_GPIO1_GPDIR_29);
+	setbits32(ccsr_base + CCSR_GPIO1_GPDIR, CCSR_GPIO1_GPDIR_29);
+
+	fsl_dp_fsm_setup(dcsr_base);
+
+	fsl_dp_enter_low(ccsr_base, dcsr_base, pld_base, pld_flag);
+
+	/* disable Warm Device Reset request */
+	clrbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+	fsl_dp_fsm_clean(dcsr_base);
+
+	return 0;
+}
diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
index 915b13b..5f2c016 100644
--- a/arch/powerpc/platforms/85xx/qoriq_pm.c
+++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
@@ -20,6 +20,8 @@
 #define FSL_SLEEP		0x1
 #define FSL_DEEP_SLEEP		0x2
 
+int (*fsl_enter_deepsleep)(void);
+
 /* specify the sleep state of the present platform */
 int sleep_pm_state;
 /* supported sleep modes by the present platform */
@@ -28,6 +30,7 @@ static unsigned int sleep_modes;
 static int qoriq_suspend_enter(suspend_state_t state)
 {
 	int ret = 0;
+	int cpu;
 
 	switch (state) {
 	case PM_SUSPEND_STANDBY:
@@ -39,6 +42,17 @@ static int qoriq_suspend_enter(suspend_state_t state)
 
 		break;
 
+	case PM_SUSPEND_MEM:
+
+		cpu = smp_processor_id();
+		qoriq_pm_ops->irq_mask(cpu);
+
+		ret = fsl_enter_deepsleep();
+
+		qoriq_pm_ops->irq_unmask(cpu);
+
+		break;
+
 	default:
 		ret = -EINVAL;
 
@@ -52,12 +66,30 @@ static int qoriq_suspend_valid(suspend_state_t state)
 	if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_SLEEP))
 		return 1;
 
+	if (state == PM_SUSPEND_MEM && (sleep_modes & FSL_DEEP_SLEEP))
+		return 1;
+
 	return 0;
 }
 
+static int qoriq_suspend_begin(suspend_state_t state)
+{
+	if (state == PM_SUSPEND_MEM)
+		return fsl_dp_iomap();
+
+	return 0;
+}
+
+static void qoriq_suspend_end(void)
+{
+	fsl_dp_iounmap();
+}
+
 static const struct platform_suspend_ops qoriq_suspend_ops = {
 	.valid = qoriq_suspend_valid,
 	.enter = qoriq_suspend_enter,
+	.begin = qoriq_suspend_begin,
+	.end = qoriq_suspend_end,
 };
 
 static int __init qoriq_suspend_init(void)
@@ -71,6 +103,12 @@ static int __init qoriq_suspend_init(void)
 	if (np)
 		sleep_pm_state = PLAT_PM_LPM20;
 
+	np = of_find_compatible_node(NULL, NULL, "fsl,t1040-rcpm");
+	if (np) {
+		fsl_enter_deepsleep = fsl_enter_epu_deepsleep;
+		sleep_modes |= FSL_DEEP_SLEEP;
+	}
+
 	suspend_set_ops(&qoriq_suspend_ops);
 
 	return 0;
diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
new file mode 100644
index 0000000..95a5746
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep.S
@@ -0,0 +1,295 @@
+/*
+ * Implement the low level part of deep sleep
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+#include <asm/booke_save_regs.h>
+#include <asm/mmu.h>
+
+#define FSLDELAY(count)		\
+	li	r3, (count)@l;	\
+	slwi	r3, r3, 10;	\
+	mtctr	r3;		\
+101:	nop;			\
+	bdnz	101b;
+
+#define FSL_DIS_ALL_IRQ		\
+	mfmsr	r8;			\
+	rlwinm	r8, r8, 0, ~MSR_CE;	\
+	rlwinm	r8, r8, 0, ~MSR_ME;	\
+	rlwinm	r8, r8, 0, ~MSR_EE;	\
+	rlwinm	r8, r8, 0, ~MSR_DE;	\
+	mtmsr	r8;			\
+	isync
+
+
+	.section .data
+	.align	6
+booke_regs_buffer:
+	.space REGS_BUFFER_SIZE
+
+	.section .txt
+	.align 6
+
+_GLOBAL(fsl_dp_enter_low)
+deepsleep_start:
+	LOAD_REG_ADDR(r9, buf_tmp)
+	PPC_STL	r3, 0(r9)
+	PPC_STL	r4, 8(r9)
+	PPC_STL	r5, 16(r9)
+	PPC_STL	r6, 24(r9)
+
+	LOAD_REG_ADDR(r3, booke_regs_buffer)
+	/* save the return address */
+	mflr	r5
+	PPC_STL r5, SR_LR(r3)
+	mfmsr	r5
+	PPC_STL r5, SR_MSR(r3)
+	li	r4, DEEPSLEEP_FLAG
+	bl	booke_cpu_state_save
+
+	LOAD_REG_ADDR(r9, buf_tmp)
+	PPC_LL	r31, 0(r9)
+	PPC_LL	r30, 8(r9)
+	PPC_LL	r29, 16(r9)
+	PPC_LL	r28, 24(r9)
+
+	/* flush caches */
+	LOAD_REG_ADDR(r3, cur_cpu_spec)
+	PPC_LL	r3, 0(r3)
+	PPC_LL	r3, CPU_FLUSH_CACHES(r3)
+	PPC_LCMPI  0, r3, 0
+	beq	6f
+#ifdef CONFIG_PPC64
+	PPC_LL	r3, 0(r3)
+#endif
+	mtctr	r3
+	bctrl
+6:
+#define CPC_OFFSET	0x10000
+	mr	r3, r31
+	addis	r3, r3, CPC_OFFSET@h
+	bl	fsl_flush_cpc_cache
+
+	LOAD_REG_ADDR(r8, deepsleep_start)
+	LOAD_REG_ADDR(r9, deepsleep_end)
+
+	/* prefecth TLB */
+#define CCSR_GPIO1_GPDAT	0x130008
+#define CCSR_GPIO1_GPDAT_29	0x4
+	LOAD_REG_IMMEDIATE(r11, CCSR_GPIO1_GPDAT)
+	add	r11, r31, r11
+	lwz	r10, 0(r11)
+
+#define CCSR_RCPM_PCPH15SETR	0xe20b4
+#define CCSR_RCPM_PCPH15SETR_CORE0	0x1
+	LOAD_REG_IMMEDIATE(r12, CCSR_RCPM_PCPH15SETR)
+	add	r12, r31, r12
+	lwz	r10, 0(r12)
+
+#define CCSR_DDR_SDRAM_CFG_2	0x8114
+#define CCSR_DDR_SDRAM_CFG_2_FRC_SR	0x80000000
+	LOAD_REG_IMMEDIATE(r13, CCSR_DDR_SDRAM_CFG_2)
+	add	r13, r31, r13
+	lwz	r10, 0(r13)
+
+#define	DCSR_EPU_EPGCR		0x000
+#define DCSR_EPU_EPGCR_GCE	0x80000000
+	li	r14, DCSR_EPU_EPGCR
+	add	r14, r30, r14
+	lwz	r10, 0(r14)
+
+#define	DCSR_EPU_EPECR15	0x33C
+#define DCSR_EPU_EPECR15_IC0	0x80000000
+	li	r15, DCSR_EPU_EPECR15
+	add	r15, r30, r15
+	lwz	r10, 0(r15)
+
+#define CCSR_SCFG_QMCRDTRSTCR		0xfc40c
+#define CCSR_SCFG_QMCRDTRSTCR_CRDTRST	0x80000000
+	LOAD_REG_IMMEDIATE(r16, CCSR_SCFG_QMCRDTRSTCR)
+	add	r16, r31, r16
+	lwz	r10, 0(r16)
+
+/*
+ * There are two kind of register maps, one for CPLD and the other for FPGA
+ */
+#define CPLD_MISCCSR		0x17
+#define CPLD_MISCCSR_SLEEPEN	0x40
+#define QIXIS_PWR_CTL2		0x21
+#define QIXIS_PWR_CTL2_PCTL	0x2
+	PPC_LCMPI  0, r28, FPGA_FLAG
+	beq	20f
+	addi	r29, r29, CPLD_MISCCSR
+20:
+	addi	r29, r29, QIXIS_PWR_CTL2
+	lbz	r10, 0(r29)
+
+	/* prefecth code to cache so that executing code after disable DDR */
+1:	lwz	r3, 0(r8)
+	addi	r8, r8, 4
+	cmpw	r8, r9
+	blt	1b
+	msync
+
+	FSL_DIS_ALL_IRQ
+
+	/*
+	 * Place DDR controller in self refresh mode.
+	 * From here on, DDR can't be access any more.
+	 */
+	lwz	r10, 0(r13)
+	oris	r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
+	stw	r10, 0(r13)
+
+	/* can't call udelay() here, so use a macro to delay */
+	FSLDELAY(50)
+
+	/*
+	 * Enable deep sleep signals by write external CPLD/FPGA register.
+	 * The bootloader will disable them when wakeup from deep sleep.
+	 */
+	lbz	r10, 0(r29)
+	PPC_LCMPI  0, r28, FPGA_FLAG
+	beq	22f
+	ori	r10, r10, CPLD_MISCCSR_SLEEPEN
+22:
+	ori	r10, r10, QIXIS_PWR_CTL2_PCTL
+	stb	r10, 0(r29)
+
+	/*
+	 * Set GPIO1_29 to lock the signal MCKE down during deep sleep.
+	 * The bootloader will clear it when wakeup.
+	 */
+	lwz	r10, 0(r11)
+	ori	r10, r10, CCSR_GPIO1_GPDAT_29
+	stw	r10, 0(r11)
+
+	FSLDELAY(10)
+
+	/* Clear the QMan CITI Credits */
+	lwz	r10, 0(r16)
+	oris	r10, r10, CCSR_SCFG_QMCRDTRSTCR_CRDTRST@h
+	stw	r10, 0(r16)
+
+	/* Enable all EPU Counters */
+	li	r10, 0
+	oris	r10, r10, DCSR_EPU_EPGCR_GCE@h
+	stw	r10, 0(r14)
+
+	/* Enable SCU15 to trigger on RCPM Concentrator 0 */
+	lwz	r10, 0(r15)
+	oris	r10, r10, DCSR_EPU_EPECR15_IC0@h
+	stw	r10, 0(r15)
+
+	/* put Core0 in PH15 mode, trigger EPU FSM */
+	lwz	r10, 0(r12)
+	ori	r10, r10, CCSR_RCPM_PCPH15SETR_CORE0
+	stw	r10, 0(r12)
+
+2:
+	b 2b
+
+	/*
+	 * Leave some space to prevent prefeching instruction
+	 * beyond deepsleep_end. The space also can be used as heap.
+	 */
+buf_tmp:
+	.space 128
+	.align 6
+deepsleep_end:
+
+#ifdef CONFIG_PPC32
+_GLOBAL(fsl_deepsleep_resume)
+	/* disable interrupts */
+	FSL_DIS_ALL_IRQ
+
+	li	r3, 0
+	mfspr   r4, SPRN_PIR
+	bl	call_setup_cpu
+
+	/* Load each CAM entry */
+	LOAD_REG_ADDR(r3, tlbcam_index)
+	lwz	r3, 0(r3)
+	mtctr	r3
+	li	r0, 0
+3:	mr	r3, r0
+	bl	loadcam_entry
+	addi	r0, r0, 1
+	bdnz	3b
+
+	/* restore cpu registers */
+	LOAD_REG_ADDR(r3, booke_regs_buffer)
+	li	r4, DEEPSLEEP_FLAG
+	bl	booke_cpu_state_restore
+
+	LOAD_REG_ADDR(r3, booke_regs_buffer)
+	lwz	r4, SR_MSR(r3)
+	mtmsr	r4
+	lwz	r4, SR_LR(r3)
+	mtlr	r4
+
+	blr
+
+#else /* CONFIG_PPC32 */
+
+_GLOBAL(__entry_deep_sleep)
+	/* disable interrupts */
+	FSL_DIS_ALL_IRQ
+
+	/* switch to 64-bit mode */
+	bl	.enable_64b_mode
+
+	/* set TOC pointer */
+	bl	.relative_toc
+
+	/* setup initial TLBs, switch to kernel space ... */
+	bl	.start_initialization_book3e
+
+	/* address space changed, set TOC pointer again */
+	bl	.relative_toc
+
+	/* call a cpu state restore handler */
+	LOAD_REG_ADDR(r23, cur_cpu_spec)
+	ld	r23,0(r23)
+	ld	r23,CPU_SPEC_RESTORE(r23)
+	cmpdi	0,r23,0
+	beq	1f
+	ld	r23,0(r23)
+	mtctr	r23
+	bctrl
+1:
+	LOAD_REG_ADDR(r3, booke_regs_buffer)
+	li	r4, DEEPSLEEP_FLAG
+	bl	booke_cpu_state_restore
+
+	/* Load each CAM entry */
+	LOAD_REG_ADDR(r3, tlbcam_index)
+	lwz	r3, 0(r3)
+	mtctr	r3
+	li	r0, 0
+3:	mr	r3, r0
+	bl	loadcam_entry
+	addi	r0, r0, 1
+	bdnz	3b
+
+	/* restore return address */
+	LOAD_REG_ADDR(r3, booke_regs_buffer)
+	ld	r4, SR_MSR(r3)
+	mtmsr	r4
+	ld	r4, SR_LR(r3)
+	mtlr	r4
+
+	blr
+
+#endif /* CONFIG_PPC32 */
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index eb83a30..7351c40 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -67,7 +67,14 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
 #define PLAT_PM_SLEEP	20
 #define PLAT_PM_LPM20	30
 
+extern int fsl_dp_iomap(void);
+extern void fsl_dp_iounmap(void);
+
 extern int fsl_rcpm_init(void);
+extern int fsl_enter_epu_deepsleep(void);
+extern void fsl_dp_enter_low(void *ccsr_base, void *dcsr_base,
+				void *pld_base, int pld_flag);
+extern void __entry_deep_sleep(void);
 
 extern void fsl_dp_fsm_setup(void *dcsr_base);
 extern void fsl_dp_fsm_clean(void *dcsr_base);
-- 
1.7.3

^ permalink raw reply related

* [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
From: Chenhui Zhao @ 2014-03-07  4:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

From: Hongbo Zhang <hongbo.zhang@freescale.com>

In the last stage of deep sleep, software will trigger a Finite
State Machine (FSM) to control the hardware precedure, such as
board isolation, killing PLLs, removing power, and so on.

When the system is waked up by an interrupt, the FSM controls the
hardware to complete the early resume precedure.

This patch configure the EPU FSM preparing for deep sleep.

Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
 arch/powerpc/platforms/85xx/Kconfig |    1 +
 arch/powerpc/sysdev/fsl_soc.h       |    3 +
 drivers/platform/Kconfig            |    4 +
 drivers/platform/Makefile           |    1 +
 drivers/platform/fsl/Kconfig        |   10 +
 drivers/platform/fsl/Makefile       |    5 +
 drivers/platform/fsl/sleep_fsm.c    |  415 +++++++++++++++++++++++++++++=
++++++
 7 files changed, 439 insertions(+), 0 deletions(-)
 create mode 100644 drivers/platform/fsl/Kconfig
 create mode 100644 drivers/platform/fsl/Makefile
 create mode 100644 drivers/platform/fsl/sleep_fsm.c

diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms=
/85xx/Kconfig
index 54d8843..27e2174 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -261,6 +261,7 @@ config CORENET_GENERIC
 	select GPIO_MPC8XXX
 	select HAS_RAPIDIO
 	select PPC_EPAPR_HV_PIC
+	select FSL_SLEEP_FSM if SUSPEND
 	help
 	  This option enables support for the FSL CoreNet based boards.
 	  For 32bit kernel, the following boards are supported:
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.=
h
index 9b9a34a..eb83a30 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -69,5 +69,8 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
=20
 extern int fsl_rcpm_init(void);
=20
+extern void fsl_dp_fsm_setup(void *dcsr_base);
+extern void fsl_dp_fsm_clean(void *dcsr_base);
+
 #endif
 #endif
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 09fde58..6539e6d 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -6,3 +6,7 @@ source "drivers/platform/goldfish/Kconfig"
 endif
=20
 source "drivers/platform/chrome/Kconfig"
+
+if FSL_SOC
+source "drivers/platform/fsl/Kconfig"
+endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 3656b7b..37c6f72 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_X86)		+=3D x86/
 obj-$(CONFIG_OLPC)		+=3D olpc/
 obj-$(CONFIG_GOLDFISH)		+=3D goldfish/
 obj-$(CONFIG_CHROME_PLATFORMS)	+=3D chrome/
+obj-$(CONFIG_FSL_SOC)		+=3D fsl/
diff --git a/drivers/platform/fsl/Kconfig b/drivers/platform/fsl/Kconfig
new file mode 100644
index 0000000..72ed053
--- /dev/null
+++ b/drivers/platform/fsl/Kconfig
@@ -0,0 +1,10 @@
+#
+# Freescale Specific Power Management Drivers
+#
+
+config FSL_SLEEP_FSM
+	bool
+	help
+	  This driver configures a hardware FSM (Finite State Machine) for deep=
 sleep.
+	  The FSM is used to finish clean-ups at the last stage of system enter=
ing deep
+	  sleep, and also wakes up system when a wake up event happens.
diff --git a/drivers/platform/fsl/Makefile b/drivers/platform/fsl/Makefil=
e
new file mode 100644
index 0000000..d99ca0e
--- /dev/null
+++ b/drivers/platform/fsl/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for linux/drivers/platform/fsl
+# Freescale Specific Power Management Drivers
+#
+obj-$(CONFIG_FSL_SLEEP_FSM)	+=3D sleep_fsm.o
diff --git a/drivers/platform/fsl/sleep_fsm.c b/drivers/platform/fsl/slee=
p_fsm.c
new file mode 100644
index 0000000..1033332
--- /dev/null
+++ b/drivers/platform/fsl/sleep_fsm.c
@@ -0,0 +1,415 @@
+/*
+ * Freescale deep sleep FSM (finite-state machine) configuration
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * Author: Hongbo Zhang <hongbo.zhang@freescale.com>
+ *         Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify=
 it
+ * under  the terms of  the GNU General  Public License as published by =
the
+ * Free Software Foundation;  either version 2 of the  License, or (at y=
our
+ * option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+#define FSL_STRIDE_4B	4
+#define FSL_STRIDE_8B	8
+
+/* Event Processor Global Control Register */
+#define	EPGCR		0x000
+
+/* Event Processor EVT Pin Control Registers */
+#define	EPEVTCR0	0x050
+#define	EPEVTCR1	0x054
+#define	EPEVTCR2	0x058
+#define	EPEVTCR3	0x05C
+#define	EPEVTCR4	0x060
+#define	EPEVTCR5	0x064
+#define	EPEVTCR6	0x068
+#define	EPEVTCR7	0x06C
+#define	EPEVTCR8	0x070
+#define	EPEVTCR9	0x074
+
+/* Event Processor Crosstrigger Control Register */
+#define	EPXTRIGCR	0x090
+
+/* Event Processor Input Mux Control Registers */
+#define	EPIMCR0		0x100
+#define	EPIMCR1		0x104
+#define	EPIMCR2		0x108
+#define	EPIMCR3		0x10C
+#define	EPIMCR4		0x110
+#define	EPIMCR5		0x114
+#define	EPIMCR6		0x118
+#define	EPIMCR7		0x11C
+#define	EPIMCR8		0x120
+#define	EPIMCR9		0x124
+#define	EPIMCR10	0x128
+#define	EPIMCR11	0x12C
+#define	EPIMCR12	0x130
+#define	EPIMCR13	0x134
+#define	EPIMCR14	0x138
+#define	EPIMCR15	0x13C
+#define	EPIMCR16	0x140
+#define	EPIMCR17	0x144
+#define	EPIMCR18	0x148
+#define	EPIMCR19	0x14C
+#define	EPIMCR20	0x150
+#define	EPIMCR21	0x154
+#define	EPIMCR22	0x158
+#define	EPIMCR23	0x15C
+#define	EPIMCR24	0x160
+#define	EPIMCR25	0x164
+#define	EPIMCR26	0x168
+#define	EPIMCR27	0x16C
+#define	EPIMCR28	0x170
+#define	EPIMCR29	0x174
+#define	EPIMCR30	0x178
+#define	EPIMCR31	0x17C
+
+/* Event Processor SCU Mux Control Registers */
+#define	EPSMCR0		0x200
+#define	EPSMCR1		0x208
+#define	EPSMCR2		0x210
+#define	EPSMCR3		0x218
+#define	EPSMCR4		0x220
+#define	EPSMCR5		0x228
+#define	EPSMCR6		0x230
+#define	EPSMCR7		0x238
+#define	EPSMCR8		0x240
+#define	EPSMCR9		0x248
+#define	EPSMCR10	0x250
+#define	EPSMCR11	0x258
+#define	EPSMCR12	0x260
+#define	EPSMCR13	0x268
+#define	EPSMCR14	0x270
+#define	EPSMCR15	0x278
+
+/* Event Processor Event Control Registers */
+#define	EPECR0		0x300
+#define	EPECR1		0x304
+#define	EPECR2		0x308
+#define	EPECR3		0x30C
+#define	EPECR4		0x310
+#define	EPECR5		0x314
+#define	EPECR6		0x318
+#define	EPECR7		0x31C
+#define	EPECR8		0x320
+#define	EPECR9		0x324
+#define	EPECR10		0x328
+#define	EPECR11		0x32C
+#define	EPECR12		0x330
+#define	EPECR13		0x334
+#define	EPECR14		0x338
+#define	EPECR15		0x33C
+
+/* Event Processor Action Control Registers */
+#define	EPACR0		0x400
+#define	EPACR1		0x404
+#define	EPACR2		0x408
+#define	EPACR3		0x40C
+#define	EPACR4		0x410
+#define	EPACR5		0x414
+#define	EPACR6		0x418
+#define	EPACR7		0x41C
+#define	EPACR8		0x420
+#define	EPACR9		0x424
+#define	EPACR10		0x428
+#define	EPACR11		0x42C
+#define	EPACR12		0x430
+#define	EPACR13		0x434
+#define	EPACR14		0x438
+#define	EPACR15		0x43C
+
+/* Event Processor Counter Control Registers */
+#define	EPCCR0		0x800
+#define	EPCCR1		0x804
+#define	EPCCR2		0x808
+#define	EPCCR3		0x80C
+#define	EPCCR4		0x810
+#define	EPCCR5		0x814
+#define	EPCCR6		0x818
+#define	EPCCR7		0x81C
+#define	EPCCR8		0x820
+#define	EPCCR9		0x824
+#define	EPCCR10		0x828
+#define	EPCCR11		0x82C
+#define	EPCCR12		0x830
+#define	EPCCR13		0x834
+#define	EPCCR14		0x838
+#define	EPCCR15		0x83C
+
+/* Event Processor Counter Compare Registers */
+#define	EPCMPR0		0x900
+#define	EPCMPR1		0x904
+#define	EPCMPR2		0x908
+#define	EPCMPR3		0x90C
+#define	EPCMPR4		0x910
+#define	EPCMPR5		0x914
+#define	EPCMPR6		0x918
+#define	EPCMPR7		0x91C
+#define	EPCMPR8		0x920
+#define	EPCMPR9		0x924
+#define	EPCMPR10	0x928
+#define	EPCMPR11	0x92C
+#define	EPCMPR12	0x930
+#define	EPCMPR13	0x934
+#define	EPCMPR14	0x938
+#define	EPCMPR15	0x93C
+
+/* Event Processor Counter Register */
+#define EPCTR0		0xA00
+#define EPCTR1		0xA04
+#define EPCTR2		0xA08
+#define EPCTR3		0xA0C
+#define EPCTR4		0xA10
+#define EPCTR5		0xA14
+#define EPCTR6		0xA18
+#define EPCTR7		0xA1C
+#define EPCTR8		0xA20
+#define EPCTR9		0xA24
+#define EPCTR10		0xA28
+#define EPCTR11		0xA2C
+#define EPCTR12		0xA30
+#define EPCTR13		0xA34
+#define EPCTR14		0xA38
+#define EPCTR15		0xA3C
+#define EPCTR16		0xA40
+#define EPCTR17		0xA44
+#define EPCTR18		0xA48
+#define EPCTR19		0xA4C
+#define EPCTR20		0xA50
+#define EPCTR21		0xA54
+#define EPCTR22		0xA58
+#define EPCTR23		0xA5C
+#define EPCTR24		0xA60
+#define EPCTR25		0xA64
+#define EPCTR26		0xA68
+#define EPCTR27		0xA6C
+#define EPCTR28		0xA70
+#define EPCTR29		0xA74
+#define EPCTR30		0xA78
+#define EPCTR31		0xA7C
+
+/* NPC triggered Memory-Mapped Access Registers */
+#define	NCR		0x000
+#define MCCR1		0x0CC
+#define	MCSR1		0x0D0
+#define	MMAR1LO		0x0D4
+#define	MMAR1HI		0x0D8
+#define	MMDR1		0x0DC
+#define	MCSR2		0x0E0
+#define	MMAR2LO		0x0E4
+#define	MMAR2HI		0x0E8
+#define	MMDR2		0x0EC
+#define	MCSR3		0x0F0
+#define	MMAR3LO		0x0F4
+#define	MMAR3HI		0x0F8
+#define	MMDR3		0x0FC
+
+/* RCPM Core State Action Control Register 0 */
+#define	CSTTACR0	0xB00
+
+/* RCPM Core Group 1 Configuration Register 0 */
+#define	CG1CR0		0x31C
+
+/* Block offsets */
+#define	RCPM_BLOCK_OFFSET	0x00022000
+#define	EPU_BLOCK_OFFSET	0x00000000
+#define	NPC_BLOCK_OFFSET	0x00001000
+
+static void *g_dcsr_base;
+
+static inline void rcpm_write(u32 offset, u32 val)
+{
+	out_be32(g_dcsr_base + RCPM_BLOCK_OFFSET + offset, val);
+}
+
+static inline void epu_write(u32 offset, u32 val)
+{
+	out_be32(g_dcsr_base + EPU_BLOCK_OFFSET + offset, val);
+}
+
+static inline void npc_write(u32 offset, u32 val)
+{
+	out_be32(g_dcsr_base + NPC_BLOCK_OFFSET + offset, val);
+}
+
+/**
+ * fsl_dp_fsm_setup - Configure EPU's FSM
+ * @dcsr_base: the base address of DCSR registers
+ */
+void fsl_dp_fsm_setup(void *dcsr_base)
+{
+	u32 offset;
+
+	/*
+	 * Globle static variable is safe here, becsuse this function is only
+	 * called once at the last stage of suspend, when there is only one CPU
+	 * running and task switching is also disabled.
+	 */
+	g_dcsr_base =3D dcsr_base;
+
+	/* Disable All SCU Actions */
+	for (offset =3D EPACR0; offset <=3D EPACR15; offset +=3D FSL_STRIDE_4B)
+		epu_write(offset, 0);
+
+	/* Clear EPEVTCRn */
+	for (offset =3D EPEVTCR0; offset <=3D EPEVTCR9; offset +=3D FSL_STRIDE_=
4B)
+		epu_write(offset, 0);
+
+	/* Clear Event Processor Global Control Register */
+	epu_write(EPGCR, 0);
+
+	/* Clear EPSMCRn */
+	for (offset =3D EPSMCR0; offset <=3D EPSMCR15; offset +=3D FSL_STRIDE_8=
B)
+		epu_write(offset, 0);
+
+	/* Clear EPCCRn */
+	for (offset =3D EPCCR0; offset <=3D EPCCR15; offset +=3D FSL_STRIDE_4B)
+		epu_write(offset, 0);
+
+	/* Clear EPCMPRn */
+	for (offset =3D EPCMPR0; offset <=3D EPCMPR15; offset +=3D FSL_STRIDE_4=
B)
+		epu_write(offset, 0);
+
+	/*
+	 * Clear EPCTRn
+	 * Warm Device Reset does NOT reset these counter, so clear them
+	 * explicitly. Or, the second time entering deep sleep will fail.
+	 */
+	for (offset =3D EPCTR0; offset <=3D EPCTR31; offset +=3D FSL_STRIDE_4B)
+		epu_write(offset, 0);
+
+	/* Clear EPIMCRn */
+	for (offset =3D EPIMCR0; offset <=3D EPIMCR31; offset +=3D FSL_STRIDE_4=
B)
+		epu_write(offset, 0);
+
+	/* Clear EPXTRIGCRn */
+	epu_write(EPXTRIGCR, 0);
+
+	/* Disable all SCUs EPECRn */
+	for (offset =3D EPECR0; offset <=3D EPECR15; offset +=3D FSL_STRIDE_4B)
+		epu_write(offset, 0);
+
+	/* Set up the SCU chaining */
+	epu_write(EPECR15, 0x00000004);
+	epu_write(EPECR14, 0x02000084);
+	epu_write(EPECR13, 0x08000084);
+	epu_write(EPECR12, 0x80000084);
+	epu_write(EPECR11, 0x90000084);
+	epu_write(EPECR10, 0x42000084);
+	epu_write(EPECR9, 0x08000084);
+	epu_write(EPECR8, 0x60000084);
+	epu_write(EPECR7, 0x80000084);
+	epu_write(EPECR6, 0x80000084);
+	epu_write(EPECR5, 0x08000004);
+	epu_write(EPECR4, 0x20000084);
+	epu_write(EPECR3, 0x80000084);
+	epu_write(EPECR2, 0xF0004004);
+
+	/* EVT Pin Configuration. SCU8 triger EVT2, and SCU11 triger EVT9 */
+	epu_write(EPEVTCR2, 0x80000001);
+	epu_write(EPEVTCR9, 0xB0000001);
+
+	/* Configure the EPU Counter Values */
+	epu_write(EPCMPR15, 0x000000FF);
+	epu_write(EPCMPR14, 0x000000FF);
+	epu_write(EPCMPR12, 0x000000FF);
+	epu_write(EPCMPR11, 0x000000FF);
+	epu_write(EPCMPR10, 0x000000FF);
+	epu_write(EPCMPR9, 0x000000FF);
+	epu_write(EPCMPR8, 0x000000FF);
+	epu_write(EPCMPR5, 0x00000020);
+	epu_write(EPCMPR4, 0x000000FF);
+	epu_write(EPCMPR2, 0x000000FF);
+
+	/* Configure the EPU Counters */
+	epu_write(EPCCR15, 0x92840000);
+	epu_write(EPCCR14, 0x92840000);
+	epu_write(EPCCR12, 0x92840000);
+	epu_write(EPCCR11, 0x92840000);
+	epu_write(EPCCR10, 0x92840000);
+	epu_write(EPCCR9, 0x92840000);
+	epu_write(EPCCR8, 0x92840000);
+	epu_write(EPCCR5, 0x92840000);
+	epu_write(EPCCR4, 0x92840000);
+	epu_write(EPCCR2, 0x92840000);
+
+	/* Configure the SCUs Inputs */
+	epu_write(EPSMCR15, 0x76000000);
+	epu_write(EPSMCR14, 0x00000031);
+	epu_write(EPSMCR13, 0x00003100);
+	epu_write(EPSMCR12, 0x7F000000);
+	epu_write(EPSMCR11, 0x31740000);
+	epu_write(EPSMCR10, 0x65000030);
+	epu_write(EPSMCR9, 0x00003000);
+	epu_write(EPSMCR8, 0x64300000);
+	epu_write(EPSMCR7, 0x30000000);
+	epu_write(EPSMCR6, 0x7C000000);
+	epu_write(EPSMCR5, 0x00002E00);
+	epu_write(EPSMCR4, 0x002F0000);
+	epu_write(EPSMCR3, 0x2F000000);
+	epu_write(EPSMCR2, 0x6C700000);
+
+	/* Configure the SCUs Actions */
+	epu_write(EPACR15, 0x02000000);
+	epu_write(EPACR14, 0x04000000);
+	epu_write(EPACR13, 0x06000000);
+	epu_write(EPACR12, 0x00000003);
+	epu_write(EPACR10, 0x00000020);
+	epu_write(EPACR9, 0x0000001C);
+	epu_write(EPACR5, 0x00000040);
+	epu_write(EPACR3, 0x00000080);
+
+	/* Configure the SCUs and Timers Mux */
+	epu_write(EPIMCR31, 0x76000000);
+	epu_write(EPIMCR28, 0x76000000);
+	epu_write(EPIMCR22, 0x6C000000);
+	epu_write(EPIMCR20, 0x48000000);
+	epu_write(EPIMCR16, 0x6A000000);
+	epu_write(EPIMCR12, 0x44000000);
+	epu_write(EPIMCR5, 0x40000000);
+	epu_write(EPIMCR4, 0x44000000);
+
+	/* Configure pulse or level triggers */
+	epu_write(EPXTRIGCR, 0x0000FFDF);
+
+	/* Configure the NPC tMMA registers*/
+	npc_write(NCR, 0x80000000);
+	npc_write(MCCR1, 0);
+	npc_write(MCSR1, 0);
+	npc_write(MMAR1LO, 0);
+	npc_write(MMAR1HI, 0);
+	npc_write(MMDR1, 0);
+	npc_write(MCSR2, 0);
+	npc_write(MMAR2LO, 0);
+	npc_write(MMAR2HI, 0);
+	npc_write(MMDR2, 0);
+	npc_write(MCSR3, 0x80000000);
+	npc_write(MMAR3LO, 0x000E2130);
+	npc_write(MMAR3HI, 0x00030000);
+	npc_write(MMDR3, 0x00020000);
+
+	/* Configure RCPM for detecting Core0=E2=80=99s PH15 state */
+	rcpm_write(CSTTACR0, 0x00001001);
+	rcpm_write(CG1CR0, 0x00000001);
+
+}
+
+void fsl_dp_fsm_clean(void *dcsr_base)
+{
+
+	epu_write(EPEVTCR2, 0);
+	epu_write(EPEVTCR9, 0);
+
+	epu_write(EPGCR, 0);
+	epu_write(EPECR15, 0);
+
+	rcpm_write(CSTTACR0, 0);
+	rcpm_write(CG1CR0, 0);
+
+}
--=20
1.7.3

^ permalink raw reply related

* [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
From: Chenhui Zhao @ 2014-03-07  4:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

In sleep mode, the clocks of e500 cores and unused IP blocks is
turned off. The IP blocks which are allowed to wake up the processor
are still running.

The sleep mode is equal to the Standby state in Linux. Use the
command to enter sleep mode:
  echo standby > /sys/power/state

Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
 arch/powerpc/Kconfig                   |    4 +-
 arch/powerpc/platforms/85xx/Makefile   |    3 +
 arch/powerpc/platforms/85xx/qoriq_pm.c |   78 ++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 05f6323..e1d6510 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -222,7 +222,7 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
 	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-		   (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+		   FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \
 		   || 44x || 40x
 
 config PPC_DCR_NATIVE
@@ -709,7 +709,7 @@ config FSL_PCI
 config FSL_PMC
 	bool
 	default y
-	depends on SUSPEND && (PPC_85xx || PPC_86xx)
+	depends on SUSPEND && (PPC_85xx && !PPC_E500MC || PPC_86xx)
 	help
 	  Freescale MPC85xx/MPC86xx power management controller support
 	  (suspend/resume). For MPC83xx see platforms/83xx/suspend.c
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 25cebe7..7fae817 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -2,6 +2,9 @@
 # Makefile for the PowerPC 85xx linux kernel.
 #
 obj-$(CONFIG_SMP) += smp.o
+ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
+obj-$(CONFIG_SUSPEND)	+= qoriq_pm.o
+endif
 
 obj-y += common.o
 
diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
new file mode 100644
index 0000000..915b13b
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
@@ -0,0 +1,78 @@
+/*
+ * Support Power Management feature
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
+
+#include <sysdev/fsl_soc.h>
+
+#define FSL_SLEEP		0x1
+#define FSL_DEEP_SLEEP		0x2
+
+/* specify the sleep state of the present platform */
+int sleep_pm_state;
+/* supported sleep modes by the present platform */
+static unsigned int sleep_modes;
+
+static int qoriq_suspend_enter(suspend_state_t state)
+{
+	int ret = 0;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+
+		if (cur_cpu_spec->cpu_flush_caches)
+			cur_cpu_spec->cpu_flush_caches();
+
+		ret = qoriq_pm_ops->plat_enter_state(sleep_pm_state);
+
+		break;
+
+	default:
+		ret = -EINVAL;
+
+	}
+
+	return ret;
+}
+
+static int qoriq_suspend_valid(suspend_state_t state)
+{
+	if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_SLEEP))
+		return 1;
+
+	return 0;
+}
+
+static const struct platform_suspend_ops qoriq_suspend_ops = {
+	.valid = qoriq_suspend_valid,
+	.enter = qoriq_suspend_enter,
+};
+
+static int __init qoriq_suspend_init(void)
+{
+	struct device_node *np;
+
+	sleep_modes = FSL_SLEEP;
+	sleep_pm_state = PLAT_PM_SLEEP;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
+	if (np)
+		sleep_pm_state = PLAT_PM_LPM20;
+
+	suspend_set_ops(&qoriq_suspend_ops);
+
+	return 0;
+}
+arch_initcall(qoriq_suspend_init);
-- 
1.7.3

^ permalink raw reply related

* [PATCH 3/9] powerpc/rcpm: add RCPM driver
From: Chenhui Zhao @ 2014-03-07  4:57 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

There is a RCPM (Run Control/Power Management) in Freescale QorIQ
series processors. The device performs tasks associated with device
run control and power management.

The driver implements some features: mask/unmask irq, enter/exit low
power states, freeze time base, etc.

There are two versions of register map in RCPM, which is specified by
the compatible entry in the RCPM node of device tree.

Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
 arch/powerpc/include/asm/fsl_guts.h           |  105 ++++++++
 arch/powerpc/platforms/85xx/Kconfig           |    1 +
 arch/powerpc/platforms/85xx/corenet_generic.c |    2 +
 arch/powerpc/sysdev/Kconfig                   |    5 +
 arch/powerpc/sysdev/Makefile                  |    1 +
 arch/powerpc/sysdev/fsl_rcpm.c                |  315 +++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.h                 |   24 ++
 7 files changed, 453 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c

diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index 77ced0b..492534a 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -185,5 +185,110 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
 
 #endif
 
+struct ccsr_rcpm_v1 {
+	u8	res0000[4];
+	__be32	cdozsr;	    /* 0x0004 Core Doze Status Register */
+	u8	res0008[4];
+	__be32	cdozcr;	    /* 0x000c Core Doze Control Register */
+	u8	res0010[4];
+	__be32	cnapsr;	    /* 0x0014 Core Nap Status Register */
+	u8	res0018[4];
+	__be32	cnapcr;	    /* 0x001c Core Nap Control Register */
+	u8	res0020[4];
+	__be32	cdozpsr;    /* 0x0024 Core Doze Previous Status Register */
+	u8	res0028[4];
+	__be32	cnappsr;    /* 0x002c Core Nap Previous Status Register */
+	u8	res0030[4];
+	__be32	cwaitsr;    /* 0x0034 Core Wait Status Register */
+	u8	res0038[4];
+	__be32	cwdtdsr;    /* 0x003c Core Watchdog Detect Status Register */
+	__be32	powmgtcsr;  /* 0x0040 Power Mangement Control&Status Register */
+#define RCPM_POWMGTCSR_SLP	0x00020000
+	u8	res0044[12];
+	__be32	ippdexpcr;  /* 0x0050 IP Powerdown Exception Control Register */
+	u8	res0054[16];
+	__be32	cpmimr;	    /* 0x0064 Core PM IRQ Mask Register */
+	u8	res0068[4];
+	__be32	cpmcimr;    /* 0x006c Core PM Critical IRQ Mask Register */
+	u8	res0070[4];
+	__be32	cpmmcmr;    /* 0x0074 Core PM Machine Check Mask Register */
+	u8	res0078[4];
+	__be32	cpmnmimr;   /* 0x007c Core PM NMI Mask Register */
+	u8	res0080[4];
+	__be32	ctbenr;	    /* 0x0084 Core Time Base Enable Register */
+	u8	res0088[4];
+	__be32	ctbckselr;  /* 0x008c Core Time Base Clock Select Register */
+	u8	res0090[4];
+	__be32	ctbhltcr;   /* 0x0094 Core Time Base Halt Control Register */
+	u8	res0098[4];
+	__be32	cmcpmaskcr; /* 0x00a4 Core Machine Check Mask Register */
+};
+
+struct ccsr_rcpm_v2 {
+	u8	res_00[12];
+	u32	tph10sr0;	/* Thread PH10 Status Register */
+	u8	res_10[12];
+	u32	tph10setr0;	/* Thread PH10 Set Control Register */
+	u8	res_20[12];
+	u32	tph10clrr0;	/* Thread PH10 Clear Control Register */
+	u8	res_30[12];
+	u32	tph10psr0;	/* Thread PH10 Previous Status Register */
+	u8	res_40[12];
+	u32	twaitsr0;	/* Thread Wait Status Register */
+	u8	res_50[96];
+	u32	pcph15sr;	/* Physical Core PH15 Status Register */
+	u32	pcph15setr;	/* Physical Core PH15 Set Control Register */
+	u32	pcph15clrr;	/* Physical Core PH15 Clear Control Register */
+	u32	pcph15psr;	/* Physical Core PH15 Prev Status Register */
+	u8	res_c0[16];
+	u32	pcph20sr;	/* Physical Core PH20 Status Register */
+	u32	pcph20setr;	/* Physical Core PH20 Set Control Register */
+	u32	pcph20clrr;	/* Physical Core PH20 Clear Control Register */
+	u32	pcph20psr;	/* Physical Core PH20 Prev Status Register */
+	u32	pcpw20sr;	/* Physical Core PW20 Status Register */
+	u8	res_e0[12];
+	u32	pcph30sr;	/* Physical Core PH30 Status Register */
+	u32	pcph30setr;	/* Physical Core PH30 Set Control Register */
+	u32	pcph30clrr;	/* Physical Core PH30 Clear Control Register */
+	u32	pcph30psr;	/* Physical Core PH30 Prev Status Register */
+	u8	res_100[32];
+	u32	ippwrgatecr;	/* IP Power Gating Control Register */
+	u8	res_124[12];
+	u32	powmgtcsr;	/* Power Management Control & Status Reg */
+#define RCPM_POWMGTCSR_LPM20_RQ		0x00100000
+#define RCPM_POWMGTCSR_LPM20_ST		0x00000200
+#define RCPM_POWMGTCSR_P_LPM20_ST	0x00000100
+	u8	res_134[12];
+	u32	ippdexpcr[4];	/* IP Powerdown Exception Control Reg */
+	u8	res_150[12];
+	u32	tpmimr0;	/* Thread PM Interrupt Mask Reg */
+	u8	res_160[12];
+	u32	tpmcimr0;	/* Thread PM Crit Interrupt Mask Reg */
+	u8	res_170[12];
+	u32	tpmmcmr0;	/* Thread PM Machine Check Interrupt Mask Reg */
+	u8	res_180[12];
+	u32	tpmnmimr0;	/* Thread PM NMI Mask Reg */
+	u8	res_190[12];
+	u32	tmcpmaskcr0;	/* Thread Machine Check Mask Control Reg */
+	u32	pctbenr;	/* Physical Core Time Base Enable Reg */
+	u32	pctbclkselr;	/* Physical Core Time Base Clock Select */
+	u32	tbclkdivr;	/* Time Base Clock Divider Register */
+	u8	res_1ac[4];
+	u32	ttbhltcr[4];	/* Thread Time Base Halt Control Register */
+	u32	clpcl10sr;	/* Cluster PCL10 Status Register */
+	u32	clpcl10setr;	/* Cluster PCL30 Set Control Register */
+	u32	clpcl10clrr;	/* Cluster PCL30 Clear Control Register */
+	u32	clpcl10psr;	/* Cluster PCL30 Prev Status Register */
+	u32	cddslpsetr;	/* Core Domain Deep Sleep Set Register */
+	u32	cddslpclrr;	/* Core Domain Deep Sleep Clear Register */
+	u32	cdpwroksetr;	/* Core Domain Power OK Set Register */
+	u32	cdpwrokclrr;	/* Core Domain Power OK Clear Register */
+	u32	cdpwrensr;	/* Core Domain Power Enable Status Register */
+	u32	cddslsr;	/* Core Domain Deep Sleep Status Register */
+	u8	res_1e8[8];
+	u32	dslpcntcr[8];	/* Deep Sleep Counter Cfg Register */
+	u8	res_300[3568];
+};
+
 #endif
 #endif
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index c17aae8..54d8843 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -8,6 +8,7 @@ menuconfig FSL_SOC_BOOKE
 	select FSL_PCI if PCI
 	select SERIAL_8250_EXTENDED if SERIAL_8250
 	select SERIAL_8250_SHARE_IRQ if SERIAL_8250
+	select FSL_CORENET_RCPM if PPC_E500MC
 	default y
 
 if FSL_SOC_BOOKE
diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index b756f3d..3fdf9f3 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -56,6 +56,8 @@ void __init corenet_gen_setup_arch(void)
 
 	swiotlb_detect_4g();
 
+	fsl_rcpm_init();
+
 	pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
 }
 
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 7baa70d..f6e7cde 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -34,3 +34,8 @@ config SCOM_DEBUGFS
 config GE_FPGA
 	bool
 	default n
+
+config FSL_CORENET_RCPM
+	bool
+	help
+	  This option enables support for RCPM (Run Control/Power Management).
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f67ac90..a6ada64 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o fsl_mpic_err.o
 obj-$(CONFIG_FSL_PCI)		+= fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)		+= fsl_pmc.o
+obj-$(CONFIG_FSL_CORENET_RCPM)	+= fsl_rcpm.o
 obj-$(CONFIG_FSL_LBC)		+= fsl_lbc.o
 obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_FSL_GTM)		+= fsl_gtm.o
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
new file mode 100644
index 0000000..493fcae
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -0,0 +1,315 @@
+/*
+ * RCPM(Run Control/Power Management) support
+ *
+ * Copyright 2012-2014 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/of_address.h>
+#include <linux/export.h>
+
+#include <asm/io.h>
+#include <asm/fsl_guts.h>
+#include <asm/cputhreads.h>
+#include <sysdev/fsl_soc.h>
+
+const struct fsl_pm_ops *qoriq_pm_ops;
+
+static struct ccsr_rcpm_v1 __iomem *rcpm_v1_regs;
+static struct ccsr_rcpm_v2 __iomem *rcpm_v2_regs;
+
+static void rcpm_v1_irq_mask(int cpu)
+{
+	int hw_cpu = get_hard_smp_processor_id(cpu);
+	unsigned int mask = 1 << hw_cpu;
+
+	setbits32(&rcpm_v1_regs->cpmimr, mask);
+	setbits32(&rcpm_v1_regs->cpmcimr, mask);
+	setbits32(&rcpm_v1_regs->cpmmcmr, mask);
+	setbits32(&rcpm_v1_regs->cpmnmimr, mask);
+}
+
+static void rcpm_v1_irq_unmask(int cpu)
+{
+	int hw_cpu = get_hard_smp_processor_id(cpu);
+	unsigned int mask = 1 << hw_cpu;
+
+	clrbits32(&rcpm_v1_regs->cpmimr, mask);
+	clrbits32(&rcpm_v1_regs->cpmcimr, mask);
+	clrbits32(&rcpm_v1_regs->cpmmcmr, mask);
+	clrbits32(&rcpm_v1_regs->cpmnmimr, mask);
+}
+
+static void rcpm_v1_set_ip_power(int enable, u32 mask)
+{
+	if (enable)
+		setbits32(&rcpm_v1_regs->ippdexpcr, mask);
+	else
+		clrbits32(&rcpm_v1_regs->ippdexpcr, mask);
+}
+
+static void rcpm_v1_cpu_enter_state(int cpu, int state)
+{
+	unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+	unsigned int mask = 1 << hw_cpu;
+
+	switch (state) {
+	case E500_PM_PH10:
+		setbits32(&rcpm_v1_regs->cdozcr, mask);
+		break;
+	case E500_PM_PH15:
+		setbits32(&rcpm_v1_regs->cnapcr, mask);
+		break;
+	default:
+		pr_err("Unknown cpu PM state\n");
+		break;
+	}
+}
+
+static void rcpm_v1_cpu_exit_state(int cpu, int state)
+{
+	unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+	unsigned int mask = 1 << hw_cpu;
+
+	switch (state) {
+	case E500_PM_PH10:
+		clrbits32(&rcpm_v1_regs->cdozcr, mask);
+		break;
+	case E500_PM_PH15:
+		clrbits32(&rcpm_v1_regs->cnapcr, mask);
+		break;
+	default:
+		pr_err("Unknown cpu PM state\n");
+		break;
+	}
+}
+
+static int rcpm_v1_plat_enter_state(int state)
+{
+	u32 *pmcsr_reg = &rcpm_v1_regs->powmgtcsr;
+	int ret = 0;
+	int result;
+
+	switch (state) {
+	case PLAT_PM_SLEEP:
+		setbits32(pmcsr_reg, RCPM_POWMGTCSR_SLP);
+
+		/* At this point, the device is in sleep mode. */
+
+		/* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
+		result = spin_event_timeout(
+		  !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_SLP), 10000, 10);
+		if (!result) {
+			pr_err("%s: timeout waiting for SLP bit to be cleared\n",
+			  __func__);
+			ret = -ETIMEDOUT;
+		}
+		break;
+	default:
+		pr_err("Unsupported platform PM state\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void rcpm_v1_freeze_time_base(int freeze)
+{
+	u32 *tben_reg = &rcpm_v1_regs->ctbenr;
+	static u32 mask;
+
+	if (freeze) {
+		mask = in_be32(tben_reg);
+		clrbits32(tben_reg, mask);
+	} else {
+		setbits32(tben_reg, mask);
+	}
+
+	/* read back to push the previous write */
+	in_be32(tben_reg);
+}
+
+static void rcpm_v2_freeze_time_base(int freeze)
+{
+	u32 *tben_reg = &rcpm_v2_regs->pctbenr;
+	static u32 mask;
+
+	if (freeze) {
+		mask = in_be32(tben_reg);
+		clrbits32(tben_reg, mask);
+	} else {
+		setbits32(tben_reg, mask);
+	}
+
+	/* read back to push the previous write */
+	in_be32(tben_reg);
+}
+
+static void rcpm_v2_irq_mask(int cpu)
+{
+	int hw_cpu = get_hard_smp_processor_id(cpu);
+	unsigned int mask = 1 << hw_cpu;
+
+	setbits32(&rcpm_v2_regs->tpmimr0, mask);
+	setbits32(&rcpm_v2_regs->tpmcimr0, mask);
+	setbits32(&rcpm_v2_regs->tpmmcmr0, mask);
+	setbits32(&rcpm_v2_regs->tpmnmimr0, mask);
+}
+
+static void rcpm_v2_irq_unmask(int cpu)
+{
+	int hw_cpu = get_hard_smp_processor_id(cpu);
+	unsigned int mask = 1 << hw_cpu;
+
+	clrbits32(&rcpm_v2_regs->tpmimr0, mask);
+	clrbits32(&rcpm_v2_regs->tpmcimr0, mask);
+	clrbits32(&rcpm_v2_regs->tpmmcmr0, mask);
+	clrbits32(&rcpm_v2_regs->tpmnmimr0, mask);
+}
+
+static void rcpm_v2_set_ip_power(int enable, u32 mask)
+{
+	if (enable)
+		/* enable power of IP blocks in deep sleep mode */
+		setbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
+	else
+		clrbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
+}
+
+static void rcpm_v2_cpu_enter_state(int cpu, int state)
+{
+	unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+	u32 mask = 1 << cpu_core_index_of_thread(hw_cpu);
+
+	switch (state) {
+	case E500_PM_PH10:
+		/* one bit corresponds to one thread for PH10 of 6500 */
+		setbits32(&rcpm_v2_regs->tph10setr0, 1 << hw_cpu);
+		break;
+	case E500_PM_PH15:
+		setbits32(&rcpm_v2_regs->pcph15setr, mask);
+		break;
+	case E500_PM_PH20:
+		setbits32(&rcpm_v2_regs->pcph20setr, mask);
+		break;
+	case E500_PM_PH30:
+		setbits32(&rcpm_v2_regs->pcph30setr, mask);
+		break;
+	default:
+		pr_err("Unsupported cpu PM state\n");
+	}
+}
+
+static void rcpm_v2_cpu_exit_state(int cpu, int state)
+{
+	unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+	u32 mask = 1 << cpu_core_index_of_thread(hw_cpu);
+
+	switch (state) {
+	case E500_PM_PH10:
+		setbits32(&rcpm_v2_regs->tph10clrr0, 1 << hw_cpu);
+		break;
+	case E500_PM_PH15:
+		setbits32(&rcpm_v2_regs->pcph15clrr, mask);
+		break;
+	case E500_PM_PH20:
+		setbits32(&rcpm_v2_regs->pcph20clrr, mask);
+		break;
+	case E500_PM_PH30:
+		setbits32(&rcpm_v2_regs->pcph30clrr, mask);
+		break;
+	default:
+		pr_err("Unsupported cpu PM state\n");
+	}
+}
+
+static int rcpm_v2_plat_enter_state(int state)
+{
+	u32 *pmcsr_reg = &rcpm_v2_regs->powmgtcsr;
+	int ret = 0;
+	int result;
+
+	switch (state) {
+	case PLAT_PM_LPM20:
+		/* clear previous LPM20 status */
+		setbits32(pmcsr_reg, RCPM_POWMGTCSR_P_LPM20_ST);
+		/* enter LPM20 status */
+		setbits32(pmcsr_reg, RCPM_POWMGTCSR_LPM20_RQ);
+
+		/* At this point, the device is in LPM20 status. */
+
+		/* resume ... */
+		result = spin_event_timeout(
+		  !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_LPM20_ST), 10000, 10);
+		if (!result) {
+			pr_err("%s: timeout waiting for LPM20 bit to be cleared\n",
+				__func__);
+			ret = -ETIMEDOUT;
+		}
+		break;
+	default:
+		pr_err("Unsupported platform PM state\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct fsl_pm_ops qoriq_rcpm_v1_ops = {
+	.irq_mask = rcpm_v1_irq_mask,
+	.irq_unmask = rcpm_v1_irq_unmask,
+	.cpu_enter_state = rcpm_v1_cpu_enter_state,
+	.cpu_exit_state = rcpm_v1_cpu_exit_state,
+	.plat_enter_state = rcpm_v1_plat_enter_state,
+	.set_ip_power = rcpm_v1_set_ip_power,
+	.freeze_time_base = rcpm_v1_freeze_time_base,
+};
+
+static const struct fsl_pm_ops qoriq_rcpm_v2_ops = {
+	.irq_mask = rcpm_v2_irq_mask,
+	.irq_unmask = rcpm_v2_irq_unmask,
+	.cpu_enter_state = rcpm_v2_cpu_enter_state,
+	.cpu_exit_state = rcpm_v2_cpu_exit_state,
+	.plat_enter_state = rcpm_v2_plat_enter_state,
+	.set_ip_power = rcpm_v2_set_ip_power,
+	.freeze_time_base = rcpm_v2_freeze_time_base,
+};
+
+int fsl_rcpm_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
+	if (np) {
+		rcpm_v2_regs = of_iomap(np, 0);
+		of_node_put(np);
+		if (!rcpm_v2_regs)
+			return -ENOMEM;
+
+		qoriq_pm_ops = &qoriq_rcpm_v2_ops;
+
+	} else {
+		np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-1.0");
+		if (np) {
+			rcpm_v1_regs = of_iomap(np, 0);
+			of_node_put(np);
+			if (!rcpm_v1_regs)
+				return -ENOMEM;
+
+			qoriq_pm_ops = &qoriq_rcpm_v1_ops;
+
+		} else {
+			pr_err("%s: can't find the rcpm node.\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 4c5a19e..9b9a34a 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -45,5 +45,29 @@ extern struct platform_diu_data_ops diu_ops;
 void fsl_hv_restart(char *cmd);
 void fsl_hv_halt(void);
 
+struct fsl_pm_ops {
+	void (*irq_mask)(int cpu);
+	void (*irq_unmask)(int cpu);
+	void (*cpu_enter_state)(int cpu, int state);
+	void (*cpu_exit_state)(int cpu, int state);
+	int (*plat_enter_state)(int state);
+	void (*freeze_time_base)(int freeze);
+	void (*set_ip_power)(int enable, u32 mask);
+};
+
+extern const struct fsl_pm_ops *qoriq_pm_ops;
+
+#define E500_PM_PH10	1
+#define E500_PM_PH15	2
+#define E500_PM_PH20	3
+#define E500_PM_PH30	4
+#define E500_PM_DOZE	E500_PM_PH10
+#define E500_PM_NAP	E500_PM_PH15
+
+#define PLAT_PM_SLEEP	20
+#define PLAT_PM_LPM20	30
+
+extern int fsl_rcpm_init(void);
+
 #endif
 #endif
-- 
1.7.3

^ permalink raw reply related

* [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit
From: Chenhui Zhao @ 2014-03-07  4:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

In 64-bit mode, kernel just clears the irq soft-enable flag
in struct paca_struct to disable external irqs. But, in
the case of suspend, irqs should be disabled by hardware.
Therefore, hook a function to ppc_md.suspend_disable_irqs
to really disable irqs.

Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
 arch/powerpc/platforms/85xx/corenet_generic.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index 3fdf9f3..983d81f 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -32,6 +32,13 @@
 #include <sysdev/fsl_pci.h>
 #include "smp.h"
 
+#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
+static void fsl_suspend_disable_irqs(void)
+{
+	__hard_irq_disable();
+}
+#endif
+
 void __init corenet_gen_pic_init(void)
 {
 	struct mpic *mpic;
@@ -58,6 +65,11 @@ void __init corenet_gen_setup_arch(void)
 
 	fsl_rcpm_init();
 
+#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
+	/* physically disable irq for 64-bit mode when suspend */
+	ppc_md.suspend_disable_irqs = fsl_suspend_disable_irqs;
+#endif
+
 	pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
 }
 
-- 
1.7.3

^ permalink raw reply related

* [PATCH 4/9] powerpc/85xx: support CPU hotplug for e500mc and e5500
From: Chenhui Zhao @ 2014-03-07  4:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

Implemented CPU hotplug on e500mc and e5500. On e5500 both 32-bit and
64-bit modes can work. Used some callback functions implemented in RCPM
driver.

Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
 arch/powerpc/Kconfig              |    2 +-
 arch/powerpc/kernel/smp.c         |    6 ++-
 arch/powerpc/mm/tlb_nohash.c      |    6 ++-
 arch/powerpc/platforms/85xx/smp.c |   94 ++++++++++++++++++++++++++++++-------
 4 files changed, 87 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a5e5d2e..05f6323 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -362,7 +362,7 @@ config SWIOTLB
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
 	depends on SMP && (PPC_PSERIES || \
-	PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
+	PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE)
 	---help---
 	  Say Y here to be able to disable and re-enable individual
 	  CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index ac2621a..f3f4401 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -405,8 +405,12 @@ void generic_cpu_die(unsigned int cpu)
 
 	for (i = 0; i < 100; i++) {
 		smp_rmb();
-		if (per_cpu(cpu_state, cpu) == CPU_DEAD)
+		if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+#ifdef CONFIG_PPC64
+			paca[cpu].cpu_start = 0;
+#endif
 			return;
+		}
 		msleep(100);
 	}
 	printk(KERN_ERR "CPU%d didn't die...\n", cpu);
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index b37a58e..d24e06c 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -648,8 +648,10 @@ static void __early_init_mmu(int boot_cpu)
 		num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
 		linear_map_top = map_mem_in_cams(linear_map_top, num_cams);
 
-		/* limit memory so we dont have linear faults */
-		memblock_enforce_memory_limit(linear_map_top);
+		if (boot_cpu) {
+			/* limit memory so we dont have linear faults */
+			memblock_enforce_memory_limit(linear_map_top);
+		}
 
 		if (book3e_htw_mode == PPC_HTW_NONE) {
 			patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 2e5911e..0047883 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -19,6 +19,7 @@
 #include <linux/kexec.h>
 #include <linux/highmem.h>
 #include <linux/cpu.h>
+#include <linux/smp.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
@@ -46,6 +47,17 @@ static u64 timebase;
 static int tb_req;
 static int tb_valid;
 
+#ifdef CONFIG_PPC_E500MC
+/* specify the cpu PM state when cpu dies, PH15/NAP is the default */
+int qoriq_cpu_die_state = E500_PM_PH15;
+#endif
+
+#ifdef CONFIG_PPC_E500MC
+static void mpc85xx_timebase_freeze(int freeze)
+{
+	qoriq_pm_ops->freeze_time_base(freeze);
+}
+#else
 static void mpc85xx_timebase_freeze(int freeze)
 {
 	uint32_t mask;
@@ -58,6 +70,7 @@ static void mpc85xx_timebase_freeze(int freeze)
 
 	in_be32(&guts->devdisr);
 }
+#endif
 
 static void mpc85xx_give_timebase(void)
 {
@@ -125,6 +138,34 @@ static void mpc85xx_take_timebase(void)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_PPC_E500MC
+static void qoriq_cpu_die(void)
+{
+	unsigned int cpu = smp_processor_id();
+
+	local_irq_disable();
+#ifdef CONFIG_PPC64
+	__hard_irq_disable();
+#endif
+	idle_task_exit();
+
+	if (qoriq_pm_ops->irq_mask)
+		qoriq_pm_ops->irq_mask(cpu);
+
+	mtspr(SPRN_TCR, 0);
+	mtspr(SPRN_TSR, mfspr(SPRN_TSR));
+
+	generic_set_cpu_dead(cpu);
+
+	if (cur_cpu_spec && cur_cpu_spec->cpu_flush_caches)
+		cur_cpu_spec->cpu_flush_caches();
+
+	qoriq_pm_ops->cpu_enter_state(cpu, qoriq_cpu_die_state);
+
+	while (1)
+		;
+}
+#else
 static void smp_85xx_mach_cpu_die(void)
 {
 	unsigned int cpu = smp_processor_id();
@@ -155,6 +196,7 @@ static void smp_85xx_mach_cpu_die(void)
 		;
 }
 #endif
+#endif
 
 static inline void flush_spin_table(void *spin_table)
 {
@@ -208,11 +250,8 @@ static int smp_85xx_kick_cpu(int nr)
 		spin_table = phys_to_virt(*cpu_rel_addr);
 
 	local_irq_save(flags);
-#ifdef CONFIG_PPC32
-#ifdef CONFIG_HOTPLUG_CPU
-	/* Corresponding to generic_set_cpu_dead() */
-	generic_set_cpu_up(nr);
 
+#ifdef CONFIG_HOTPLUG_CPU
 	if (system_state == SYSTEM_RUNNING) {
 		/*
 		 * To keep it compatible with old boot program which uses
@@ -225,6 +264,12 @@ static int smp_85xx_kick_cpu(int nr)
 		out_be32(&spin_table->addr_l, 0);
 		flush_spin_table(spin_table);
 
+#ifdef CONFIG_PPC_E500MC
+		/* Due to an erratum, wake the core before reset. */
+		if (qoriq_pm_ops && qoriq_pm_ops->cpu_exit_state)
+			qoriq_pm_ops->cpu_exit_state(nr, qoriq_cpu_die_state);
+#endif
+
 		/*
 		 * We don't set the BPTR register here since it already points
 		 * to the boot page properly.
@@ -247,13 +292,30 @@ static int smp_85xx_kick_cpu(int nr)
 
 		/*  clear the acknowledge status */
 		__secondary_hold_acknowledge = -1;
+
+#ifdef CONFIG_PPC_E500MC
+		if (qoriq_pm_ops->irq_unmask)
+			qoriq_pm_ops->irq_unmask(nr);
+#endif
 	}
+
+	/* Corresponding to generic_set_cpu_dead() */
+	generic_set_cpu_up(nr);
 #endif
+
 	flush_spin_table(spin_table);
 	out_be32(&spin_table->pir, hw_cpu);
+#ifdef CONFIG_PPC32
 	out_be32(&spin_table->addr_l, __pa(__early_start));
+#else
+	out_be32(&spin_table->addr_h,
+		__pa(*(u64 *)generic_secondary_smp_init) >> 32);
+	out_be32(&spin_table->addr_l,
+		__pa(*(u64 *)generic_secondary_smp_init) & 0xffffffff);
+#endif
 	flush_spin_table(spin_table);
 
+#ifdef CONFIG_PPC32
 	/* Wait a bit for the CPU to ack. */
 	if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
 					10000, 100)) {
@@ -262,17 +324,10 @@ static int smp_85xx_kick_cpu(int nr)
 		ret = -ENOENT;
 		goto out;
 	}
-out:
 #else
 	smp_generic_kick_cpu(nr);
-
-	flush_spin_table(spin_table);
-	out_be32(&spin_table->pir, hw_cpu);
-	out_be64((u64 *)(&spin_table->addr_h),
-	  __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
-	flush_spin_table(spin_table);
 #endif
-
+out:
 	local_irq_restore(flags);
 
 	if (ioremappable)
@@ -445,13 +500,18 @@ void __init mpc85xx_smp_init(void)
 								__func__);
 			return;
 		}
-		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
-		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
-#ifdef CONFIG_HOTPLUG_CPU
-		ppc_md.cpu_die = smp_85xx_mach_cpu_die;
-#endif
 	}
 
+	smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+	smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+
+#ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_PPC_E500MC
+	ppc_md.cpu_die = qoriq_cpu_die;
+#else
+	ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+#endif
+#endif
 	smp_ops = &smp_85xx_ops;
 
 #ifdef CONFIG_KEXEC
-- 
1.7.3

^ permalink raw reply related

* [PATCH 2/9] powerpc/cache: add cache flush operation for various e500
From: Chenhui Zhao @ 2014-03-07  4:57 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In-Reply-To: <1394168285-32275-1-git-send-email-chenhui.zhao@freescale.com>

Various e500 core have different cache architecture, so they
need different cache flush operations. Therefore, add a callback
function cpu_flush_caches to the struct cpu_spec. The cache flush
operation for the specific kind of e500 is selected at init time.
The callback function will flush all caches in the current cpu.

Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
 arch/powerpc/include/asm/cacheflush.h     |    2 -
 arch/powerpc/include/asm/cputable.h       |   11 +++
 arch/powerpc/kernel/asm-offsets.c         |    3 +
 arch/powerpc/kernel/cpu_setup_fsl_booke.S |  114 ++++++++++++++++++++++++++++-
 arch/powerpc/kernel/cputable.c            |    4 +
 arch/powerpc/kernel/head_fsl_booke.S      |   74 -------------------
 arch/powerpc/platforms/85xx/smp.c         |    4 +-
 7 files changed, 134 insertions(+), 78 deletions(-)

diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index 5b93122..039753e 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -30,8 +30,6 @@ extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
 
-extern void __flush_disable_L1(void);
-
 extern void flush_icache_range(unsigned long, unsigned long);
 extern void flush_icache_user_range(struct vm_area_struct *vma,
 				    struct page *page, unsigned long addr,
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 617cc76..2c497a2 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -43,6 +43,13 @@ extern int machine_check_e500(struct pt_regs *regs);
 extern int machine_check_e200(struct pt_regs *regs);
 extern int machine_check_47x(struct pt_regs *regs);
 
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+extern void __flush_caches_e500v2(void);
+extern void __flush_caches_e500mc(void);
+extern void __flush_caches_e5500(void);
+extern void __flush_caches_e6500(void);
+#endif
+
 /* NOTE WELL: Update identify_cpu() if fields are added or removed! */
 struct cpu_spec {
 	/* CPU is matched via (PVR & pvr_mask) == pvr_value */
@@ -59,6 +66,10 @@ struct cpu_spec {
 	unsigned int	icache_bsize;
 	unsigned int	dcache_bsize;
 
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+	/* flush caches of the cpu which is running the function */
+	void (*cpu_flush_caches)(void);
+#endif
 	/* number of performance monitor counters */
 	unsigned int	num_pmcs;
 	enum powerpc_pmc_type pmc_type;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8d1d94d..5157fb4 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -372,6 +372,9 @@ int main(void)
 	DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
 	DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
 	DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+	DEFINE(CPU_FLUSH_CACHES, offsetof(struct cpu_spec, cpu_flush_caches));
+#endif
 
 	DEFINE(pbe_address, offsetof(struct pbe, address));
 	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index cc2d896..e59d6de 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -1,7 +1,7 @@
 /*
  * This file contains low level CPU setup functions.
  * Kumar Gala <galak@kernel.crashing.org>
- * Copyright 2009 Freescale Semiconductor, Inc.
+ * Copyright 2009, 2014 Freescale Semiconductor, Inc.
  *
  * Based on cpu_setup_6xx code by
  * Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -13,11 +13,13 @@
  *
  */
 
+#include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
 #include <asm/mmu-book3e.h>
 #include <asm/asm-offsets.h>
+#include <asm/mpc85xx.h>
 
 _GLOBAL(__e500_icache_setup)
 	mfspr	r0, SPRN_L1CSR1
@@ -223,3 +225,113 @@ _GLOBAL(__setup_cpu_e5500)
 	mtlr	r5
 	blr
 #endif
+
+/* flush L1 date cache, it can apply to e500v2, e500mc and e5500 */
+_GLOBAL(flush_dcache_L1)
+	mfmsr	r10
+	wrteei	0
+
+	mfspr	r3,SPRN_L1CFG0
+	rlwinm	r5,r3,9,3	/* Extract cache block size */
+	twlgti	r5,1		/* Only 32 and 64 byte cache blocks
+				 * are currently defined.
+				 */
+	li	r4,32
+	subfic	r6,r5,2		/* r6 = log2(1KiB / cache block size) -
+				 *      log2(number of ways)
+				 */
+	slw	r5,r4,r5	/* r5 = cache block size */
+
+	rlwinm	r7,r3,0,0xff	/* Extract number of KiB in the cache */
+	mulli	r7,r7,13	/* An 8-way cache will require 13
+				 * loads per set.
+				 */
+	slw	r7,r7,r6
+
+	/* save off HID0 and set DCFA */
+	mfspr	r8,SPRN_HID0
+	ori	r9,r8,HID0_DCFA@l
+	mtspr	SPRN_HID0,r9
+	isync
+
+	LOAD_REG_IMMEDIATE(r6, KERNELBASE)
+	mr	r4, r6
+	mtctr	r7
+
+1:	lwz	r3,0(r4)	/* Load... */
+	add	r4,r4,r5
+	bdnz	1b
+
+	msync
+	mr	r4, r6
+	mtctr	r7
+
+1:	dcbf	0,r4		/* ...and flush. */
+	add	r4,r4,r5
+	bdnz	1b
+
+	/* restore HID0 */
+	mtspr	SPRN_HID0,r8
+	isync
+
+	wrtee r10
+
+	blr
+
+has_L2_cache:
+	/* skip L2 cache on P2040/P2040E as they have no L2 cache */
+	mfspr	r3, SPRN_SVR
+	/* shift right by 8 bits and clear E bit of SVR */
+	rlwinm	r4, r3, 24, ~0x800
+
+	lis	r3, SVR_P2040@h
+	ori	r3, r3, SVR_P2040@l
+	cmpw	r4, r3
+	beq	1f
+
+	li	r3, 1
+	blr
+1:
+	li	r3, 0
+	blr
+
+/* flush backside L2 cache */
+flush_backside_L2_cache:
+	mflr	r10
+	bl	has_L2_cache
+	mtlr	r10
+	cmpwi	r3, 0
+	beq	2f
+
+	/* Flush the L2 cache */
+	mfspr	r3, SPRN_L2CSR0
+	ori	r3, r3, L2CSR0_L2FL@l
+	msync
+	isync
+	mtspr	SPRN_L2CSR0,r3
+	isync
+
+	/* check if it is complete */
+1:	mfspr	r3,SPRN_L2CSR0
+	andi.	r3, r3, L2CSR0_L2FL@l
+	bne	1b
+2:
+	blr
+
+_GLOBAL(__flush_caches_e500v2)
+	mflr r0
+	bl	flush_dcache_L1
+	mtlr r0
+	blr
+
+_GLOBAL(__flush_caches_e500mc)
+_GLOBAL(__flush_caches_e5500)
+	mflr r0
+	bl	flush_dcache_L1
+	bl	flush_backside_L2_cache
+	mtlr r0
+	blr
+
+/* L1 Data Cache of e6500 contains no modified data, no flush is required */
+_GLOBAL(__flush_caches_e6500)
+	blr
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 6c8dd5d..8e70aa7 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -2068,6 +2068,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_e500v2,
 		.machine_check		= machine_check_e500,
 		.platform		= "ppc8548",
+		.cpu_flush_caches	= __flush_caches_e500v2,
 	},
 	{	/* e500mc */
 		.pvr_mask		= 0xffff0000,
@@ -2086,6 +2087,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_e500mc,
 		.machine_check		= machine_check_e500mc,
 		.platform		= "ppce500mc",
+		.cpu_flush_caches	= __flush_caches_e500mc,
 	},
 #endif /* CONFIG_PPC32 */
 	{	/* e5500 */
@@ -2108,6 +2110,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 #endif
 		.machine_check		= machine_check_e500mc,
 		.platform		= "ppce5500",
+		.cpu_flush_caches	= __flush_caches_e5500,
 	},
 	{	/* e6500 */
 		.pvr_mask		= 0xffff0000,
@@ -2130,6 +2133,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 #endif
 		.machine_check		= machine_check_e500mc,
 		.platform		= "ppce6500",
+		.cpu_flush_caches	= __flush_caches_e6500,
 	},
 #ifdef CONFIG_PPC32
 	{	/* default match */
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index b497188..20204fe 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -1067,80 +1067,6 @@ _GLOBAL(set_context)
 	isync			/* Force context change */
 	blr
 
-_GLOBAL(flush_dcache_L1)
-	mfspr	r3,SPRN_L1CFG0
-
-	rlwinm	r5,r3,9,3	/* Extract cache block size */
-	twlgti	r5,1		/* Only 32 and 64 byte cache blocks
-				 * are currently defined.
-				 */
-	li	r4,32
-	subfic	r6,r5,2		/* r6 = log2(1KiB / cache block size) -
-				 *      log2(number of ways)
-				 */
-	slw	r5,r4,r5	/* r5 = cache block size */
-
-	rlwinm	r7,r3,0,0xff	/* Extract number of KiB in the cache */
-	mulli	r7,r7,13	/* An 8-way cache will require 13
-				 * loads per set.
-				 */
-	slw	r7,r7,r6
-
-	/* save off HID0 and set DCFA */
-	mfspr	r8,SPRN_HID0
-	ori	r9,r8,HID0_DCFA@l
-	mtspr	SPRN_HID0,r9
-	isync
-
-	lis	r4,KERNELBASE@h
-	mtctr	r7
-
-1:	lwz	r3,0(r4)	/* Load... */
-	add	r4,r4,r5
-	bdnz	1b
-
-	msync
-	lis	r4,KERNELBASE@h
-	mtctr	r7
-
-1:	dcbf	0,r4		/* ...and flush. */
-	add	r4,r4,r5
-	bdnz	1b
-	
-	/* restore HID0 */
-	mtspr	SPRN_HID0,r8
-	isync
-
-	blr
-
-/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
-_GLOBAL(__flush_disable_L1)
-	mflr	r10
-	bl	flush_dcache_L1	/* Flush L1 d-cache */
-	mtlr	r10
-
-	mfspr	r4, SPRN_L1CSR0	/* Invalidate and disable d-cache */
-	li	r5, 2
-	rlwimi	r4, r5, 0, 3
-
-	msync
-	isync
-	mtspr	SPRN_L1CSR0, r4
-	isync
-
-1:	mfspr	r4, SPRN_L1CSR0	/* Wait for the invalidate to finish */
-	andi.	r4, r4, 2
-	bne	1b
-
-	mfspr	r4, SPRN_L1CSR1	/* Invalidate and disable i-cache */
-	li	r5, 2
-	rlwimi	r4, r5, 0, 3
-
-	mtspr	SPRN_L1CSR1, r4
-	isync
-
-	blr
-
 #ifdef CONFIG_SMP
 /* When we get here, r24 needs to hold the CPU # */
 	.globl __secondary_start
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 6382098..2e5911e 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -137,7 +137,9 @@ static void smp_85xx_mach_cpu_die(void)
 
 	mtspr(SPRN_TCR, 0);
 
-	__flush_disable_L1();
+	if (cur_cpu_spec && cur_cpu_spec->cpu_flush_caches)
+		cur_cpu_spec->cpu_flush_caches();
+
 	tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
 	mtspr(SPRN_HID0, tmp);
 	isync();
-- 
1.7.3

^ permalink raw reply related

* [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500
From: Chenhui Zhao @ 2014-03-07  4:57 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin

From: Wang Dongsheng <dongsheng.wang@freescale.com>

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
---
 arch/powerpc/include/asm/reg.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 62b114e..cd7b630 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -1075,6 +1075,8 @@
 #define PVR_8560	0x80200000
 #define PVR_VER_E500V1	0x8020
 #define PVR_VER_E500V2	0x8021
+#define PVR_VER_E500MC	0x8023
+#define PVR_VER_E5500	0x8024
 #define PVR_VER_E6500	0x8040
 
 /*
-- 
1.7.3

^ permalink raw reply related

* Re: [PATCH RFC/RFT v3 6/9] powerpc: move cacheinfo sysfs to generic cacheinfo infrastructure
From: Anshuman Khandual @ 2014-03-07  4:06 UTC (permalink / raw)
  To: Sudeep Holla; +Cc: linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <1392825976-17633-7-git-send-email-sudeep.holla@arm.com>

On 02/19/2014 09:36 PM, Sudeep Holla wrote:
> From: Sudeep Holla <sudeep.holla@arm.com>
> 
> This patch removes the redundant sysfs cacheinfo code by making use of
> the newly introduced generic cacheinfo infrastructure.
> 
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: linuxppc-dev@lists.ozlabs.org
> ---
>  arch/powerpc/kernel/cacheinfo.c | 831 ++++++----------------------------------
>  arch/powerpc/kernel/cacheinfo.h |   8 -
>  arch/powerpc/kernel/sysfs.c     |   4 -
>  3 files changed, 109 insertions(+), 734 deletions(-)
>  delete mode 100644 arch/powerpc/kernel/cacheinfo.h
> 
> diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
> index 2912b87..05b7580 100644
> --- a/arch/powerpc/kernel/cacheinfo.c
> +++ b/arch/powerpc/kernel/cacheinfo.c
> @@ -10,38 +10,10 @@
>   * 2 as published by the Free Software Foundation.
>   */
> 
> +#include <linux/cacheinfo.h>
>  #include <linux/cpu.h>
> -#include <linux/cpumask.h>
>  #include <linux/kernel.h>
> -#include <linux/kobject.h>
> -#include <linux/list.h>
> -#include <linux/notifier.h>
>  #include <linux/of.h>
> -#include <linux/percpu.h>
> -#include <linux/slab.h>
> -#include <asm/prom.h>
> -
> -#include "cacheinfo.h"
> -
> -/* per-cpu object for tracking:
> - * - a "cache" kobject for the top-level directory
> - * - a list of "index" objects representing the cpu's local cache hierarchy
> - */
> -struct cache_dir {
> -	struct kobject *kobj; /* bare (not embedded) kobject for cache
> -			       * directory */
> -	struct cache_index_dir *index; /* list of index objects */
> -};
> -
> -/* "index" object: each cpu's cache directory has an index
> - * subdirectory corresponding to a cache object associated with the
> - * cpu.  This object's lifetime is managed via the embedded kobject.
> - */
> -struct cache_index_dir {
> -	struct kobject kobj;
> -	struct cache_index_dir *next; /* next index in parent directory */
> -	struct cache *cache;
> -};
> 
>  /* Template for determining which OF properties to query for a given
>   * cache type */
> @@ -60,11 +32,6 @@ struct cache_type_info {
>  	const char *nr_sets_prop;
>  };
> 
> -/* These are used to index the cache_type_info array. */
> -#define CACHE_TYPE_UNIFIED     0
> -#define CACHE_TYPE_INSTRUCTION 1
> -#define CACHE_TYPE_DATA        2
> -
>  static const struct cache_type_info cache_type_info[] = {
>  	{
>  		/* PowerPC Processor binding says the [di]-cache-*
> @@ -77,246 +44,115 @@ static const struct cache_type_info cache_type_info[] = {
>  		.nr_sets_prop    = "d-cache-sets",
>  	},
>  	{
> -		.name            = "Instruction",
> -		.size_prop       = "i-cache-size",
> -		.line_size_props = { "i-cache-line-size",
> -				     "i-cache-block-size", },
> -		.nr_sets_prop    = "i-cache-sets",
> -	},
> -	{
>  		.name            = "Data",
>  		.size_prop       = "d-cache-size",
>  		.line_size_props = { "d-cache-line-size",
>  				     "d-cache-block-size", },
>  		.nr_sets_prop    = "d-cache-sets",
>  	},
> +	{
> +		.name            = "Instruction",
> +		.size_prop       = "i-cache-size",
> +		.line_size_props = { "i-cache-line-size",
> +				     "i-cache-block-size", },
> +		.nr_sets_prop    = "i-cache-sets",
> +	},
>  };


Hey Sudeep,

After applying this patch, the cache_type_info array looks like this.

static const struct cache_type_info cache_type_info[] = {
        {
                /* 
                 * PowerPC Processor binding says the [di]-cache-*
                 * must be equal on unified caches, so just use
                 * d-cache properties.
                 */
                .name            = "Unified",
                .size_prop       = "d-cache-size",
                .line_size_props = { "d-cache-line-size",
                                     "d-cache-block-size", },
                .nr_sets_prop    = "d-cache-sets",
        },
        {
                .name            = "Data",
                .size_prop       = "d-cache-size",
                .line_size_props = { "d-cache-line-size",
                                     "d-cache-block-size", },
                .nr_sets_prop    = "d-cache-sets",
        },
        {
                .name            = "Instruction",
                .size_prop       = "i-cache-size",
                .line_size_props = { "i-cache-line-size",
                                     "i-cache-block-size", },
                .nr_sets_prop    = "i-cache-sets",
        },
};

and this function computes the the array index for any given cache type
define for PowerPC.

static inline int get_cacheinfo_idx(enum cache_type type)
{
        if (type == CACHE_TYPE_UNIFIED)
                return 0;
        else
                return type;
}

These types are define in include/linux/cacheinfo.h as

enum cache_type {
        CACHE_TYPE_NOCACHE = 0,
        CACHE_TYPE_INST = BIT(0),		---> 1
        CACHE_TYPE_DATA = BIT(1),		---> 2
        CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA,
        CACHE_TYPE_UNIFIED = BIT(2),
};

When it is UNIFIED we return index 0, which is correct. But the index
for instruction and data cache seems to be swapped which wrong. This
will fetch invalid properties for any given cache type.

I have done some initial review and testing for this patch's impact on
PowerPC (ppc64 POWER specifically). I am trying to do some code clean-up
and re-arrangements. Will post out soon. Thanks !

Regards
Anshuman

^ permalink raw reply

* Re: [PATCH v2 14/52] powerpc, sysfs: Fix CPU hotplug callback registration
From: Benjamin Herrenschmidt @ 2014-03-07  2:57 UTC (permalink / raw)
  To: Srivatsa S. Bhat
  Cc: linux-arch, ego, walken, linux, akpm, Wang Dongsheng, peterz,
	rusty, rjw, oleg, linux-kernel, Olof Johansson,
	Madhavan Srinivasan, paulus, tj, tglx, paulmck, linuxppc-dev,
	mingo
In-Reply-To: <20140214075215.22701.23653.stgit@srivatsabhat.in.ibm.com>

On Fri, 2014-02-14 at 13:22 +0530, Srivatsa S. Bhat wrote:
> Subsystems that want to register CPU hotplug callbacks, as well as perform
> initialization for the CPUs that are already online, often do it as shown
> below:
> 
> 	get_online_cpus();
> 
> 	for_each_online_cpu(cpu)
> 		init_cpu(cpu);
> 
> 	register_cpu_notifier(&foobar_cpu_notifier);
> 
> 	put_online_cpus();

This patch breaks a good half of my test configs with:

/home/benh/linux-powerpc-test/arch/powerpc/kernel/sysfs.c: In function 'topology_init':
/home/benh/linux-powerpc-test/arch/powerpc/kernel/sysfs.c:979:2: error: implicit declaration of function 'cpu_notifier_register_begin' [-Werror=implicit-function-declaration]
/home/benh/linux-powerpc-test/arch/powerpc/kernel/sysfs.c:1004:2: error: implicit declaration of function '__register_cpu_notifier' [-Werror=implicit-function-declaration]
/home/benh/linux-powerpc-test/arch/powerpc/kernel/sysfs.c:1006:2: error: implicit declaration of function 'cpu_notifier_register_done' [-Werror=implicit-function-declaration]
cc1: all warnings being treated as errors
make[2]: *** [arch/powerpc/kernel/sysfs.o] Error 1
make[2]: *** Waiting for unfinished jobs....

^ permalink raw reply

* Re: [PATCH] kexec/powerpc: fix exporting memory limit
From: Michael Ellerman @ 2014-03-07  0:47 UTC (permalink / raw)
  To: Nikita Yushchenko
  Cc: yadviga, lugovskoy, kexec, linux-kernel, Paul Mackerras,
	Anton Blanchard, Mahesh Salgaonkar, Hari Bathini, linuxppc-dev
In-Reply-To: <1394115854-11709-1-git-send-email-nyushchenko@dev.rtsoft.ru>

On Thu, 2014-03-06 at 18:24 +0400, Nikita Yushchenko wrote:
> When preparing dump-capturing kernel, kexec userspace tool needs to know
> actual amount of memory used by the running kernel. This may differ from
> extire available DRAM for a couple of reasons. To address this issue,
> kdump kernel support code injects several attributes into device tree that
> are later captured by userspace kexec tool via /proc interface.
> 
> One such attrubute is 'chosen/linux,memory_limit' that is used to pass
> memory limit of the running kernel.
> 
> This was initialized using kernel's 'memory_limit' variable, that is set
> by early init code based on mem= kernel parameter and other reasons.
> 
> But there are cases when memory_limit variable does not contain proper
> information. One such case is when !CONFIG_HIGHMEM kernel runs on system
> with memory large enough not to fit into lowmem.

Why doesn't the !CONFIG_HIGHMEM code update memory_limit to reflect reality.

cheers

^ permalink raw reply

* Re: ibmveth: Fix endian issues with MAC addresses
From: David Miller @ 2014-03-06 21:27 UTC (permalink / raw)
  To: anton; +Cc: linuxppc-dev, dvaleev, agraf, netdev, joe, santil
In-Reply-To: <20140305145137.3460dbe7@kryten>

From: Anton Blanchard <anton@samba.org>
Date: Wed, 5 Mar 2014 14:51:37 +1100

> The code to load a MAC address into a u64 for passing to the
> hypervisor via a register is broken on little endian.
> 
> Create a helper function called ibmveth_encode_mac_addr
> which does the right thing in both big and little endian.
> 
> We were storing the MAC address in a long in struct ibmveth_adapter.
> It's never used so remove it - we don't need another place in the
> driver where we create endian issues with MAC addresses.
> 
> Signed-off-by: Anton Blanchard <anton@samba.org>
> Cc: stable@vger.kernel.org

Applied, thanks Anton.

> -	memcpy(&adapter->mac_addr, mac_addr_p, ETH_ALEN);
 ...
> -    unsigned long mac_addr;

That's some scary stuff right there.

^ permalink raw reply

* Re: [PATCH 3/3] perf: Use 64-bit value when comparing sample_regs
From: Jiri Olsa @ 2014-03-06 17:06 UTC (permalink / raw)
  To: Gabriel Paubert
  Cc: Michael Ellerman, linux-kernel@vger.kernel.org, Stephane Eranian,
	linuxppc-dev@ozlabs.org, David Laight, Paul Mackerras,
	Arnaldo Carvalho de Melo, 'Sukadev Bhattiprolu'
In-Reply-To: <20140306113332.GA7827@visitor2.iram.es>

On Thu, Mar 06, 2014 at 12:33:32PM +0100, Gabriel Paubert wrote:
> On Thu, Mar 06, 2014 at 09:44:47AM +0000, David Laight wrote:
> > From: Sukadev Bhattiprolu
> > > When checking whether a bit representing a register is set in
> > > sample_regs, a 64-bit mask, use 64-bit value (1LL).
> > > 
> > > Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
> > > ---
> > >  tools/perf/util/unwind.c |    4 ++--
> > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
> > > index 742f23b..2b888c6 100644
> > > --- a/tools/perf/util/unwind.c
> > > +++ b/tools/perf/util/unwind.c
> > > @@ -396,11 +396,11 @@ static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
> > >  {
> > >  	int i, idx = 0;
> > > 
> > > -	if (!(sample_regs & (1 << id)))
> > > +	if (!(sample_regs & (1LL << id)))
> > >  		return -EINVAL;
> > > 
> > >  	for (i = 0; i < id; i++) {
> > > -		if (sample_regs & (1 << i))
> > > +		if (sample_regs & (1LL << i))
> > >  			idx++;
> > >  	}
> > 
> > There are much faster ways to count the number of set bits, especially
> > if you might need to check a significant number of bits.
> > There might even be a function defined somewhere to do it.
> 
> Indeed, look for Hamming weight (hweight family of functions)
> in asm/hweight.h and what is included from there.
> 
> Besides that, many modern processors also have a machine instruction
> to perform this task. In the processor manuals the instruction is 
> described as population count and the mnemonic starts with "popcnt"
> on x86 and ppc.
> 
> 	Gabriel
> 
> > Basically you just add up the bits, for 16 bit it would be:
> > 	val = (val & 0x5555) + (val >> 1) & 0x5555;
> > 	val = (val & 0x3333) + (val >> 2) & 0x3333;
> > 	val = (val & 0x0f0f) + (val >> 4) & 0x0f0f;
> > 	val = (val & 0x00ff) + (val >> 8) & 0x00ff;
> > As the size of the work increases the improvement is more significant.
> > (Some of the later masking can probably be proven unnecessary.)

right I think the loop could be replaced by:

  idx = hweight(mask & ((1 << id) - 1))

Sukadev,
please also rebase against latest Arnaldo's perf/core,
this code has changed just recently, it's now in:
  util/perf_regs.c:perf_reg_value

thanks,
jirka

^ permalink raw reply

* Re: [PATCH 0/3] powerpc/perf: Enable linking with libunwind
From: Jiri Olsa @ 2014-03-06 17:49 UTC (permalink / raw)
  To: Sukadev Bhattiprolu
  Cc: Michael Ellerman, linux-kernel, Stephane Eranian, linuxppc-dev,
	Paul Mackerras, Arnaldo Carvalho de Melo, Jean Pihet
In-Reply-To: <1394080919-17957-1-git-send-email-sukadev@linux.vnet.ibm.com>

On Wed, Mar 05, 2014 at 08:41:56PM -0800, Sukadev Bhattiprolu wrote:
> When we try to create backtraces (call-graphs) with the perf tool
> 
> 	perf record -g /tmp/sprintft
> 
> we get backtraces with duplicate arcs for sprintft[1]:
> 
>     14.61%  sprintft  libc-2.18.so       [.] __random                            
>             |
>             --- __random
>                |
>                |--61.09%-- __random
>                |          |
>                |          |--97.18%-- rand
>                |          |          do_my_sprintf
>                |          |          main
>                |          |          generic_start_main.isra.0
>                |          |          __libc_start_main
>                |          |          0x0
>                |          |
>                |           --2.82%-- do_my_sprintf
>                |                     main
>                |                     generic_start_main.isra.0
>                |                     __libc_start_main
>                |                     0x0
>                |
>                 --38.91%-- rand
>                           |          
>                           |--92.90%-- rand
>                           |          |
>                           |          |--99.87%-- do_my_sprintf
>                           |          |          main
>                           |          |          generic_start_main.isra.0
>                           |          |          __libc_start_main
>                           |          |          0x0
>                           |           --0.13%-- [...]
>                           |
>                            --7.10%-- do_my_sprintf
>                                      main
>                                      generic_start_main.isra.0
>                                      __libc_start_main
>                                      0x0
> 
> (where the two arcs both have the same backtrace but are not merged).
> 
> Linking with libunwind seems to create better backtraces. While x86 and
> ARM processors have support for linking with libunwind but Power does not.
> This patchset is an RFC for linking with libunwind.
> 
> With this patchset and running:
> 
> 	/tmp/perf record --call-graph=dwarf,8192 /tmp/sprintft
> 
> the backtrace is:
> 
>     14.94%  sprintft  libc-2.18.so       [.] __random                            
>             |
>             --- __random
>                 rand
>                 do_my_sprintf
>                 main
>                 generic_start_main.isra.0
>                 __libc_start_main
>                 (nil)
> 
> This appears better.
> 
> One downside is that we now need the kernel to save the entire user stack
> (the 8192 in the command line is the default user stack size).
> 
> A second issue is that this invocation of perf (with --call-graph=dwarf,8192)
> seems to fail for backtraces involving tail-calls[2]
> 
> 	/tmp/perf record -g ./tailcall
> gives 
> 
>     20.00%  tailcall  tailcall           [.] work2
>             |
>             --- work2
>                 work
> 
> shows the tail function 'work2' as "called from" 'work()'
> 
> But with libunwind:
> 
> 	/tmp/perf record --call-graph=dwarf,8192 ./tailcall
> we get:
> 
>    20.50%  tailcall  tailcall           [.] work2
>             |
>             --- work2
> 
> the caller of 'work' is not shown.
> 
> I am debugging this, but would appreciate any feedback/pointers on the
> patchset/direction:
> 
> 	- Does libunwind need the entire user stack to work or are there
> 	  optimizations we can do to save the minimal entries for it to
> 	  perform the unwind.

AFAIK you dont need to provide whole stack, but the more
you have the bigger chance you'll get full(er) backtrace

> 
> 	- Does libunwind work with tailcalls like the one above ?

not sure, but if you have x86 alternative to your tailcall (i cannot
read ppc assembly) I could try on x86 ;-)

CC-ing Jean, as he might have seen this issue..


> 
> 	- Are there benefits to linking with libunwind (even if it does not
> 	  yet solve the tailcall problem)

provides backtrace for binaries/distros/archs compiled without framepointer

> 
> 	- Are there any examples of using libdwarf to solve the tailcall
> 	  issue ?


btw there's now remote unwinder in elfutils (version 0.158)
the perf supprot is in Arnaldo's perf/core tree

jirka

^ permalink raw reply

* [PATCH] kexec/powerpc: fix exporting memory limit
From: Nikita Yushchenko @ 2014-03-06 14:24 UTC (permalink / raw)
  To: kexec, Benjamin Herrenschmidt, Paul Mackerras, Anton Blanchard,
	Hari Bathini, Mahesh Salgaonkar, linuxppc-dev
  Cc: yadviga, nyushchenko, lugovskoy, linux-kernel

When preparing dump-capturing kernel, kexec userspace tool needs to know
actual amount of memory used by the running kernel. This may differ from
extire available DRAM for a couple of reasons. To address this issue,
kdump kernel support code injects several attributes into device tree that
are later captured by userspace kexec tool via /proc interface.

One such attrubute is 'chosen/linux,memory_limit' that is used to pass
memory limit of the running kernel.

This was initialized using kernel's 'memory_limit' variable, that is set
by early init code based on mem= kernel parameter and other reasons.

But there are cases when memory_limit variable does not contain proper
information. One such case is when !CONFIG_HIGHMEM kernel runs on system
with memory large enough not to fit into lowmem.

This patch fixes initialization of 'chosen/linux,memory_limit' to use
values from memblock subsystem. These are adjusted at kernel memory
management init and thus always contain values that match reality.

Signed-off-by: Nikita Yushchenko <nyushchenko@dev.rtsoft.ru>
---
 arch/powerpc/kernel/machine_kexec.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index 015ae55..372cda5 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -250,8 +250,14 @@ static void __init export_crashk_values(struct device_node *node)
 	/*
 	 * memory_limit is required by the kexec-tools to limit the
 	 * crash regions to the actual memory used.
+	 *
+	 * There are cases when memory_limit variable does not hold actual
+	 * limit, for example when memory was limited by no kernel support
+	 * for HIGHMEM. Reliable information is known by memblock because
+	 * memory management init adjusts it.
 	 */
-	mem_limit = cpu_to_be_ulong(memory_limit);
+	mem_limit = cpu_to_be_ulong(memblock_end_of_DRAM() -
+					memblock_start_of_DRAM());
 	of_update_property(node, &memory_limit_prop);
 }
 
-- 
1.7.10.4

^ permalink raw reply related

* Re: [PATCH RFC v8 5/5] dma: mpc512x: register for device tree channel lookup
From: Alexander Popov @ 2014-03-06 14:28 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: devicetree, Lars-Peter Clausen, Arnd Bergmann, Vinod Koul,
	Gerhard Sittig, Alexander Popov, dmaengine, Dan Williams,
	Anatolij Gustschin, linuxppc-dev
In-Reply-To: <1393247295.28803.10.camel@smile.fi.intel.com>

Hello Andy.

2014-02-24 17:08 GMT+04:00 Andy Shevchenko <andriy.shevchenko@linux.intel.com>:
> On Mon, 2014-02-24 at 15:09 +0400, Alexander Popov wrote:
>> @@ -1018,11 +1019,23 @@ static int mpc_dma_probe(struct platform_device *op)
>>       /* Register DMA engine */
>>       dev_set_drvdata(dev, mdma);
>>       retval = dma_async_device_register(dma);
>> -     if (retval) {
>> -             devm_free_irq(dev, mdma->irq, mdma);
>> -             irq_dispose_mapping(mdma->irq);
>> +     if (retval)
>> +             goto out_irq;
>> +
>> +     /* register with OF helpers for DMA lookups (nonfatal) */
>> +     if (dev->of_node) {
>> +             retval = of_dma_controller_register(dev->of_node,
>> +                                                 of_dma_xlate_by_chan_id,
>> +                                                 mdma);
>> +             if (retval)
>> +                     dev_warn(dev, "could not register for OF lookup\n");
>>       }
>>
>> +     return 0;
>> +
>> +out_irq:
>> +     devm_free_irq(dev, mdma->irq, mdma);
>
> Something wrong either with devm_request_irq() or you don't need to call
> devm_free_irq() explicitly. Once we already try to discuss this earlier
> in this mailing list with Lars-Peter(?), though there were no solution
> how to keep devm_*_irq usability.

Thanks, I've read this discussion. It seems that the current code doesn't do
anything bad, though devm_request_irq() and devm_free_irq() can be changed
to request_irq() and free_irq() accordingly. Do you think it's worth being done
in a separate patch in this series?

>> +     irq_dispose_mapping(mdma->irq);
>>       return retval;
>>  }
>>
>> @@ -1031,6 +1044,8 @@ static int mpc_dma_remove(struct platform_device *op)
>>       struct device *dev = &op->dev;
>>       struct mpc_dma *mdma = dev_get_drvdata(dev);
>>
>> +     if (dev->of_node)
>> +             of_dma_controller_free(dev->of_node);
>>       dma_async_device_unregister(&mdma->dma);
>>       devm_free_irq(dev, mdma->irq, mdma);
>>       irq_dispose_mapping(mdma->irq);

Best regards,
Alexander

^ permalink raw reply

* Re: [PATCH 1/2] Revert "KVM: PPC: Book3S HV: Add new state for transactional memory"
From: Aneesh Kumar K.V @ 2014-03-06 13:29 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Michael Neuling, kvm, agraf, kvm-ppc, linuxppc-dev
In-Reply-To: <20140306111836.GA5729@iris.ozlabs.ibm.com>

Paul Mackerras <paulus@samba.org> writes:

> On Thu, Mar 06, 2014 at 04:06:09PM +0530, Aneesh Kumar K.V wrote:
>> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>> 
>> This reverts commit 7b490411c37f7ab7965cbdfe5e3ec28eadb6db5b which cause
>> the below crash in the host.
>> 
>> Unable to handle kernel paging request for data at address 0xf00000001223f278
>> Faulting instruction address: 0xc000000000202a00
>
> Why exactly does it cause that crash?  What is the actual problem here?
> Under what specific circumstances do you see the crash?

When we exit from guest, we find that 263 index in the
kvm->arch.vcore is always corrupted. The way to reproduce is to start
the guest and use Qemu monitor to quit. That will result in the below
crash.

Now the commit in 7b490411c37f7ab7965cbdfe5e3ec28eadb6db5b is not
complete. If you look at series

http://article.gmane.org/gmane.comp.emulators.kvm.powerpc.devel/8562

Andreas didn't pull all the changes because TM changes had issues like

http://article.gmane.org/gmane.comp.emulators.kvm.devel/118411

+<<<<<<< HEAD
+=======
+	/* Save DEC */
+	mfspr	r5,SPRN_DEC
+	mftb	r6
+	extsw	r5,r5
+	add	r5,r5,r6
+	std	r5,VCPU_DEC_EXPIRES(r9)
+

and

+	/* Save and reset AMR and UAMOR before turning on the MMU */
+BEGIN_FTR_SECTION
+	mfspr	r5,SPRN_AMR
+	mfspr	r6,SPRN_UAMOR
+	std	r5,VCPU_AMR(r9)
+	std	r6,VCPU_UAMOR(r9)
+	li	r6,0
+	mtspr	SPRN_AMR,r6
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+
+>>>>>>> a65ae5a... KVM: PPC: Book3S HV: Add new state for transactional memory


Which got reverted in the next patch

http://article.gmane.org/gmane.comp.emulators.kvm.powerpc.devel/8571

-<<<<<<< HEAD
-=======
-	/* Save DEC */
-	mfspr	r5,SPRN_DEC
-	mftb	r6
-	extsw	r5,r5
-	add	r5,r5,r6
-	std	r5,VCPU_DEC_EXPIRES(r9)
-
-BEGIN_FTR_SECTION

and

-
-	/* Save and reset AMR and UAMOR before turning on the MMU */
-BEGIN_FTR_SECTION
-	mfspr	r5,SPRN_AMR
-	mfspr	r6,SPRN_UAMOR
-	std	r5,VCPU_AMR(r9)
-	std	r6,VCPU_UAMOR(r9)
-	li	r6,0
-	mtspr	SPRN_AMR,r6
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
->>>>>>> a65ae5a... KVM: PPC: Book3S HV: Add new state for transactional memory

I guess the complete series will possibly work. But since we dropped
patch 16 and 17 we ended up with broken code

http://article.gmane.org/gmane.comp.emulators.kvm.powerpc.devel/8667

Hence the idea that we will revert TM stuff for 3.14 and do it properly
for 3.15 ?

>
>> cpu 0x30: Vector: 300 (Data Access) at [c000001e4debb2d0]
>>     pc: c000000000202a00: .kfree+0x40/0x200
>>     lr: c000000000098338: .kvmppc_core_destroy_vm_hv+0x38/0x90
>>     sp: c000001e4debb550
>>    msr: 9000000000009032
>>    dar: f00000001223f278
>>  dsisr: 40000000
>>   current = 0xc000001e4de195c0
>>   paca    = 0xc00000000fefb000   softe: 0        irq_happened: 0x01
>>     pid   = 29379, comm = qemu-system-ppc
>> enter ? for help
>> [c000001e4debb5e0] c000000000098338 .kvmppc_core_destroy_vm_hv+0x38/0x90
>> [c000001e4debb670] c000000000087f80 .kvmppc_core_destroy_vm+0x30/0x70
>> [c000001e4debb6f0] c000000000084f28 .kvm_arch_destroy_vm+0xd8/0x120
>> [c000001e4debb780] c000000000080218 .kvm_put_kvm+0x198/0x2e0
>> [c000001e4debb820] c0000000000880d4 .kvm_spapr_tce_release+0xe4/0x110
>> [c000001e4debb8b0] c000000000218578 .__fput+0xb8/0x2a0
>> [c000001e4debb950] c0000000000d9af4 .task_work_run+0x114/0x150
>> [c000001e4debb9f0] c0000000000b31e8 .do_exit+0x328/0xbc0
>> [c000001e4debbae0] c0000000000b4cd4 .do_group_exit+0x54/0xf0
>> [c000001e4debbb70] c0000000000c8448 .get_signal_to_deliver+0x1e8/0x6f0
>> [c000001e4debbc70] c000000000017ee4 .do_signal+0x54/0x320
>> [c000001e4debbdb0] c0000000000182e8 .do_notify_resume+0x68/0x80
>> [c000001e4debbe30] c00000000000a7b0 .ret_from_except_lite+0x5c/0x60
>> --- Exception: c00 (System Call) at 00003fffb38a4744
>> SP (3ffd36ffe360) is in userspace
>> 30:mon> zr
>> 
>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>> ---
>>  arch/powerpc/include/asm/kvm_host.h     | 24 ++---------
>>  arch/powerpc/kernel/asm-offsets.c       | 19 ++-------
>>  arch/powerpc/kvm/book3s_hv.c            |  4 --
>>  arch/powerpc/kvm/book3s_hv_rmhandlers.S | 75 +--------------------------------
>>  4 files changed, 8 insertions(+), 114 deletions(-)
>> 
>> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
>> index 1eaea2dea174..7726a3bc8ff0 100644
>> --- a/arch/powerpc/include/asm/kvm_host.h
>> +++ b/arch/powerpc/include/asm/kvm_host.h
>> @@ -475,6 +475,9 @@ struct kvm_vcpu_arch {
>>  	ulong ppr;
>>  	ulong pspb;
>>  	ulong fscr;
>> +	ulong tfhar;
>> +	ulong tfiar;
>> +	ulong texasr;
>>  	ulong ebbhr;
>>  	ulong ebbrr;
>>  	ulong bescr;
>> @@ -523,27 +526,6 @@ struct kvm_vcpu_arch {
>>  	u64 siar;
>>  	u64 sdar;
>>  	u64 sier;
>> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>> -	u64 tfhar;
>> -	u64 texasr;
>> -	u64 tfiar;
>> -
>> -	u32 cr_tm;
>> -	u64 lr_tm;
>> -	u64 ctr_tm;
>> -	u64 amr_tm;
>> -	u64 ppr_tm;
>> -	u64 dscr_tm;
>> -	u64 tar_tm;
>> -
>> -	ulong gpr_tm[32];
>> -
>> -	struct thread_fp_state fp_tm;
>> -
>> -	struct thread_vr_state vr_tm;
>> -	u32 vrsave_tm; /* also USPRG0 */
>> -
>> -#endif
>>  
>>  #ifdef CONFIG_KVM_EXIT_TIMING
>>  	struct mutex exit_timing_lock;
>> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
>> index b5aacf72ae6f..936d445b961a 100644
>> --- a/arch/powerpc/kernel/asm-offsets.c
>> +++ b/arch/powerpc/kernel/asm-offsets.c
>> @@ -534,6 +534,9 @@ int main(void)
>>  	DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr));
>>  	DEFINE(VCPU_FSCR, offsetof(struct kvm_vcpu, arch.fscr));
>>  	DEFINE(VCPU_PSPB, offsetof(struct kvm_vcpu, arch.pspb));
>> +	DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar));
>> +	DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar));
>> +	DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr));
>>  	DEFINE(VCPU_EBBHR, offsetof(struct kvm_vcpu, arch.ebbhr));
>>  	DEFINE(VCPU_EBBRR, offsetof(struct kvm_vcpu, arch.ebbrr));
>>  	DEFINE(VCPU_BESCR, offsetof(struct kvm_vcpu, arch.bescr));
>> @@ -555,22 +558,6 @@ int main(void)
>>  	DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
>>  	DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv));
>>  	DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb));
>> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>> -	DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar));
>> -	DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar));
>> -	DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr));
>> -	DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.gpr_tm));
>> -	DEFINE(VCPU_FPRS_TM, offsetof(struct kvm_vcpu, arch.fp_tm.fpr));
>> -	DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
>> -	DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
>> -	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm));
>> -	DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
>> -	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
>> -	DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
>> -	DEFINE(VCPU_PPR_TM, offsetof(struct kvm_vcpu, arch.ppr_tm));
>> -	DEFINE(VCPU_DSCR_TM, offsetof(struct kvm_vcpu, arch.dscr_tm));
>> -	DEFINE(VCPU_TAR_TM, offsetof(struct kvm_vcpu, arch.tar_tm));
>> -#endif
>>  
>>  #ifdef CONFIG_PPC_BOOK3S_64
>>  #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
>> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
>> index 3b498d942a22..71f2e8e6e7b1 100644
>> --- a/arch/powerpc/kvm/book3s_hv.c
>> +++ b/arch/powerpc/kvm/book3s_hv.c
>> @@ -879,7 +879,6 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>>  	case KVM_REG_PPC_IAMR:
>>  		*val = get_reg_val(id, vcpu->arch.iamr);
>>  		break;
>> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>>  	case KVM_REG_PPC_TFHAR:
>>  		*val = get_reg_val(id, vcpu->arch.tfhar);
>>  		break;
>> @@ -889,7 +888,6 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>>  	case KVM_REG_PPC_TEXASR:
>>  		*val = get_reg_val(id, vcpu->arch.texasr);
>>  		break;
>> -#endif
>>  	case KVM_REG_PPC_FSCR:
>>  		*val = get_reg_val(id, vcpu->arch.fscr);
>>  		break;
>> @@ -1039,7 +1037,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>>  	case KVM_REG_PPC_IAMR:
>>  		vcpu->arch.iamr = set_reg_val(id, *val);
>>  		break;
>> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>>  	case KVM_REG_PPC_TFHAR:
>>  		vcpu->arch.tfhar = set_reg_val(id, *val);
>>  		break;
>> @@ -1049,7 +1046,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>>  	case KVM_REG_PPC_TEXASR:
>>  		vcpu->arch.texasr = set_reg_val(id, *val);
>>  		break;
>> -#endif
>>  	case KVM_REG_PPC_FSCR:
>>  		vcpu->arch.fscr = set_reg_val(id, *val);
>>  		break;
>> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
>> index e66d4ec04d95..557a47800ca1 100644
>> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
>> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
>> @@ -704,15 +704,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
>>  	ld	r6, VCPU_VTB(r4)
>>  	mtspr	SPRN_IC, r5
>>  	mtspr	SPRN_VTB, r6
>> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>>  	ld	r5, VCPU_TFHAR(r4)
>>  	ld	r6, VCPU_TFIAR(r4)
>>  	ld	r7, VCPU_TEXASR(r4)
>> +	ld	r8, VCPU_EBBHR(r4)
>>  	mtspr	SPRN_TFHAR, r5
>>  	mtspr	SPRN_TFIAR, r6
>>  	mtspr	SPRN_TEXASR, r7
>> -#endif
>> -	ld	r8, VCPU_EBBHR(r4)
>>  	mtspr	SPRN_EBBHR, r8
>>  	ld	r5, VCPU_EBBRR(r4)
>>  	ld	r6, VCPU_BESCR(r4)
>> @@ -1122,15 +1120,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
>>  	std	r5, VCPU_IC(r9)
>>  	std	r6, VCPU_VTB(r9)
>>  	std	r7, VCPU_TAR(r9)
>> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>>  	mfspr	r5, SPRN_TFHAR
>>  	mfspr	r6, SPRN_TFIAR
>>  	mfspr	r7, SPRN_TEXASR
>> +	mfspr	r8, SPRN_EBBHR
>>  	std	r5, VCPU_TFHAR(r9)
>>  	std	r6, VCPU_TFIAR(r9)
>>  	std	r7, VCPU_TEXASR(r9)
>> -#endif
>> -	mfspr	r8, SPRN_EBBHR
>>  	std	r8, VCPU_EBBHR(r9)
>>  	mfspr	r5, SPRN_EBBRR
>>  	mfspr	r6, SPRN_BESCR
>> @@ -1504,73 +1500,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
>>  1:	addi	r8,r8,16
>>  	.endr
>>  
>> -	/* Save DEC */
>> -	mfspr	r5,SPRN_DEC
>> -	mftb	r6
>> -	extsw	r5,r5
>> -	add	r5,r5,r6
>> -	std	r5,VCPU_DEC_EXPIRES(r9)
>> -
>> -BEGIN_FTR_SECTION
>> -	b	8f
>> -END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
>> -	/* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
>> -	mfmsr	r8
>> -	li	r0, 1
>> -	rldimi	r8, r0, MSR_TM_LG, 63-MSR_TM_LG
>> -	mtmsrd	r8
>> -
>> -	/* Save POWER8-specific registers */
>> -	mfspr	r5, SPRN_IAMR
>> -	mfspr	r6, SPRN_PSPB
>> -	mfspr	r7, SPRN_FSCR
>> -	std	r5, VCPU_IAMR(r9)
>> -	stw	r6, VCPU_PSPB(r9)
>> -	std	r7, VCPU_FSCR(r9)
>> -	mfspr	r5, SPRN_IC
>> -	mfspr	r6, SPRN_VTB
>> -	mfspr	r7, SPRN_TAR
>> -	std	r5, VCPU_IC(r9)
>> -	std	r6, VCPU_VTB(r9)
>> -	std	r7, VCPU_TAR(r9)
>> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>> -	mfspr	r5, SPRN_TFHAR
>> -	mfspr	r6, SPRN_TFIAR
>> -	mfspr	r7, SPRN_TEXASR
>> -	std	r5, VCPU_TFHAR(r9)
>> -	std	r6, VCPU_TFIAR(r9)
>> -	std	r7, VCPU_TEXASR(r9)
>> -#endif
>> -	mfspr	r8, SPRN_EBBHR
>> -	std	r8, VCPU_EBBHR(r9)
>> -	mfspr	r5, SPRN_EBBRR
>> -	mfspr	r6, SPRN_BESCR
>> -	mfspr	r7, SPRN_CSIGR
>> -	mfspr	r8, SPRN_TACR
>> -	std	r5, VCPU_EBBRR(r9)
>> -	std	r6, VCPU_BESCR(r9)
>> -	std	r7, VCPU_CSIGR(r9)
>> -	std	r8, VCPU_TACR(r9)
>> -	mfspr	r5, SPRN_TCSCR
>> -	mfspr	r6, SPRN_ACOP
>> -	mfspr	r7, SPRN_PID
>> -	mfspr	r8, SPRN_WORT
>> -	std	r5, VCPU_TCSCR(r9)
>> -	std	r6, VCPU_ACOP(r9)
>> -	stw	r7, VCPU_GUEST_PID(r9)
>> -	std	r8, VCPU_WORT(r9)
>> -8:
>> -
>> -	/* Save and reset AMR and UAMOR before turning on the MMU */
>> -BEGIN_FTR_SECTION
>> -	mfspr	r5,SPRN_AMR
>> -	mfspr	r6,SPRN_UAMOR
>> -	std	r5,VCPU_AMR(r9)
>> -	std	r6,VCPU_UAMOR(r9)
>> -	li	r6,0
>> -	mtspr	SPRN_AMR,r6
>> -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
>> -
>>  	/* Unset guest mode */
>>  	li	r0, KVM_GUEST_MODE_NONE
>>  	stb	r0, HSTATE_IN_GUEST(r13)
>> -- 
>> 1.8.3.2
>

-aneesh

^ permalink raw reply

* Re: [PATCH 3/3] perf: Use 64-bit value when comparing sample_regs
From: Gabriel Paubert @ 2014-03-06 11:33 UTC (permalink / raw)
  To: David Laight
  Cc: Michael Ellerman, linux-kernel@vger.kernel.org, Stephane Eranian,
	linuxppc-dev@ozlabs.org, Paul Mackerras, Arnaldo Carvalho de Melo,
	'Sukadev Bhattiprolu', Jiri Olsa
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D0F6D3983@AcuExch.aculab.com>

On Thu, Mar 06, 2014 at 09:44:47AM +0000, David Laight wrote:
> From: Sukadev Bhattiprolu
> > When checking whether a bit representing a register is set in
> > sample_regs, a 64-bit mask, use 64-bit value (1LL).
> > 
> > Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
> > ---
> >  tools/perf/util/unwind.c |    4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
> > index 742f23b..2b888c6 100644
> > --- a/tools/perf/util/unwind.c
> > +++ b/tools/perf/util/unwind.c
> > @@ -396,11 +396,11 @@ static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
> >  {
> >  	int i, idx = 0;
> > 
> > -	if (!(sample_regs & (1 << id)))
> > +	if (!(sample_regs & (1LL << id)))
> >  		return -EINVAL;
> > 
> >  	for (i = 0; i < id; i++) {
> > -		if (sample_regs & (1 << i))
> > +		if (sample_regs & (1LL << i))
> >  			idx++;
> >  	}
> 
> There are much faster ways to count the number of set bits, especially
> if you might need to check a significant number of bits.
> There might even be a function defined somewhere to do it.

Indeed, look for Hamming weight (hweight family of functions)
in asm/hweight.h and what is included from there.

Besides that, many modern processors also have a machine instruction
to perform this task. In the processor manuals the instruction is 
described as population count and the mnemonic starts with "popcnt"
on x86 and ppc.

	Gabriel

> Basically you just add up the bits, for 16 bit it would be:
> 	val = (val & 0x5555) + (val >> 1) & 0x5555;
> 	val = (val & 0x3333) + (val >> 2) & 0x3333;
> 	val = (val & 0x0f0f) + (val >> 4) & 0x0f0f;
> 	val = (val & 0x00ff) + (val >> 8) & 0x00ff;
> As the size of the work increases the improvement is more significant.
> (Some of the later masking can probably be proven unnecessary.)
> 
> 	David
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* Re: [PATCH 1/2] Revert "KVM: PPC: Book3S HV: Add new state for transactional memory"
From: Paul Mackerras @ 2014-03-06 11:18 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: Michael Neuling, kvm, agraf, kvm-ppc, linuxppc-dev
In-Reply-To: <1394102170-22126-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

On Thu, Mar 06, 2014 at 04:06:09PM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> 
> This reverts commit 7b490411c37f7ab7965cbdfe5e3ec28eadb6db5b which cause
> the below crash in the host.
> 
> Unable to handle kernel paging request for data at address 0xf00000001223f278
> Faulting instruction address: 0xc000000000202a00

Why exactly does it cause that crash?  What is the actual problem here?
Under what specific circumstances do you see the crash?

> cpu 0x30: Vector: 300 (Data Access) at [c000001e4debb2d0]
>     pc: c000000000202a00: .kfree+0x40/0x200
>     lr: c000000000098338: .kvmppc_core_destroy_vm_hv+0x38/0x90
>     sp: c000001e4debb550
>    msr: 9000000000009032
>    dar: f00000001223f278
>  dsisr: 40000000
>   current = 0xc000001e4de195c0
>   paca    = 0xc00000000fefb000   softe: 0        irq_happened: 0x01
>     pid   = 29379, comm = qemu-system-ppc
> enter ? for help
> [c000001e4debb5e0] c000000000098338 .kvmppc_core_destroy_vm_hv+0x38/0x90
> [c000001e4debb670] c000000000087f80 .kvmppc_core_destroy_vm+0x30/0x70
> [c000001e4debb6f0] c000000000084f28 .kvm_arch_destroy_vm+0xd8/0x120
> [c000001e4debb780] c000000000080218 .kvm_put_kvm+0x198/0x2e0
> [c000001e4debb820] c0000000000880d4 .kvm_spapr_tce_release+0xe4/0x110
> [c000001e4debb8b0] c000000000218578 .__fput+0xb8/0x2a0
> [c000001e4debb950] c0000000000d9af4 .task_work_run+0x114/0x150
> [c000001e4debb9f0] c0000000000b31e8 .do_exit+0x328/0xbc0
> [c000001e4debbae0] c0000000000b4cd4 .do_group_exit+0x54/0xf0
> [c000001e4debbb70] c0000000000c8448 .get_signal_to_deliver+0x1e8/0x6f0
> [c000001e4debbc70] c000000000017ee4 .do_signal+0x54/0x320
> [c000001e4debbdb0] c0000000000182e8 .do_notify_resume+0x68/0x80
> [c000001e4debbe30] c00000000000a7b0 .ret_from_except_lite+0x5c/0x60
> --- Exception: c00 (System Call) at 00003fffb38a4744
> SP (3ffd36ffe360) is in userspace
> 30:mon> zr
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
>  arch/powerpc/include/asm/kvm_host.h     | 24 ++---------
>  arch/powerpc/kernel/asm-offsets.c       | 19 ++-------
>  arch/powerpc/kvm/book3s_hv.c            |  4 --
>  arch/powerpc/kvm/book3s_hv_rmhandlers.S | 75 +--------------------------------
>  4 files changed, 8 insertions(+), 114 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
> index 1eaea2dea174..7726a3bc8ff0 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -475,6 +475,9 @@ struct kvm_vcpu_arch {
>  	ulong ppr;
>  	ulong pspb;
>  	ulong fscr;
> +	ulong tfhar;
> +	ulong tfiar;
> +	ulong texasr;
>  	ulong ebbhr;
>  	ulong ebbrr;
>  	ulong bescr;
> @@ -523,27 +526,6 @@ struct kvm_vcpu_arch {
>  	u64 siar;
>  	u64 sdar;
>  	u64 sier;
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> -	u64 tfhar;
> -	u64 texasr;
> -	u64 tfiar;
> -
> -	u32 cr_tm;
> -	u64 lr_tm;
> -	u64 ctr_tm;
> -	u64 amr_tm;
> -	u64 ppr_tm;
> -	u64 dscr_tm;
> -	u64 tar_tm;
> -
> -	ulong gpr_tm[32];
> -
> -	struct thread_fp_state fp_tm;
> -
> -	struct thread_vr_state vr_tm;
> -	u32 vrsave_tm; /* also USPRG0 */
> -
> -#endif
>  
>  #ifdef CONFIG_KVM_EXIT_TIMING
>  	struct mutex exit_timing_lock;
> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
> index b5aacf72ae6f..936d445b961a 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -534,6 +534,9 @@ int main(void)
>  	DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr));
>  	DEFINE(VCPU_FSCR, offsetof(struct kvm_vcpu, arch.fscr));
>  	DEFINE(VCPU_PSPB, offsetof(struct kvm_vcpu, arch.pspb));
> +	DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar));
> +	DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar));
> +	DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr));
>  	DEFINE(VCPU_EBBHR, offsetof(struct kvm_vcpu, arch.ebbhr));
>  	DEFINE(VCPU_EBBRR, offsetof(struct kvm_vcpu, arch.ebbrr));
>  	DEFINE(VCPU_BESCR, offsetof(struct kvm_vcpu, arch.bescr));
> @@ -555,22 +558,6 @@ int main(void)
>  	DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
>  	DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv));
>  	DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb));
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> -	DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar));
> -	DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar));
> -	DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr));
> -	DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.gpr_tm));
> -	DEFINE(VCPU_FPRS_TM, offsetof(struct kvm_vcpu, arch.fp_tm.fpr));
> -	DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
> -	DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
> -	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm));
> -	DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
> -	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
> -	DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
> -	DEFINE(VCPU_PPR_TM, offsetof(struct kvm_vcpu, arch.ppr_tm));
> -	DEFINE(VCPU_DSCR_TM, offsetof(struct kvm_vcpu, arch.dscr_tm));
> -	DEFINE(VCPU_TAR_TM, offsetof(struct kvm_vcpu, arch.tar_tm));
> -#endif
>  
>  #ifdef CONFIG_PPC_BOOK3S_64
>  #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 3b498d942a22..71f2e8e6e7b1 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -879,7 +879,6 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>  	case KVM_REG_PPC_IAMR:
>  		*val = get_reg_val(id, vcpu->arch.iamr);
>  		break;
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>  	case KVM_REG_PPC_TFHAR:
>  		*val = get_reg_val(id, vcpu->arch.tfhar);
>  		break;
> @@ -889,7 +888,6 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>  	case KVM_REG_PPC_TEXASR:
>  		*val = get_reg_val(id, vcpu->arch.texasr);
>  		break;
> -#endif
>  	case KVM_REG_PPC_FSCR:
>  		*val = get_reg_val(id, vcpu->arch.fscr);
>  		break;
> @@ -1039,7 +1037,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>  	case KVM_REG_PPC_IAMR:
>  		vcpu->arch.iamr = set_reg_val(id, *val);
>  		break;
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>  	case KVM_REG_PPC_TFHAR:
>  		vcpu->arch.tfhar = set_reg_val(id, *val);
>  		break;
> @@ -1049,7 +1046,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
>  	case KVM_REG_PPC_TEXASR:
>  		vcpu->arch.texasr = set_reg_val(id, *val);
>  		break;
> -#endif
>  	case KVM_REG_PPC_FSCR:
>  		vcpu->arch.fscr = set_reg_val(id, *val);
>  		break;
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index e66d4ec04d95..557a47800ca1 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -704,15 +704,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
>  	ld	r6, VCPU_VTB(r4)
>  	mtspr	SPRN_IC, r5
>  	mtspr	SPRN_VTB, r6
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>  	ld	r5, VCPU_TFHAR(r4)
>  	ld	r6, VCPU_TFIAR(r4)
>  	ld	r7, VCPU_TEXASR(r4)
> +	ld	r8, VCPU_EBBHR(r4)
>  	mtspr	SPRN_TFHAR, r5
>  	mtspr	SPRN_TFIAR, r6
>  	mtspr	SPRN_TEXASR, r7
> -#endif
> -	ld	r8, VCPU_EBBHR(r4)
>  	mtspr	SPRN_EBBHR, r8
>  	ld	r5, VCPU_EBBRR(r4)
>  	ld	r6, VCPU_BESCR(r4)
> @@ -1122,15 +1120,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
>  	std	r5, VCPU_IC(r9)
>  	std	r6, VCPU_VTB(r9)
>  	std	r7, VCPU_TAR(r9)
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>  	mfspr	r5, SPRN_TFHAR
>  	mfspr	r6, SPRN_TFIAR
>  	mfspr	r7, SPRN_TEXASR
> +	mfspr	r8, SPRN_EBBHR
>  	std	r5, VCPU_TFHAR(r9)
>  	std	r6, VCPU_TFIAR(r9)
>  	std	r7, VCPU_TEXASR(r9)
> -#endif
> -	mfspr	r8, SPRN_EBBHR
>  	std	r8, VCPU_EBBHR(r9)
>  	mfspr	r5, SPRN_EBBRR
>  	mfspr	r6, SPRN_BESCR
> @@ -1504,73 +1500,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
>  1:	addi	r8,r8,16
>  	.endr
>  
> -	/* Save DEC */
> -	mfspr	r5,SPRN_DEC
> -	mftb	r6
> -	extsw	r5,r5
> -	add	r5,r5,r6
> -	std	r5,VCPU_DEC_EXPIRES(r9)
> -
> -BEGIN_FTR_SECTION
> -	b	8f
> -END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
> -	/* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
> -	mfmsr	r8
> -	li	r0, 1
> -	rldimi	r8, r0, MSR_TM_LG, 63-MSR_TM_LG
> -	mtmsrd	r8
> -
> -	/* Save POWER8-specific registers */
> -	mfspr	r5, SPRN_IAMR
> -	mfspr	r6, SPRN_PSPB
> -	mfspr	r7, SPRN_FSCR
> -	std	r5, VCPU_IAMR(r9)
> -	stw	r6, VCPU_PSPB(r9)
> -	std	r7, VCPU_FSCR(r9)
> -	mfspr	r5, SPRN_IC
> -	mfspr	r6, SPRN_VTB
> -	mfspr	r7, SPRN_TAR
> -	std	r5, VCPU_IC(r9)
> -	std	r6, VCPU_VTB(r9)
> -	std	r7, VCPU_TAR(r9)
> -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> -	mfspr	r5, SPRN_TFHAR
> -	mfspr	r6, SPRN_TFIAR
> -	mfspr	r7, SPRN_TEXASR
> -	std	r5, VCPU_TFHAR(r9)
> -	std	r6, VCPU_TFIAR(r9)
> -	std	r7, VCPU_TEXASR(r9)
> -#endif
> -	mfspr	r8, SPRN_EBBHR
> -	std	r8, VCPU_EBBHR(r9)
> -	mfspr	r5, SPRN_EBBRR
> -	mfspr	r6, SPRN_BESCR
> -	mfspr	r7, SPRN_CSIGR
> -	mfspr	r8, SPRN_TACR
> -	std	r5, VCPU_EBBRR(r9)
> -	std	r6, VCPU_BESCR(r9)
> -	std	r7, VCPU_CSIGR(r9)
> -	std	r8, VCPU_TACR(r9)
> -	mfspr	r5, SPRN_TCSCR
> -	mfspr	r6, SPRN_ACOP
> -	mfspr	r7, SPRN_PID
> -	mfspr	r8, SPRN_WORT
> -	std	r5, VCPU_TCSCR(r9)
> -	std	r6, VCPU_ACOP(r9)
> -	stw	r7, VCPU_GUEST_PID(r9)
> -	std	r8, VCPU_WORT(r9)
> -8:
> -
> -	/* Save and reset AMR and UAMOR before turning on the MMU */
> -BEGIN_FTR_SECTION
> -	mfspr	r5,SPRN_AMR
> -	mfspr	r6,SPRN_UAMOR
> -	std	r5,VCPU_AMR(r9)
> -	std	r6,VCPU_UAMOR(r9)
> -	li	r6,0
> -	mtspr	SPRN_AMR,r6
> -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
> -
>  	/* Unset guest mode */
>  	li	r0, KVM_GUEST_MODE_NONE
>  	stb	r0, HSTATE_IN_GUEST(r13)
> -- 
> 1.8.3.2

Paul.

^ permalink raw reply

* Re: [PATCH 2/3] dts: mpc512x: adjust clock specs for FEC nodes
From: Sascha Hauer @ 2014-03-06 10:21 UTC (permalink / raw)
  To: Gerhard Sittig
  Cc: Mark Rutland, devicetree, Anatolij Gustschin, Mike Turquette,
	Pawel Moll, Ian Campbell, Rob Herring, Shawn Guo, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <20140305105209.GZ3327@book.gsilab.sittig.org>

On Wed, Mar 05, 2014 at 11:52:09AM +0100, Gerhard Sittig wrote:
> On Wed, Mar 05, 2014 at 09:48 +0800, Shawn Guo wrote:
> > 
> > On Mon, Mar 03, 2014 at 10:22:31AM +0100, Gerhard Sittig wrote:
> > > On Mon, Feb 24, 2014 at 11:25 +0100, Gerhard Sittig wrote:
> > > > 
> > > > a recent FEC binding document update that was motivated by i.MX
> > > > development revealed that ARM and PowerPC implementations in Linux
> > > > did not agree on the clock names to use for the FEC nodes
> > > > 
> > > > change clock names from "per" to "ipg" in the FEC nodes of the
> > > > mpc5121.dtsi include file such that the .dts specs comply with
> > > > the common FEC binding
> > > > 
> > > > this "incompatible" change does not break operation, because
> > > > - COMMON_CLK support for MPC5121/23/25 and adjusted .dts files
> > > >   were only introduced in Linux v3.14-rc1, no mainline release
> > > >   provided these specs before
> > > > - if this change won't make it for v3.14, the MPC512x CCF support
> > > >   provides full backwards compability, and keeps operating with
> > > >   device trees which lack clock specs or don't match in the names
> > > > 
> > > > Signed-off-by: Gerhard Sittig <gsi@denx.de>
> > > 
> > > ping
> > > 
> > > Are there opinions about making PowerPC users of FEC use the same
> > > clock names as ARM users do, to re-use (actually: keep sharing)
> > > the FEC binding?  The alternative would be to fragment the FEC
> > > binding into several bindings for ARM and PowerPC, which I feel
> > > would be undesirable, and is not necessary.
> > 
> > As I already said, Documentation/devicetree/bindings/net/fsl-fec.txt
> > was created specifically for i.MX FEC controller from day one.  And even
> > as of today, it doesn't serve PowerPC, because for example the property
> > 'phy-mode' documented as required one is not required by PowerPC FEC.
> > My opinion would be to patch fsl-fec.txt a little bit to make it clear
> > that it's a binding doc for i.MX FEC, and create the other one for
> > PowerPC FEC.  This is the way less confusing to people and easier for
> > binding maintenance.
> 
> Should we still try to have a common behaviour where possible?
> Such that even if there are two bindings, they don't diverge in
> "unnecessary" ways?

Maybe the long term goal should be to share the code. The MPC5200 FEC
and the i.MX FEC are very similar. Only the DMA engine is quite
different.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply


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