162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/debugfs.h>
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "ixgbe.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistatic struct dentry *ixgbe_dbg_root;
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic char ixgbe_dbg_reg_ops_buf[256] = "";
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_common_ops_read(struct file *filp, char __user *buffer,
1462306a36Sopenharmony_ci					 size_t count, loff_t *ppos,
1562306a36Sopenharmony_ci					 char *dbg_buf)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = filp->private_data;
1862306a36Sopenharmony_ci	char *buf;
1962306a36Sopenharmony_ci	int len;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	/* don't allow partial reads */
2262306a36Sopenharmony_ci	if (*ppos != 0)
2362306a36Sopenharmony_ci		return 0;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	buf = kasprintf(GFP_KERNEL, "%s: %s\n",
2662306a36Sopenharmony_ci			adapter->netdev->name, dbg_buf);
2762306a36Sopenharmony_ci	if (!buf)
2862306a36Sopenharmony_ci		return -ENOMEM;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (count < strlen(buf)) {
3162306a36Sopenharmony_ci		kfree(buf);
3262306a36Sopenharmony_ci		return -ENOSPC;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	kfree(buf);
3862306a36Sopenharmony_ci	return len;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/**
4262306a36Sopenharmony_ci * ixgbe_dbg_reg_ops_read - read for reg_ops datum
4362306a36Sopenharmony_ci * @filp: the opened file
4462306a36Sopenharmony_ci * @buffer: where to write the data for the user to read
4562306a36Sopenharmony_ci * @count: the size of the user's buffer
4662306a36Sopenharmony_ci * @ppos: file position offset
4762306a36Sopenharmony_ci **/
4862306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_reg_ops_read(struct file *filp, char __user *buffer,
4962306a36Sopenharmony_ci				      size_t count, loff_t *ppos)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos,
5262306a36Sopenharmony_ci					 ixgbe_dbg_reg_ops_buf);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/**
5662306a36Sopenharmony_ci * ixgbe_dbg_reg_ops_write - write into reg_ops datum
5762306a36Sopenharmony_ci * @filp: the opened file
5862306a36Sopenharmony_ci * @buffer: where to find the user's data
5962306a36Sopenharmony_ci * @count: the length of the user's data
6062306a36Sopenharmony_ci * @ppos: file position offset
6162306a36Sopenharmony_ci **/
6262306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_reg_ops_write(struct file *filp,
6362306a36Sopenharmony_ci				     const char __user *buffer,
6462306a36Sopenharmony_ci				     size_t count, loff_t *ppos)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = filp->private_data;
6762306a36Sopenharmony_ci	int len;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* don't allow partial writes */
7062306a36Sopenharmony_ci	if (*ppos != 0)
7162306a36Sopenharmony_ci		return 0;
7262306a36Sopenharmony_ci	if (count >= sizeof(ixgbe_dbg_reg_ops_buf))
7362306a36Sopenharmony_ci		return -ENOSPC;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	len = simple_write_to_buffer(ixgbe_dbg_reg_ops_buf,
7662306a36Sopenharmony_ci				     sizeof(ixgbe_dbg_reg_ops_buf)-1,
7762306a36Sopenharmony_ci				     ppos,
7862306a36Sopenharmony_ci				     buffer,
7962306a36Sopenharmony_ci				     count);
8062306a36Sopenharmony_ci	if (len < 0)
8162306a36Sopenharmony_ci		return len;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	ixgbe_dbg_reg_ops_buf[len] = '\0';
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (strncmp(ixgbe_dbg_reg_ops_buf, "write", 5) == 0) {
8662306a36Sopenharmony_ci		u32 reg, value;
8762306a36Sopenharmony_ci		int cnt;
8862306a36Sopenharmony_ci		cnt = sscanf(&ixgbe_dbg_reg_ops_buf[5], "%x %x", &reg, &value);
8962306a36Sopenharmony_ci		if (cnt == 2) {
9062306a36Sopenharmony_ci			IXGBE_WRITE_REG(&adapter->hw, reg, value);
9162306a36Sopenharmony_ci			value = IXGBE_READ_REG(&adapter->hw, reg);
9262306a36Sopenharmony_ci			e_dev_info("write: 0x%08x = 0x%08x\n", reg, value);
9362306a36Sopenharmony_ci		} else {
9462306a36Sopenharmony_ci			e_dev_info("write <reg> <value>\n");
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci	} else if (strncmp(ixgbe_dbg_reg_ops_buf, "read", 4) == 0) {
9762306a36Sopenharmony_ci		u32 reg, value;
9862306a36Sopenharmony_ci		int cnt;
9962306a36Sopenharmony_ci		cnt = sscanf(&ixgbe_dbg_reg_ops_buf[4], "%x", &reg);
10062306a36Sopenharmony_ci		if (cnt == 1) {
10162306a36Sopenharmony_ci			value = IXGBE_READ_REG(&adapter->hw, reg);
10262306a36Sopenharmony_ci			e_dev_info("read 0x%08x = 0x%08x\n", reg, value);
10362306a36Sopenharmony_ci		} else {
10462306a36Sopenharmony_ci			e_dev_info("read <reg>\n");
10562306a36Sopenharmony_ci		}
10662306a36Sopenharmony_ci	} else {
10762306a36Sopenharmony_ci		e_dev_info("Unknown command %s\n", ixgbe_dbg_reg_ops_buf);
10862306a36Sopenharmony_ci		e_dev_info("Available commands:\n");
10962306a36Sopenharmony_ci		e_dev_info("   read <reg>\n");
11062306a36Sopenharmony_ci		e_dev_info("   write <reg> <value>\n");
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	return count;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const struct file_operations ixgbe_dbg_reg_ops_fops = {
11662306a36Sopenharmony_ci	.owner = THIS_MODULE,
11762306a36Sopenharmony_ci	.open = simple_open,
11862306a36Sopenharmony_ci	.read =  ixgbe_dbg_reg_ops_read,
11962306a36Sopenharmony_ci	.write = ixgbe_dbg_reg_ops_write,
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic char ixgbe_dbg_netdev_ops_buf[256] = "";
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/**
12562306a36Sopenharmony_ci * ixgbe_dbg_netdev_ops_read - read for netdev_ops datum
12662306a36Sopenharmony_ci * @filp: the opened file
12762306a36Sopenharmony_ci * @buffer: where to write the data for the user to read
12862306a36Sopenharmony_ci * @count: the size of the user's buffer
12962306a36Sopenharmony_ci * @ppos: file position offset
13062306a36Sopenharmony_ci **/
13162306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_netdev_ops_read(struct file *filp, char __user *buffer,
13262306a36Sopenharmony_ci					 size_t count, loff_t *ppos)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos,
13562306a36Sopenharmony_ci					 ixgbe_dbg_netdev_ops_buf);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/**
13962306a36Sopenharmony_ci * ixgbe_dbg_netdev_ops_write - write into netdev_ops datum
14062306a36Sopenharmony_ci * @filp: the opened file
14162306a36Sopenharmony_ci * @buffer: where to find the user's data
14262306a36Sopenharmony_ci * @count: the length of the user's data
14362306a36Sopenharmony_ci * @ppos: file position offset
14462306a36Sopenharmony_ci **/
14562306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_netdev_ops_write(struct file *filp,
14662306a36Sopenharmony_ci					  const char __user *buffer,
14762306a36Sopenharmony_ci					  size_t count, loff_t *ppos)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct ixgbe_adapter *adapter = filp->private_data;
15062306a36Sopenharmony_ci	int len;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* don't allow partial writes */
15362306a36Sopenharmony_ci	if (*ppos != 0)
15462306a36Sopenharmony_ci		return 0;
15562306a36Sopenharmony_ci	if (count >= sizeof(ixgbe_dbg_netdev_ops_buf))
15662306a36Sopenharmony_ci		return -ENOSPC;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	len = simple_write_to_buffer(ixgbe_dbg_netdev_ops_buf,
15962306a36Sopenharmony_ci				     sizeof(ixgbe_dbg_netdev_ops_buf)-1,
16062306a36Sopenharmony_ci				     ppos,
16162306a36Sopenharmony_ci				     buffer,
16262306a36Sopenharmony_ci				     count);
16362306a36Sopenharmony_ci	if (len < 0)
16462306a36Sopenharmony_ci		return len;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	ixgbe_dbg_netdev_ops_buf[len] = '\0';
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (strncmp(ixgbe_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) {
16962306a36Sopenharmony_ci		/* TX Queue number below is wrong, but ixgbe does not use it */
17062306a36Sopenharmony_ci		adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev,
17162306a36Sopenharmony_ci							    UINT_MAX);
17262306a36Sopenharmony_ci		e_dev_info("tx_timeout called\n");
17362306a36Sopenharmony_ci	} else {
17462306a36Sopenharmony_ci		e_dev_info("Unknown command: %s\n", ixgbe_dbg_netdev_ops_buf);
17562306a36Sopenharmony_ci		e_dev_info("Available commands:\n");
17662306a36Sopenharmony_ci		e_dev_info("    tx_timeout\n");
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci	return count;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic const struct file_operations ixgbe_dbg_netdev_ops_fops = {
18262306a36Sopenharmony_ci	.owner = THIS_MODULE,
18362306a36Sopenharmony_ci	.open = simple_open,
18462306a36Sopenharmony_ci	.read = ixgbe_dbg_netdev_ops_read,
18562306a36Sopenharmony_ci	.write = ixgbe_dbg_netdev_ops_write,
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/**
18962306a36Sopenharmony_ci * ixgbe_dbg_adapter_init - setup the debugfs directory for the adapter
19062306a36Sopenharmony_ci * @adapter: the adapter that is starting up
19162306a36Sopenharmony_ci **/
19262306a36Sopenharmony_civoid ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	const char *name = pci_name(adapter->pdev);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	adapter->ixgbe_dbg_adapter = debugfs_create_dir(name, ixgbe_dbg_root);
19762306a36Sopenharmony_ci	debugfs_create_file("reg_ops", 0600, adapter->ixgbe_dbg_adapter,
19862306a36Sopenharmony_ci			    adapter, &ixgbe_dbg_reg_ops_fops);
19962306a36Sopenharmony_ci	debugfs_create_file("netdev_ops", 0600, adapter->ixgbe_dbg_adapter,
20062306a36Sopenharmony_ci			    adapter, &ixgbe_dbg_netdev_ops_fops);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/**
20462306a36Sopenharmony_ci * ixgbe_dbg_adapter_exit - clear out the adapter's debugfs entries
20562306a36Sopenharmony_ci * @adapter: the adapter that is exiting
20662306a36Sopenharmony_ci **/
20762306a36Sopenharmony_civoid ixgbe_dbg_adapter_exit(struct ixgbe_adapter *adapter)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	debugfs_remove_recursive(adapter->ixgbe_dbg_adapter);
21062306a36Sopenharmony_ci	adapter->ixgbe_dbg_adapter = NULL;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/**
21462306a36Sopenharmony_ci * ixgbe_dbg_init - start up debugfs for the driver
21562306a36Sopenharmony_ci **/
21662306a36Sopenharmony_civoid ixgbe_dbg_init(void)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	ixgbe_dbg_root = debugfs_create_dir(ixgbe_driver_name, NULL);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/**
22262306a36Sopenharmony_ci * ixgbe_dbg_exit - clean out the driver's debugfs entries
22362306a36Sopenharmony_ci **/
22462306a36Sopenharmony_civoid ixgbe_dbg_exit(void)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	debugfs_remove_recursive(ixgbe_dbg_root);
22762306a36Sopenharmony_ci}
228