675 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2022, Intel Corporation. */3 4#include <linux/fs.h>5#include <linux/debugfs.h>6#include <linux/random.h>7#include <linux/vmalloc.h>8#include "ice.h"9 10static struct dentry *ice_debugfs_root;11 12/* create a define that has an extra module that doesn't really exist. this13 * is so we can add a module 'all' to easily enable/disable all the modules14 */15#define ICE_NR_FW_LOG_MODULES (ICE_AQC_FW_LOG_ID_MAX + 1)16 17/* the ordering in this array is important. it matches the ordering of the18 * values in the FW so the index is the same value as in ice_aqc_fw_logging_mod19 */20static const char * const ice_fwlog_module_string[] = {21 "general",22 "ctrl",23 "link",24 "link_topo",25 "dnl",26 "i2c",27 "sdp",28 "mdio",29 "adminq",30 "hdma",31 "lldp",32 "dcbx",33 "dcb",34 "xlr",35 "nvm",36 "auth",37 "vpd",38 "iosf",39 "parser",40 "sw",41 "scheduler",42 "txq",43 "rsvd",44 "post",45 "watchdog",46 "task_dispatch",47 "mng",48 "synce",49 "health",50 "tsdrv",51 "pfreg",52 "mdlver",53 "all",54};55 56/* the ordering in this array is important. it matches the ordering of the57 * values in the FW so the index is the same value as in ice_fwlog_level58 */59static const char * const ice_fwlog_level_string[] = {60 "none",61 "error",62 "warning",63 "normal",64 "verbose",65};66 67static const char * const ice_fwlog_log_size[] = {68 "128K",69 "256K",70 "512K",71 "1M",72 "2M",73};74 75/**76 * ice_fwlog_print_module_cfg - print current FW logging module configuration77 * @hw: pointer to the HW structure78 * @module: module to print79 * @s: the seq file to put data into80 */81static void82ice_fwlog_print_module_cfg(struct ice_hw *hw, int module, struct seq_file *s)83{84 struct ice_fwlog_cfg *cfg = &hw->fwlog_cfg;85 struct ice_fwlog_module_entry *entry;86 87 if (module != ICE_AQC_FW_LOG_ID_MAX) {88 entry = &cfg->module_entries[module];89 90 seq_printf(s, "\tModule: %s, Log Level: %s\n",91 ice_fwlog_module_string[entry->module_id],92 ice_fwlog_level_string[entry->log_level]);93 } else {94 int i;95 96 for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {97 entry = &cfg->module_entries[i];98 99 seq_printf(s, "\tModule: %s, Log Level: %s\n",100 ice_fwlog_module_string[entry->module_id],101 ice_fwlog_level_string[entry->log_level]);102 }103 }104}105 106static int ice_find_module_by_dentry(struct ice_pf *pf, struct dentry *d)107{108 int i, module;109 110 module = -1;111 /* find the module based on the dentry */112 for (i = 0; i < ICE_NR_FW_LOG_MODULES; i++) {113 if (d == pf->ice_debugfs_pf_fwlog_modules[i]) {114 module = i;115 break;116 }117 }118 119 return module;120}121 122/**123 * ice_debugfs_module_show - read from 'module' file124 * @s: the opened file125 * @v: pointer to the offset126 */127static int ice_debugfs_module_show(struct seq_file *s, void *v)128{129 const struct file *filp = s->file;130 struct dentry *dentry;131 struct ice_pf *pf;132 int module;133 134 dentry = file_dentry(filp);135 pf = s->private;136 137 module = ice_find_module_by_dentry(pf, dentry);138 if (module < 0) {139 dev_info(ice_pf_to_dev(pf), "unknown module\n");140 return -EINVAL;141 }142 143 ice_fwlog_print_module_cfg(&pf->hw, module, s);144 145 return 0;146}147 148static int ice_debugfs_module_open(struct inode *inode, struct file *filp)149{150 return single_open(filp, ice_debugfs_module_show, inode->i_private);151}152 153/**154 * ice_debugfs_module_write - write into 'module' file155 * @filp: the opened file156 * @buf: where to find the user's data157 * @count: the length of the user's data158 * @ppos: file position offset159 */160static ssize_t161ice_debugfs_module_write(struct file *filp, const char __user *buf,162 size_t count, loff_t *ppos)163{164 struct ice_pf *pf = file_inode(filp)->i_private;165 struct dentry *dentry = file_dentry(filp);166 struct device *dev = ice_pf_to_dev(pf);167 char user_val[16], *cmd_buf;168 int module, log_level, cnt;169 170 /* don't allow partial writes or invalid input */171 if (*ppos != 0 || count > 8)172 return -EINVAL;173 174 cmd_buf = memdup_user_nul(buf, count);175 if (IS_ERR(cmd_buf))176 return PTR_ERR(cmd_buf);177 178 module = ice_find_module_by_dentry(pf, dentry);179 if (module < 0) {180 dev_info(dev, "unknown module\n");181 return -EINVAL;182 }183 184 cnt = sscanf(cmd_buf, "%s", user_val);185 if (cnt != 1)186 return -EINVAL;187 188 log_level = sysfs_match_string(ice_fwlog_level_string, user_val);189 if (log_level < 0) {190 dev_info(dev, "unknown log level '%s'\n", user_val);191 return -EINVAL;192 }193 194 if (module != ICE_AQC_FW_LOG_ID_MAX) {195 ice_pf_fwlog_update_module(pf, log_level, module);196 } else {197 /* the module 'all' is a shortcut so that we can set198 * all of the modules to the same level quickly199 */200 int i;201 202 for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++)203 ice_pf_fwlog_update_module(pf, log_level, i);204 }205 206 return count;207}208 209static const struct file_operations ice_debugfs_module_fops = {210 .owner = THIS_MODULE,211 .open = ice_debugfs_module_open,212 .read = seq_read,213 .release = single_release,214 .write = ice_debugfs_module_write,215};216 217/**218 * ice_debugfs_nr_messages_read - read from 'nr_messages' file219 * @filp: the opened file220 * @buffer: where to write the data for the user to read221 * @count: the size of the user's buffer222 * @ppos: file position offset223 */224static ssize_t ice_debugfs_nr_messages_read(struct file *filp,225 char __user *buffer, size_t count,226 loff_t *ppos)227{228 struct ice_pf *pf = filp->private_data;229 struct ice_hw *hw = &pf->hw;230 char buff[32] = {};231 232 snprintf(buff, sizeof(buff), "%d\n",233 hw->fwlog_cfg.log_resolution);234 235 return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));236}237 238/**239 * ice_debugfs_nr_messages_write - write into 'nr_messages' file240 * @filp: the opened file241 * @buf: where to find the user's data242 * @count: the length of the user's data243 * @ppos: file position offset244 */245static ssize_t246ice_debugfs_nr_messages_write(struct file *filp, const char __user *buf,247 size_t count, loff_t *ppos)248{249 struct ice_pf *pf = filp->private_data;250 struct device *dev = ice_pf_to_dev(pf);251 struct ice_hw *hw = &pf->hw;252 char user_val[8], *cmd_buf;253 s16 nr_messages;254 ssize_t ret;255 256 /* don't allow partial writes or invalid input */257 if (*ppos != 0 || count > 4)258 return -EINVAL;259 260 cmd_buf = memdup_user_nul(buf, count);261 if (IS_ERR(cmd_buf))262 return PTR_ERR(cmd_buf);263 264 ret = sscanf(cmd_buf, "%s", user_val);265 if (ret != 1)266 return -EINVAL;267 268 ret = kstrtos16(user_val, 0, &nr_messages);269 if (ret)270 return ret;271 272 if (nr_messages < ICE_AQC_FW_LOG_MIN_RESOLUTION ||273 nr_messages > ICE_AQC_FW_LOG_MAX_RESOLUTION) {274 dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",275 nr_messages, ICE_AQC_FW_LOG_MIN_RESOLUTION,276 ICE_AQC_FW_LOG_MAX_RESOLUTION);277 return -EINVAL;278 }279 280 hw->fwlog_cfg.log_resolution = nr_messages;281 282 return count;283}284 285static const struct file_operations ice_debugfs_nr_messages_fops = {286 .owner = THIS_MODULE,287 .open = simple_open,288 .read = ice_debugfs_nr_messages_read,289 .write = ice_debugfs_nr_messages_write,290};291 292/**293 * ice_debugfs_enable_read - read from 'enable' file294 * @filp: the opened file295 * @buffer: where to write the data for the user to read296 * @count: the size of the user's buffer297 * @ppos: file position offset298 */299static ssize_t ice_debugfs_enable_read(struct file *filp,300 char __user *buffer, size_t count,301 loff_t *ppos)302{303 struct ice_pf *pf = filp->private_data;304 struct ice_hw *hw = &pf->hw;305 char buff[32] = {};306 307 snprintf(buff, sizeof(buff), "%u\n",308 (u16)(hw->fwlog_cfg.options &309 ICE_FWLOG_OPTION_IS_REGISTERED) >> 3);310 311 return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));312}313 314/**315 * ice_debugfs_enable_write - write into 'enable' file316 * @filp: the opened file317 * @buf: where to find the user's data318 * @count: the length of the user's data319 * @ppos: file position offset320 */321static ssize_t322ice_debugfs_enable_write(struct file *filp, const char __user *buf,323 size_t count, loff_t *ppos)324{325 struct ice_pf *pf = filp->private_data;326 struct ice_hw *hw = &pf->hw;327 char user_val[8], *cmd_buf;328 bool enable;329 ssize_t ret;330 331 /* don't allow partial writes or invalid input */332 if (*ppos != 0 || count > 2)333 return -EINVAL;334 335 cmd_buf = memdup_user_nul(buf, count);336 if (IS_ERR(cmd_buf))337 return PTR_ERR(cmd_buf);338 339 ret = sscanf(cmd_buf, "%s", user_val);340 if (ret != 1)341 return -EINVAL;342 343 ret = kstrtobool(user_val, &enable);344 if (ret)345 goto enable_write_error;346 347 if (enable)348 hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_ARQ_ENA;349 else350 hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA;351 352 ret = ice_fwlog_set(hw, &hw->fwlog_cfg);353 if (ret)354 goto enable_write_error;355 356 if (enable)357 ret = ice_fwlog_register(hw);358 else359 ret = ice_fwlog_unregister(hw);360 361 if (ret)362 goto enable_write_error;363 364 /* if we get here, nothing went wrong; return count since we didn't365 * really write anything366 */367 ret = (ssize_t)count;368 369enable_write_error:370 /* This function always consumes all of the written input, or produces371 * an error. Check and enforce this. Otherwise, the write operation372 * won't complete properly.373 */374 if (WARN_ON(ret != (ssize_t)count && ret >= 0))375 ret = -EIO;376 377 return ret;378}379 380static const struct file_operations ice_debugfs_enable_fops = {381 .owner = THIS_MODULE,382 .open = simple_open,383 .read = ice_debugfs_enable_read,384 .write = ice_debugfs_enable_write,385};386 387/**388 * ice_debugfs_log_size_read - read from 'log_size' file389 * @filp: the opened file390 * @buffer: where to write the data for the user to read391 * @count: the size of the user's buffer392 * @ppos: file position offset393 */394static ssize_t ice_debugfs_log_size_read(struct file *filp,395 char __user *buffer, size_t count,396 loff_t *ppos)397{398 struct ice_pf *pf = filp->private_data;399 struct ice_hw *hw = &pf->hw;400 char buff[32] = {};401 int index;402 403 index = hw->fwlog_ring.index;404 snprintf(buff, sizeof(buff), "%s\n", ice_fwlog_log_size[index]);405 406 return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));407}408 409/**410 * ice_debugfs_log_size_write - write into 'log_size' file411 * @filp: the opened file412 * @buf: where to find the user's data413 * @count: the length of the user's data414 * @ppos: file position offset415 */416static ssize_t417ice_debugfs_log_size_write(struct file *filp, const char __user *buf,418 size_t count, loff_t *ppos)419{420 struct ice_pf *pf = filp->private_data;421 struct device *dev = ice_pf_to_dev(pf);422 struct ice_hw *hw = &pf->hw;423 char user_val[8], *cmd_buf;424 ssize_t ret;425 int index;426 427 /* don't allow partial writes or invalid input */428 if (*ppos != 0 || count > 5)429 return -EINVAL;430 431 cmd_buf = memdup_user_nul(buf, count);432 if (IS_ERR(cmd_buf))433 return PTR_ERR(cmd_buf);434 435 ret = sscanf(cmd_buf, "%s", user_val);436 if (ret != 1)437 return -EINVAL;438 439 index = sysfs_match_string(ice_fwlog_log_size, user_val);440 if (index < 0) {441 dev_info(dev, "Invalid log size '%s'. The value must be one of 128K, 256K, 512K, 1M, 2M\n",442 user_val);443 ret = -EINVAL;444 goto log_size_write_error;445 } else if (hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED) {446 dev_info(dev, "FW logging is currently running. Please disable FW logging to change log_size\n");447 ret = -EINVAL;448 goto log_size_write_error;449 }450 451 /* free all the buffers and the tracking info and resize */452 ice_fwlog_realloc_rings(hw, index);453 454 /* if we get here, nothing went wrong; return count since we didn't455 * really write anything456 */457 ret = (ssize_t)count;458 459log_size_write_error:460 /* This function always consumes all of the written input, or produces461 * an error. Check and enforce this. Otherwise, the write operation462 * won't complete properly.463 */464 if (WARN_ON(ret != (ssize_t)count && ret >= 0))465 ret = -EIO;466 467 return ret;468}469 470static const struct file_operations ice_debugfs_log_size_fops = {471 .owner = THIS_MODULE,472 .open = simple_open,473 .read = ice_debugfs_log_size_read,474 .write = ice_debugfs_log_size_write,475};476 477/**478 * ice_debugfs_data_read - read from 'data' file479 * @filp: the opened file480 * @buffer: where to write the data for the user to read481 * @count: the size of the user's buffer482 * @ppos: file position offset483 */484static ssize_t ice_debugfs_data_read(struct file *filp, char __user *buffer,485 size_t count, loff_t *ppos)486{487 struct ice_pf *pf = filp->private_data;488 struct ice_hw *hw = &pf->hw;489 int data_copied = 0;490 bool done = false;491 492 if (ice_fwlog_ring_empty(&hw->fwlog_ring))493 return 0;494 495 while (!ice_fwlog_ring_empty(&hw->fwlog_ring) && !done) {496 struct ice_fwlog_data *log;497 u16 cur_buf_len;498 499 log = &hw->fwlog_ring.rings[hw->fwlog_ring.head];500 cur_buf_len = log->data_size;501 if (cur_buf_len >= count) {502 done = true;503 continue;504 }505 506 if (copy_to_user(buffer, log->data, cur_buf_len)) {507 /* if there is an error then bail and return whatever508 * the driver has copied so far509 */510 done = true;511 continue;512 }513 514 data_copied += cur_buf_len;515 buffer += cur_buf_len;516 count -= cur_buf_len;517 *ppos += cur_buf_len;518 ice_fwlog_ring_increment(&hw->fwlog_ring.head,519 hw->fwlog_ring.size);520 }521 522 return data_copied;523}524 525/**526 * ice_debugfs_data_write - write into 'data' file527 * @filp: the opened file528 * @buf: where to find the user's data529 * @count: the length of the user's data530 * @ppos: file position offset531 */532static ssize_t533ice_debugfs_data_write(struct file *filp, const char __user *buf, size_t count,534 loff_t *ppos)535{536 struct ice_pf *pf = filp->private_data;537 struct device *dev = ice_pf_to_dev(pf);538 struct ice_hw *hw = &pf->hw;539 ssize_t ret;540 541 /* don't allow partial writes */542 if (*ppos != 0)543 return 0;544 545 /* any value is allowed to clear the buffer so no need to even look at546 * what the value is547 */548 if (!(hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED)) {549 hw->fwlog_ring.head = 0;550 hw->fwlog_ring.tail = 0;551 } else {552 dev_info(dev, "Can't clear FW log data while FW log running\n");553 ret = -EINVAL;554 goto nr_buffs_write_error;555 }556 557 /* if we get here, nothing went wrong; return count since we didn't558 * really write anything559 */560 ret = (ssize_t)count;561 562nr_buffs_write_error:563 /* This function always consumes all of the written input, or produces564 * an error. Check and enforce this. Otherwise, the write operation565 * won't complete properly.566 */567 if (WARN_ON(ret != (ssize_t)count && ret >= 0))568 ret = -EIO;569 570 return ret;571}572 573static const struct file_operations ice_debugfs_data_fops = {574 .owner = THIS_MODULE,575 .open = simple_open,576 .read = ice_debugfs_data_read,577 .write = ice_debugfs_data_write,578};579 580/**581 * ice_debugfs_fwlog_init - setup the debugfs directory582 * @pf: the ice that is starting up583 */584void ice_debugfs_fwlog_init(struct ice_pf *pf)585{586 const char *name = pci_name(pf->pdev);587 struct dentry *fw_modules_dir;588 struct dentry **fw_modules;589 int i;590 591 /* only support fw log commands on PF 0 */592 if (pf->hw.bus.func)593 return;594 595 /* allocate space for this first because if it fails then we don't596 * need to unwind597 */598 fw_modules = kcalloc(ICE_NR_FW_LOG_MODULES, sizeof(*fw_modules),599 GFP_KERNEL);600 if (!fw_modules)601 return;602 603 pf->ice_debugfs_pf = debugfs_create_dir(name, ice_debugfs_root);604 if (IS_ERR(pf->ice_debugfs_pf))605 goto err_create_module_files;606 607 pf->ice_debugfs_pf_fwlog = debugfs_create_dir("fwlog",608 pf->ice_debugfs_pf);609 if (IS_ERR(pf->ice_debugfs_pf))610 goto err_create_module_files;611 612 fw_modules_dir = debugfs_create_dir("modules",613 pf->ice_debugfs_pf_fwlog);614 if (IS_ERR(fw_modules_dir))615 goto err_create_module_files;616 617 for (i = 0; i < ICE_NR_FW_LOG_MODULES; i++) {618 fw_modules[i] = debugfs_create_file(ice_fwlog_module_string[i],619 0600, fw_modules_dir, pf,620 &ice_debugfs_module_fops);621 if (IS_ERR(fw_modules[i]))622 goto err_create_module_files;623 }624 625 debugfs_create_file("nr_messages", 0600,626 pf->ice_debugfs_pf_fwlog, pf,627 &ice_debugfs_nr_messages_fops);628 629 pf->ice_debugfs_pf_fwlog_modules = fw_modules;630 631 debugfs_create_file("enable", 0600, pf->ice_debugfs_pf_fwlog,632 pf, &ice_debugfs_enable_fops);633 634 debugfs_create_file("log_size", 0600, pf->ice_debugfs_pf_fwlog,635 pf, &ice_debugfs_log_size_fops);636 637 debugfs_create_file("data", 0600, pf->ice_debugfs_pf_fwlog,638 pf, &ice_debugfs_data_fops);639 640 return;641 642err_create_module_files:643 debugfs_remove_recursive(pf->ice_debugfs_pf_fwlog);644 kfree(fw_modules);645}646 647/**648 * ice_debugfs_pf_deinit - cleanup PF's debugfs649 * @pf: pointer to the PF struct650 */651void ice_debugfs_pf_deinit(struct ice_pf *pf)652{653 debugfs_remove_recursive(pf->ice_debugfs_pf);654 pf->ice_debugfs_pf = NULL;655}656 657/**658 * ice_debugfs_init - create root directory for debugfs entries659 */660void ice_debugfs_init(void)661{662 ice_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);663 if (IS_ERR(ice_debugfs_root))664 pr_info("init of debugfs failed\n");665}666 667/**668 * ice_debugfs_exit - remove debugfs entries669 */670void ice_debugfs_exit(void)671{672 debugfs_remove_recursive(ice_debugfs_root);673 ice_debugfs_root = NULL;674}675