brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · 9fc0fd9 Raw
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