151dce24bSJeff Kirsher // SPDX-License-Identifier: GPL-2.0
251dce24bSJeff Kirsher /* Copyright(c) 1999 - 2018 Intel Corporation. */
300949167SCatherine Sullivan 
400949167SCatherine Sullivan #include <linux/debugfs.h>
500949167SCatherine Sullivan #include <linux/module.h>
600949167SCatherine Sullivan 
700949167SCatherine Sullivan #include "ixgbe.h"
800949167SCatherine Sullivan 
900949167SCatherine Sullivan static struct dentry *ixgbe_dbg_root;
1000949167SCatherine Sullivan 
1191fbd8f0SCatherine Sullivan static char ixgbe_dbg_reg_ops_buf[256] = "";
1291fbd8f0SCatherine Sullivan 
ixgbe_dbg_common_ops_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos,char * dbg_buf)13e9c72183SYueHaibing static ssize_t ixgbe_dbg_common_ops_read(struct file *filp, char __user *buffer,
14e9c72183SYueHaibing 					 size_t count, loff_t *ppos,
15e9c72183SYueHaibing 					 char *dbg_buf)
1691fbd8f0SCatherine Sullivan {
1791fbd8f0SCatherine Sullivan 	struct ixgbe_adapter *adapter = filp->private_data;
183288d735Sjoshua.a.hay@intel.com 	char *buf;
1991fbd8f0SCatherine Sullivan 	int len;
2091fbd8f0SCatherine Sullivan 
2191fbd8f0SCatherine Sullivan 	/* don't allow partial reads */
2291fbd8f0SCatherine Sullivan 	if (*ppos != 0)
2391fbd8f0SCatherine Sullivan 		return 0;
2491fbd8f0SCatherine Sullivan 
253288d735Sjoshua.a.hay@intel.com 	buf = kasprintf(GFP_KERNEL, "%s: %s\n",
26e9c72183SYueHaibing 			adapter->netdev->name, dbg_buf);
273288d735Sjoshua.a.hay@intel.com 	if (!buf)
283288d735Sjoshua.a.hay@intel.com 		return -ENOMEM;
2991fbd8f0SCatherine Sullivan 
303288d735Sjoshua.a.hay@intel.com 	if (count < strlen(buf)) {
313288d735Sjoshua.a.hay@intel.com 		kfree(buf);
323288d735Sjoshua.a.hay@intel.com 		return -ENOSPC;
333288d735Sjoshua.a.hay@intel.com 	}
343288d735Sjoshua.a.hay@intel.com 
353288d735Sjoshua.a.hay@intel.com 	len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
363288d735Sjoshua.a.hay@intel.com 
373288d735Sjoshua.a.hay@intel.com 	kfree(buf);
3891fbd8f0SCatherine Sullivan 	return len;
3991fbd8f0SCatherine Sullivan }
4091fbd8f0SCatherine Sullivan 
4191fbd8f0SCatherine Sullivan /**
42e9c72183SYueHaibing  * ixgbe_dbg_reg_ops_read - read for reg_ops datum
43e9c72183SYueHaibing  * @filp: the opened file
44e9c72183SYueHaibing  * @buffer: where to write the data for the user to read
45e9c72183SYueHaibing  * @count: the size of the user's buffer
46e9c72183SYueHaibing  * @ppos: file position offset
47e9c72183SYueHaibing  **/
ixgbe_dbg_reg_ops_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)48e9c72183SYueHaibing static ssize_t ixgbe_dbg_reg_ops_read(struct file *filp, char __user *buffer,
49e9c72183SYueHaibing 				      size_t count, loff_t *ppos)
50e9c72183SYueHaibing {
51e9c72183SYueHaibing 	return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos,
52e9c72183SYueHaibing 					 ixgbe_dbg_reg_ops_buf);
53e9c72183SYueHaibing }
54e9c72183SYueHaibing 
55e9c72183SYueHaibing /**
5691fbd8f0SCatherine Sullivan  * ixgbe_dbg_reg_ops_write - write into reg_ops datum
5791fbd8f0SCatherine Sullivan  * @filp: the opened file
5891fbd8f0SCatherine Sullivan  * @buffer: where to find the user's data
5991fbd8f0SCatherine Sullivan  * @count: the length of the user's data
6091fbd8f0SCatherine Sullivan  * @ppos: file position offset
6191fbd8f0SCatherine Sullivan  **/
ixgbe_dbg_reg_ops_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)6291fbd8f0SCatherine Sullivan static ssize_t ixgbe_dbg_reg_ops_write(struct file *filp,
6391fbd8f0SCatherine Sullivan 				     const char __user *buffer,
6491fbd8f0SCatherine Sullivan 				     size_t count, loff_t *ppos)
6591fbd8f0SCatherine Sullivan {
6691fbd8f0SCatherine Sullivan 	struct ixgbe_adapter *adapter = filp->private_data;
673288d735Sjoshua.a.hay@intel.com 	int len;
6891fbd8f0SCatherine Sullivan 
6991fbd8f0SCatherine Sullivan 	/* don't allow partial writes */
7091fbd8f0SCatherine Sullivan 	if (*ppos != 0)
7191fbd8f0SCatherine Sullivan 		return 0;
7291fbd8f0SCatherine Sullivan 	if (count >= sizeof(ixgbe_dbg_reg_ops_buf))
7391fbd8f0SCatherine Sullivan 		return -ENOSPC;
7491fbd8f0SCatherine Sullivan 
753288d735Sjoshua.a.hay@intel.com 	len = simple_write_to_buffer(ixgbe_dbg_reg_ops_buf,
763288d735Sjoshua.a.hay@intel.com 				     sizeof(ixgbe_dbg_reg_ops_buf)-1,
773288d735Sjoshua.a.hay@intel.com 				     ppos,
783288d735Sjoshua.a.hay@intel.com 				     buffer,
793288d735Sjoshua.a.hay@intel.com 				     count);
803288d735Sjoshua.a.hay@intel.com 	if (len < 0)
813288d735Sjoshua.a.hay@intel.com 		return len;
823288d735Sjoshua.a.hay@intel.com 
833288d735Sjoshua.a.hay@intel.com 	ixgbe_dbg_reg_ops_buf[len] = '\0';
8491fbd8f0SCatherine Sullivan 
8591fbd8f0SCatherine Sullivan 	if (strncmp(ixgbe_dbg_reg_ops_buf, "write", 5) == 0) {
8691fbd8f0SCatherine Sullivan 		u32 reg, value;
8791fbd8f0SCatherine Sullivan 		int cnt;
8891fbd8f0SCatherine Sullivan 		cnt = sscanf(&ixgbe_dbg_reg_ops_buf[5], "%x %x", &reg, &value);
8991fbd8f0SCatherine Sullivan 		if (cnt == 2) {
9091fbd8f0SCatherine Sullivan 			IXGBE_WRITE_REG(&adapter->hw, reg, value);
9191fbd8f0SCatherine Sullivan 			value = IXGBE_READ_REG(&adapter->hw, reg);
9291fbd8f0SCatherine Sullivan 			e_dev_info("write: 0x%08x = 0x%08x\n", reg, value);
9391fbd8f0SCatherine Sullivan 		} else {
9491fbd8f0SCatherine Sullivan 			e_dev_info("write <reg> <value>\n");
9591fbd8f0SCatherine Sullivan 		}
9691fbd8f0SCatherine Sullivan 	} else if (strncmp(ixgbe_dbg_reg_ops_buf, "read", 4) == 0) {
9791fbd8f0SCatherine Sullivan 		u32 reg, value;
9891fbd8f0SCatherine Sullivan 		int cnt;
9991fbd8f0SCatherine Sullivan 		cnt = sscanf(&ixgbe_dbg_reg_ops_buf[4], "%x", &reg);
10091fbd8f0SCatherine Sullivan 		if (cnt == 1) {
10191fbd8f0SCatherine Sullivan 			value = IXGBE_READ_REG(&adapter->hw, reg);
10291fbd8f0SCatherine Sullivan 			e_dev_info("read 0x%08x = 0x%08x\n", reg, value);
10391fbd8f0SCatherine Sullivan 		} else {
10491fbd8f0SCatherine Sullivan 			e_dev_info("read <reg>\n");
10591fbd8f0SCatherine Sullivan 		}
10691fbd8f0SCatherine Sullivan 	} else {
10791fbd8f0SCatherine Sullivan 		e_dev_info("Unknown command %s\n", ixgbe_dbg_reg_ops_buf);
10891fbd8f0SCatherine Sullivan 		e_dev_info("Available commands:\n");
10991fbd8f0SCatherine Sullivan 		e_dev_info("   read <reg>\n");
11091fbd8f0SCatherine Sullivan 		e_dev_info("   write <reg> <value>\n");
11191fbd8f0SCatherine Sullivan 	}
11291fbd8f0SCatherine Sullivan 	return count;
11391fbd8f0SCatherine Sullivan }
11491fbd8f0SCatherine Sullivan 
11591fbd8f0SCatherine Sullivan static const struct file_operations ixgbe_dbg_reg_ops_fops = {
11691fbd8f0SCatherine Sullivan 	.owner = THIS_MODULE,
11721cc57fbSWei Yongjun 	.open = simple_open,
11891fbd8f0SCatherine Sullivan 	.read =  ixgbe_dbg_reg_ops_read,
11991fbd8f0SCatherine Sullivan 	.write = ixgbe_dbg_reg_ops_write,
12091fbd8f0SCatherine Sullivan };
12191fbd8f0SCatherine Sullivan 
122826ff0deSCatherine Sullivan static char ixgbe_dbg_netdev_ops_buf[256] = "";
123826ff0deSCatherine Sullivan 
124826ff0deSCatherine Sullivan /**
125826ff0deSCatherine Sullivan  * ixgbe_dbg_netdev_ops_read - read for netdev_ops datum
126826ff0deSCatherine Sullivan  * @filp: the opened file
127826ff0deSCatherine Sullivan  * @buffer: where to write the data for the user to read
128826ff0deSCatherine Sullivan  * @count: the size of the user's buffer
129826ff0deSCatherine Sullivan  * @ppos: file position offset
130826ff0deSCatherine Sullivan  **/
ixgbe_dbg_netdev_ops_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)131e9c72183SYueHaibing static ssize_t ixgbe_dbg_netdev_ops_read(struct file *filp, char __user *buffer,
132826ff0deSCatherine Sullivan 					 size_t count, loff_t *ppos)
133826ff0deSCatherine Sullivan {
134e9c72183SYueHaibing 	return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos,
1353288d735Sjoshua.a.hay@intel.com 					 ixgbe_dbg_netdev_ops_buf);
136826ff0deSCatherine Sullivan }
137826ff0deSCatherine Sullivan 
138826ff0deSCatherine Sullivan /**
139826ff0deSCatherine Sullivan  * ixgbe_dbg_netdev_ops_write - write into netdev_ops datum
140826ff0deSCatherine Sullivan  * @filp: the opened file
141826ff0deSCatherine Sullivan  * @buffer: where to find the user's data
142826ff0deSCatherine Sullivan  * @count: the length of the user's data
143826ff0deSCatherine Sullivan  * @ppos: file position offset
144826ff0deSCatherine Sullivan  **/
ixgbe_dbg_netdev_ops_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)145826ff0deSCatherine Sullivan static ssize_t ixgbe_dbg_netdev_ops_write(struct file *filp,
146826ff0deSCatherine Sullivan 					  const char __user *buffer,
147826ff0deSCatherine Sullivan 					  size_t count, loff_t *ppos)
148826ff0deSCatherine Sullivan {
149826ff0deSCatherine Sullivan 	struct ixgbe_adapter *adapter = filp->private_data;
1503288d735Sjoshua.a.hay@intel.com 	int len;
151826ff0deSCatherine Sullivan 
152826ff0deSCatherine Sullivan 	/* don't allow partial writes */
153826ff0deSCatherine Sullivan 	if (*ppos != 0)
154826ff0deSCatherine Sullivan 		return 0;
155826ff0deSCatherine Sullivan 	if (count >= sizeof(ixgbe_dbg_netdev_ops_buf))
156826ff0deSCatherine Sullivan 		return -ENOSPC;
157826ff0deSCatherine Sullivan 
1583288d735Sjoshua.a.hay@intel.com 	len = simple_write_to_buffer(ixgbe_dbg_netdev_ops_buf,
1593288d735Sjoshua.a.hay@intel.com 				     sizeof(ixgbe_dbg_netdev_ops_buf)-1,
1603288d735Sjoshua.a.hay@intel.com 				     ppos,
1613288d735Sjoshua.a.hay@intel.com 				     buffer,
1623288d735Sjoshua.a.hay@intel.com 				     count);
1633288d735Sjoshua.a.hay@intel.com 	if (len < 0)
1643288d735Sjoshua.a.hay@intel.com 		return len;
1653288d735Sjoshua.a.hay@intel.com 
1663288d735Sjoshua.a.hay@intel.com 	ixgbe_dbg_netdev_ops_buf[len] = '\0';
167826ff0deSCatherine Sullivan 
168826ff0deSCatherine Sullivan 	if (strncmp(ixgbe_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) {
1690290bd29SMichael S. Tsirkin 		/* TX Queue number below is wrong, but ixgbe does not use it */
1700290bd29SMichael S. Tsirkin 		adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev,
1710290bd29SMichael S. Tsirkin 							    UINT_MAX);
172826ff0deSCatherine Sullivan 		e_dev_info("tx_timeout called\n");
173826ff0deSCatherine Sullivan 	} else {
174826ff0deSCatherine Sullivan 		e_dev_info("Unknown command: %s\n", ixgbe_dbg_netdev_ops_buf);
175826ff0deSCatherine Sullivan 		e_dev_info("Available commands:\n");
176826ff0deSCatherine Sullivan 		e_dev_info("    tx_timeout\n");
177826ff0deSCatherine Sullivan 	}
178826ff0deSCatherine Sullivan 	return count;
179826ff0deSCatherine Sullivan }
180826ff0deSCatherine Sullivan 
181826ff0deSCatherine Sullivan static const struct file_operations ixgbe_dbg_netdev_ops_fops = {
182826ff0deSCatherine Sullivan 	.owner = THIS_MODULE,
18321cc57fbSWei Yongjun 	.open = simple_open,
184826ff0deSCatherine Sullivan 	.read = ixgbe_dbg_netdev_ops_read,
185826ff0deSCatherine Sullivan 	.write = ixgbe_dbg_netdev_ops_write,
186826ff0deSCatherine Sullivan };
187826ff0deSCatherine Sullivan 
18800949167SCatherine Sullivan /**
18900949167SCatherine Sullivan  * ixgbe_dbg_adapter_init - setup the debugfs directory for the adapter
19000949167SCatherine Sullivan  * @adapter: the adapter that is starting up
19100949167SCatherine Sullivan  **/
ixgbe_dbg_adapter_init(struct ixgbe_adapter * adapter)19200949167SCatherine Sullivan void ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter)
19300949167SCatherine Sullivan {
19400949167SCatherine Sullivan 	const char *name = pci_name(adapter->pdev);
19535dc61ebSGreg Kroah-Hartman 
19600949167SCatherine Sullivan 	adapter->ixgbe_dbg_adapter = debugfs_create_dir(name, ixgbe_dbg_root);
19735dc61ebSGreg Kroah-Hartman 	debugfs_create_file("reg_ops", 0600, adapter->ixgbe_dbg_adapter,
19835dc61ebSGreg Kroah-Hartman 			    adapter, &ixgbe_dbg_reg_ops_fops);
19935dc61ebSGreg Kroah-Hartman 	debugfs_create_file("netdev_ops", 0600, adapter->ixgbe_dbg_adapter,
20035dc61ebSGreg Kroah-Hartman 			    adapter, &ixgbe_dbg_netdev_ops_fops);
201826ff0deSCatherine Sullivan }
20200949167SCatherine Sullivan 
20300949167SCatherine Sullivan /**
20400949167SCatherine Sullivan  * ixgbe_dbg_adapter_exit - clear out the adapter's debugfs entries
2055ba643c6STony Nguyen  * @adapter: the adapter that is exiting
20600949167SCatherine Sullivan  **/
ixgbe_dbg_adapter_exit(struct ixgbe_adapter * adapter)20700949167SCatherine Sullivan void ixgbe_dbg_adapter_exit(struct ixgbe_adapter *adapter)
20800949167SCatherine Sullivan {
20900949167SCatherine Sullivan 	debugfs_remove_recursive(adapter->ixgbe_dbg_adapter);
21000949167SCatherine Sullivan 	adapter->ixgbe_dbg_adapter = NULL;
21100949167SCatherine Sullivan }
21200949167SCatherine Sullivan 
21300949167SCatherine Sullivan /**
21400949167SCatherine Sullivan  * ixgbe_dbg_init - start up debugfs for the driver
21500949167SCatherine Sullivan  **/
ixgbe_dbg_init(void)21600949167SCatherine Sullivan void ixgbe_dbg_init(void)
21700949167SCatherine Sullivan {
21800949167SCatherine Sullivan 	ixgbe_dbg_root = debugfs_create_dir(ixgbe_driver_name, NULL);
21900949167SCatherine Sullivan }
22000949167SCatherine Sullivan 
22100949167SCatherine Sullivan /**
22200949167SCatherine Sullivan  * ixgbe_dbg_exit - clean out the driver's debugfs entries
22300949167SCatherine Sullivan  **/
ixgbe_dbg_exit(void)22400949167SCatherine Sullivan void ixgbe_dbg_exit(void)
22500949167SCatherine Sullivan {
22600949167SCatherine Sullivan 	debugfs_remove_recursive(ixgbe_dbg_root);
22700949167SCatherine Sullivan }
228