linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] mfd: cros_ec: Add debugfs directory to capture logs/panicinfo
@ 2016-08-23  4:34 Nicolas Boichat
  2016-08-23  4:34 ` [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions Nicolas Boichat
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Nicolas Boichat @ 2016-08-23  4:34 UTC (permalink / raw)
  To: Lee Jones; +Cc: gwendal, ejcaruso, Olof Johansson, linux-kernel, groeck

This series makes it possible to capture EC console and panicinfo by reading
files in /sys/kernel/debug/cros_ec/*. This is very useful for debugging
purpose (e.g. when a user files a feedback on Chrome OS).

Eric Caruso (1):
  mfd: cros_ec: add debugfs, console log file

Nicolas Boichat (2):
  mfd: cros_ec: Add EC console read structures definitions
  mfd: cros_ec: Add support for dumping panic information

 drivers/platform/chrome/Makefile          |   3 +-
 drivers/platform/chrome/cros_ec_debugfs.c | 401 ++++++++++++++++++++++++++++++
 drivers/platform/chrome/cros_ec_debugfs.h |  27 ++
 drivers/platform/chrome/cros_ec_dev.c     |   7 +
 include/linux/mfd/cros_ec.h               |   4 +
 include/linux/mfd/cros_ec_commands.h      |  21 +-
 6 files changed, 461 insertions(+), 2 deletions(-)
 create mode 100644 drivers/platform/chrome/cros_ec_debugfs.c
 create mode 100644 drivers/platform/chrome/cros_ec_debugfs.h

-- 
2.8.0.rc3.226.g39d4020

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

* [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions
  2016-08-23  4:34 [PATCH 0/3] mfd: cros_ec: Add debugfs directory to capture logs/panicinfo Nicolas Boichat
@ 2016-08-23  4:34 ` Nicolas Boichat
  2016-08-23 21:15   ` Guenter Roeck
  2016-08-31 11:45   ` Lee Jones
  2016-08-23  4:34 ` [PATCH 2/3] mfd: cros_ec: add debugfs, console log file Nicolas Boichat
  2016-08-23  4:34 ` [PATCH 3/3] mfd: cros_ec: Add support for dumping panic information Nicolas Boichat
  2 siblings, 2 replies; 13+ messages in thread
From: Nicolas Boichat @ 2016-08-23  4:34 UTC (permalink / raw)
  To: Lee Jones; +Cc: gwendal, ejcaruso, Olof Johansson, linux-kernel, groeck

ec_params_console_read_v1 is used to capture EC logs from kernel,
and ec_params_get_cmd_versions_v1 is used to probe whether EC
supports that command.

Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
---
 include/linux/mfd/cros_ec_commands.h | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
index 7e7a8d4..74c84e82 100644
--- a/include/linux/mfd/cros_ec_commands.h
+++ b/include/linux/mfd/cros_ec_commands.h
@@ -625,6 +625,10 @@ struct ec_params_get_cmd_versions {
 	uint8_t cmd;      /* Command to check */
 } __packed;
 
