linux/drivers/platform/chrome/cros_ec_debugfs.c
<<
>>
Prefs
   1/*
   2 * cros_ec_debugfs - debug logs for Chrome OS EC
   3 *
   4 * Copyright 2015 Google, Inc.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include <linux/circ_buf.h>
  21#include <linux/debugfs.h>
  22#include <linux/delay.h>
  23#include <linux/fs.h>
  24#include <linux/mfd/cros_ec.h>
  25#include <linux/mfd/cros_ec_commands.h>
  26#include <linux/mutex.h>
  27#include <linux/poll.h>
  28#include <linux/sched.h>
  29#include <linux/slab.h>
  30#include <linux/wait.h>
  31
  32#define LOG_SHIFT               14
  33#define LOG_SIZE                (1 << LOG_SHIFT)
  34#define LOG_POLL_SEC            10
  35
  36#define CIRC_ADD(idx, size, value)      (((idx) + (value)) & ((size) - 1))
  37
  38/* struct cros_ec_debugfs - ChromeOS EC debugging information
  39 *
  40 * @ec: EC device this debugfs information belongs to
  41 * @dir: dentry for debugfs files
  42 * @log_buffer: circular buffer for console log information
  43 * @read_msg: preallocated EC command and buffer to read console log
  44 * @log_mutex: mutex to protect circular buffer
  45 * @log_wq: waitqueue for log readers
  46 * @log_poll_work: recurring task to poll EC for new console log data
  47 * @panicinfo_blob: panicinfo debugfs blob
  48 */
  49struct cros_ec_debugfs {
  50        struct cros_ec_dev *ec;
  51        struct dentry *dir;
  52        /* EC log */
  53        struct circ_buf log_buffer;
  54        struct cros_ec_command *read_msg;
  55        struct mutex log_mutex;
  56        wait_queue_head_t log_wq;
  57        struct delayed_work log_poll_work;
  58        /* EC panicinfo */
  59        struct debugfs_blob_wrapper panicinfo_blob;
  60};
  61
  62/*
  63 * We need to make sure that the EC log buffer on the UART is large enough,
  64 * so that it is unlikely enough to overlow within LOG_POLL_SEC.
  65 */
  66static void cros_ec_console_log_work(struct work_struct *__work)
  67{
  68        struct cros_ec_debugfs *debug_info =
  69                container_of(to_delayed_work(__work),
  70                             struct cros_ec_debugfs,
  71                             log_poll_work);
  72        struct cros_ec_dev *ec = debug_info->ec;
  73        struct circ_buf *cb = &debug_info->log_buffer;
  74        struct cros_ec_command snapshot_msg = {
  75                .command = EC_CMD_CONSOLE_SNAPSHOT + ec->cmd_offset,
  76        };
  77
  78        struct ec_params_console_read_v1 *read_params =
  79                (struct ec_params_console_read_v1 *)debug_info->read_msg->data;
  80        uint8_t *ec_buffer = (uint8_t *)debug_info->read_msg->data;
  81        int idx;
  82        int buf_space;
  83        int ret;
  84
  85        ret = cros_ec_cmd_xfer(ec->ec_dev, &snapshot_msg);
  86        if (ret < 0) {
  87                dev_err(ec->dev, "EC communication failed\n");
  88                goto resched;
  89        }
  90        if (snapshot_msg.result != EC_RES_SUCCESS) {
  91                dev_err(ec->dev, "EC failed to snapshot the console log\n");
  92                goto resched;
  93        }
  94
  95        /* Loop until we have read everything, or there's an error. */
  96        mutex_lock(&debug_info->log_mutex);
  97        buf_space = CIRC_SPACE(cb->head, cb->tail, LOG_SIZE);
  98
  99        while (1) {
 100                if (!buf_space) {
 101                        dev_info_once(ec->dev,
 102                                      "Some logs may have been dropped...\n");
 103                        break;
 104                }
 105
 106                memset(read_params, '\0', sizeof(*read_params));
 107                read_params->subcmd = CONSOLE_READ_RECENT;
 108                ret = cros_ec_cmd_xfer(ec->ec_dev, debug_info->read_msg);
 109                if (ret < 0) {
 110                        dev_err(ec->dev, "EC communication failed\n");
 111                        break;
 112                }
 113                if (debug_info->read_msg->result != EC_RES_SUCCESS) {
 114                        dev_err(ec->dev,
 115                                "EC failed to read the console log\n");
 116                        break;
 117                }
 118
 119                /* If the buffer is empty, we're done here. */
 120                if (ret == 0 || ec_buffer[0] == '\0')
 121                        break;
 122
 123                idx = 0;
 124                while (idx < ret && ec_buffer[idx] != '\0' && buf_space > 0) {
 125                        cb->buf[cb->head] = ec_buffer[idx];
 126                        cb->head = CIRC_ADD(cb->head, LOG_SIZE, 1);
 127                        idx++;
 128                        buf_space--;
 129                }
 130
 131                wake_up(&debug_info->log_wq);
 132        }
 133
 134        mutex_unlock(&debug_info->log_mutex);
 135
 136resched:
 137        schedule_delayed_work(&debug_info->log_poll_work,
 138                              msecs_to_jiffies(LOG_POLL_SEC * 1000));
 139}
 140
 141static int cros_ec_console_log_open(struct inode *inode, struct file *file)
 142{
 143        file->private_data = inode->i_private;
 144
 145        return nonseekable_open(inode, file);
 146}
 147
 148static ssize_t cros_ec_console_log_read(struct file *file, char __user *buf,
 149                                        size_t count, loff_t *ppos)
 150{
 151        struct cros_ec_debugfs *debug_info = file->private_data;
 152        struct circ_buf *cb = &debug_info->log_buffer;
 153        ssize_t ret;
 154
 155        mutex_lock(&debug_info->log_mutex);
 156
 157        while (!CIRC_CNT(cb->head, cb->tail, LOG_SIZE)) {
 158                if (file->f_flags & O_NONBLOCK) {
 159                        ret = -EAGAIN;
 160                        goto error;
 161                }
 162
 163                mutex_unlock(&debug_info->log_mutex);
 164
 165                ret = wait_event_interruptible(debug_info->log_wq,
 166                                        CIRC_CNT(cb->head, cb->tail, LOG_SIZE));
 167                if (ret < 0)
 168                        return ret;
 169
 170                mutex_lock(&debug_info->log_mutex);
 171        }
 172
 173        /* Only copy until the end of the circular buffer, and let userspace
 174         * retry to get the rest of the data.
 175         */
 176        ret = min_t(size_t, CIRC_CNT_TO_END(cb->head, cb->tail, LOG_SIZE),
 177                    count);
 178
 179        if (copy_to_user(buf, cb->buf + cb->tail, ret)) {
 180                ret = -EFAULT;
 181                goto error;
 182        }
 183
 184        cb->tail = CIRC_ADD(cb->tail, LOG_SIZE, ret);
 185
 186error:
 187        mutex_unlock(&debug_info->log_mutex);
 188        return ret;
 189}
 190
 191static __poll_t cros_ec_console_log_poll(struct file *file,
 192                                             poll_table *wait)
 193{
 194        struct cros_ec_debugfs *debug_info = file->private_data;
 195        __poll_t mask = 0;
 196
 197        poll_wait(file, &debug_info->log_wq, wait);
 198
 199        mutex_lock(&debug_info->log_mutex);
 200        if (CIRC_CNT(debug_info->log_buffer.head,
 201                     debug_info->log_buffer.tail,
 202                     LOG_SIZE))
 203                mask |= EPOLLIN | EPOLLRDNORM;
 204        mutex_unlock(&debug_info->log_mutex);
 205
 206        return mask;
 207}
 208
 209static int cros_ec_console_log_release(struct inode *inode, struct file *file)
 210{
 211        return 0;
 212}
 213
 214static ssize_t cros_ec_pdinfo_read(struct file *file,
 215                                   char __user *user_buf,
 216                                   size_t count,
 217                                   loff_t *ppos)
 218{
 219        char read_buf[EC_USB_PD_MAX_PORTS * 40], *p = read_buf;
 220        struct cros_ec_debugfs *debug_info = file->private_data;
 221        struct cros_ec_device *ec_dev = debug_info->ec->ec_dev;
 222        struct {
 223                struct cros_ec_command msg;
 224                union {
 225                        struct ec_response_usb_pd_control_v1 resp;
 226                        struct ec_params_usb_pd_control params;
 227                };
 228        } __packed ec_buf;
 229        struct cros_ec_command *msg;
 230        struct ec_response_usb_pd_control_v1 *resp;
 231        struct ec_params_usb_pd_control *params;
 232        int i;
 233
 234        msg = &ec_buf.msg;
 235        params = (struct ec_params_usb_pd_control *)msg->data;
 236        resp = (struct ec_response_usb_pd_control_v1 *)msg->data;
 237
 238        msg->command = EC_CMD_USB_PD_CONTROL;
 239        msg->version = 1;
 240        msg->insize = sizeof(*resp);
 241        msg->outsize = sizeof(*params);
 242
 243        /*
 244         * Read status from all PD ports until failure, typically caused
 245         * by attempting to read status on a port that doesn't exist.
 246         */
 247        for (i = 0; i < EC_USB_PD_MAX_PORTS; ++i) {
 248                params->port = i;
 249                params->role = 0;
 250                params->mux = 0;
 251                params->swap = 0;
 252
 253                if (cros_ec_cmd_xfer_status(ec_dev, msg) < 0)
 254                        break;
 255
 256                p += scnprintf(p, sizeof(read_buf) + read_buf - p,
 257                               "p%d: %s en:%.2x role:%.2x pol:%.2x\n", i,
 258                               resp->state, resp->enabled, resp->role,
 259                               resp->polarity);
 260        }
 261
 262        return simple_read_from_buffer(user_buf, count, ppos,
 263                                       read_buf, p - read_buf);
 264}
 265
 266const struct file_operations cros_ec_console_log_fops = {
 267        .owner = THIS_MODULE,
 268        .open = cros_ec_console_log_open,
 269        .read = cros_ec_console_log_read,
 270        .llseek = no_llseek,
 271        .poll = cros_ec_console_log_poll,
 272        .release = cros_ec_console_log_release,
 273};
 274
 275const struct file_operations cros_ec_pdinfo_fops = {
 276        .owner = THIS_MODULE,
 277        .open = simple_open,
 278        .read = cros_ec_pdinfo_read,
 279        .llseek = default_llseek,
 280};
 281
 282static int ec_read_version_supported(struct cros_ec_dev *ec)
 283{
 284        struct ec_params_get_cmd_versions_v1 *params;
 285        struct ec_response_get_cmd_versions *response;
 286        int ret;
 287
 288        struct cros_ec_command *msg;
 289
 290        msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*response)),
 291                GFP_KERNEL);
 292        if (!msg)
 293                return 0;
 294
 295        msg->command = EC_CMD_GET_CMD_VERSIONS + ec->cmd_offset;
 296        msg->outsize = sizeof(*params);
 297        msg->insize = sizeof(*response);
 298
 299        params = (struct ec_params_get_cmd_versions_v1 *)msg->data;
 300        params->cmd = EC_CMD_CONSOLE_READ;
 301        response = (struct ec_response_get_cmd_versions *)msg->data;
 302
 303        ret = cros_ec_cmd_xfer(ec->ec_dev, msg) >= 0 &&
 304                msg->result == EC_RES_SUCCESS &&
 305                (response->version_mask & EC_VER_MASK(1));
 306
 307        kfree(msg);
 308
 309        return ret;
 310}
 311
 312static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info)
 313{
 314        struct cros_ec_dev *ec = debug_info->ec;
 315        char *buf;
 316        int read_params_size;
 317        int read_response_size;
 318
 319        if (!ec_read_version_supported(ec)) {
 320                dev_warn(ec->dev,
 321                        "device does not support reading the console log\n");
 322                return 0;
 323        }
 324
 325        buf = devm_kzalloc(ec->dev, LOG_SIZE, GFP_KERNEL);
 326        if (!buf)
 327                return -ENOMEM;
 328
 329        read_params_size = sizeof(struct ec_params_console_read_v1);
 330        read_response_size = ec->ec_dev->max_response;
 331        debug_info->read_msg = devm_kzalloc(ec->dev,
 332                sizeof(*debug_info->read_msg) +
 333                        max(read_params_size, read_response_size), GFP_KERNEL);
 334        if (!debug_info->read_msg)
 335                return -ENOMEM;
 336
 337        debug_info->read_msg->version = 1;
 338        debug_info->read_msg->command = EC_CMD_CONSOLE_READ + ec->cmd_offset;
 339        debug_info->read_msg->outsize = read_params_size;
 340        debug_info->read_msg->insize = read_response_size;
 341
 342        debug_info->log_buffer.buf = buf;
 343        debug_info->log_buffer.head = 0;
 344        debug_info->log_buffer.tail = 0;
 345
 346        mutex_init(&debug_info->log_mutex);
 347        init_waitqueue_head(&debug_info->log_wq);
 348
 349        if (!debugfs_create_file("console_log",
 350                                 S_IFREG | 0444,
 351                                 debug_info->dir,
 352                                 debug_info,
 353                                 &cros_ec_console_log_fops))
 354                return -ENOMEM;
 355
 356        INIT_DELAYED_WORK(&debug_info->log_poll_work,
 357                          cros_ec_console_log_work);
 358        schedule_delayed_work(&debug_info->log_poll_work, 0);
 359
 360        return 0;
 361}
 362
 363static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info)
 364{
 365        if (debug_info->log_buffer.buf) {
 366                cancel_delayed_work_sync(&debug_info->log_poll_work);
 367                mutex_destroy(&debug_info->log_mutex);
 368        }
 369}
 370
 371static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info)
 372{
 373        struct cros_ec_device *ec_dev = debug_info->ec->ec_dev;
 374        int ret;
 375        struct cros_ec_command *msg;
 376        int insize;
 377
 378        insize = ec_dev->max_response;
 379
 380        msg = devm_kzalloc(debug_info->ec->dev,
 381                        sizeof(*msg) + insize, GFP_KERNEL);
 382        if (!msg)
 383                return -ENOMEM;
 384
 385        msg->command = EC_CMD_GET_PANIC_INFO;
 386        msg->insize = insize;
 387
 388        ret = cros_ec_cmd_xfer(ec_dev, msg);
 389        if (ret < 0) {
 390                dev_warn(debug_info->ec->dev, "Cannot read panicinfo.\n");
 391                ret = 0;
 392                goto free;
 393        }
 394
 395        /* No panic data */
 396        if (ret == 0)
 397                goto free;
 398
 399        debug_info->panicinfo_blob.data = msg->data;
 400        debug_info->panicinfo_blob.size = ret;
 401
 402        if (!debugfs_create_blob("panicinfo",
 403                                 S_IFREG | 0444,
 404                                 debug_info->dir,
 405                                 &debug_info->panicinfo_blob)) {
 406                ret = -ENOMEM;
 407                goto free;
 408        }
 409
 410        return 0;
 411
 412free:
 413        devm_kfree(debug_info->ec->dev, msg);
 414        return ret;
 415}
 416
 417static int cros_ec_create_pdinfo(struct cros_ec_debugfs *debug_info)
 418{
 419        if (!debugfs_create_file("pdinfo", 0444, debug_info->dir, debug_info,
 420                                 &cros_ec_pdinfo_fops))
 421                return -ENOMEM;
 422
 423        return 0;
 424}
 425
 426int cros_ec_debugfs_init(struct cros_ec_dev *ec)
 427{
 428        struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
 429        const char *name = ec_platform->ec_name;
 430        struct cros_ec_debugfs *debug_info;
 431        int ret;
 432
 433        debug_info = devm_kzalloc(ec->dev, sizeof(*debug_info), GFP_KERNEL);
 434        if (!debug_info)
 435                return -ENOMEM;
 436
 437        debug_info->ec = ec;
 438        debug_info->dir = debugfs_create_dir(name, NULL);
 439        if (!debug_info->dir)
 440                return -ENOMEM;
 441
 442        ret = cros_ec_create_panicinfo(debug_info);
 443        if (ret)
 444                goto remove_debugfs;
 445
 446        ret = cros_ec_create_console_log(debug_info);
 447        if (ret)
 448                goto remove_debugfs;
 449
 450        ret = cros_ec_create_pdinfo(debug_info);
 451        if (ret)
 452                goto remove_debugfs;
 453
 454        ec->debug_info = debug_info;
 455
 456        return 0;
 457
 458remove_debugfs:
 459        debugfs_remove_recursive(debug_info->dir);
 460        return ret;
 461}
 462EXPORT_SYMBOL(cros_ec_debugfs_init);
 463
 464void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
 465{
 466        if (!ec->debug_info)
 467                return;
 468
 469        debugfs_remove_recursive(ec->debug_info->dir);
 470        cros_ec_cleanup_console_log(ec->debug_info);
 471}
 472EXPORT_SYMBOL(cros_ec_debugfs_remove);
 473