File Index
Files and directories
Sign in
FILE

fwlog.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/intel/libie/fwlog.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c) 2022, Intel Corporation. */
   3
   4#include <linux/debugfs.h>
   5#include <linux/export.h>
   6#include <linux/fs.h>
   7#include <linux/net/intel/libie/fwlog.h>
   8#include <linux/pci.h>
   9#include <linux/random.h>
  10#include <linux/vmalloc.h>
  11
  12#define DEFAULT_SYMBOL_NAMESPACE	"LIBIE_FWLOG"
  13
  14/* create a define that has an extra module that doesn't really exist. this
  15 * is so we can add a module 'all' to easily enable/disable all the modules
  16 */
  17#define LIBIE_NR_FW_LOG_MODULES (LIBIE_AQC_FW_LOG_ID_MAX + 1)
  18
  19/* the ordering in this array is important. it matches the ordering of the
  20 * values in the FW so the index is the same value as in
  21 * libie_aqc_fw_logging_mod
  22 */
  23static const char * const libie_fwlog_module_string[] = {
  24	"general",
  25	"ctrl",
  26	"link",
  27	"link_topo",
  28	"dnl",
  29	"i2c",
  30	"sdp",
  31	"mdio",
  32	"adminq",
  33	"hdma",
  34	"lldp",
  35	"dcbx",
  36	"dcb",
  37	"xlr",
  38	"nvm",
  39	"auth",
  40	"vpd",
  41	"iosf",
  42	"parser",
  43	"sw",
  44	"scheduler",
  45	"txq",
  46	"rsvd",
  47	"post",
  48	"watchdog",
  49	"task_dispatch",
  50	"mng",
  51	"synce",
  52	"health",
  53	"tsdrv",
  54	"pfreg",
  55	"mdlver",
  56	"all",
  57};
  58
  59/* the ordering in this array is important. it matches the ordering of the
  60 * values in the FW so the index is the same value as in libie_fwlog_level
  61 */
  62static const char * const libie_fwlog_level_string[] = {
  63	"none",
  64	"error",
  65	"warning",
  66	"normal",
  67	"verbose",
  68};
  69
  70static const char * const libie_fwlog_log_size[] = {
  71	"128K",
  72	"256K",
  73	"512K",
  74	"1M",
  75	"2M",
  76};
  77
  78static bool libie_fwlog_ring_empty(struct libie_fwlog_ring *rings)
  79{
  80	return rings->head == rings->tail;
  81}
  82
  83static void libie_fwlog_ring_increment(u16 *item, u16 size)
  84{
  85	*item = (*item + 1) & (size - 1);
  86}
  87
  88static int libie_fwlog_alloc_ring_buffs(struct libie_fwlog_ring *rings)
  89{
  90	int i, nr_bytes;
  91	u8 *mem;
  92
  93	nr_bytes = rings->size * LIBIE_AQ_MAX_BUF_LEN;
  94	mem = vzalloc(nr_bytes);
  95	if (!mem)
  96		return -ENOMEM;
  97
  98	for (i = 0; i < rings->size; i++) {
  99		struct libie_fwlog_data *ring = &rings->rings[i];
 100
 101		ring->data_size = LIBIE_AQ_MAX_BUF_LEN;
 102		ring->data = mem;
 103		mem += LIBIE_AQ_MAX_BUF_LEN;
 104	}
 105
 106	return 0;
 107}
 108
 109static void libie_fwlog_free_ring_buffs(struct libie_fwlog_ring *rings)
 110{
 111	int i;
 112
 113	for (i = 0; i < rings->size; i++) {
 114		struct libie_fwlog_data *ring = &rings->rings[i];
 115
 116		/* the first ring is the base memory for the whole range so
 117		 * free it
 118		 */
 119		if (!i)
 120			vfree(ring->data);
 121
 122		ring->data = NULL;
 123		ring->data_size = 0;
 124	}
 125}
 126
 127#define LIBIE_FWLOG_INDEX_TO_BYTES(n) ((128 * 1024) << (n))
 128/**
 129 * libie_fwlog_realloc_rings - reallocate the FW log rings
 130 * @fwlog: pointer to the fwlog structure
 131 * @index: the new index to use to allocate memory for the log data
 132 *
 133 */
 134static void libie_fwlog_realloc_rings(struct libie_fwlog *fwlog, int index)
 135{
 136	struct libie_fwlog_ring ring;
 137	int status, ring_size;
 138
 139	/* convert the number of bytes into a number of 4K buffers. externally
 140	 * the driver presents the interface to the FW log data as a number of
 141	 * bytes because that's easy for users to understand. internally the
 142	 * driver uses a ring of buffers because the driver doesn't know where
 143	 * the beginning and end of any line of log data is so the driver has
 144	 * to overwrite data as complete blocks. when the data is returned to
 145	 * the user the driver knows that the data is correct and the FW log
 146	 * can be correctly parsed by the tools
 147	 */
 148	ring_size = LIBIE_FWLOG_INDEX_TO_BYTES(index) / LIBIE_AQ_MAX_BUF_LEN;
 149	if (ring_size == fwlog->ring.size)
 150		return;
 151
 152	/* allocate space for the new rings and buffers then release the
 153	 * old rings and buffers. that way if we don't have enough
 154	 * memory then we at least have what we had before
 155	 */
 156	ring.rings = kcalloc(ring_size, sizeof(*ring.rings), GFP_KERNEL);
 157	if (!ring.rings)
 158		return;
 159
 160	ring.size = ring_size;
 161
 162	status = libie_fwlog_alloc_ring_buffs(&ring);
 163	if (status) {
 164		dev_warn(&fwlog->pdev->dev, "Unable to allocate memory for FW log ring data buffers\n");
 165		libie_fwlog_free_ring_buffs(&ring);
 166		kfree(ring.rings);
 167		return;
 168	}
 169
 170	libie_fwlog_free_ring_buffs(&fwlog->ring);
 171	kfree(fwlog->ring.rings);
 172
 173	fwlog->ring.rings = ring.rings;
 174	fwlog->ring.size = ring.size;
 175	fwlog->ring.index = index;
 176	fwlog->ring.head = 0;
 177	fwlog->ring.tail = 0;
 178}
 179
 180/**
 181 * libie_fwlog_supported - Cached for whether FW supports FW logging or not
 182 * @fwlog: pointer to the fwlog structure
 183 *
 184 * This will always return false if called before libie_init_hw(), so it must be
 185 * called after libie_init_hw().
 186 */
 187static bool libie_fwlog_supported(struct libie_fwlog *fwlog)
 188{
 189	return fwlog->supported;
 190}
 191
 192/**
 193 * libie_aq_fwlog_set - Set FW logging configuration AQ command (0xFF30)
 194 * @fwlog: pointer to the fwlog structure
 195 * @entries: entries to configure
 196 * @num_entries: number of @entries
 197 * @options: options from libie_fwlog_cfg->options structure
 198 * @log_resolution: logging resolution
 199 */
 200static int
 201libie_aq_fwlog_set(struct libie_fwlog *fwlog,
 202		   struct libie_fwlog_module_entry *entries, u16 num_entries,
 203		   u16 options, u16 log_resolution)
 204{
 205	struct libie_aqc_fw_log_cfg_resp *fw_modules;
 206	struct libie_aq_desc desc = {0};
 207	struct libie_aqc_fw_log *cmd;
 208	int status;
 209	int i;
 210
 211	fw_modules = kcalloc(num_entries, sizeof(*fw_modules), GFP_KERNEL);
 212	if (!fw_modules)
 213		return -ENOMEM;
 214
 215	for (i = 0; i < num_entries; i++) {
 216		fw_modules[i].module_identifier =
 217			cpu_to_le16(entries[i].module_id);
 218		fw_modules[i].log_level = entries[i].log_level;
 219	}
 220
 221	desc.opcode = cpu_to_le16(libie_aqc_opc_fw_logs_config);
 222	desc.flags = cpu_to_le16(LIBIE_AQ_FLAG_SI) |
 223		     cpu_to_le16(LIBIE_AQ_FLAG_RD);
 224
 225	cmd = libie_aq_raw(&desc);
 226
 227	cmd->cmd_flags = LIBIE_AQC_FW_LOG_CONF_SET_VALID;
 228	cmd->ops.cfg.log_resolution = cpu_to_le16(log_resolution);
 229	cmd->ops.cfg.mdl_cnt = cpu_to_le16(num_entries);
 230
 231	if (options & LIBIE_FWLOG_OPTION_ARQ_ENA)
 232		cmd->cmd_flags |= LIBIE_AQC_FW_LOG_CONF_AQ_EN;
 233	if (options & LIBIE_FWLOG_OPTION_UART_ENA)
 234		cmd->cmd_flags |= LIBIE_AQC_FW_LOG_CONF_UART_EN;
 235
 236	status = fwlog->send_cmd(fwlog->priv, &desc, fw_modules,
 237				 sizeof(*fw_modules) * num_entries);
 238
 239	kfree(fw_modules);
 240
 241	return status;
 242}
 243
 244/**
 245 * libie_fwlog_set - Set the firmware logging settings
 246 * @fwlog: pointer to the fwlog structure
 247 * @cfg: config used to set firmware logging
 248 *
 249 * This function should be called whenever the driver needs to set the firmware
 250 * logging configuration. It can be called on initialization, reset, or during
 251 * runtime.
 252 *
 253 * If the PF wishes to receive FW logging then it must register via
 254 * libie_fwlog_register. Note, that libie_fwlog_register does not need to be called
 255 * for init.
 256 */
 257static int libie_fwlog_set(struct libie_fwlog *fwlog,
 258			   struct libie_fwlog_cfg *cfg)
 259{
 260	if (!libie_fwlog_supported(fwlog))
 261		return -EOPNOTSUPP;
 262
 263	return libie_aq_fwlog_set(fwlog, cfg->module_entries,
 264				LIBIE_AQC_FW_LOG_ID_MAX, cfg->options,
 265				cfg->log_resolution);
 266}
 267
 268/**
 269 * libie_aq_fwlog_register - Register PF for firmware logging events (0xFF31)
 270 * @fwlog: pointer to the fwlog structure
 271 * @reg: true to register and false to unregister
 272 */
 273static int libie_aq_fwlog_register(struct libie_fwlog *fwlog, bool reg)
 274{
 275	struct libie_aq_desc desc = {0};
 276	struct libie_aqc_fw_log *cmd;
 277
 278	desc.opcode = cpu_to_le16(libie_aqc_opc_fw_logs_register);
 279	desc.flags = cpu_to_le16(LIBIE_AQ_FLAG_SI);
 280	cmd = libie_aq_raw(&desc);
 281
 282	if (reg)
 283		cmd->cmd_flags = LIBIE_AQC_FW_LOG_AQ_REGISTER;
 284
 285	return fwlog->send_cmd(fwlog->priv, &desc, NULL, 0);
 286}
 287
 288/**
 289 * libie_fwlog_register - Register the PF for firmware logging
 290 * @fwlog: pointer to the fwlog structure
 291 *
 292 * After this call the PF will start to receive firmware logging based on the
 293 * configuration set in libie_fwlog_set.
 294 */
 295static int libie_fwlog_register(struct libie_fwlog *fwlog)
 296{
 297	int status;
 298
 299	if (!libie_fwlog_supported(fwlog))
 300		return -EOPNOTSUPP;
 301
 302	status = libie_aq_fwlog_register(fwlog, true);
 303	if (status)
 304		dev_dbg(&fwlog->pdev->dev, "Failed to register for firmware logging events over ARQ\n");
 305	else
 306		fwlog->cfg.options |= LIBIE_FWLOG_OPTION_IS_REGISTERED;
 307
 308	return status;
 309}
 310
 311/**
 312 * libie_fwlog_unregister - Unregister the PF from firmware logging
 313 * @fwlog: pointer to the fwlog structure
 314 */
 315static int libie_fwlog_unregister(struct libie_fwlog *fwlog)
 316{
 317	int status;
 318
 319	if (!libie_fwlog_supported(fwlog))
 320		return -EOPNOTSUPP;
 321
 322	status = libie_aq_fwlog_register(fwlog, false);
 323	if (status)
 324		dev_dbg(&fwlog->pdev->dev, "Failed to unregister from firmware logging events over ARQ\n");
 325	else
 326		fwlog->cfg.options &= ~LIBIE_FWLOG_OPTION_IS_REGISTERED;
 327
 328	return status;
 329}
 330
 331/**
 332 * libie_fwlog_print_module_cfg - print current FW logging module configuration
 333 * @cfg: pointer to the fwlog cfg structure
 334 * @module: module to print
 335 * @s: the seq file to put data into
 336 */
 337static void
 338libie_fwlog_print_module_cfg(struct libie_fwlog_cfg *cfg, int module,
 339			     struct seq_file *s)
 340{
 341	struct libie_fwlog_module_entry *entry;
 342
 343	if (module != LIBIE_AQC_FW_LOG_ID_MAX) {
 344		entry =	&cfg->module_entries[module];
 345
 346		seq_printf(s, "\tModule: %s, Log Level: %s\n",
 347			   libie_fwlog_module_string[entry->module_id],
 348			   libie_fwlog_level_string[entry->log_level]);
 349	} else {
 350		int i;
 351
 352		for (i = 0; i < LIBIE_AQC_FW_LOG_ID_MAX; i++) {
 353			entry =	&cfg->module_entries[i];
 354
 355			seq_printf(s, "\tModule: %s, Log Level: %s\n",
 356				   libie_fwlog_module_string[entry->module_id],
 357				   libie_fwlog_level_string[entry->log_level]);
 358		}
 359	}
 360}
 361
 362static int libie_find_module_by_dentry(struct dentry **modules, struct dentry *d)
 363{
 364	int i, module;
 365
 366	module = -1;
 367	/* find the module based on the dentry */
 368	for (i = 0; i < LIBIE_NR_FW_LOG_MODULES; i++) {
 369		if (d == modules[i]) {
 370			module = i;
 371			break;
 372		}
 373	}
 374
 375	return module;
 376}
 377
 378/**
 379 * libie_debugfs_module_show - read from 'module' file
 380 * @s: the opened file
 381 * @v: pointer to the offset
 382 */
 383static int libie_debugfs_module_show(struct seq_file *s, void *v)
 384{
 385	struct libie_fwlog *fwlog = s->private;
 386	const struct file *filp = s->file;
 387	struct dentry *dentry;
 388	int module;
 389
 390	dentry = file_dentry(filp);
 391
 392	module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
 393	if (module < 0) {
 394		dev_info(&fwlog->pdev->dev, "unknown module\n");
 395		return -EINVAL;
 396	}
 397
 398	libie_fwlog_print_module_cfg(&fwlog->cfg, module, s);
 399
 400	return 0;
 401}
 402
 403static int libie_debugfs_module_open(struct inode *inode, struct file *filp)
 404{
 405	return single_open(filp, libie_debugfs_module_show, inode->i_private);
 406}
 407
 408/**
 409 * libie_debugfs_module_write - write into 'module' file
 410 * @filp: the opened file
 411 * @buf: where to find the user's data
 412 * @count: the length of the user's data
 413 * @ppos: file position offset
 414 */
 415static ssize_t
 416libie_debugfs_module_write(struct file *filp, const char __user *buf,
 417			   size_t count, loff_t *ppos)
 418{
 419	struct libie_fwlog *fwlog = file_inode(filp)->i_private;
 420	struct dentry *dentry = file_dentry(filp);
 421	struct device *dev = &fwlog->pdev->dev;
 422	char user_val[16], *cmd_buf;
 423	int module, log_level, cnt;
 424
 425	/* don't allow partial writes or invalid input */
 426	if (*ppos != 0 || count > 8)
 427		return -EINVAL;
 428
 429	cmd_buf = memdup_user_nul(buf, count);
 430	if (IS_ERR(cmd_buf))
 431		return PTR_ERR(cmd_buf);
 432
 433	module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
 434	if (module < 0) {
 435		dev_info(dev, "unknown module\n");
 436		count = -EINVAL;
 437		goto free_cmd_buf;
 438	}
 439
 440	cnt = sscanf(cmd_buf, "%s", user_val);
 441	if (cnt != 1) {
 442		count = -EINVAL;
 443		goto free_cmd_buf;
 444	}
 445
 446	log_level = sysfs_match_string(libie_fwlog_level_string, user_val);
 447	if (log_level < 0) {
 448		dev_info(dev, "unknown log level '%s'\n", user_val);
 449		count = -EINVAL;
 450		goto free_cmd_buf;
 451	}
 452
 453	if (module != LIBIE_AQC_FW_LOG_ID_MAX) {
 454		fwlog->cfg.module_entries[module].log_level = log_level;
 455	} else {
 456		/* the module 'all' is a shortcut so that we can set
 457		 * all of the modules to the same level quickly
 458		 */
 459		int i;
 460
 461		for (i = 0; i < LIBIE_AQC_FW_LOG_ID_MAX; i++)
 462			fwlog->cfg.module_entries[i].log_level = log_level;
 463	}
 464
 465free_cmd_buf:
 466	kfree(cmd_buf);
 467
 468	return count;
 469}
 470
 471static const struct file_operations libie_debugfs_module_fops = {
 472	.owner = THIS_MODULE,
 473	.open  = libie_debugfs_module_open,
 474	.read = seq_read,
 475	.release = single_release,
 476	.write = libie_debugfs_module_write,
 477};
 478
 479/**
 480 * libie_debugfs_nr_messages_read - read from 'nr_messages' file
 481 * @filp: the opened file
 482 * @buffer: where to write the data for the user to read
 483 * @count: the size of the user's buffer
 484 * @ppos: file position offset
 485 */
 486static ssize_t libie_debugfs_nr_messages_read(struct file *filp,
 487					      char __user *buffer, size_t count,
 488					      loff_t *ppos)
 489{
 490	struct libie_fwlog *fwlog = filp->private_data;
 491	char buff[32] = {};
 492
 493	snprintf(buff, sizeof(buff), "%d\n",
 494		 fwlog->cfg.log_resolution);
 495
 496	return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
 497}
 498
 499/**
 500 * libie_debugfs_nr_messages_write - write into 'nr_messages' file
 501 * @filp: the opened file
 502 * @buf: where to find the user's data
 503 * @count: the length of the user's data
 504 * @ppos: file position offset
 505 */
 506static ssize_t
 507libie_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
 508				size_t count, loff_t *ppos)
 509{
 510	struct libie_fwlog *fwlog = filp->private_data;
 511	struct device *dev = &fwlog->pdev->dev;
 512	char user_val[8], *cmd_buf;
 513	s16 nr_messages;
 514	ssize_t ret;
 515
 516	/* don't allow partial writes or invalid input */
 517	if (*ppos != 0 || count > 4)
 518		return -EINVAL;
 519
 520	cmd_buf = memdup_user_nul(buf, count);
 521	if (IS_ERR(cmd_buf))
 522		return PTR_ERR(cmd_buf);
 523
 524	ret = sscanf(cmd_buf, "%s", user_val);
 525	if (ret != 1) {
 526		count = -EINVAL;
 527		goto free_cmd_buf;
 528	}
 529
 530	ret = kstrtos16(user_val, 0, &nr_messages);
 531	if (ret) {
 532		count = ret;
 533		goto free_cmd_buf;
 534	}
 535
 536	if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION ||
 537	    nr_messages > LIBIE_AQC_FW_LOG_MAX_RESOLUTION) {
 538		dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",
 539			nr_messages, LIBIE_AQC_FW_LOG_MIN_RESOLUTION,
 540			LIBIE_AQC_FW_LOG_MAX_RESOLUTION);
 541		count = -EINVAL;
 542		goto free_cmd_buf;
 543	}
 544
 545	fwlog->cfg.log_resolution = nr_messages;
 546
 547free_cmd_buf:
 548	kfree(cmd_buf);
 549
 550	return count;
 551}
 552
 553static const struct file_operations libie_debugfs_nr_messages_fops = {
 554	.owner = THIS_MODULE,
 555	.open  = simple_open,
 556	.read = libie_debugfs_nr_messages_read,
 557	.write = libie_debugfs_nr_messages_write,
 558};
 559
 560/**
 561 * libie_debugfs_enable_read - read from 'enable' file
 562 * @filp: the opened file
 563 * @buffer: where to write the data for the user to read
 564 * @count: the size of the user's buffer
 565 * @ppos: file position offset
 566 */
 567static ssize_t libie_debugfs_enable_read(struct file *filp,
 568					 char __user *buffer, size_t count,
 569					 loff_t *ppos)
 570{
 571	struct libie_fwlog *fwlog = filp->private_data;
 572	char buff[32] = {};
 573
 574	snprintf(buff, sizeof(buff), "%u\n",
 575		 (u16)(fwlog->cfg.options &
 576		 LIBIE_FWLOG_OPTION_IS_REGISTERED) >> 3);
 577
 578	return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
 579}
 580
 581/**
 582 * libie_debugfs_enable_write - write into 'enable' file
 583 * @filp: the opened file
 584 * @buf: where to find the user's data
 585 * @count: the length of the user's data
 586 * @ppos: file position offset
 587 */
 588static ssize_t
 589libie_debugfs_enable_write(struct file *filp, const char __user *buf,
 590			   size_t count, loff_t *ppos)
 591{
 592	struct libie_fwlog *fwlog = filp->private_data;
 593	char user_val[8], *cmd_buf;
 594	bool enable;
 595	ssize_t ret;
 596
 597	/* don't allow partial writes or invalid input */
 598	if (*ppos != 0 || count > 2)
 599		return -EINVAL;
 600
 601	cmd_buf = memdup_user_nul(buf, count);
 602	if (IS_ERR(cmd_buf))
 603		return PTR_ERR(cmd_buf);
 604
 605	ret = sscanf(cmd_buf, "%s", user_val);
 606	if (ret != 1) {
 607		ret = -EINVAL;
 608		goto free_cmd_buf;
 609	}
 610
 611	ret = kstrtobool(user_val, &enable);
 612	if (ret)
 613		goto enable_write_error;
 614
 615	if (enable)
 616		fwlog->cfg.options |= LIBIE_FWLOG_OPTION_ARQ_ENA;
 617	else
 618		fwlog->cfg.options &= ~LIBIE_FWLOG_OPTION_ARQ_ENA;
 619
 620	ret = libie_fwlog_set(fwlog, &fwlog->cfg);
 621	if (ret)
 622		goto enable_write_error;
 623
 624	if (enable)
 625		ret = libie_fwlog_register(fwlog);
 626	else
 627		ret = libie_fwlog_unregister(fwlog);
 628
 629	if (ret)
 630		goto enable_write_error;
 631
 632	/* if we get here, nothing went wrong; return count since we didn't
 633	 * really write anything
 634	 */
 635	ret = (ssize_t)count;
 636
 637enable_write_error:
 638	/* This function always consumes all of the written input, or produces
 639	 * an error. Check and enforce this. Otherwise, the write operation
 640	 * won't complete properly.
 641	 */
 642	if (WARN_ON(ret != (ssize_t)count && ret >= 0))
 643		ret = -EIO;
 644free_cmd_buf:
 645	kfree(cmd_buf);
 646
 647	return ret;
 648}
 649
 650static const struct file_operations libie_debugfs_enable_fops = {
 651	.owner = THIS_MODULE,
 652	.open  = simple_open,
 653	.read = libie_debugfs_enable_read,
 654	.write = libie_debugfs_enable_write,
 655};
 656
 657/**
 658 * libie_debugfs_log_size_read - read from 'log_size' file
 659 * @filp: the opened file
 660 * @buffer: where to write the data for the user to read
 661 * @count: the size of the user's buffer
 662 * @ppos: file position offset
 663 */
 664static ssize_t libie_debugfs_log_size_read(struct file *filp,
 665					   char __user *buffer, size_t count,
 666					   loff_t *ppos)
 667{
 668	struct libie_fwlog *fwlog = filp->private_data;
 669	char buff[32] = {};
 670	int index;
 671
 672	index = fwlog->ring.index;
 673	snprintf(buff, sizeof(buff), "%s\n", libie_fwlog_log_size[index]);
 674
 675	return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
 676}
 677
 678/**
 679 * libie_debugfs_log_size_write - write into 'log_size' file
 680 * @filp: the opened file
 681 * @buf: where to find the user's data
 682 * @count: the length of the user's data
 683 * @ppos: file position offset
 684 */
 685static ssize_t
 686libie_debugfs_log_size_write(struct file *filp, const char __user *buf,
 687			     size_t count, loff_t *ppos)
 688{
 689	struct libie_fwlog *fwlog = filp->private_data;
 690	struct device *dev = &fwlog->pdev->dev;
 691	char user_val[8], *cmd_buf;
 692	ssize_t ret;
 693	int index;
 694
 695	/* don't allow partial writes or invalid input */
 696	if (*ppos != 0 || count > 5)
 697		return -EINVAL;
 698
 699	cmd_buf = memdup_user_nul(buf, count);
 700	if (IS_ERR(cmd_buf))
 701		return PTR_ERR(cmd_buf);
 702
 703	ret = sscanf(cmd_buf, "%s", user_val);
 704	if (ret != 1) {
 705		ret = -EINVAL;
 706		goto free_cmd_buf;
 707	}
 708
 709	index = sysfs_match_string(libie_fwlog_log_size, user_val);
 710	if (index < 0) {
 711		dev_info(dev, "Invalid log size '%s'. The value must be one of 128K, 256K, 512K, 1M, 2M\n",
 712			 user_val);
 713		ret = -EINVAL;
 714		goto log_size_write_error;
 715	} else if (fwlog->cfg.options & LIBIE_FWLOG_OPTION_IS_REGISTERED) {
 716		dev_info(dev, "FW logging is currently running. Please disable FW logging to change log_size\n");
 717		ret = -EINVAL;
 718		goto log_size_write_error;
 719	}
 720
 721	/* free all the buffers and the tracking info and resize */
 722	libie_fwlog_realloc_rings(fwlog, index);
 723
 724	/* if we get here, nothing went wrong; return count since we didn't
 725	 * really write anything
 726	 */
 727	ret = (ssize_t)count;
 728
 729log_size_write_error:
 730	/* This function always consumes all of the written input, or produces
 731	 * an error. Check and enforce this. Otherwise, the write operation
 732	 * won't complete properly.
 733	 */
 734	if (WARN_ON(ret != (ssize_t)count && ret >= 0))
 735		ret = -EIO;
 736free_cmd_buf:
 737	kfree(cmd_buf);
 738
 739	return ret;
 740}
 741
 742static const struct file_operations libie_debugfs_log_size_fops = {
 743	.owner = THIS_MODULE,
 744	.open  = simple_open,
 745	.read = libie_debugfs_log_size_read,
 746	.write = libie_debugfs_log_size_write,
 747};
 748
 749/**
 750 * libie_debugfs_data_read - read from 'data' file
 751 * @filp: the opened file
 752 * @buffer: where to write the data for the user to read
 753 * @count: the size of the user's buffer
 754 * @ppos: file position offset
 755 */
 756static ssize_t libie_debugfs_data_read(struct file *filp, char __user *buffer,
 757				       size_t count, loff_t *ppos)
 758{
 759	struct libie_fwlog *fwlog = filp->private_data;
 760	int data_copied = 0;
 761	bool done = false;
 762
 763	if (libie_fwlog_ring_empty(&fwlog->ring))
 764		return 0;
 765
 766	while (!libie_fwlog_ring_empty(&fwlog->ring) && !done) {
 767		struct libie_fwlog_data *log;
 768		u16 cur_buf_len;
 769
 770		log = &fwlog->ring.rings[fwlog->ring.head];
 771		cur_buf_len = log->data_size;
 772		if (cur_buf_len >= count) {
 773			done = true;
 774			continue;
 775		}
 776
 777		if (copy_to_user(buffer, log->data, cur_buf_len)) {
 778			/* if there is an error then bail and return whatever
 779			 * the driver has copied so far
 780			 */
 781			done = true;
 782			continue;
 783		}
 784
 785		data_copied += cur_buf_len;
 786		buffer += cur_buf_len;
 787		count -= cur_buf_len;
 788		*ppos += cur_buf_len;
 789		libie_fwlog_ring_increment(&fwlog->ring.head, fwlog->ring.size);
 790	}
 791
 792	return data_copied;
 793}
 794
 795/**
 796 * libie_debugfs_data_write - write into 'data' file
 797 * @filp: the opened file
 798 * @buf: where to find the user's data
 799 * @count: the length of the user's data
 800 * @ppos: file position offset
 801 */
 802static ssize_t
 803libie_debugfs_data_write(struct file *filp, const char __user *buf, size_t count,
 804			 loff_t *ppos)
 805{
 806	struct libie_fwlog *fwlog = filp->private_data;
 807	struct device *dev = &fwlog->pdev->dev;
 808	ssize_t ret;
 809
 810	/* don't allow partial writes */
 811	if (*ppos != 0)
 812		return 0;
 813
 814	/* any value is allowed to clear the buffer so no need to even look at
 815	 * what the value is
 816	 */
 817	if (!(fwlog->cfg.options & LIBIE_FWLOG_OPTION_IS_REGISTERED)) {
 818		fwlog->ring.head = 0;
 819		fwlog->ring.tail = 0;
 820	} else {
 821		dev_info(dev, "Can't clear FW log data while FW log running\n");
 822		ret = -EINVAL;
 823		goto nr_buffs_write_error;
 824	}
 825
 826	/* if we get here, nothing went wrong; return count since we didn't
 827	 * really write anything
 828	 */
 829	ret = (ssize_t)count;
 830
 831nr_buffs_write_error:
 832	/* This function always consumes all of the written input, or produces
 833	 * an error. Check and enforce this. Otherwise, the write operation
 834	 * won't complete properly.
 835	 */
 836	if (WARN_ON(ret != (ssize_t)count && ret >= 0))
 837		ret = -EIO;
 838
 839	return ret;
 840}
 841
 842static const struct file_operations libie_debugfs_data_fops = {
 843	.owner = THIS_MODULE,
 844	.open  = simple_open,
 845	.read = libie_debugfs_data_read,
 846	.write = libie_debugfs_data_write,
 847};
 848
 849/**
 850 * libie_debugfs_fwlog_init - setup the debugfs directory
 851 * @fwlog: pointer to the fwlog structure
 852 * @root: debugfs root entry on which fwlog director will be registered
 853 */
 854static void libie_debugfs_fwlog_init(struct libie_fwlog *fwlog,
 855				     struct dentry *root)
 856{
 857	struct dentry *fw_modules_dir;
 858	struct dentry **fw_modules;
 859	int i;
 860
 861	/* allocate space for this first because if it fails then we don't
 862	 * need to unwind
 863	 */
 864	fw_modules = kcalloc(LIBIE_NR_FW_LOG_MODULES, sizeof(*fw_modules),
 865			     GFP_KERNEL);
 866	if (!fw_modules)
 867		return;
 868
 869	fwlog->debugfs = debugfs_create_dir("fwlog", root);
 870	if (IS_ERR(fwlog->debugfs))
 871		goto err_create_module_files;
 872
 873	fw_modules_dir = debugfs_create_dir("modules", fwlog->debugfs);
 874	if (IS_ERR(fw_modules_dir))
 875		goto err_create_module_files;
 876
 877	for (i = 0; i < LIBIE_NR_FW_LOG_MODULES; i++) {
 878		fw_modules[i] = debugfs_create_file(libie_fwlog_module_string[i],
 879						    0600, fw_modules_dir, fwlog,
 880						    &libie_debugfs_module_fops);
 881		if (IS_ERR(fw_modules[i]))
 882			goto err_create_module_files;
 883	}
 884
 885	debugfs_create_file("nr_messages", 0600, fwlog->debugfs, fwlog,
 886			    &libie_debugfs_nr_messages_fops);
 887
 888	fwlog->debugfs_modules = fw_modules;
 889
 890	debugfs_create_file("enable", 0600, fwlog->debugfs, fwlog,
 891			    &libie_debugfs_enable_fops);
 892
 893	debugfs_create_file("log_size", 0600, fwlog->debugfs, fwlog,
 894			    &libie_debugfs_log_size_fops);
 895
 896	debugfs_create_file("data", 0600, fwlog->debugfs, fwlog,
 897			    &libie_debugfs_data_fops);
 898
 899	return;
 900
 901err_create_module_files:
 902	debugfs_remove_recursive(fwlog->debugfs);
 903	kfree(fw_modules);
 904}
 905
 906static bool libie_fwlog_ring_full(struct libie_fwlog_ring *rings)
 907{
 908	u16 head, tail;
 909
 910	head = rings->head;
 911	tail = rings->tail;
 912
 913	if (head < tail && (tail - head == (rings->size - 1)))
 914		return true;
 915	else if (head > tail && (tail == (head - 1)))
 916		return true;
 917
 918	return false;
 919}
 920
 921/**
 922 * libie_aq_fwlog_get - Get the current firmware logging configuration (0xFF32)
 923 * @fwlog: pointer to the fwlog structure
 924 * @cfg: firmware logging configuration to populate
 925 */
 926static int libie_aq_fwlog_get(struct libie_fwlog *fwlog,
 927			      struct libie_fwlog_cfg *cfg)
 928{
 929	struct libie_aqc_fw_log_cfg_resp *fw_modules;
 930	struct libie_aq_desc desc = {0};
 931	struct libie_aqc_fw_log *cmd;
 932	u16 module_id_cnt;
 933	int status;
 934	void *buf;
 935	int i;
 936
 937	memset(cfg, 0, sizeof(*cfg));
 938
 939	buf = kzalloc(LIBIE_AQ_MAX_BUF_LEN, GFP_KERNEL);
 940	if (!buf)
 941		return -ENOMEM;
 942
 943	desc.opcode = cpu_to_le16(libie_aqc_opc_fw_logs_query);
 944	desc.flags = cpu_to_le16(LIBIE_AQ_FLAG_SI);
 945	cmd = libie_aq_raw(&desc);
 946
 947	cmd->cmd_flags = LIBIE_AQC_FW_LOG_AQ_QUERY;
 948
 949	status = fwlog->send_cmd(fwlog->priv, &desc, buf, LIBIE_AQ_MAX_BUF_LEN);
 950	if (status) {
 951		dev_dbg(&fwlog->pdev->dev, "Failed to get FW log configuration\n");
 952		goto status_out;
 953	}
 954
 955	module_id_cnt = le16_to_cpu(cmd->ops.cfg.mdl_cnt);
 956	if (module_id_cnt < LIBIE_AQC_FW_LOG_ID_MAX) {
 957		dev_dbg(&fwlog->pdev->dev, "FW returned less than the expected number of FW log module IDs\n");
 958	} else if (module_id_cnt > LIBIE_AQC_FW_LOG_ID_MAX) {
 959		dev_dbg(&fwlog->pdev->dev, "FW returned more than expected number of FW log module IDs, setting module_id_cnt to software expected max %u\n",
 960			LIBIE_AQC_FW_LOG_ID_MAX);
 961		module_id_cnt = LIBIE_AQC_FW_LOG_ID_MAX;
 962	}
 963
 964	cfg->log_resolution = le16_to_cpu(cmd->ops.cfg.log_resolution);
 965	if (cmd->cmd_flags & LIBIE_AQC_FW_LOG_CONF_AQ_EN)
 966		cfg->options |= LIBIE_FWLOG_OPTION_ARQ_ENA;
 967	if (cmd->cmd_flags & LIBIE_AQC_FW_LOG_CONF_UART_EN)
 968		cfg->options |= LIBIE_FWLOG_OPTION_UART_ENA;
 969	if (cmd->cmd_flags & LIBIE_AQC_FW_LOG_QUERY_REGISTERED)
 970		cfg->options |= LIBIE_FWLOG_OPTION_IS_REGISTERED;
 971
 972	fw_modules = (struct libie_aqc_fw_log_cfg_resp *)buf;
 973
 974	for (i = 0; i < module_id_cnt; i++) {
 975		struct libie_aqc_fw_log_cfg_resp *fw_module = &fw_modules[i];
 976
 977		cfg->module_entries[i].module_id =
 978			le16_to_cpu(fw_module->module_identifier);
 979		cfg->module_entries[i].log_level = fw_module->log_level;
 980	}
 981
 982status_out:
 983	kfree(buf);
 984	return status;
 985}
 986
 987/**
 988 * libie_fwlog_set_supported - Set if FW logging is supported by FW
 989 * @fwlog: pointer to the fwlog structure
 990 *
 991 * If FW returns success to the libie_aq_fwlog_get call then it supports FW
 992 * logging, else it doesn't. Set the fwlog_supported flag accordingly.
 993 *
 994 * This function is only meant to be called during driver init to determine if
 995 * the FW support FW logging.
 996 */
 997static void libie_fwlog_set_supported(struct libie_fwlog *fwlog)
 998{
 999	struct libie_fwlog_cfg *cfg;
1000	int status;
1001
1002	fwlog->supported = false;
1003
1004	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
1005	if (!cfg)
1006		return;
1007
1008	status = libie_aq_fwlog_get(fwlog, cfg);
1009	if (status)
1010		dev_dbg(&fwlog->pdev->dev, "libie_aq_fwlog_get failed, FW logging is not supported on this version of FW, status %d\n",
1011			status);
1012	else
1013		fwlog->supported = true;
1014
1015	kfree(cfg);
1016}
1017
1018/**
1019 * libie_fwlog_init - Initialize FW logging configuration
1020 * @fwlog: pointer to the fwlog structure
1021 * @api: api structure to init fwlog
1022 *
1023 * This function should be called on driver initialization during
1024 * libie_init_hw().
1025 */
1026int libie_fwlog_init(struct libie_fwlog *fwlog, struct libie_fwlog_api *api)
1027{
1028	fwlog->api = *api;
1029	libie_fwlog_set_supported(fwlog);
1030
1031	if (libie_fwlog_supported(fwlog)) {
1032		int status;
1033
1034		/* read the current config from the FW and store it */
1035		status = libie_aq_fwlog_get(fwlog, &fwlog->cfg);
1036		if (status)
1037			return status;
1038
1039		fwlog->ring.rings = kcalloc(LIBIE_FWLOG_RING_SIZE_DFLT,
1040					    sizeof(*fwlog->ring.rings),
1041					    GFP_KERNEL);
1042		if (!fwlog->ring.rings) {
1043			dev_warn(&fwlog->pdev->dev, "Unable to allocate memory for FW log rings\n");
1044			return -ENOMEM;
1045		}
1046
1047		fwlog->ring.size = LIBIE_FWLOG_RING_SIZE_DFLT;
1048		fwlog->ring.index = LIBIE_FWLOG_RING_SIZE_INDEX_DFLT;
1049
1050		status = libie_fwlog_alloc_ring_buffs(&fwlog->ring);
1051		if (status) {
1052			dev_warn(&fwlog->pdev->dev, "Unable to allocate memory for FW log ring data buffers\n");
1053			libie_fwlog_free_ring_buffs(&fwlog->ring);
1054			kfree(fwlog->ring.rings);
1055			return status;
1056		}
1057
1058		libie_debugfs_fwlog_init(fwlog, api->debugfs_root);
1059	} else {
1060		dev_warn(&fwlog->pdev->dev, "FW logging is not supported in this NVM image. Please update the NVM to get FW log support\n");
1061	}
1062
1063	return 0;
1064}
1065EXPORT_SYMBOL_GPL(libie_fwlog_init);
1066
1067/**
1068 * libie_fwlog_deinit - unroll FW logging configuration
1069 * @fwlog: pointer to the fwlog structure
1070 *
1071 * This function should be called in libie_deinit_hw().
1072 */
1073void libie_fwlog_deinit(struct libie_fwlog *fwlog)
1074{
1075	int status;
1076
1077	/* if FW logging isn't supported it means no configuration was done */
1078	if (!libie_fwlog_supported(fwlog))
1079		return;
1080
1081	/* make sure FW logging is disabled to not put the FW in a weird state
1082	 * for the next driver load
1083	 */
1084	fwlog->cfg.options &= ~LIBIE_FWLOG_OPTION_ARQ_ENA;
1085	status = libie_fwlog_set(fwlog, &fwlog->cfg);
1086	if (status)
1087		dev_warn(&fwlog->pdev->dev, "Unable to turn off FW logging, status: %d\n",
1088			 status);
1089
1090	kfree(fwlog->debugfs_modules);
1091
1092	fwlog->debugfs_modules = NULL;
1093
1094	status = libie_fwlog_unregister(fwlog);
1095	if (status)
1096		dev_warn(&fwlog->pdev->dev, "Unable to unregister FW logging, status: %d\n",
1097			 status);
1098
1099	if (fwlog->ring.rings) {
1100		libie_fwlog_free_ring_buffs(&fwlog->ring);
1101		kfree(fwlog->ring.rings);
1102	}
1103}
1104EXPORT_SYMBOL_GPL(libie_fwlog_deinit);
1105
1106/**
1107 * libie_get_fwlog_data - copy the FW log data from ARQ event
1108 * @fwlog: fwlog that the FW log event is associated with
1109 * @buf: event buffer pointer
1110 * @len: len of event descriptor
1111 */
1112void libie_get_fwlog_data(struct libie_fwlog *fwlog, u8 *buf, u16 len)
1113{
1114	struct libie_fwlog_data *log;
1115
1116	log = &fwlog->ring.rings[fwlog->ring.tail];
1117
1118	memset(log->data, 0, PAGE_SIZE);
1119	log->data_size = len;
1120
1121	memcpy(log->data, buf, log->data_size);
1122	libie_fwlog_ring_increment(&fwlog->ring.tail, fwlog->ring.size);
1123
1124	if (libie_fwlog_ring_full(&fwlog->ring)) {
1125		/* the rings are full so bump the head to create room */
1126		libie_fwlog_ring_increment(&fwlog->ring.head, fwlog->ring.size);
1127	}
1128}
1129EXPORT_SYMBOL_GPL(libie_get_fwlog_data);
1130
1131void libie_fwlog_reregister(struct libie_fwlog *fwlog)
1132{
1133	if (!(fwlog->cfg.options & LIBIE_FWLOG_OPTION_IS_REGISTERED))
1134		return;
1135
1136	if (libie_fwlog_register(fwlog))
1137		fwlog->cfg.options &= ~LIBIE_FWLOG_OPTION_IS_REGISTERED;
1138}
1139EXPORT_SYMBOL_GPL(libie_fwlog_reregister);
1140
1141MODULE_DESCRIPTION("Intel(R) Ethernet common library");
1142MODULE_LICENSE("GPL");
~/ Read-only file preview.