1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright(c) 1999 - 2018 Intel Corporation. */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/debugfs.h>
5*4882a593Smuzhiyun #include <linux/module.h>
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include "ixgbe.h"
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun static struct dentry *ixgbe_dbg_root;
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun static char ixgbe_dbg_reg_ops_buf[256] = "";
12*4882a593Smuzhiyun
ixgbe_dbg_common_ops_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos,char * dbg_buf)13*4882a593Smuzhiyun static ssize_t ixgbe_dbg_common_ops_read(struct file *filp, char __user *buffer,
14*4882a593Smuzhiyun size_t count, loff_t *ppos,
15*4882a593Smuzhiyun char *dbg_buf)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun struct ixgbe_adapter *adapter = filp->private_data;
18*4882a593Smuzhiyun char *buf;
19*4882a593Smuzhiyun int len;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* don't allow partial reads */
22*4882a593Smuzhiyun if (*ppos != 0)
23*4882a593Smuzhiyun return 0;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun buf = kasprintf(GFP_KERNEL, "%s: %s\n",
26*4882a593Smuzhiyun adapter->netdev->name, dbg_buf);
27*4882a593Smuzhiyun if (!buf)
28*4882a593Smuzhiyun return -ENOMEM;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun if (count < strlen(buf)) {
31*4882a593Smuzhiyun kfree(buf);
32*4882a593Smuzhiyun return -ENOSPC;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun kfree(buf);
38*4882a593Smuzhiyun return len;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /**
42*4882a593Smuzhiyun * ixgbe_dbg_reg_ops_read - read for reg_ops datum
43*4882a593Smuzhiyun * @filp: the opened file
44*4882a593Smuzhiyun * @buffer: where to write the data for the user to read
45*4882a593Smuzhiyun * @count: the size of the user's buffer
46*4882a593Smuzhiyun * @ppos: file position offset
47*4882a593Smuzhiyun **/
ixgbe_dbg_reg_ops_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)48*4882a593Smuzhiyun static ssize_t ixgbe_dbg_reg_ops_read(struct file *filp, char __user *buffer,
49*4882a593Smuzhiyun size_t count, loff_t *ppos)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos,
52*4882a593Smuzhiyun ixgbe_dbg_reg_ops_buf);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /**
56*4882a593Smuzhiyun * ixgbe_dbg_reg_ops_write - write into reg_ops datum
57*4882a593Smuzhiyun * @filp: the opened file
58*4882a593Smuzhiyun * @buffer: where to find the user's data
59*4882a593Smuzhiyun * @count: the length of the user's data
60*4882a593Smuzhiyun * @ppos: file position offset
61*4882a593Smuzhiyun **/
ixgbe_dbg_reg_ops_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)62*4882a593Smuzhiyun static ssize_t ixgbe_dbg_reg_ops_write(struct file *filp,
63*4882a593Smuzhiyun const char __user *buffer,
64*4882a593Smuzhiyun size_t count, loff_t *ppos)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun struct ixgbe_adapter *adapter = filp->private_data;
67*4882a593Smuzhiyun int len;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* don't allow partial writes */
70*4882a593Smuzhiyun if (*ppos != 0)
71*4882a593Smuzhiyun return 0;
72*4882a593Smuzhiyun if (count >= sizeof(ixgbe_dbg_reg_ops_buf))
73*4882a593Smuzhiyun return -ENOSPC;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun len = simple_write_to_buffer(ixgbe_dbg_reg_ops_buf,
76*4882a593Smuzhiyun sizeof(ixgbe_dbg_reg_ops_buf)-1,
77*4882a593Smuzhiyun ppos,
78*4882a593Smuzhiyun buffer,
79*4882a593Smuzhiyun count);
80*4882a593Smuzhiyun if (len < 0)
81*4882a593Smuzhiyun return len;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun ixgbe_dbg_reg_ops_buf[len] = '\0';
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (strncmp(ixgbe_dbg_reg_ops_buf, "write", 5) == 0) {
86*4882a593Smuzhiyun u32 reg, value;
87*4882a593Smuzhiyun int cnt;
88*4882a593Smuzhiyun cnt = sscanf(&ixgbe_dbg_reg_ops_buf[5], "%x %x", ®, &value);
89*4882a593Smuzhiyun if (cnt == 2) {
90*4882a593Smuzhiyun IXGBE_WRITE_REG(&adapter->hw, reg, value);
91*4882a593Smuzhiyun value = IXGBE_READ_REG(&adapter->hw, reg);
92*4882a593Smuzhiyun e_dev_info("write: 0x%08x = 0x%08x\n", reg, value);
93*4882a593Smuzhiyun } else {
94*4882a593Smuzhiyun e_dev_info("write <reg> <value>\n");
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun } else if (strncmp(ixgbe_dbg_reg_ops_buf, "read", 4) == 0) {
97*4882a593Smuzhiyun u32 reg, value;
98*4882a593Smuzhiyun int cnt;
99*4882a593Smuzhiyun cnt = sscanf(&ixgbe_dbg_reg_ops_buf[4], "%x", ®);
100*4882a593Smuzhiyun if (cnt == 1) {
101*4882a593Smuzhiyun value = IXGBE_READ_REG(&adapter->hw, reg);
102*4882a593Smuzhiyun e_dev_info("read 0x%08x = 0x%08x\n", reg, value);
103*4882a593Smuzhiyun } else {
104*4882a593Smuzhiyun e_dev_info("read <reg>\n");
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun } else {
107*4882a593Smuzhiyun e_dev_info("Unknown command %s\n", ixgbe_dbg_reg_ops_buf);
108*4882a593Smuzhiyun e_dev_info("Available commands:\n");
109*4882a593Smuzhiyun e_dev_info(" read <reg>\n");
110*4882a593Smuzhiyun e_dev_info(" write <reg> <value>\n");
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun return count;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun static const struct file_operations ixgbe_dbg_reg_ops_fops = {
116*4882a593Smuzhiyun .owner = THIS_MODULE,
117*4882a593Smuzhiyun .open = simple_open,
118*4882a593Smuzhiyun .read = ixgbe_dbg_reg_ops_read,
119*4882a593Smuzhiyun .write = ixgbe_dbg_reg_ops_write,
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun static char ixgbe_dbg_netdev_ops_buf[256] = "";
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /**
125*4882a593Smuzhiyun * ixgbe_dbg_netdev_ops_read - read for netdev_ops datum
126*4882a593Smuzhiyun * @filp: the opened file
127*4882a593Smuzhiyun * @buffer: where to write the data for the user to read
128*4882a593Smuzhiyun * @count: the size of the user's buffer
129*4882a593Smuzhiyun * @ppos: file position offset
130*4882a593Smuzhiyun **/
ixgbe_dbg_netdev_ops_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)131*4882a593Smuzhiyun static ssize_t ixgbe_dbg_netdev_ops_read(struct file *filp, char __user *buffer,
132*4882a593Smuzhiyun size_t count, loff_t *ppos)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos,
135*4882a593Smuzhiyun ixgbe_dbg_netdev_ops_buf);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /**
139*4882a593Smuzhiyun * ixgbe_dbg_netdev_ops_write - write into netdev_ops datum
140*4882a593Smuzhiyun * @filp: the opened file
141*4882a593Smuzhiyun * @buffer: where to find the user's data
142*4882a593Smuzhiyun * @count: the length of the user's data
143*4882a593Smuzhiyun * @ppos: file position offset
144*4882a593Smuzhiyun **/
ixgbe_dbg_netdev_ops_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)145*4882a593Smuzhiyun static ssize_t ixgbe_dbg_netdev_ops_write(struct file *filp,
146*4882a593Smuzhiyun const char __user *buffer,
147*4882a593Smuzhiyun size_t count, loff_t *ppos)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun struct ixgbe_adapter *adapter = filp->private_data;
150*4882a593Smuzhiyun int len;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /* don't allow partial writes */
153*4882a593Smuzhiyun if (*ppos != 0)
154*4882a593Smuzhiyun return 0;
155*4882a593Smuzhiyun if (count >= sizeof(ixgbe_dbg_netdev_ops_buf))
156*4882a593Smuzhiyun return -ENOSPC;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun len = simple_write_to_buffer(ixgbe_dbg_netdev_ops_buf,
159*4882a593Smuzhiyun sizeof(ixgbe_dbg_netdev_ops_buf)-1,
160*4882a593Smuzhiyun ppos,
161*4882a593Smuzhiyun buffer,
162*4882a593Smuzhiyun count);
163*4882a593Smuzhiyun if (len < 0)
164*4882a593Smuzhiyun return len;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun ixgbe_dbg_netdev_ops_buf[len] = '\0';
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (strncmp(ixgbe_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) {
169*4882a593Smuzhiyun /* TX Queue number below is wrong, but ixgbe does not use it */
170*4882a593Smuzhiyun adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev,
171*4882a593Smuzhiyun UINT_MAX);
172*4882a593Smuzhiyun e_dev_info("tx_timeout called\n");
173*4882a593Smuzhiyun } else {
174*4882a593Smuzhiyun e_dev_info("Unknown command: %s\n", ixgbe_dbg_netdev_ops_buf);
175*4882a593Smuzhiyun e_dev_info("Available commands:\n");
176*4882a593Smuzhiyun e_dev_info(" tx_timeout\n");
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun return count;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun static const struct file_operations ixgbe_dbg_netdev_ops_fops = {
182*4882a593Smuzhiyun .owner = THIS_MODULE,
183*4882a593Smuzhiyun .open = simple_open,
184*4882a593Smuzhiyun .read = ixgbe_dbg_netdev_ops_read,
185*4882a593Smuzhiyun .write = ixgbe_dbg_netdev_ops_write,
186*4882a593Smuzhiyun };
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /**
189*4882a593Smuzhiyun * ixgbe_dbg_adapter_init - setup the debugfs directory for the adapter
190*4882a593Smuzhiyun * @adapter: the adapter that is starting up
191*4882a593Smuzhiyun **/
ixgbe_dbg_adapter_init(struct ixgbe_adapter * adapter)192*4882a593Smuzhiyun void ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun const char *name = pci_name(adapter->pdev);
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun adapter->ixgbe_dbg_adapter = debugfs_create_dir(name, ixgbe_dbg_root);
197*4882a593Smuzhiyun debugfs_create_file("reg_ops", 0600, adapter->ixgbe_dbg_adapter,
198*4882a593Smuzhiyun adapter, &ixgbe_dbg_reg_ops_fops);
199*4882a593Smuzhiyun debugfs_create_file("netdev_ops", 0600, adapter->ixgbe_dbg_adapter,
200*4882a593Smuzhiyun adapter, &ixgbe_dbg_netdev_ops_fops);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /**
204*4882a593Smuzhiyun * ixgbe_dbg_adapter_exit - clear out the adapter's debugfs entries
205*4882a593Smuzhiyun * @adapter: the adapter that is exiting
206*4882a593Smuzhiyun **/
ixgbe_dbg_adapter_exit(struct ixgbe_adapter * adapter)207*4882a593Smuzhiyun void ixgbe_dbg_adapter_exit(struct ixgbe_adapter *adapter)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun debugfs_remove_recursive(adapter->ixgbe_dbg_adapter);
210*4882a593Smuzhiyun adapter->ixgbe_dbg_adapter = NULL;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /**
214*4882a593Smuzhiyun * ixgbe_dbg_init - start up debugfs for the driver
215*4882a593Smuzhiyun **/
ixgbe_dbg_init(void)216*4882a593Smuzhiyun void ixgbe_dbg_init(void)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun ixgbe_dbg_root = debugfs_create_dir(ixgbe_driver_name, NULL);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /**
222*4882a593Smuzhiyun * ixgbe_dbg_exit - clean out the driver's debugfs entries
223*4882a593Smuzhiyun **/
ixgbe_dbg_exit(void)224*4882a593Smuzhiyun void ixgbe_dbg_exit(void)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun debugfs_remove_recursive(ixgbe_dbg_root);
227*4882a593Smuzhiyun }
228