+struct ec_params_get_cmd_versions_v1 {
+	uint16_t cmd;     /* Command to check */
+} __packed;
+
 struct ec_response_get_cmd_versions {
 	/*
 	 * Mask of supported versions; use EC_VER_MASK() to compare with a
@@ -2003,13 +2007,28 @@ struct ec_params_charge_control {
 #define EC_CMD_CONSOLE_SNAPSHOT 0x97
 
 /*
- * Read next chunk of data from saved snapshot.
+ * Read data from the saved snapshot. If the subcmd parameter is
+ * CONSOLE_READ_NEXT, this will return data starting from the beginning of
+ * the latest snapshot. If it is CONSOLE_READ_RECENT, it will start from the
+ * end of the previous snapshot.
+ *
+ * The params are only looked at in version >= 1 of this command. Prior
+ * versions will just default to CONSOLE_READ_NEXT behavior.
  *
  * Response is null-terminated string.  Empty string, if there is no more
  * remaining output.
  */
 #define EC_CMD_CONSOLE_READ 0x98
 
+enum ec_console_read_subcmd {
+	CONSOLE_READ_NEXT = 0,
+	CONSOLE_READ_RECENT
+};
+
+struct ec_params_console_read_v1 {
+	uint8_t subcmd; /* enum ec_console_read_subcmd */
+} __packed;
+
 /*****************************************************************************/
 
 /*
-- 
2.8.0.rc3.226.g39d4020

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

* [PATCH 2/3] mfd: cros_ec: add debugfs, console log file
  2016-08-23  4:34 [PATCH 0/3] mfd: cros_ec: Add debugfs directory to capture logs/panicinfo Nicolas Boichat
  2016-08-23  4:34 ` [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions Nicolas Boichat
@ 2016-08-23  4:34 ` Nicolas Boichat
  2016-08-23 21:17   ` Guenter Roeck
                     ` (2 more replies)
  2016-08-23  4:34 ` [PATCH 3/3] mfd: cros_ec: Add support for dumping panic information Nicolas Boichat
  2 siblings, 3 replies; 13+ messages in thread
From: Nicolas Boichat @ 2016-08-23  4:34 UTC (permalink / raw)
  To: Lee Jones; +Cc: gwendal, ejcaruso, Olof Johansson, linux-kernel, groeck

From: Eric Caruso <ejcaruso@chromium.org>

If the EC supports the new CONSOLE_READ command type, then we
place a console_log file in debugfs for that EC device which allows
us to grab EC logs. The kernel will poll every 10 seconds for the
log and keep its own buffer, but userspace should grab this and
write it out to some logs which actually get rotated.

Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
---
 drivers/platform/chrome/Makefile          |   3 +-
 drivers/platform/chrome/cros_ec_debugfs.c | 347 ++++++++++++++++++++++++++++++
 drivers/platform/chrome/cros_ec_debugfs.h |  27 +++
 drivers/platform/chrome/cros_ec_dev.c     |   7 +
 include/linux/mfd/cros_ec.h               |   4 +
 5 files changed, 387 insertions(+), 1 deletion(-)
 create mode 100644 drivers/platform/chrome/cros_ec_debugfs.c
 create mode 100644 drivers/platform/chrome/cros_ec_debugfs.h

diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 4f34627..3870afe 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -2,7 +2,8 @@
 obj-$(CONFIG_CHROMEOS_LAPTOP)		+= chromeos_laptop.o
 obj-$(CONFIG_CHROMEOS_PSTORE)		+= chromeos_pstore.o
 cros_ec_devs-objs			:= cros_ec_dev.o cros_ec_sysfs.o \
-					   cros_ec_lightbar.o cros_ec_vbc.o
+					   cros_ec_lightbar.o cros_ec_vbc.o \
+					   cros_ec_debugfs.o
 obj-$(CONFIG_CROS_EC_CHARDEV)		+= cros_ec_devs.o
 obj-$(CONFIG_CROS_EC_LPC)		+= cros_ec_lpc.o
 obj-$(CONFIG_CROS_EC_PROTO)		+= cros_ec_proto.o
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
new file mode 100644
index 0000000..225f936
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -0,0 +1,347 @@
+/*
+ * cros_ec_debugfs - debug logs for Chrome OS EC
+ *
+ * Copyright 2015 Google, 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.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/circ_buf.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include "cros_ec_dev.h"
+#include "cros_ec_debugfs.h"
+
+#define LOG_SHIFT		14
+#define LOG_SIZE		(1 << LOG_SHIFT)
+#define LOG_POLL_SEC		10
+
+#define CIRC_ADD(idx, size, value)	(((idx) + (value)) & ((size) - 1))
+
+/* struct cros_ec_debugfs - ChromeOS EC debugging information
+ *
+ * @ec: EC device this debugfs information belongs to
+ * @dir: dentry for debugfs files
+ * @log_buffer: circular buffer for console log information
+ * @read_msg: preallocated EC command and buffer to read console log
+ * @log_mutex: mutex to protect circular buffer
+ * @log_wq: waitqueue for log readers
+ * @log_poll_work: recurring task to poll EC for new console log data
+ */
+struct cros_ec_debugfs {
+	struct cros_ec_dev *ec;
+	struct dentry *dir;
+	struct circ_buf log_buffer;
+	struct cros_ec_command *read_msg;
+	struct mutex log_mutex;
+	wait_queue_head_t log_wq;
+	struct delayed_work log_poll_work;
+};
+
+/*
+ * We need to make sure that the EC log buffer on the UART is large enough,
+ * so that it is unlikely enough to overlow within LOG_POLL_SEC.
+ */
+static void cros_ec_console_log_work(struct work_struct *__work)
+{
+	struct cros_ec_debugfs *debug_info =
+		container_of(to_delayed_work(__work),
+			     struct cros_ec_debugfs,
+			     log_poll_work);
+	struct cros_ec_dev *ec = debug_info->ec;
+	struct circ_buf *cb = &debug_info->log_buffer;
+	struct cros_ec_command snapshot_msg = {
+		.command = EC_CMD_CONSOLE_SNAPSHOT + ec->cmd_offset,
+	};
+
+	struct ec_params_console_read_v1 *read_params =
+		(struct ec_params_console_read_v1 *)debug_info->read_msg->data;
+	uint8_t *ec_buffer = (uint8_t *)debug_info->read_msg->data;
+	int idx;
+	int buf_space;
+	int ret;
+
+	ret = cros_ec_cmd_xfer(ec->ec_dev, &snapshot_msg);
+	if (ret < 0) {
+		dev_err(ec->dev, "EC communication failed\n");
+		goto resched;
+	}
+	if (snapshot_msg.result != EC_RES_SUCCESS) {
+		dev_err(ec->dev, "EC failed to snapshot the console log\n");
+		goto resched;
+	}
+
+	/* Loop until we have read everything, or there's an error. */
+	mutex_lock(&debug_info->log_mutex);
+	buf_space = CIRC_SPACE(cb->head, cb->tail, LOG_SIZE);
+
+	while (1) {
+		if (!buf_space) {
+			dev_info_once(ec->dev,
+				      "Some logs may have been dropped...\n");
+			break;
+		}
+
+		memset(read_params, '\0', sizeof(*read_params));
+		read_params->subcmd = CONSOLE_READ_RECENT;
+		ret = cros_ec_cmd_xfer(ec->ec_dev, debug_info->read_msg);
+		if (ret < 0) {
+			dev_err(ec->dev, "EC communication failed\n");
+			break;
+		}
+		if (debug_info->read_msg->result != EC_RES_SUCCESS) {
+			dev_err(ec->dev,
+				"EC failed to read the console log\n");
+			break;
+		}
+
+		/* If the buffer is empty, we're done here. */
+		if (ret == 0 || ec_buffer[0] == '\0')
+			break;
+
+		idx = 0;
+		while (idx < ret && ec_buffer[idx] != '\0' && buf_space > 0) {
+			cb->buf[cb->head] = ec_buffer[idx];
+			cb->head = CIRC_ADD(cb->head, LOG_SIZE, 1);
+			idx++;
+			buf_space--;
+		}
+
+		wake_up(&debug_info->log_wq);
+	}
+
+	mutex_unlock(&debug_info->log_mutex);
+
+resched:
+	schedule_delayed_work(&debug_info->log_poll_work,
+			      msecs_to_jiffies(LOG_POLL_SEC * 1000));
+}
+
+static int cros_ec_console_log_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t cros_ec_console_log_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	struct cros_ec_debugfs *debug_info = file->private_data;
+	struct circ_buf *cb = &debug_info->log_buffer;
+	ssize_t ret;
+
+	mutex_lock(&debug_info->log_mutex);
+
+	while (!CIRC_CNT(cb->head, cb->tail, LOG_SIZE)) {
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			goto error;
+		}
+
+		mutex_unlock(&debug_info->log_mutex);
+
+		ret = wait_event_interruptible(debug_info->log_wq,
+					CIRC_CNT(cb->head, cb->tail, LOG_SIZE));
+		if (ret < 0)
+			return ret;
+
+		mutex_lock(&debug_info->log_mutex);
+	}
+
+	/* Only copy until the end of the circular buffer, and let userspace
+	 * retry to get the rest of the data.
+	 */
+	ret = min_t(size_t, CIRC_CNT_TO_END(cb->head, cb->tail, LOG_SIZE),
+		    count);
+
+	if (copy_to_user(buf, cb->buf + cb->tail, ret)) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	cb->tail = CIRC_ADD(cb->tail, LOG_SIZE, ret);
+
+error:
+	mutex_unlock(&debug_info->log_mutex);
+	return ret;
+}
+
+static unsigned int cros_ec_console_log_poll(struct file *file,
+					     poll_table *wait)
+{
+	struct cros_ec_debugfs *debug_info = file->private_data;
+	unsigned int mask = 0;
+
+	poll_wait(file, &debug_info->log_wq, wait);
+
+	mutex_lock(&debug_info->log_mutex);
+	if (CIRC_CNT(debug_info->log_buffer.head,
+		     debug_info->log_buffer.tail,
+		     LOG_SIZE))
+		mask |= POLLIN | POLLRDNORM;
+	mutex_unlock(&debug_info->log_mutex);
+
+	return mask;
+}
+
+static int cros_ec_console_log_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+const struct file_operations cros_ec_console_log_fops = {
+	.owner = THIS_MODULE,
+	.open = cros_ec_console_log_open,
+	.read = cros_ec_console_log_read,
+	.llseek = no_llseek,
+	.poll = cros_ec_console_log_poll,
+	.release = cros_ec_console_log_release,
+};
+
+static int ec_read_version_supported(struct cros_ec_dev *ec)
+{
+	struct ec_params_get_cmd_versions_v1 *params;
+	struct ec_response_get_cmd_versions *response;
+	int ret;
+
+	struct cros_ec_command *msg;
+
+	msg = kzalloc(sizeof(*msg) + max(sizeof(params), sizeof(response)),
+		GFP_KERNEL);
+	if (!msg)
+		return 0;
+
+	msg->command = EC_CMD_GET_CMD_VERSIONS + ec->cmd_offset;
+	msg->outsize = sizeof(params);
+	msg->insize = sizeof(response);
+
+	params = (struct ec_params_get_cmd_versions_v1 *)msg->data;
+	params->cmd = EC_CMD_CONSOLE_READ;
+	response = (struct ec_response_get_cmd_versions *)msg->data;
+
+	ret = cros_ec_cmd_xfer(ec->ec_dev, msg) >= 0 &&
+		msg->result == EC_RES_SUCCESS &&
+		(response->version_mask & EC_VER_MASK(1));
+
+	kfree(msg);
+
+	return ret;
+}
+
+static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info)
+{
+	struct cros_ec_dev *ec = debug_info->ec;
+	char *buf;
+	int read_params_size;
+	int read_response_size;
+
+	if (!ec_read_version_supported(ec)) {
+		dev_warn(ec->dev,
+			"device does not support reading the console log\n");
+		return 0;
+	}
+
+	buf = devm_kzalloc(ec->dev, LOG_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	read_params_size = sizeof(struct ec_params_console_read_v1);
+	read_response_size = ec->ec_dev->max_response;
+	debug_info->read_msg = devm_kzalloc(ec->dev,
+		sizeof(*debug_info->read_msg) +
+			max(read_params_size, read_response_size), GFP_KERNEL);
+	if (!debug_info->read_msg)
+		return -ENOMEM;
+
+	debug_info->read_msg->version = 1;
+	debug_info->read_msg->command = EC_CMD_CONSOLE_READ + ec->cmd_offset;
+	debug_info->read_msg->outsize = read_params_size;
+	debug_info->read_msg->insize = read_response_size;
+
+	debug_info->log_buffer.buf = buf;
+	debug_info->log_buffer.head = 0;
+	debug_info->log_buffer.tail = 0;
+
+	mutex_init(&debug_info->log_mutex);
+	init_waitqueue_head(&debug_info->log_wq);
+
+	if (!debugfs_create_file("console_log",
+				 S_IFREG | S_IRUGO,
+				 debug_info->dir,
+				 debug_info,
+				 &cros_ec_console_log_fops))
+		return -ENOMEM;
+
+	INIT_DELAYED_WORK(&debug_info->log_poll_work,
+			  cros_ec_console_log_work);
+	schedule_delayed_work(&debug_info->log_poll_work, 0);
+
+	return 0;
+}
+
+static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
+{
+	if (debug_info->log_buffer.buf) {
+		cancel_delayed_work_sync(&debug_info->log_poll_work);
+		mutex_destroy(&debug_info->log_mutex);
+	}
+}
+
+int cros_ec_debugfs_init(struct cros_ec_dev *ec)
+{
+	struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
+	const char *name = ec_platform->ec_name;
+	struct cros_ec_debugfs *debug_info;
+	int ret;
+
+	debug_info = devm_kzalloc(ec->dev, sizeof(*debug_info), GFP_KERNEL);
+	if (!debug_info)
+		return -ENOMEM;
+
+	debug_info->ec = ec;
+	debug_info->dir = debugfs_create_dir(name, NULL);
+	if (!debug_info->dir)
+		return -ENOMEM;
+
+	ret = cros_ec_create_console_log(debug_info);
+	if (ret)
+		goto remove_debugfs;
+
+	ec->debug_info = debug_info;
+
+	return 0;
+
+remove_debugfs:
+	debugfs_remove_recursive(debug_info->dir);
+	return ret;
+}
+
+void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
+{
+	if (!ec->debug_info)
+		return;
+
+	debugfs_remove_recursive(ec->debug_info->dir);
+	cros_ec_cleanup_console_log(ec->debug_info);
+}
diff --git a/drivers/platform/chrome/cros_ec_debugfs.h b/drivers/platform/chrome/cros_ec_debugfs.h
new file mode 100644
index 0000000..1ff3a50
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_debugfs.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 Google, 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.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DRV_CROS_EC_DEBUGFS_H_
+#define _DRV_CROS_EC_DEBUGFS_H_
+
+#include "cros_ec_dev.h"
+
+/* debugfs stuff */
+int cros_ec_debugfs_init(struct cros_ec_dev *ec);
+void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
+
+#endif  /* _DRV_CROS_EC_DEBUGFS_H_ */
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
index 8abd80d..7d51f69 100644
--- a/drivers/platform/chrome/cros_ec_dev.c
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 
+#include "cros_ec_debugfs.h"
 #include "cros_ec_dev.h"
 
 /* Device variables */
@@ -282,6 +283,9 @@ static int ec_device_probe(struct platform_device *pdev)
 		goto dev_reg_failed;
 	}
 
+	if (cros_ec_debugfs_init(ec))
+		dev_warn(dev, "failed to create debugfs directory\n");
+
 	return 0;
 
 dev_reg_failed:
