GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / ethernet / huawei / hinic / hinic_debugfs.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Huawei HiNIC PCI Express Linux driver
3  * Copyright(c) 2017 Huawei Technologies Co., Ltd
4  */
5
6 #include <linux/debugfs.h>
7 #include <linux/device.h>
8
9 #include "hinic_debugfs.h"
10
11 static struct dentry *hinic_dbgfs_root;
12
13 enum sq_dbg_info {
14         GLB_SQ_ID,
15         SQ_PI,
16         SQ_CI,
17         SQ_FI,
18         SQ_MSIX_ENTRY,
19 };
20
21 static char *sq_fields[] = {"glb_sq_id", "sq_pi", "sq_ci", "sq_fi", "sq_msix_entry"};
22
23 static u64 hinic_dbg_get_sq_info(struct hinic_dev *nic_dev, struct hinic_sq *sq, int idx)
24 {
25         struct hinic_wq *wq = sq->wq;
26
27         switch (idx) {
28         case GLB_SQ_ID:
29                 return nic_dev->hwdev->func_to_io.global_qpn + sq->qid;
30         case SQ_PI:
31                 return atomic_read(&wq->prod_idx) & wq->mask;
32         case SQ_CI:
33                 return atomic_read(&wq->cons_idx) & wq->mask;
34         case SQ_FI:
35                 return be16_to_cpu(*(__be16 *)(sq->hw_ci_addr)) & wq->mask;
36         case SQ_MSIX_ENTRY:
37                 return sq->msix_entry;
38         }
39
40         return 0;
41 }
42
43 enum rq_dbg_info {
44         GLB_RQ_ID,
45         RQ_HW_PI,
46         RQ_SW_CI,
47         RQ_SW_PI,
48         RQ_MSIX_ENTRY,
49 };
50
51 static char *rq_fields[] = {"glb_rq_id", "rq_hw_pi", "rq_sw_ci", "rq_sw_pi", "rq_msix_entry"};
52
53 static u64 hinic_dbg_get_rq_info(struct hinic_dev *nic_dev, struct hinic_rq *rq, int idx)
54 {
55         struct hinic_wq *wq = rq->wq;
56
57         switch (idx) {
58         case GLB_RQ_ID:
59                 return nic_dev->hwdev->func_to_io.global_qpn + rq->qid;
60         case RQ_HW_PI:
61                 return be16_to_cpu(*(__be16 *)(rq->pi_virt_addr)) & wq->mask;
62         case RQ_SW_CI:
63                 return atomic_read(&wq->cons_idx) & wq->mask;
64         case RQ_SW_PI:
65                 return atomic_read(&wq->prod_idx) & wq->mask;
66         case RQ_MSIX_ENTRY:
67                 return rq->msix_entry;
68         }
69
70         return 0;
71 }
72
73 enum func_tbl_info {
74         VALID,
75         RX_MODE,
76         MTU,
77         RQ_DEPTH,
78         QUEUE_NUM,
79 };
80
81 static char *func_table_fields[] = {"valid", "rx_mode", "mtu", "rq_depth", "cfg_q_num"};
82
83 static int hinic_dbg_get_func_table(struct hinic_dev *nic_dev, int idx)
84 {
85         struct tag_sml_funcfg_tbl *funcfg_table_elem;
86         struct hinic_cmd_lt_rd *read_data;
87         u16 out_size = sizeof(*read_data);
88         int ret = ~0;
89         int err;
90
91         read_data = kzalloc(sizeof(*read_data), GFP_KERNEL);
92         if (!read_data)
93                 return ~0;
94
95         read_data->node = TBL_ID_FUNC_CFG_SM_NODE;
96         read_data->inst = TBL_ID_FUNC_CFG_SM_INST;
97         read_data->entry_size = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;
98         read_data->lt_index = HINIC_HWIF_FUNC_IDX(nic_dev->hwdev->hwif);
99         read_data->len = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;
100
101         err = hinic_port_msg_cmd(nic_dev->hwdev, HINIC_PORT_CMD_RD_LINE_TBL, read_data,
102                                  sizeof(*read_data), read_data, &out_size);
103         if (err || out_size != sizeof(*read_data) || read_data->status) {
104                 netif_err(nic_dev, drv, nic_dev->netdev,
105                           "Failed to get func table, err: %d, status: 0x%x, out size: 0x%x\n",
106                           err, read_data->status, out_size);
107                 kfree(read_data);
108                 return ~0;
109         }
110
111         funcfg_table_elem = (struct tag_sml_funcfg_tbl *)read_data->data;
112
113         switch (idx) {
114         case VALID:
115                 ret = funcfg_table_elem->dw0.bs.valid;
116                 break;
117         case RX_MODE:
118                 ret = funcfg_table_elem->dw0.bs.nic_rx_mode;
119                 break;
120         case MTU:
121                 ret = funcfg_table_elem->dw1.bs.mtu;
122                 break;
123         case RQ_DEPTH:
124                 ret = funcfg_table_elem->dw13.bs.cfg_rq_depth;
125                 break;
126         case QUEUE_NUM:
127                 ret = funcfg_table_elem->dw13.bs.cfg_q_num;
128                 break;
129         }
130
131         kfree(read_data);
132
133         return ret;
134 }
135
136 static ssize_t hinic_dbg_cmd_read(struct file *filp, char __user *buffer, size_t count,
137                                   loff_t *ppos)
138 {
139         struct hinic_debug_priv *dbg;
140         char ret_buf[20];
141         int *desc;
142         u64 out;
143         int ret;
144
145         desc = filp->private_data;
146         dbg = container_of(desc, struct hinic_debug_priv, field_id[*desc]);
147
148         switch (dbg->type) {
149         case HINIC_DBG_SQ_INFO:
150                 out = hinic_dbg_get_sq_info(dbg->dev, dbg->object, *desc);
151                 break;
152
153         case HINIC_DBG_RQ_INFO:
154                 out = hinic_dbg_get_rq_info(dbg->dev, dbg->object, *desc);
155                 break;
156
157         case HINIC_DBG_FUNC_TABLE:
158                 out = hinic_dbg_get_func_table(dbg->dev, *desc);
159                 break;
160
161         default:
162                 netif_warn(dbg->dev, drv, dbg->dev->netdev, "Invalid hinic debug cmd: %d\n",
163                            dbg->type);
164                 return -EINVAL;
165         }
166
167         ret = snprintf(ret_buf, sizeof(ret_buf), "0x%llx\n", out);
168
169         return simple_read_from_buffer(buffer, count, ppos, ret_buf, ret);
170 }
171
172 static const struct file_operations hinic_dbg_cmd_fops = {
173         .owner = THIS_MODULE,
174         .open  = simple_open,
175         .read  = hinic_dbg_cmd_read,
176 };
177
178 static int create_dbg_files(struct hinic_dev *dev, enum hinic_dbg_type type, void *data,
179                             struct dentry *root, struct hinic_debug_priv **dbg, char **field,
180                             int nfile)
181 {
182         struct hinic_debug_priv *tmp;
183         int i;
184
185         tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
186         if (!tmp)
187                 return -ENOMEM;
188
189         tmp->dev = dev;
190         tmp->object = data;
191         tmp->type = type;
192         tmp->root = root;
193
194         for (i = 0; i < nfile; i++) {
195                 tmp->field_id[i] = i;
196                 debugfs_create_file(field[i], 0400, root, &tmp->field_id[i], &hinic_dbg_cmd_fops);
197         }
198
199         *dbg = tmp;
200
201         return 0;
202 }
203
204 static void rem_dbg_files(struct hinic_debug_priv *dbg)
205 {
206         if (dbg->type != HINIC_DBG_FUNC_TABLE)
207                 debugfs_remove_recursive(dbg->root);
208
209         kfree(dbg);
210 }
211
212 int hinic_sq_debug_add(struct hinic_dev *dev, u16 sq_id)
213 {
214         struct hinic_sq *sq;
215         struct dentry *root;
216         char sub_dir[16];
217
218         sq = dev->txqs[sq_id].sq;
219
220         sprintf(sub_dir, "0x%x", sq_id);
221
222         root = debugfs_create_dir(sub_dir, dev->sq_dbgfs);
223
224         return create_dbg_files(dev, HINIC_DBG_SQ_INFO, sq, root, &sq->dbg, sq_fields,
225                                 ARRAY_SIZE(sq_fields));
226 }
227
228 void hinic_sq_debug_rem(struct hinic_sq *sq)
229 {
230         if (sq->dbg)
231                 rem_dbg_files(sq->dbg);
232 }
233
234 int hinic_rq_debug_add(struct hinic_dev *dev, u16 rq_id)
235 {
236         struct hinic_rq *rq;
237         struct dentry *root;
238         char sub_dir[16];
239
240         rq = dev->rxqs[rq_id].rq;
241
242         sprintf(sub_dir, "0x%x", rq_id);
243
244         root = debugfs_create_dir(sub_dir, dev->rq_dbgfs);
245
246         return create_dbg_files(dev, HINIC_DBG_RQ_INFO, rq, root, &rq->dbg, rq_fields,
247                                 ARRAY_SIZE(rq_fields));
248 }
249
250 void hinic_rq_debug_rem(struct hinic_rq *rq)
251 {
252         if (rq->dbg)
253                 rem_dbg_files(rq->dbg);
254 }
255
256 int hinic_func_table_debug_add(struct hinic_dev *dev)
257 {
258         if (HINIC_IS_VF(dev->hwdev->hwif))
259                 return 0;
260
261         return create_dbg_files(dev, HINIC_DBG_FUNC_TABLE, dev, dev->func_tbl_dbgfs, &dev->dbg,
262                                 func_table_fields, ARRAY_SIZE(func_table_fields));
263 }
264
265 void hinic_func_table_debug_rem(struct hinic_dev *dev)
266 {
267         if (!HINIC_IS_VF(dev->hwdev->hwif) && dev->dbg)
268                 rem_dbg_files(dev->dbg);
269 }
270
271 void hinic_sq_dbgfs_init(struct hinic_dev *nic_dev)
272 {
273         nic_dev->sq_dbgfs = debugfs_create_dir("SQs", nic_dev->dbgfs_root);
274 }
275
276 void hinic_sq_dbgfs_uninit(struct hinic_dev *nic_dev)
277 {
278         debugfs_remove_recursive(nic_dev->sq_dbgfs);
279 }
280
281 void hinic_rq_dbgfs_init(struct hinic_dev *nic_dev)
282 {
283         nic_dev->rq_dbgfs = debugfs_create_dir("RQs", nic_dev->dbgfs_root);
284 }
285
286 void hinic_rq_dbgfs_uninit(struct hinic_dev *nic_dev)
287 {
288         debugfs_remove_recursive(nic_dev->rq_dbgfs);
289 }
290
291 void hinic_func_tbl_dbgfs_init(struct hinic_dev *nic_dev)
292 {
293         if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
294                 nic_dev->func_tbl_dbgfs = debugfs_create_dir("func_table", nic_dev->dbgfs_root);
295 }
296
297 void hinic_func_tbl_dbgfs_uninit(struct hinic_dev *nic_dev)
298 {
299         if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
300                 debugfs_remove_recursive(nic_dev->func_tbl_dbgfs);
301 }
302
303 void hinic_dbg_init(struct hinic_dev *nic_dev)
304 {
305         nic_dev->dbgfs_root = debugfs_create_dir(pci_name(nic_dev->hwdev->hwif->pdev),
306                                                  hinic_dbgfs_root);
307 }
308
309 void hinic_dbg_uninit(struct hinic_dev *nic_dev)
310 {
311         debugfs_remove_recursive(nic_dev->dbgfs_root);
312         nic_dev->dbgfs_root = NULL;
313 }
314
315 void hinic_dbg_register_debugfs(const char *debugfs_dir_name)
316 {
317         hinic_dbgfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
318 }
319
320 void hinic_dbg_unregister_debugfs(void)
321 {
322         debugfs_remove_recursive(hinic_dbgfs_root);
323         hinic_dbgfs_root = NULL;
324 }