1 /*
2  * Intel Wireless Multicomm 3200 WiFi driver
3  *
4  * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5  * Samuel Ortiz <samuel.ortiz@intel.com>
6  * Zhu Yi <yi.zhu@intel.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version
10  * 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  */
23 
24 #include <linux/slab.h>
25 #include <linux/kernel.h>
26 #include <linux/bitops.h>
27 #include <linux/debugfs.h>
28 #include <linux/export.h>
29 
30 #include "iwm.h"
31 #include "bus.h"
32 #include "rx.h"
33 #include "debug.h"
34 
35 static struct {
36 	u8 id;
37 	char *name;
38 } iwm_debug_module[__IWM_DM_NR] = {
39 	 {IWM_DM_BOOT, "boot"},
40 	 {IWM_DM_FW,   "fw"},
41 	 {IWM_DM_SDIO, "sdio"},
42 	 {IWM_DM_NTF,  "ntf"},
43 	 {IWM_DM_RX,   "rx"},
44 	 {IWM_DM_TX,   "tx"},
45 	 {IWM_DM_MLME, "mlme"},
46 	 {IWM_DM_CMD,  "cmd"},
47 	 {IWM_DM_WEXT,  "wext"},
48 };
49 
50 #define add_dbg_module(dbg, name, id, initlevel) 	\
51 do {							\
52 	dbg.dbg_module[id] = (initlevel);		\
53 	dbg.dbg_module_dentries[id] =			\
54 		debugfs_create_x8(name, 0600,		\
55 				dbg.dbgdir,		\
56 				&(dbg.dbg_module[id]));	\
57 } while (0)
58 
iwm_debugfs_u32_read(void * data,u64 * val)59 static int iwm_debugfs_u32_read(void *data, u64 *val)
60 {
61 	struct iwm_priv *iwm = data;
62 
63 	*val = iwm->dbg.dbg_level;
64 	return 0;
65 }
66 
iwm_debugfs_dbg_level_write(void * data,u64 val)67 static int iwm_debugfs_dbg_level_write(void *data, u64 val)
68 {
69 	struct iwm_priv *iwm = data;
70 	int i;
71 
72 	iwm->dbg.dbg_level = val;
73 
74 	for (i = 0; i < __IWM_DM_NR; i++)
75 		iwm->dbg.dbg_module[i] = val;
76 
77 	return 0;
78 }
79 DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level,
80 			iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write,
81 			"%llu\n");
82 
iwm_debugfs_dbg_modules_write(void * data,u64 val)83 static int iwm_debugfs_dbg_modules_write(void *data, u64 val)
84 {
85 	struct iwm_priv *iwm = data;
86 	int i, bit;
87 
88 	iwm->dbg.dbg_modules = val;
89 
90 	for (i = 0; i < __IWM_DM_NR; i++)
91 		iwm->dbg.dbg_module[i] = 0;
92 
93 	for_each_set_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR)
94 		iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level;
95 
96 	return 0;
97 }
98 DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules,
99 			iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write,
100 			"%llu\n");
101 
iwm_generic_open(struct inode * inode,struct file * filp)102 static int iwm_generic_open(struct inode *inode, struct file *filp)
103 {
104 	filp->private_data = inode->i_private;
105 	return 0;
106 }
107 
108 
iwm_debugfs_txq_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)109 static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer,
110 				   size_t count, loff_t *ppos)
111 {
112 	struct iwm_priv *iwm = filp->private_data;
113 	char *buf;
114 	int i, buf_len = 4096;
115 	size_t len = 0;
116 	ssize_t ret;
117 
118 	if (*ppos != 0)
119 		return 0;
120 	if (count < sizeof(buf))
121 		return -ENOSPC;
122 
123 	buf = kzalloc(buf_len, GFP_KERNEL);
124 	if (!buf)
125 		return -ENOMEM;
126 
127 	for (i = 0; i < IWM_TX_QUEUES; i++) {
128 		struct iwm_tx_queue *txq = &iwm->txq[i];
129 		struct sk_buff *skb;
130 		int j;
131 		unsigned long flags;
132 
133 		spin_lock_irqsave(&txq->queue.lock, flags);
134 
135 		skb = (struct sk_buff *)&txq->queue;
136 
137 		len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i);
138 		len += snprintf(buf + len, buf_len - len, "\tStopped:     %d\n",
139 				__netif_subqueue_stopped(iwm_to_ndev(iwm),
140 							 txq->id));
141 		len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n",
142 				txq->concat_count);
143 		len += snprintf(buf + len, buf_len - len, "\tQueue len:   %d\n",
144 				skb_queue_len(&txq->queue));
145 		for (j = 0; j < skb_queue_len(&txq->queue); j++) {
146 			struct iwm_tx_info *tx_info;
147 
148 			skb = skb->next;
149 			tx_info = skb_to_tx_info(skb);
150 
151 			len += snprintf(buf + len, buf_len - len,
152 					"\tSKB #%d\n", j);
153 			len += snprintf(buf + len, buf_len - len,
154 					"\t\tsta:   %d\n", tx_info->sta);
155 			len += snprintf(buf + len, buf_len - len,
156 					"\t\tcolor: %d\n", tx_info->color);
157 			len += snprintf(buf + len, buf_len - len,
158 					"\t\ttid:   %d\n", tx_info->tid);
159 		}
160 
161 		spin_unlock_irqrestore(&txq->queue.lock, flags);
162 
163 		spin_lock_irqsave(&txq->stopped_queue.lock, flags);
164 
165 		len += snprintf(buf + len, buf_len - len,
166 				"\tStopped Queue len:   %d\n",
167 				skb_queue_len(&txq->stopped_queue));
168 		for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) {
169 			struct iwm_tx_info *tx_info;
170 
171 			skb = skb->next;
172 			tx_info = skb_to_tx_info(skb);
173 
174 			len += snprintf(buf + len, buf_len - len,
175 					"\tSKB #%d\n", j);
176 			len += snprintf(buf + len, buf_len - len,
177 					"\t\tsta:   %d\n", tx_info->sta);
178 			len += snprintf(buf + len, buf_len - len,
179 					"\t\tcolor: %d\n", tx_info->color);
180 			len += snprintf(buf + len, buf_len - len,
181 					"\t\ttid:   %d\n", tx_info->tid);
182 		}
183 
184 		spin_unlock_irqrestore(&txq->stopped_queue.lock, flags);
185 	}
186 
187 	ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
188 	kfree(buf);
189 
190 	return ret;
191 }
192 
iwm_debugfs_tx_credit_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)193 static ssize_t iwm_debugfs_tx_credit_read(struct file *filp,
194 					  char __user *buffer,
195 					  size_t count, loff_t *ppos)
196 {
197 	struct iwm_priv *iwm = filp->private_data;
198 	struct iwm_tx_credit *credit = &iwm->tx_credit;
199 	char *buf;
200 	int i, buf_len = 4096;
201 	size_t len = 0;
202 	ssize_t ret;
203 
204 	if (*ppos != 0)
205 		return 0;
206 	if (count < sizeof(buf))
207 		return -ENOSPC;
208 
209 	buf = kzalloc(buf_len, GFP_KERNEL);
210 	if (!buf)
211 		return -ENOMEM;
212 
213 	len += snprintf(buf + len, buf_len - len,
214 			"NR pools:  %d\n", credit->pool_nr);
215 	len += snprintf(buf + len, buf_len - len,
216 			"pools map: 0x%lx\n", credit->full_pools_map);
217 
218 	len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n");
219 	for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) {
220 		len += snprintf(buf + len, buf_len - len,
221 				"pools entry #%d\n", i);
222 		len += snprintf(buf + len, buf_len - len,
223 				"\tid:          %d\n",
224 				credit->pools[i].id);
225 		len += snprintf(buf + len, buf_len - len,
226 				"\tsid:         %d\n",
227 				credit->pools[i].sid);
228 		len += snprintf(buf + len, buf_len - len,
229 				"\tmin_pages:   %d\n",
230 				credit->pools[i].min_pages);
231 		len += snprintf(buf + len, buf_len - len,
232 				"\tmax_pages:   %d\n",
233 				credit->pools[i].max_pages);
234 		len += snprintf(buf + len, buf_len - len,
235 				"\talloc_pages: %d\n",
236 				credit->pools[i].alloc_pages);
237 		len += snprintf(buf + len, buf_len - len,
238 				"\tfreed_pages: %d\n",
239 				credit->pools[i].total_freed_pages);
240 	}
241 
242 	len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n");
243 	for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) {
244 		len += snprintf(buf + len, buf_len - len,
245 				"spools entry #%d\n", i);
246 		len += snprintf(buf + len, buf_len - len,
247 				"\tid:          %d\n",
248 				credit->spools[i].id);
249 		len += snprintf(buf + len, buf_len - len,
250 				"\tmax_pages:   %d\n",
251 				credit->spools[i].max_pages);
252 		len += snprintf(buf + len, buf_len - len,
253 				"\talloc_pages: %d\n",
254 				credit->spools[i].alloc_pages);
255 
256 	}
257 
258 	ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
259 	kfree(buf);
260 
261 	return ret;
262 }
263 
iwm_debugfs_rx_ticket_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)264 static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
265 					  char __user *buffer,
266 					  size_t count, loff_t *ppos)
267 {
268 	struct iwm_priv *iwm = filp->private_data;
269 	struct iwm_rx_ticket_node *ticket;
270 	char *buf;
271 	int buf_len = 4096, i;
272 	size_t len = 0;
273 	ssize_t ret;
274 
275 	if (*ppos != 0)
276 		return 0;
277 	if (count < sizeof(buf))
278 		return -ENOSPC;
279 
280 	buf = kzalloc(buf_len, GFP_KERNEL);
281 	if (!buf)
282 		return -ENOMEM;
283 
284 	spin_lock(&iwm->ticket_lock);
285 	list_for_each_entry(ticket, &iwm->rx_tickets, node) {
286 		len += snprintf(buf + len, buf_len - len, "Ticket #%d\n",
287 				ticket->ticket->id);
288 		len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n",
289 				ticket->ticket->action);
290 		len += snprintf(buf + len, buf_len - len, "\tflags:  0x%x\n",
291 				ticket->ticket->flags);
292 	}
293 	spin_unlock(&iwm->ticket_lock);
294 
295 	for (i = 0; i < IWM_RX_ID_HASH; i++) {
296 		struct iwm_rx_packet *packet;
297 		struct list_head *pkt_list = &iwm->rx_packets[i];
298 
299 		if (!list_empty(pkt_list)) {
300 			len += snprintf(buf + len, buf_len - len,
301 					"Packet hash #%d\n", i);
302 			spin_lock(&iwm->packet_lock[i]);
303 			list_for_each_entry(packet, pkt_list, node) {
304 				len += snprintf(buf + len, buf_len - len,
305 						"\tPacket id:     %d\n",
306 						packet->id);
307 				len += snprintf(buf + len, buf_len - len,
308 						"\tPacket length: %lu\n",
309 						packet->pkt_size);
310 			}
311 			spin_unlock(&iwm->packet_lock[i]);
312 		}
313 	}
314 
315 	ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
316 	kfree(buf);
317 
318 	return ret;
319 }
320 
iwm_debugfs_fw_err_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)321 static ssize_t iwm_debugfs_fw_err_read(struct file *filp,
322 				       char __user *buffer,
323 				       size_t count, loff_t *ppos)
324 {
325 
326 	struct iwm_priv *iwm = filp->private_data;
327 	char buf[512];
328 	int buf_len = 512;
329 	size_t len = 0;
330 
331 	if (*ppos != 0)
332 		return 0;
333 	if (count < sizeof(buf))
334 		return -ENOSPC;
335 
336 	if (!iwm->last_fw_err)
337 		return -ENOMEM;
338 
339 	if (iwm->last_fw_err->line_num == 0)
340 		goto out;
341 
342 	len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n",
343 	     (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC)
344 			? 'L' : 'U');
345 	len += snprintf(buf + len, buf_len - len,
346 			"\tCategory:    %d\n",
347 			le32_to_cpu(iwm->last_fw_err->category));
348 
349 	len += snprintf(buf + len, buf_len - len,
350 			"\tStatus:      0x%x\n",
351 			le32_to_cpu(iwm->last_fw_err->status));
352 
353 	len += snprintf(buf + len, buf_len - len,
354 			"\tPC:          0x%x\n",
355 			le32_to_cpu(iwm->last_fw_err->pc));
356 
357 	len += snprintf(buf + len, buf_len - len,
358 			"\tblink1:      %d\n",
359 			le32_to_cpu(iwm->last_fw_err->blink1));
360 
361 	len += snprintf(buf + len, buf_len - len,
362 			"\tblink2:      %d\n",
363 			le32_to_cpu(iwm->last_fw_err->blink2));
364 
365 	len += snprintf(buf + len, buf_len - len,
366 			"\tilink1:      %d\n",
367 			le32_to_cpu(iwm->last_fw_err->ilink1));
368 
369 	len += snprintf(buf + len, buf_len - len,
370 			"\tilink2:      %d\n",
371 			le32_to_cpu(iwm->last_fw_err->ilink2));
372 
373 	len += snprintf(buf + len, buf_len - len,
374 			"\tData1:       0x%x\n",
375 			le32_to_cpu(iwm->last_fw_err->data1));
376 
377 	len += snprintf(buf + len, buf_len - len,
378 			"\tData2:       0x%x\n",
379 			le32_to_cpu(iwm->last_fw_err->data2));
380 
381 	len += snprintf(buf + len, buf_len - len,
382 			"\tLine number: %d\n",
383 			le32_to_cpu(iwm->last_fw_err->line_num));
384 
385 	len += snprintf(buf + len, buf_len - len,
386 			"\tUMAC status: 0x%x\n",
387 			le32_to_cpu(iwm->last_fw_err->umac_status));
388 
389 	len += snprintf(buf + len, buf_len - len,
390 			"\tLMAC status: 0x%x\n",
391 			le32_to_cpu(iwm->last_fw_err->lmac_status));
392 
393 	len += snprintf(buf + len, buf_len - len,
394 			"\tSDIO status: 0x%x\n",
395 			le32_to_cpu(iwm->last_fw_err->sdio_status));
396 
397 out:
398 
399 	return simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
400 }
401 
402 static const struct file_operations iwm_debugfs_txq_fops = {
403 	.owner =	THIS_MODULE,
404 	.open =		iwm_generic_open,
405 	.read =		iwm_debugfs_txq_read,
406 	.llseek =	default_llseek,
407 };
408 
409 static const struct file_operations iwm_debugfs_tx_credit_fops = {
410 	.owner =	THIS_MODULE,
411 	.open =		iwm_generic_open,
412 	.read =		iwm_debugfs_tx_credit_read,
413 	.llseek =	default_llseek,
414 };
415 
416 static const struct file_operations iwm_debugfs_rx_ticket_fops = {
417 	.owner =	THIS_MODULE,
418 	.open =		iwm_generic_open,
419 	.read =		iwm_debugfs_rx_ticket_read,
420 	.llseek =	default_llseek,
421 };
422 
423 static const struct file_operations iwm_debugfs_fw_err_fops = {
424 	.owner =	THIS_MODULE,
425 	.open =		iwm_generic_open,
426 	.read =		iwm_debugfs_fw_err_read,
427 	.llseek =	default_llseek,
428 };
429 
iwm_debugfs_init(struct iwm_priv * iwm)430 void iwm_debugfs_init(struct iwm_priv *iwm)
431 {
432 	int i;
433 
434 	iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
435 	iwm->dbg.devdir = debugfs_create_dir(wiphy_name(iwm_to_wiphy(iwm)),
436 					     iwm->dbg.rootdir);
437 	iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir);
438 	iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir);
439 	iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir);
440 	iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir);
441 	if (iwm->bus_ops->debugfs_init)
442 		iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir);
443 
444 	iwm->dbg.dbg_level = IWM_DL_NONE;
445 	iwm->dbg.dbg_level_dentry =
446 		debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm,
447 				    &fops_iwm_dbg_level);
448 
449 	iwm->dbg.dbg_modules = IWM_DM_DEFAULT;
450 	iwm->dbg.dbg_modules_dentry =
451 		debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm,
452 				    &fops_iwm_dbg_modules);
453 
454 	for (i = 0; i < __IWM_DM_NR; i++)
455 		add_dbg_module(iwm->dbg, iwm_debug_module[i].name,
456 			       iwm_debug_module[i].id, IWM_DL_DEFAULT);
457 
458 	iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200,
459 						  iwm->dbg.txdir, iwm,
460 						  &iwm_debugfs_txq_fops);
461 	iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200,
462 						   iwm->dbg.txdir, iwm,
463 						   &iwm_debugfs_tx_credit_fops);
464 	iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200,
465 						  iwm->dbg.rxdir, iwm,
466 						  &iwm_debugfs_rx_ticket_fops);
467 	iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200,
468 						     iwm->dbg.dbgdir, iwm,
469 						     &iwm_debugfs_fw_err_fops);
470 }
471 
iwm_debugfs_exit(struct iwm_priv * iwm)472 void iwm_debugfs_exit(struct iwm_priv *iwm)
473 {
474 	int i;
475 
476 	for (i = 0; i < __IWM_DM_NR; i++)
477 		debugfs_remove(iwm->dbg.dbg_module_dentries[i]);
478 
479 	debugfs_remove(iwm->dbg.dbg_modules_dentry);
480 	debugfs_remove(iwm->dbg.dbg_level_dentry);
481 	debugfs_remove(iwm->dbg.txq_dentry);
482 	debugfs_remove(iwm->dbg.tx_credit_dentry);
483 	debugfs_remove(iwm->dbg.rx_ticket_dentry);
484 	debugfs_remove(iwm->dbg.fw_err_dentry);
485 	if (iwm->bus_ops->debugfs_exit)
486 		iwm->bus_ops->debugfs_exit(iwm);
487 
488 	debugfs_remove(iwm->dbg.busdir);
489 	debugfs_remove(iwm->dbg.dbgdir);
490 	debugfs_remove(iwm->dbg.txdir);
491 	debugfs_remove(iwm->dbg.rxdir);
492 	debugfs_remove(iwm->dbg.devdir);
493 	debugfs_remove(iwm->dbg.rootdir);
494 }
495