@@ -296,6 +300,9 @@ cdev_add_failed:
 static int ec_device_remove(struct platform_device *pdev)
 {
 	struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
+
+	cros_ec_debugfs_remove(ec);
+
 	cdev_del(&ec->cdev);
 	device_unregister(&ec->class_dev);
 	return 0;
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index d641a18..e7001a7 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -151,6 +151,8 @@ struct cros_ec_platform {
 	u16 cmd_offset;
 };
 
+struct cros_ec_debugfs;
+
 /*
  * struct cros_ec_dev - ChromeOS EC device entry point
  *
@@ -158,6 +160,7 @@ struct cros_ec_platform {
  * @cdev: Character device structure in /dev
  * @ec_dev: cros_ec_device structure to talk to the physical device
  * @dev: pointer to the platform device
+ * @debug_info: cros_ec_debugfs structure for debugging information
  * @cmd_offset: offset to apply for each command.
  */
 struct cros_ec_dev {
@@ -165,6 +168,7 @@ struct cros_ec_dev {
 	struct cdev cdev;
 	struct cros_ec_device *ec_dev;
 	struct device *dev;
+	struct cros_ec_debugfs *debug_info;
 	u16 cmd_offset;
 };
 
-- 
2.8.0.rc3.226.g39d4020

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

* [PATCH 3/3] mfd: cros_ec: Add support for dumping panic information
  2016-08-23  4:34 [PATCH 0/3] mfd: cros_ec: Add debugfs directory to capture logs/panicinfo Nicolas Boichat
  2016-08-23  4:34 ` [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions Nicolas Boichat
  2016-08-23  4:34 ` [PATCH 2/3] mfd: cros_ec: add debugfs, console log file Nicolas Boichat
@ 2016-08-23  4:34 ` Nicolas Boichat
  2016-08-23 21:19   ` Guenter Roeck
  2 siblings, 1 reply; 13+ messages in thread
From: Nicolas Boichat @ 2016-08-23  4:34 UTC (permalink / raw)
  To: Lee Jones; +Cc: gwendal, ejcaruso, Olof Johansson, linux-kernel, groeck

This dumps the EC panic information from the previous reboot.

Similar to the information presented by ectool panicinfo, except
that we do not bother doing any parsing (we should write a small
offline tool for that).

Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
---
 drivers/platform/chrome/cros_ec_debugfs.c | 54 +++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
index 225f936..f4b6a29 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -47,15 +47,19 @@
  * @log_mutex: mutex to protect circular buffer
  * @log_wq: waitqueue for log readers
  * @log_poll_work: recurring task to poll EC for new console log data
+ * @panicinfo_blob: panicinfo debugfs blob
  */
 struct cros_ec_debugfs {
 	struct cros_ec_dev *ec;
 	struct dentry *dir;
+	/* EC log */
 	struct circ_buf log_buffer;
 	struct cros_ec_command *read_msg;
 	struct mutex log_mutex;
 	wait_queue_head_t log_wq;
 	struct delayed_work log_poll_work;
+	/* EC panicinfo */
+	struct debugfs_blob_wrapper panicinfo_blob;
 };
 
 /*
@@ -308,6 +312,52 @@ static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
 	}
 }
 
+static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
+{
+	struct cros_ec_device *ec_dev = debug_info->ec->ec_dev;
+	int ret;
+	struct cros_ec_command *msg;
+	int insize;
+
+	insize = ec_dev->max_response;
+
+	msg = devm_kzalloc(debug_info->ec->dev,
+			sizeof(*msg) + insize, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	msg->command = EC_CMD_GET_PANIC_INFO;
+	msg->insize = insize;
+
+	ret = cros_ec_cmd_xfer(ec_dev, msg);
+	if (ret < 0) {
+		dev_warn(debug_info->ec->dev, "Cannot read panicinfo.\n");
+		ret = 0;
+		goto free;
+	}
+
+	/* No panic data */
+	if (ret == 0)
+		goto free;
+
+	debug_info->panicinfo_blob.data = msg->data;
+	debug_info->panicinfo_blob.size = ret;
+
+	if (!debugfs_create_blob("panicinfo",
+				 S_IFREG | S_IRUGO,
+				 debug_info->dir,
+				 &debug_info->panicinfo_blob)) {
+		ret = -ENOMEM;
+		goto free;
+	}
+
+	return 0;
+
+free:
+	devm_kfree(debug_info->ec->dev, msg);
+	return ret;
+}
+
 int cros_ec_debugfs_init(struct cros_ec_dev *ec)
 {
 	struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
@@ -324,6 +374,10 @@ int cros_ec_debugfs_init(struct cros_ec_dev *ec)
 	if (!debug_info->dir)
 		return -ENOMEM;
 
+	ret = cros_ec_create_panicinfo(debug_info);
+	if (ret)
+		goto remove_debugfs;
+
 	ret = cros_ec_create_console_log(debug_info);
 	if (ret)
 		goto remove_debugfs;
-- 
2.8.0.rc3.226.g39d4020

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

* Re: [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions
  2016-08-23  4:34 ` [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions Nicolas Boichat
@ 2016-08-23 21:15   ` Guenter Roeck
  2016-08-31 11:45   ` Lee Jones
  1 sibling, 0 replies; 13+ messages in thread
From: Guenter Roeck @ 2016-08-23 21:15 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Lee Jones, Gwendal Grignou, ejcaruso, Olof Johansson,
	linux-kernel, Guenter Roeck

On Mon, Aug 22, 2016 at 9:34 PM, Nicolas Boichat <drinkcat@chromium.org> wrote:
> ec_params_console_read_v1 is used to capture EC logs from kernel,
> and ec_params_get_cmd_versions_v1 is used to probe whether EC
> supports that command.
>
> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>

Reviewed-by: Guenter Roeck <groeck@chromium.org>

> ---
>  include/linux/mfd/cros_ec_commands.h | 21 ++++++++++++++++++++-
>  1 file changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
> index 7e7a8d4..74c84e82 100644
> --- a/include/linux/mfd/cros_ec_commands.h
> +++ b/include/linux/mfd/cros_ec_commands.h
> @@ -625,6 +625,10 @@ struct ec_params_get_cmd_versions {
>         uint8_t cmd;      /* Command to check */
>  } __packed;
>
> +struct ec_params_get_cmd_versions_v1 {
> +       uint16_t cmd;     /* Command to check */
> +} __packed;
> +
>  struct ec_response_get_cmd_versions {
>         /*
>          * Mask of supported versions; use EC_VER_MASK() to compare with a
> @@ -2003,13 +2007,28 @@ struct ec_params_charge_control {
>  #define EC_CMD_CONSOLE_SNAPSHOT 0x97
>
>  /*
> - * Read next chunk of data from saved snapshot.
> + * Read data from the saved snapshot. If the subcmd parameter is
> + * CONSOLE_READ_NEXT, this will return data starting from the beginning of
> + * the latest snapshot. If it is CONSOLE_READ_RECENT, it will start from the
> + * end of the previous snapshot.
> + *
> + * The params are only looked at in version >= 1 of this command. Prior
> + * versions will just default to CONSOLE_READ_NEXT behavior.
>   *
>   * Response is null-terminated string.  Empty string, if there is no more
>   * remaining output.
>   */
>  #define EC_CMD_CONSOLE_READ 0x98
>
> +enum ec_console_read_subcmd {
> +       CONSOLE_READ_NEXT = 0,
> +       CONSOLE_READ_RECENT
> +};
> +
> +struct ec_params_console_read_v1 {
> +       uint8_t subcmd; /* enum ec_console_read_subcmd */
> +} __packed;
> +
>  /*****************************************************************************/
>
>  /*
> --
> 2.8.0.rc3.226.g39d4020
>

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

* Re: [PATCH 2/3] mfd: cros_ec: add debugfs, console log file
  2016-08-23  4:34 ` [PATCH 2/3] mfd: cros_ec: add debugfs, console log file Nicolas Boichat
@ 2016-08-23 21:17   ` Guenter Roeck
  2016-08-31 11:45   ` Lee Jones
  2017-02-22 21:49   ` Doug Anderson
  2 siblings, 0 replies; 13+ messages in thread
From: Guenter Roeck @ 2016-08-23 21:17 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Lee Jones, Gwendal Grignou, ejcaruso, Olof Johansson,
	linux-kernel, Guenter Roeck

On Mon, Aug 22, 2016 at 9:34 PM, Nicolas Boichat <drinkcat@chromium.org> wrote:
> From: Eric Caruso <ejcaruso@chromium.org>
>
> If the EC supports the new CONSOLE_READ command type, then we
> place a console_log file in debugfs for that EC device which allows
> us to grab EC logs. The kernel will poll every 10 seconds for the
> log and keep its own buffer, but userspace should grab this and
> write it out to some logs which actually get rotated.
>
> Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>

Reviewed-by: Guenter Roeck <groeck@chromium.org>

> ---
>  drivers/platform/chrome/Makefile          |   3 +-
>  drivers/platform/chrome/cros_ec_debugfs.c | 347 ++++++++++++++++++++++++++++++
>  drivers/platform/chrome/cros_ec_debugfs.h |  27 +++
>  drivers/platform/chrome/cros_ec_dev.c     |   7 +
>  include/linux/mfd/cros_ec.h               |   4 +
>  5 files changed, 387 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/platform/chrome/cros_ec_debugfs.c
>  create mode 100644 drivers/platform/chrome/cros_ec_debugfs.h
>
> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
> index 4f34627..3870afe 100644
> --- a/drivers/platform/chrome/Makefile
> +++ b/drivers/platform/chrome/Makefile
> @@ -2,7 +2,8 @@
>  obj-$(CONFIG_CHROMEOS_LAPTOP)          += chromeos_laptop.o
>  obj-$(CONFIG_CHROMEOS_PSTORE)          += chromeos_pstore.o
>  cros_ec_devs-objs                      := cros_ec_dev.o cros_ec_sysfs.o \
> -                                          cros_ec_lightbar.o cros_ec_vbc.o
> +                                          cros_ec_lightbar.o cros_ec_vbc.o \
> +                                          cros_ec_debugfs.o
>  obj-$(CONFIG_CROS_EC_CHARDEV)          += cros_ec_devs.o
>  obj-$(CONFIG_CROS_EC_LPC)              += cros_ec_lpc.o
>  obj-$(CONFIG_CROS_EC_PROTO)            += cros_ec_proto.o
> diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
> new file mode 100644
> index 0000000..225f936
> --- /dev/null
> +++ b/drivers/platform/chrome/cros_ec_debugfs.c
> @@ -0,0 +1,347 @@
> +/*
> + * cros_ec_debugfs - debug logs for Chrome OS EC
> + *
> + * Copyright 2015 Google, 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.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/circ_buf.h>
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/fs.h>
> +#include <linux/mfd/cros_ec.h>
> +#include <linux/mfd/cros_ec_commands.h>
> +#include <linux/mutex.h>
> +#include <linux/poll.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/wait.h>
> +
> +#include "cros_ec_dev.h"
> +#include "cros_ec_debugfs.h"
> +
> +#define LOG_SHIFT              14
> +#define LOG_SIZE               (1 << LOG_SHIFT)
> +#define LOG_POLL_SEC           10
> +
> +#define CIRC_ADD(idx, size, value)     (((idx) + (value)) & ((size) - 1))
> +
> +/* struct cros_ec_debugfs - ChromeOS EC debugging information
> + *
> + * @ec: EC device this debugfs information belongs to
> + * @dir: dentry for debugfs files
> + * @log_buffer: circular buffer for console log information
> + * @read_msg: preallocated EC command and buffer to read console log
> + * @log_mutex: mutex to protect circular buffer
> + * @log_wq: waitqueue for log readers
> + * @log_poll_work: recurring task to poll EC for new console log data
> + */
> +struct cros_ec_debugfs {
> +       struct cros_ec_dev *ec;
> +       struct dentry *dir;
> +       struct circ_buf log_buffer;
> +       struct cros_ec_command *read_msg;
> +       struct mutex log_mutex;
> +       wait_queue_head_t log_wq;
> +       struct delayed_work log_poll_work;
> +};
> +
> +/*
> + * We need to make sure that the EC log buffer on the UART is large enough,
> + * so that it is unlikely enough to overlow within LOG_POLL_SEC.
> + */
> +static void cros_ec_console_log_work(struct work_struct *__work)
> +{
> +       struct cros_ec_debugfs *debug_info =
> +               container_of(to_delayed_work(__work),
> +                            struct cros_ec_debugfs,
> +                            log_poll_work);
> +       struct cros_ec_dev *ec = debug_info->ec;
> +       struct circ_buf *cb = &debug_info->log_buffer;
> +       struct cros_ec_command snapshot_msg = {
> +               .command = EC_CMD_CONSOLE_SNAPSHOT + ec->cmd_offset,
> +       };
> +
> +       struct ec_params_console_read_v1 *read_params =
> +               (struct ec_params_console_read_v1 *)debug_info->read_msg->data;
> +       uint8_t *ec_buffer = (uint8_t *)debug_info->read_msg->data;
> +       int idx;
> +       int buf_space;
> +       int ret;
> +
> +       ret = cros_ec_cmd_xfer(ec->ec_dev, &snapshot_msg);
> +       if (ret < 0) {
> +               dev_err(ec->dev, "EC communication failed\n");
> +               goto resched;
> +       }
> +       if (snapshot_msg.result != EC_RES_SUCCESS) {
> +               dev_err(ec->dev, "EC failed to snapshot the console log\n");
> +               goto resched;
> +       }
> +
> +       /* Loop until we have read everything, or there's an error. */
> +       mutex_lock(&debug_info->log_mutex);
> +       buf_space = CIRC_SPACE(cb->head, cb->tail, LOG_SIZE);
> +
> +       while (1) {
> +               if (!buf_space) {
> +                       dev_info_once(ec->dev,
> +                                     "Some logs may have been dropped...\n");
> +                       break;
> +               }
> +
> +               memset(read_params, '\0', sizeof(*read_params));
> +               read_params->subcmd = CONSOLE_READ_RECENT;
> +               ret = cros_ec_cmd_xfer(ec->ec_dev, debug_info->read_msg);
> +               if (ret < 0) {
> +                       dev_err(ec->dev, "EC communication failed\n");
> +                       break;
> +               }
> +               if (debug_info->read_msg->result != EC_RES_SUCCESS) {
> +                       dev_err(ec->dev,
> +                               "EC failed to read the console log\n");
> +                       break;
> +               }
> +
> +               /* If the buffer is empty, we're done here. */
> +               if (ret == 0 || ec_buffer[0] == '\0')
> +                       break;
> +
> +               idx = 0;
> +               while (idx < ret && ec_buffer[idx] != '\0' && buf_space > 0) {
> +                       cb->buf[cb->head] = ec_buffer[idx];
> +                       cb->head = CIRC_ADD(cb->head, LOG_SIZE, 1);
> +                       idx++;
> +                       buf_space--;
> +               }
> +
> +               wake_up(&debug_info->log_wq);
> +       }
> +
> +       mutex_unlock(&debug_info->log_mutex);
> +
> +resched:
> +       schedule_delayed_work(&debug_info->log_poll_work,
> +                             msecs_to_jiffies(LOG_POLL_SEC * 1000));
> +}
> +
> +static int cros_ec_console_log_open(struct inode *inode, struct file *file)
> +{
> +       file->private_data = inode->i_private;
> +
> +       return nonseekable_open(inode, file);
> +}
> +
> +static ssize_t cros_ec_console_log_read(struct file *file, char __user *buf,
> +                                       size_t count, loff_t *ppos)
> +{
> +       struct cros_ec_debugfs *debug_info = file->private_data;
> +       struct circ_buf *cb = &debug_info->log_buffer;
> +       ssize_t ret;
> +
> +       mutex_lock(&debug_info->log_mutex);
> +
> +       while (!CIRC_CNT(cb->head, cb->tail, LOG_SIZE)) {
> +               if (file->f_flags & O_NONBLOCK) {
> +                       ret = -EAGAIN;
> +                       goto error;
> +               }
> +
> +               mutex_unlock(&debug_info->log_mutex);
> +
> +               ret = wait_event_interruptible(debug_info->log_wq,
> +                                       CIRC_CNT(cb->head, cb->tail, LOG_SIZE));
> +               if (ret < 0)
> +                       return ret;
> +
> +               mutex_lock(&debug_info->log_mutex);
> +       }
> +
> +       /* Only copy until the end of the circular buffer, and let userspace
> +        * retry to get the rest of the data.
> +        */
> +       ret = min_t(size_t, CIRC_CNT_TO_END(cb->head, cb->tail, LOG_SIZE),
> +                   count);
> +
> +       if (copy_to_user(buf, cb->buf + cb->tail, ret)) {
> +               ret = -EFAULT;
> +               goto error;
> +       }
> +
> +       cb->tail = CIRC_ADD(cb->tail, LOG_SIZE, ret);
> +
> +error:
> +       mutex_unlock(&debug_info->log_mutex);
> +       return ret;
> +}
> +
> +static unsigned int cros_ec_console_log_poll(struct file *file,
> +                                            poll_table *wait)
> +{
> +       struct cros_ec_debugfs *debug_info = file->private_data;
> +       unsigned int mask = 0;
> +
> +       poll_wait(file, &debug_info->log_wq, wait);
> +
> +       mutex_lock(&debug_info->log_mutex);
> +       if (CIRC_CNT(debug_info->log_buffer.head,
> +                    debug_info->log_buffer.tail,
> +                    LOG_SIZE))
> +               mask |= POLLIN | POLLRDNORM;
> +       mutex_unlock(&debug_info->log_mutex);
> +
> +       return mask;
> +}
> +
> +static int cros_ec_console_log_release(struct inode *inode, struct file *file)
> +{
> +       return 0;
> +}
> +
> +const struct file_operations cros_ec_console_log_fops = {
> +       .owner = THIS_MODULE,
> +       .open = cros_ec_console_log_open,
> +       .read = cros_ec_console_log_read,
> +       .llseek = no_llseek,
> +       .poll = cros_ec_console_log_poll,
> +       .release = cros_ec_console_log_release,
> +};
> +
> +static int ec_read_version_supported(struct cros_ec_dev *ec)
> +{
> +       struct ec_params_get_cmd_versions_v1 *params;
> +       struct ec_response_get_cmd_versions *response;
> +       int ret;
> +
> +       struct cros_ec_command *msg;
> +
> +       msg = kzalloc(sizeof(*msg) + max(sizeof(params), sizeof(response)),
> +               GFP_KERNEL);
> +       if (!msg)
> +               return 0;
> +
> +       msg->command = EC_CMD_GET_CMD_VERSIONS + ec->cmd_offset;
> +       msg->outsize = sizeof(params);
> +       msg->insize = sizeof(response);
> +
> +       params = (struct ec_params_get_cmd_versions_v1 *)msg->data;
> +       params->cmd = EC_CMD_CONSOLE_READ;
> +       response = (struct ec_response_get_cmd_versions *)msg->data;
> +
> +       ret = cros_ec_cmd_xfer(ec->ec_dev, msg) >= 0 &&
> +               msg->result == EC_RES_SUCCESS &&
> +               (response->version_mask & EC_VER_MASK(1));
> +
> +       kfree(msg);
> +
> +       return ret;
> +}
> +
> +static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info)
> +{
> +       struct cros_ec_dev *ec = debug_info->ec;
> +       char *buf;
> +       int read_params_size;
> +       int read_response_size;
> +
> +       if (!ec_read_version_supported(ec)) {
> +               dev_warn(ec->dev,
> +                       "device does not support reading the console log\n");
> +               return 0;
> +       }
> +
> +       buf = devm_kzalloc(ec->dev, LOG_SIZE, GFP_KERNEL);
> +       if (!buf)
> +               return -ENOMEM;
> +
> +       read_params_size = sizeof(struct ec_params_console_read_v1);
> +       read_response_size = ec->ec_dev->max_response;
> +       debug_info->read_msg = devm_kzalloc(ec->dev,
> +               sizeof(*debug_info->read_msg) +
> +                       max(read_params_size, read_response_size), GFP_KERNEL);
> +       if (!debug_info->read_msg)
> +               return -ENOMEM;
> +
> +       debug_info->read_msg->version = 1;
> +       debug_info->read_msg->command = EC_CMD_CONSOLE_READ + ec->cmd_offset;
> +       debug_info->read_msg->outsize = read_params_size;
> +       debug_info->read_msg->insize = read_response_size;
> +
> +       debug_info->log_buffer.buf = buf;
> +       debug_info->log_buffer.head = 0;
> +       debug_info->log_buffer.tail = 0;
> +
> +       mutex_init(&debug_info->log_mutex);
> +       init_waitqueue_head(&debug_info->log_wq);
> +
> +       if (!debugfs_create_file("console_log",
> +                                S_IFREG | S_IRUGO,
> +                                debug_info->dir,
> +                                debug_info,
> +                                &cros_ec_console_log_fops))
> +               return -ENOMEM;
> +
> +       INIT_DELAYED_WORK(&debug_info->log_poll_work,
> +                         cros_ec_console_log_work);
> +       schedule_delayed_work(&debug_info->log_poll_work, 0);
> +
> +       return 0;
> +}
> +
> +static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
> +{
> +       if (debug_info->log_buffer.buf) {
> +               cancel_delayed_work_sync(&debug_info->log_poll_work);
> +               mutex_destroy(&debug_info->log_mutex);
> +       }
> +}
> +
> +int cros_ec_debugfs_init(struct cros_ec_dev *ec)
> +{
> +       struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
> +       const char *name = ec_platform->ec_name;
> +       struct cros_ec_debugfs *debug_info;
> +       int ret;
> +
> +       debug_info = devm_kzalloc(ec->dev, sizeof(*debug_info), GFP_KERNEL);
> +       if (!debug_info)
> +               return -ENOMEM;
> +
> +       debug_info->ec = ec;
> +       debug_info->dir = debugfs_create_dir(name, NULL);
> +       if (!debug_info->dir)
> +               return -ENOMEM;
> +
> +       ret = cros_ec_create_console_log(debug_info);
> +       if (ret)
> +               goto remove_debugfs;
> +
> +       ec->debug_info = debug_info;
> +
> +       return 0;
> +
> +remove_debugfs:
> +       debugfs_remove_recursive(debug_info->dir);
> +       return ret;
> +}
> +
> +void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
> +{
> +       if (!ec->debug_info)
> +               return;
> +
> +       debugfs_remove_recursive(ec->debug_info->dir);
> +       cros_ec_cleanup_console_log(ec->debug_info);
> +}
> diff --git a/drivers/platform/chrome/cros_ec_debugfs.h b/drivers/platform/chrome/cros_ec_debugfs.h
> new file mode 100644
> index 0000000..1ff3a50
> --- /dev/null
> +++ b/drivers/platform/chrome/cros_ec_debugfs.h
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright 2015 Google, 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.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _DRV_CROS_EC_DEBUGFS_H_
> +#define _DRV_CROS_EC_DEBUGFS_H_
> +
> +#include "cros_ec_dev.h"
> +
> +/* debugfs stuff */
> +int cros_ec_debugfs_init(struct cros_ec_dev *ec);
> +void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
> +
> +#endif  /* _DRV_CROS_EC_DEBUGFS_H_ */
> diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
> index 8abd80d..7d51f69 100644
> --- a/drivers/platform/chrome/cros_ec_dev.c
> +++ b/drivers/platform/chrome/cros_ec_dev.c
> @@ -23,6 +23,7 @@
>  #include <linux/slab.h>
>  #include <linux/uaccess.h>
>
> +#include "cros_ec_debugfs.h"
>  #include "cros_ec_dev.h"
>
>  /* Device variables */
> @@ -282,6 +283,9 @@ static int ec_device_probe(struct platform_device *pdev)
>                 goto dev_reg_failed;
>         }
>
> +       if (cros_ec_debugfs_init(ec))
> +               dev_warn(dev, "failed to create debugfs directory\n");
> +
>         return 0;
>
>  dev_reg_failed:
> @@ -296,6 +300,9 @@ cdev_add_failed:
>  static int ec_device_remove(struct platform_device *pdev)
>  {
>         struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
> +
> +       cros_ec_debugfs_remove(ec);
> +
>         cdev_del(&ec->cdev);
>         device_unregister(&ec->class_dev);
>         return 0;
> diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
> index d641a18..e7001a7 100644
> --- a/include/linux/mfd/cros_ec.h
> +++ b/include/linux/mfd/cros_ec.h
> @@ -151,6 +151,8 @@ struct cros_ec_platform {
>         u16 cmd_offset;
>  };
>
> +struct cros_ec_debugfs;
> +
>  /*
>   * struct cros_ec_dev - ChromeOS EC device entry point
>   *
> @@ -158,6 +160,7 @@ struct cros_ec_platform {
>   * @cdev: Character device structure in /dev
>   * @ec_dev: cros_ec_device structure to talk to the physical device
>   * @dev: pointer to the platform device
> + * @debug_info: cros_ec_debugfs structure for debugging information
>   * @cmd_offset: offset to apply for each command.
>   */
>  struct cros_ec_dev {
> @@ -165,6 +168,7 @@ struct cros_ec_dev {
>         struct cdev cdev;
>         struct cros_ec_device *ec_dev;
>         struct device *dev;
> +       struct cros_ec_debugfs *debug_info;
>         u16 cmd_offset;
>  };
>
> --
> 2.8.0.rc3.226.g39d4020
>

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

* Re: [PATCH 3/3] mfd: cros_ec: Add support for dumping panic information
  2016-08-23  4:34 ` [PATCH 3/3] mfd: cros_ec: Add support for dumping panic information Nicolas Boichat
@ 2016-08-23 21:19   ` Guenter Roeck
  0 siblings, 0 replies; 13+ messages in thread
From: Guenter Roeck @ 2016-08-23 21:19 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Lee Jones, Gwendal Grignou, ejcaruso, Olof Johansson,
	linux-kernel, Guenter Roeck

On Mon, Aug 22, 2016 at 9:34 PM, Nicolas Boichat <drinkcat@chromium.org> wrote:
> This dumps the EC panic information from the previous reboot.
>
> Similar to the information presented by ectool panicinfo, except
> that we do not bother doing any parsing (we should write a small
> offline tool for that).
>
> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>

Reviewed-by: Guenter Roeck <groeck@chromium.org>

> ---
>  drivers/platform/chrome/cros_ec_debugfs.c | 54 +++++++++++++++++++++++++++++++
>  1 file changed, 54 insertions(+)
>
> diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
> index 225f936..f4b6a29 100644
> --- a/drivers/platform/chrome/cros_ec_debugfs.c
> +++ b/drivers/platform/chrome/cros_ec_debugfs.c
> @@ -47,15 +47,19 @@
>   * @log_mutex: mutex to protect circular buffer
>   * @log_wq: waitqueue for log readers
>   * @log_poll_work: recurring task to poll EC for new console log data
> + * @panicinfo_blob: panicinfo debugfs blob
>   */
>  struct cros_ec_debugfs {
>         struct cros_ec_dev *ec;
>         struct dentry *dir;
> +       /* EC log */
>         struct circ_buf log_buffer;
>         struct cros_ec_command *read_msg;
>         struct mutex log_mutex;
>         wait_queue_head_t log_wq;
>         struct delayed_work log_poll_work;
> +       /* EC panicinfo */
> +       struct debugfs_blob_wrapper panicinfo_blob;
>  };
>
>  /*
> @@ -308,6 +312,52 @@ static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
>         }
>  }
>
> +static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
> +{
> +       struct cros_ec_device *ec_dev = debug_info->ec->ec_dev;
> +       int ret;
> +       struct cros_ec_command *msg;
> +       int insize;
> +
> +       insize = ec_dev->max_response;
> +
> +       msg = devm_kzalloc(debug_info->ec->dev,
> +                       sizeof(*msg) + insize, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +
> +       msg->command = EC_CMD_GET_PANIC_INFO;
> +       msg->insize = insize;
> +
> +       ret = cros_ec_cmd_xfer(ec_dev, msg);
> +       if (ret < 0) {
> +               dev_warn(debug_info->ec->dev, "Cannot read panicinfo.\n");
> +               ret = 0;
> +               goto free;
> +       }
> +
> +       /* No panic data */
> +       if (ret == 0)
> +               goto free;
> +
> +       debug_info->panicinfo_blob.data = msg->data;
> +       debug_info->panicinfo_blob.size = ret;
> +
> +       if (!debugfs_create_blob("panicinfo",
> +                                S_IFREG | S_IRUGO,
> +                                debug_info->dir,
> +                                &debug_info->panicinfo_blob)) {
> +               ret = -ENOMEM;
> +               goto free;
> +       }
> +
> +       return 0;
> +
> +free:
> +       devm_kfree(debug_info->ec->dev, msg);
> +       return ret;
> +}
> +
>  int cros_ec_debugfs_init(struct cros_ec_dev *ec)
>  {
>         struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
> @@ -324,6 +374,10 @@ int cros_ec_debugfs_init(struct cros_ec_dev *ec)
>         if (!debug_info->dir)
>                 return -ENOMEM;
>
> +       ret = cros_ec_create_panicinfo(debug_info);
> +       if (ret)
> +               goto remove_debugfs;
> +
>         ret = cros_ec_create_console_log(debug_info);
>         if (ret)
>                 goto remove_debugfs;
> --
> 2.8.0.rc3.226.g39d4020
>

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

* Re: [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions
  2016-08-23  4:34 ` [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions Nicolas Boichat
  2016-08-23 21:15   ` Guenter Roeck
@ 2016-08-31 11:45   ` Lee Jones
  2016-10-13  3:24     ` Nicolas Boichat
  1 sibling, 1 reply; 13+ messages in thread
From: Lee Jones @ 2016-08-31 11:45 UTC (permalink / raw)
  To: Nicolas Boichat; +Cc: gwendal, ejcaruso, Olof Johansson, linux-kernel, groeck

On Tue, 23 Aug 2016, Nicolas Boichat wrote:

> ec_params_console_read_v1 is used to capture EC logs from kernel,
> and ec_params_get_cmd_versions_v1 is used to probe whether EC
> supports that command.
> 
> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> ---
>  include/linux/mfd/cros_ec_commands.h | 21 ++++++++++++++++++++-

Acked-by: Lee Jones <lee.jones@linaro.org>

I guess this will be taken through Olof's tree?

>  1 file changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
> index 7e7a8d4..74c84e82 100644
> --- a/include/linux/mfd/cros_ec_commands.h
> +++ b/include/linux/mfd/cros_ec_commands.h
> @@ -625,6 +625,10 @@ struct ec_params_get_cmd_versions {
>  	uint8_t cmd;      /* Command to check */
>  } __packed;
>  
> +struct ec_params_get_cmd_versions_v1 {
> +	uint16_t cmd;     /* Command to check */
> +} __packed;
> +
>  struct ec_response_get_cmd_versions {
>  	/*
>  	 * Mask of supported versions; use EC_VER_MASK() to compare with a
> @@ -2003,13 +2007,28 @@ struct ec_params_charge_control {
>  #define EC_CMD_CONSOLE_SNAPSHOT 0x97
>  
>  /*
> - * Read next chunk of data from saved snapshot.
> + * Read data from the saved snapshot. If the subcmd parameter is
> + * CONSOLE_READ_NEXT, this will return data starting from the beginning of
> + * the latest snapshot. If it is CONSOLE_READ_RECENT, it will start from the
> + * end of the previous snapshot.
> + *
> + * The params are only looked at in version >= 1 of this command. Prior
> + * versions will just default to CONSOLE_READ_NEXT behavior.
>   *
>   * Response is null-terminated string.  Empty string, if there is no more
>   * remaining output.
>   */
>  #define EC_CMD_CONSOLE_READ 0x98
>  
> +enum ec_console_read_subcmd {
> +	CONSOLE_READ_NEXT = 0,
> +	CONSOLE_READ_RECENT
> +};
> +
> +struct ec_params_console_read_v1 {
> +	uint8_t subcmd; /* enum ec_console_read_subcmd */
> +} __packed;
> +
>  /*****************************************************************************/
>  
>  /*

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH 2/3] mfd: cros_ec: add debugfs, console log file
  2016-08-23  4:34 ` [PATCH 2/3] mfd: cros_ec: add debugfs, console log file Nicolas Boichat
  2016-08-23 21:17   ` Guenter Roeck
@ 2016-08-31 11:45   ` Lee Jones
  2017-02-22 21:49   ` Doug Anderson
  2 siblings, 0 replies; 13+ messages in thread
From: Lee Jones @ 2016-08-31 11:45 UTC (permalink / raw)
  To: Nicolas Boichat; +Cc: gwendal, ejcaruso, Olof Johansson, linux-kernel, groeck

On Tue, 23 Aug 2016, Nicolas Boichat wrote:

> From: Eric Caruso <ejcaruso@chromium.org>
> 
> If the EC supports the new CONSOLE_READ command type, then we
> place a console_log file in debugfs for that EC device which allows
> us to grab EC logs. The kernel will poll every 10 seconds for the
> log and keep its own buffer, but userspace should grab this and
> write it out to some logs which actually get rotated.
> 
> Signed-off-by: Eric Caruso <ejcaruso@chromium.org>
> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> ---
>  drivers/platform/chrome/Makefile          |   3 +-
>  drivers/platform/chrome/cros_ec_debugfs.c | 347 ++++++++++++++++++++++++++++++
>  drivers/platform/chrome/cros_ec_debugfs.h |  27 +++
>  drivers/platform/chrome/cros_ec_dev.c     |   7 +
>  include/linux/mfd/cros_ec.h               |   4 +

Acked-by: Lee Jones <lee.jones@linaro.org>

I guess this will be taken through Olof's tree?

>  5 files changed, 387 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/platform/chrome/cros_ec_debugfs.c
>  create mode 100644 drivers/platform/chrome/cros_ec_debugfs.h
> 
> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
> index 4f34627..3870afe 100644
> --- a/drivers/platform/chrome/Makefile
> +++ b/drivers/platform/chrome/Makefile
> @@ -2,7 +2,8 @@
>  obj-$(CONFIG_CHROMEOS_LAPTOP)		+= chromeos_laptop.o
>  obj-$(CONFIG_CHROMEOS_PSTORE)		+= chromeos_pstore.o
>  cros_ec_devs-objs			:= cros_ec_dev.o cros_ec_sysfs.o \
> -					   cros_ec_lightbar.o cros_ec_vbc.o
> +					   cros_ec_lightbar.o cros_ec_vbc.o \
> +					   cros_ec_debugfs.o
>  obj-$(CONFIG_CROS_EC_CHARDEV)		+= cros_ec_devs.o
>  obj-$(CONFIG_CROS_EC_LPC)		+= cros_ec_lpc.o
>  obj-$(CONFIG_CROS_EC_PROTO)		+= cros_ec_proto.o
> diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
> new file mode 100644
> index 0000000..225f936
> --- /dev/null
> +++ b/drivers/platform/chrome/cros_ec_debugfs.c
> @@ -0,0 +1,347 @@
> +/*
> + * cros_ec_debugfs - debug logs for Chrome OS EC
> + *
> + * Copyright 2015 Google, 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.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/circ_buf.h>
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/fs.h>
> +#include <linux/mfd/cros_ec.h>
> +#include <linux/mfd/cros_ec_commands.h>
> +#include <linux/mutex.h>
> +#include <linux/poll.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/wait.h>
> +
> +#include "cros_ec_dev.h"
> +#include "cros_ec_debugfs.h"
> +
> +#define LOG_SHIFT		14
> +#define LOG_SIZE		(1 << LOG_SHIFT)
> +#define LOG_POLL_SEC		10
> +
> +#define CIRC_ADD(idx, size, value)	(((idx) + (value)) & ((size) - 1))
> +
> +/* struct cros_ec_debugfs - ChromeOS EC debugging information
> + *
> + * @ec: EC device this debugfs information belongs to
> + * @dir: dentry for debugfs files
> + * @log_buffer: circular buffer for console log information
> + * @read_msg: preallocated EC command and buffer to read console log
> + * @log_mutex: mutex to protect circular buffer
> + * @log_wq: waitqueue for log readers
> + * @log_poll_work: recurring task to poll EC for new console log data
> + */
> +struct cros_ec_debugfs {
> +	struct cros_ec_dev *ec;
> +	struct dentry *dir;
> +	struct circ_buf log_buffer;
> +	struct cros_ec_command *read_msg;
> +	struct mutex log_mutex;
> +	wait_queue_head_t log_wq;
> +	struct delayed_work log_poll_work;
> +};
> +
> +/*
> + * We need to make sure that the EC log buffer on the UART is large enough,
> + * so that it is unlikely enough to overlow within LOG_POLL_SEC.
> + */
> +static void cros_ec_console_log_work(struct work_struct *__work)
> +{
> +	struct cros_ec_debugfs *debug_info =
> +		container_of(to_delayed_work(__work),
> +			     struct cros_ec_debugfs,
> +			     log_poll_work);
> +	struct cros_ec_dev *ec = debug_info->ec;
> +	struct circ_buf *cb = &debug_info->log_buffer;
> +	struct cros_ec_command snapshot_msg = {
> +		.command = EC_CMD_CONSOLE_SNAPSHOT + ec->cmd_offset,
> +	};
> +
> +	struct ec_params_console_read_v1 *read_params =
> +		(struct ec_params_console_read_v1 *)debug_info->read_msg->data;
> +	uint8_t *ec_buffer = (uint8_t *)debug_info->read_msg->data;
> +	int idx;
> +	int buf_space;
> +	int ret;
> +
> +	ret = cros_ec_cmd_xfer(ec->ec_dev, &snapshot_msg);
> +	if (ret < 0) {
> +		dev_err(ec->dev, "EC communication failed\n");
> +		goto resched;
> +	}
> +	if (snapshot_msg.result != EC_RES_SUCCESS) {
> +		dev_err(ec->dev, "EC failed to snapshot the console log\n");
> +		goto resched;
> +	}
> +
> +	/* Loop until we have read everything, or there's an error. */
> +	mutex_lock(&debug_info->log_mutex);
> +	buf_space = CIRC_SPACE(cb->head, cb->tail, LOG_SIZE);
> +
> +	while (1) {
> +		if (!buf_space) {
> +			dev_info_once(ec->dev,
> +				      "Some logs may have been dropped...\n");
> +			break;
> +		}
> +
> +		memset(read_params, '\0', sizeof(*read_params));
> +		read_params->subcmd = CONSOLE_READ_RECENT;
> +		ret = cros_ec_cmd_xfer(ec->ec_dev, debug_info->read_msg);
> +		if (ret < 0) {
> +			dev_err(ec->dev, "EC communication failed\n");
> +			break;
> +		}
> +		if (debug_info->read_msg->result != EC_RES_SUCCESS) {
> +			dev_err(ec->dev,
> +				"EC failed to read the console log\n");
> +			break;
> +		}
> +
> +		/* If the buffer is empty, we're done here. */
> +		if (ret == 0 || ec_buffer[0] == '\0')
> +			break;
> +
> +		idx = 0;
> +		while (idx < ret && ec_buffer[idx] != '\0' && buf_space > 0) {
> +			cb->buf[cb->head] = ec_buffer[idx];
> +			cb->head = CIRC_ADD(cb->head, LOG_SIZE, 1);
> +			idx++;
> +			buf_space--;
> +		}
> +
> +		wake_up(&debug_info->log_wq);
> +	}
> +
> +	mutex_unlock(&debug_info->log_mutex);
> +
> +resched:
> +	schedule_delayed_work(&debug_info->log_poll_work,
> +			      msecs_to_jiffies(LOG_POLL_SEC * 1000));
> +}
> +
> +static int cros_ec_console_log_open(struct inode *inode, struct file *file)
> +{
> +	file->private_data = inode->i_private;
> +
> +	return nonseekable_open(inode, file);
> +}
> +
> +static ssize_t cros_ec_console_log_read(struct file *file, char __user *buf,
> +					size_t count, loff_t *ppos)
> +{
> +	struct cros_ec_debugfs *debug_info = file->private_data;
> +	struct circ_buf *cb = &debug_info->log_buffer;
> +	ssize_t ret;
> +
> +	mutex_lock(&debug_info->log_mutex);
> +
> +	while (!CIRC_CNT(cb->head, cb->tail, LOG_SIZE)) {
> +		if (file->f_flags & O_NONBLOCK) {
> +			ret = -EAGAIN;
> +			goto error;
> +		}
> +
> +		mutex_unlock(&debug_info->log_mutex);
> +
> +		ret = wait_event_interruptible(debug_info->log_wq,
> +					CIRC_CNT(cb->head, cb->tail, LOG_SIZE));
> +		if (ret < 0)
> +			return ret;
> +
> +		mutex_lock(&debug_info->log_mutex);
> +	}
> +
> +	/* Only copy until the end of the circular buffer, and let userspace
> +	 * retry to get the rest of the data.
> +	 */
> +	ret = min_t(size_t, CIRC_CNT_TO_END(cb->head, cb->tail, LOG_SIZE),
> +		    count);
> +
> +	if (copy_to_user(buf, cb->buf + cb->tail, ret)) {
> +		ret = -EFAULT;
> +		goto error;
> +	}
> +
> +	cb->tail = CIRC_ADD(cb->tail, LOG_SIZE, ret);
> +
> +error:
> +	mutex_unlock(&debug_info->log_mutex);
> +	return ret;
> +}
> +
> +static unsigned int cros_ec_console_log_poll(struct file *file,
> +					     poll_table *wait)
> +{
> +	struct cros_ec_debugfs *debug_info = file->private_data;
> +	unsigned int mask = 0;
> +
> +	poll_wait(file, &debug_info->log_wq, wait);
> +
> +	mutex_lock(&debug_info->log_mutex);
> +	if (CIRC_CNT(debug_info->log_buffer.head,
> +		     debug_info->log_buffer.tail,
> +		     LOG_SIZE))
> +		mask |= POLLIN | POLLRDNORM;
> +	mutex_unlock(&debug_info->log_mutex);
> +
> +	return mask;
> +}
> +
> +static int cros_ec_console_log_release(struct inode *inode, struct file *file)
> +{
> +	return 0;
> +}
> +
> +const struct file_operations cros_ec_console_log_fops = {
> +	.owner = THIS_MODULE,
> +	.open = cros_ec_console_log_open,
> +	.read = cros_ec_console_log_read,
> +	.llseek = no_llseek,
> +	.poll = cros_ec_console_log_poll,
> +	.release = cros_ec_console_log_release,
> +};
> +
> +static int ec_read_version_supported(struct cros_ec_dev *ec)
> +{
> +	struct ec_params_get_cmd_versions_v1 *params;
> +	struct ec_response_get_cmd_versions *response;
> +	int ret;
> +
> +	struct cros_ec_command *msg;
> +
> +	msg = kzalloc(sizeof(*msg) + max(sizeof(params), sizeof(response)),
> +		GFP_KERNEL);
> +	if (!msg)
> +		return 0;
> +
> +	msg->command = EC_CMD_GET_CMD_VERSIONS + ec->cmd_offset;
> +	msg->outsize = sizeof(params);
> +	msg->insize = sizeof(response);
> +
> +	params = (struct ec_params_get_cmd_versions_v1 *)msg->data;
> +	params->cmd = EC_CMD_CONSOLE_READ;
> +	response = (struct ec_response_get_cmd_versions *)msg->data;
> +
> +	ret = cros_ec_cmd_xfer(ec->ec_dev, msg) >= 0 &&
> +		msg->result == EC_RES_SUCCESS &&
> +		(response->version_mask & EC_VER_MASK(1));
> +
> +	kfree(msg);
> +
> +	return ret;
> +}
> +
> +static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info)
> +{
> +	struct cros_ec_dev *ec = debug_info->ec;
> +	char *buf;
> +	int read_params_size;
> +	int read_response_size;
> +
> +	if (!ec_read_version_supported(ec)) {
> +		dev_warn(ec->dev,
> +			"device does not support reading the console log\n");
> +		return 0;
> +	}
> +
> +	buf = devm_kzalloc(ec->dev, LOG_SIZE, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	read_params_size = sizeof(struct ec_params_console_read_v1);
> +	read_response_size = ec->ec_dev->max_response;
> +	debug_info->read_msg = devm_kzalloc(ec->dev,
> +		sizeof(*debug_info->read_msg) +
> +			max(read_params_size, read_response_size), GFP_KERNEL);
> +	if (!debug_info->read_msg)
> +		return -ENOMEM;
> +
> +	debug_info->read_msg->version = 1;
> +	debug_info->read_msg->command = EC_CMD_CONSOLE_READ + ec->cmd_offset;
> +	debug_info->read_msg->outsize = read_params_size;
> +	debug_info->read_msg->insize = read_response_size;
> +
> +	debug_info->log_buffer.buf = buf;
> +	debug_info->log_buffer.head = 0;
> +	debug_info->log_buffer.tail = 0;
> +
> +	mutex_init(&debug_info->log_mutex);
> +	init_waitqueue_head(&debug_info->log_wq);
> +
> +	if (!debugfs_create_file("console_log",
> +				 S_IFREG | S_IRUGO,
> +				 debug_info->dir,
> +				 debug_info,
> +				 &cros_ec_console_log_fops))
> +		return -ENOMEM;
> +
> +	INIT_DELAYED_WORK(&debug_info->log_poll_work,
> +			  cros_ec_console_log_work);
> +	schedule_delayed_work(&debug_info->log_poll_work, 0);
> +
> +	return 0;
> +}
> +
> +static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
> +{
> +	if (debug_info->log_buffer.buf) {
> +		cancel_delayed_work_sync(&debug_info->log_poll_work);
> +		mutex_destroy(&debug_info->log_mutex);
> +	}
> +}
> +
> +int cros_ec_debugfs_init(struct cros_ec_dev *ec)
> +{
> +	struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
> +	const char *name = ec_platform->ec_name;
> +	struct cros_ec_debugfs *debug_info;
> +	int ret;
> +
> +	debug_info = devm_kzalloc(ec->dev, sizeof(*debug_info), GFP_KERNEL);
> +	if (!debug_info)
> +		return -ENOMEM;
> +
> +	debug_info->ec = ec;
> +	debug_info->dir = debugfs_create_dir(name, NULL);
> +	if (!debug_info->dir)
> +		return -ENOMEM;
> +
> +	ret = cros_ec_create_console_log(debug_info);
> +	if (ret)
> +		goto remove_debugfs;
> +
> +	ec->debug_info = debug_info;
> +
> +	return 0;
> +
> +remove_debugfs:
> +	debugfs_remove_recursive(debug_info->dir);
> +	return ret;
> +}
> +
> +void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
> +{
> +	if (!ec->debug_info)
> +		return;
> +
> +	debugfs_remove_recursive(ec->debug_info->dir);
> +	cros_ec_cleanup_console_log(ec->debug_info);
> +}
> diff --git a/drivers/platform/chrome/cros_ec_debugfs.h b/drivers/platform/chrome/cros_ec_debugfs.h
> new file mode 100644
> index 0000000..1ff3a50
> --- /dev/null
> +++ b/drivers/platform/chrome/cros_ec_debugfs.h
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright 2015 Google, 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.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _DRV_CROS_EC_DEBUGFS_H_
> +#define _DRV_CROS_EC_DEBUGFS_H_
> +
> +#include "cros_ec_dev.h"
> +
> +/* debugfs stuff */
> +int cros_ec_debugfs_init(struct cros_ec_dev *ec);
> +void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
> +
> +#endif  /* _DRV_CROS_EC_DEBUGFS_H_ */
> diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
> index 8abd80d..7d51f69 100644
> --- a/drivers/platform/chrome/cros_ec_dev.c
> +++ b/drivers/platform/chrome/cros_ec_dev.c
> @@ -23,6 +23,7 @@
>  #include <linux/slab.h>
>  #include <linux/uaccess.h>
>  
> +#include "cros_ec_debugfs.h"
>  #include "cros_ec_dev.h"
>  
>  /* Device variables */
> @@ -282,6 +283,9 @@ static int ec_device_probe(struct platform_device *pdev)
>  		goto dev_reg_failed;
>  	}
>  
> +	if (cros_ec_debugfs_init(ec))
> +		dev_warn(dev, "failed to create debugfs directory\n");
> +
>  	return 0;
>  
>  dev_reg_failed:
> @@ -296,6 +300,9 @@ cdev_add_failed:
>  static int ec_device_remove(struct platform_device *pdev)
>  {
>  	struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
> +
> +	cros_ec_debugfs_remove(ec);
> +
>  	cdev_del(&ec->cdev);
>  	device_unregister(&ec->class_dev);
>  	return 0;
> diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
> index d641a18..e7001a7 100644
> --- a/include/linux/mfd/cros_ec.h
> +++ b/include/linux/mfd/cros_ec.h
> @@ -151,6 +151,8 @@ struct cros_ec_platform {
>  	u16 cmd_offset;
>  };
>  
> +struct cros_ec_debugfs;
> +
>  /*
>   * struct cros_ec_dev - ChromeOS EC device entry point
>   *
> @@ -158,6 +160,7 @@ struct cros_ec_platform {
>   * @cdev: Character device structure in /dev
>   * @ec_dev: cros_ec_device structure to talk to the physical device
>   * @dev: pointer to the platform device
> + * @debug_info: cros_ec_debugfs structure for debugging information
>   * @cmd_offset: offset to apply for each command.
>   */
>  struct cros_ec_dev {
> @@ -165,6 +168,7 @@ struct cros_ec_dev {
>  	struct cdev cdev;
>  	struct cros_ec_device *ec_dev;
>  	struct device *dev;
> +	struct cros_ec_debugfs *debug_info;
>  	u16 cmd_offset;
>  };
>  

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions
  2016-08-31 11:45   ` Lee Jones
@ 2016-10-13  3:24     ` Nicolas Boichat
  2016-10-13 18:06       ` Olof Johansson
  0 siblings, 1 reply; 13+ messages in thread
From: Nicolas Boichat @ 2016-10-13  3:24 UTC (permalink / raw)
  To: Lee Jones
  Cc: Gwendal Grignou, Eric Caruso, Olof Johansson, linux-kernel,
	Guenter Roeck

On Wed, Aug 31, 2016 at 4:45 AM, Lee Jones <lee.jones@linaro.org> wrote:
> On Tue, 23 Aug 2016, Nicolas Boichat wrote:
>
>> ec_params_console_read_v1 is used to capture EC logs from kernel,
>> and ec_params_get_cmd_versions_v1 is used to probe whether EC
>> supports that command.
>>
>> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
>> ---
>>  include/linux/mfd/cros_ec_commands.h | 21 ++++++++++++++++++++-
>
> Acked-by: Lee Jones <lee.jones@linaro.org>
>
> I guess this will be taken through Olof's tree?

What's the status on this patch series? I don't see it being picked up
in any tree...

Thanks,

>>  1 file changed, 20 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
>> index 7e7a8d4..74c84e82 100644
>> --- a/include/linux/mfd/cros_ec_commands.h
>> +++ b/include/linux/mfd/cros_ec_commands.h
>> @@ -625,6 +625,10 @@ struct ec_params_get_cmd_versions {
>>       uint8_t cmd;      /* Command to check */
>>  } __packed;
>>
>> +struct ec_params_get_cmd_versions_v1 {
>> +     uint16_t cmd;     /* Command to check */
>> +} __packed;
>> +
>>  struct ec_response_get_cmd_versions {
>>       /*
>>        * Mask of supported versions; use EC_VER_MASK() to compare with a
>> @@ -2003,13 +2007,28 @@ struct ec_params_charge_control {
>>  #define EC_CMD_CONSOLE_SNAPSHOT 0x97
>>
>>  /*
>> - * Read next chunk of data from saved snapshot.
>> + * Read data from the saved snapshot. If the subcmd parameter is
>> + * CONSOLE_READ_NEXT, this will return data starting from the beginning of
>> + * the latest snapshot. If it is CONSOLE_READ_RECENT, it will start from the
>> + * end of the previous snapshot.
>> + *
>> + * The params are only looked at in version >= 1 of this command. Prior
>> + * versions will just default to CONSOLE_READ_NEXT behavior.
>>   *
>>   * Response is null-terminated string.  Empty string, if there is no more
>>   * remaining output.
>>   */
>>  #define EC_CMD_CONSOLE_READ 0x98
>>
>> +enum ec_console_read_subcmd {
>> +     CONSOLE_READ_NEXT = 0,
>> +     CONSOLE_READ_RECENT
>> +};
>> +
>> +struct ec_params_console_read_v1 {
>> +     uint8_t subcmd; /* enum ec_console_read_subcmd */
>> +} __packed;
>> +
>>  /*****************************************************************************/
>>
>>  /*
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions
  2016-10-13  3:24     ` Nicolas Boichat
@ 2016-10-13 18:06       ` Olof Johansson
  2016-10-13 20:32         ` Nicolas Boichat
  0 siblings, 1 reply; 13+ messages in thread
From: Olof Johansson @ 2016-10-13 18:06 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Lee Jones, Gwendal Grignou, Eric Caruso, linux-kernel, Guenter Roeck

On Wed, Oct 12, 2016 at 8:24 PM, Nicolas Boichat <drinkcat@chromium.org> wrote:
> On Wed, Aug 31, 2016 at 4:45 AM, Lee Jones <lee.jones@linaro.org> wrote:
>> On Tue, 23 Aug 2016, Nicolas Boichat wrote:
>>
>>> ec_params_console_read_v1 is used to capture EC logs from kernel,
>>> and ec_params_get_cmd_versions_v1 is used to probe whether EC
>>> supports that command.
>>>
>>> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
>>> ---
>>>  include/linux/mfd/cros_ec_commands.h | 21 ++++++++++++++++++++-
>>
>> Acked-by: Lee Jones <lee.jones@linaro.org>
>>
>> I guess this will be taken through Olof's tree?
>
> What's the status on this patch series? I don't see it being picked up
> in any tree...

It didn't get caught in my filter so I missed it. I can apply it for 4.10.


-Olof

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

* Re: [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions
  2016-10-13 18:06       ` Olof Johansson
@ 2016-10-13 20:32         ` Nicolas Boichat
  0 siblings, 0 replies; 13+ messages in thread
From: Nicolas Boichat @ 2016-10-13 20:32 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Lee Jones, Gwendal Grignou, Eric Caruso, linux-kernel, Guenter Roeck

On Thu, Oct 13, 2016 at 11:06 AM, Olof Johansson <olof@lixom.net> wrote:
> On Wed, Oct 12, 2016 at 8:24 PM, Nicolas Boichat <drinkcat@chromium.org> wrote:
>> On Wed, Aug 31, 2016 at 4:45 AM, Lee Jones <lee.jones@linaro.org> wrote:
>>> On Tue, 23 Aug 2016, Nicolas Boichat wrote:
>>>
>>>> ec_params_console_read_v1 is used to capture EC logs from kernel,
>>>> and ec_params_get_cmd_versions_v1 is used to probe whether EC
>>>> supports that command.
>>>>
>>>> Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
>>>> ---
>>>>  include/linux/mfd/cros_ec_commands.h | 21 ++++++++++++++++++++-
>>>
>>> Acked-by: Lee Jones <lee.jones@linaro.org>
>>>
>>> I guess this will be taken through Olof's tree?
>>
>> What's the status on this patch series? I don't see it being picked up
>> in any tree...
>
> It didn't get caught in my filter so I missed it. I can apply it for 4.10.

Sounds good, thanks!

> -Olof

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

* Re: [PATCH 2/3] mfd: cros_ec: add debugfs, console log file
  2016-08-23  4:34 ` [PATCH 2/3] mfd: cros_ec: add debugfs, console log file Nicolas Boichat
  2016-08-23 21:17   ` Guenter Roeck
  2016-08-31 11:45   ` Lee Jones
@ 2017-02-22 21:49   ` Doug Anderson
  2 siblings, 0 replies; 13+ messages in thread
From: Doug Anderson @ 2017-02-22 21:49 UTC (permalink / raw)
  To: Nicolas Boichat
  Cc: Lee Jones, gwendal, ejcaruso, Olof Johansson, linux-kernel,
	Guenter Roeck, Enric Balletbo i Serra, Thierry Escande,
	Benson Leung

Hi,

I'm not sure what happened to this patch, but I found it when making
sure that the bugfix pointed out in
<https://chromium-review.googlesource.com/c/444085/3/drivers/platform/chrome/cros_ec_debugfs.c#240>.
Presumably someone will want to pick it up eventually?  +Benson

On Mon, Aug 22, 2016 at 9:34 PM, Nicolas Boichat <drinkcat@chromium.org> wrote:
> +static int ec_read_version_supported(struct cros_ec_dev *ec)
> +{
> +       struct ec_params_get_cmd_versions_v1 *params;
> +       struct ec_response_get_cmd_versions *response;
> +       int ret;
> +
> +       struct cros_ec_command *msg;
> +
> +       msg = kzalloc(sizeof(*msg) + max(sizeof(params), sizeof(response)),
> +               GFP_KERNEL);
> +       if (!msg)
> +               return 0;
> +
> +       msg->command = EC_CMD_GET_CMD_VERSIONS + ec->cmd_offset;
> +       msg->outsize = sizeof(params);
> +       msg->insize = sizeof(response);

The above sizeof() calls are wrong.  They need "*"

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

end of thread, other threads:[~2017-02-22 21:49 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-23  4:34 [PATCH 0/3] mfd: cros_ec: Add debugfs directory to capture logs/panicinfo Nicolas Boichat
2016-08-23  4:34 ` [PATCH 1/3] mfd: cros_ec: Add EC console read structures definitions Nicolas Boichat
2016-08-23 21:15   ` Guenter Roeck
2016-08-31 11:45   ` Lee Jones
2016-10-13  3:24     ` Nicolas Boichat
2016-10-13 18:06       ` Olof Johansson
2016-10-13 20:32         ` Nicolas Boichat
2016-08-23  4:34 ` [PATCH 2/3] mfd: cros_ec: add debugfs, console log file Nicolas Boichat
2016-08-23 21:17   ` Guenter Roeck
2016-08-31 11:45   ` Lee Jones
2017-02-22 21:49   ` Doug Anderson
2016-08-23  4:34 ` [PATCH 3/3] mfd: cros_ec: Add support for dumping panic information Nicolas Boichat
2016-08-23 21:19   ` Guenter Roeck

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