diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2009-09-01 09:14:06 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-09-01 12:48:28 -0400 |
commit | 04e715cd46ba523806070fbf9ded009f10e107cd (patch) | |
tree | ed6f3130398a7d6e8b64d39ae87c241652348ed1 /drivers/net/wireless/iwmc3200wifi | |
parent | d210176eaaed0c7883caba52665bcfb5d420c660 (diff) |
iwmc3200wifi: Add a last_fw_err debugfs entry
In order to check what was the last fw error we got accross resets, we add
this debugfs entry. It displays the complete ASSERT information.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/debug.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/debugfs.c | 105 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/iwm.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/rx.c | 2 |
5 files changed, 113 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h index 8fbb42d9c21f..e35c9b693d1f 100644 --- a/drivers/net/wireless/iwmc3200wifi/debug.h +++ b/drivers/net/wireless/iwmc3200wifi/debug.h | |||
@@ -108,6 +108,8 @@ struct iwm_debugfs { | |||
108 | struct dentry *txq_dentry; | 108 | struct dentry *txq_dentry; |
109 | struct dentry *tx_credit_dentry; | 109 | struct dentry *tx_credit_dentry; |
110 | struct dentry *rx_ticket_dentry; | 110 | struct dentry *rx_ticket_dentry; |
111 | |||
112 | struct dentry *fw_err_dentry; | ||
111 | }; | 113 | }; |
112 | 114 | ||
113 | #ifdef CONFIG_IWM_DEBUG | 115 | #ifdef CONFIG_IWM_DEBUG |
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index 0fa7b9150d58..1465379f900a 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c | |||
@@ -98,7 +98,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, | |||
98 | iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, | 98 | iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, |
99 | "%llu\n"); | 99 | "%llu\n"); |
100 | 100 | ||
101 | static int iwm_txrx_open(struct inode *inode, struct file *filp) | 101 | static int iwm_generic_open(struct inode *inode, struct file *filp) |
102 | { | 102 | { |
103 | filp->private_data = inode->i_private; | 103 | filp->private_data = inode->i_private; |
104 | return 0; | 104 | return 0; |
@@ -289,25 +289,111 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, | |||
289 | return ret; | 289 | return ret; |
290 | } | 290 | } |
291 | 291 | ||
292 | static ssize_t iwm_debugfs_fw_err_read(struct file *filp, | ||
293 | char __user *buffer, | ||
294 | size_t count, loff_t *ppos) | ||
295 | { | ||
296 | |||
297 | struct iwm_priv *iwm = filp->private_data; | ||
298 | char buf[512]; | ||
299 | int buf_len = 512; | ||
300 | size_t len = 0; | ||
301 | |||
302 | if (*ppos != 0) | ||
303 | return 0; | ||
304 | if (count < sizeof(buf)) | ||
305 | return -ENOSPC; | ||
306 | |||
307 | if (!iwm->last_fw_err) | ||
308 | return -ENOMEM; | ||
309 | |||
310 | if (iwm->last_fw_err->line_num == 0) | ||
311 | goto out; | ||
312 | |||
313 | len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n", | ||
314 | (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) | ||
315 | ? 'L' : 'U'); | ||
316 | len += snprintf(buf + len, buf_len - len, | ||
317 | "\tCategory: %d\n", | ||
318 | le32_to_cpu(iwm->last_fw_err->category)); | ||
319 | |||
320 | len += snprintf(buf + len, buf_len - len, | ||
321 | "\tStatus: 0x%x\n", | ||
322 | le32_to_cpu(iwm->last_fw_err->status)); | ||
323 | |||
324 | len += snprintf(buf + len, buf_len - len, | ||
325 | "\tPC: 0x%x\n", | ||
326 | le32_to_cpu(iwm->last_fw_err->pc)); | ||
327 | |||
328 | len += snprintf(buf + len, buf_len - len, | ||
329 | "\tblink1: %d\n", | ||
330 | le32_to_cpu(iwm->last_fw_err->blink1)); | ||
331 | |||
332 | len += snprintf(buf + len, buf_len - len, | ||
333 | "\tblink2: %d\n", | ||
334 | le32_to_cpu(iwm->last_fw_err->blink2)); | ||
335 | |||
336 | len += snprintf(buf + len, buf_len - len, | ||
337 | "\tilink1: %d\n", | ||
338 | le32_to_cpu(iwm->last_fw_err->ilink1)); | ||
339 | |||
340 | len += snprintf(buf + len, buf_len - len, | ||
341 | "\tilink2: %d\n", | ||
342 | le32_to_cpu(iwm->last_fw_err->ilink2)); | ||
343 | |||
344 | len += snprintf(buf + len, buf_len - len, | ||
345 | "\tData1: 0x%x\n", | ||
346 | le32_to_cpu(iwm->last_fw_err->data1)); | ||
347 | |||
348 | len += snprintf(buf + len, buf_len - len, | ||
349 | "\tData2: 0x%x\n", | ||
350 | le32_to_cpu(iwm->last_fw_err->data2)); | ||
351 | |||
352 | len += snprintf(buf + len, buf_len - len, | ||
353 | "\tLine number: %d\n", | ||
354 | le32_to_cpu(iwm->last_fw_err->line_num)); | ||
355 | |||
356 | len += snprintf(buf + len, buf_len - len, | ||
357 | "\tUMAC status: 0x%x\n", | ||
358 | le32_to_cpu(iwm->last_fw_err->umac_status)); | ||
359 | |||
360 | len += snprintf(buf + len, buf_len - len, | ||
361 | "\tLMAC status: 0x%x\n", | ||
362 | le32_to_cpu(iwm->last_fw_err->lmac_status)); | ||
363 | |||
364 | len += snprintf(buf + len, buf_len - len, | ||
365 | "\tSDIO status: 0x%x\n", | ||
366 | le32_to_cpu(iwm->last_fw_err->sdio_status)); | ||
367 | |||
368 | out: | ||
369 | |||
370 | return simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
371 | } | ||
292 | 372 | ||
293 | static const struct file_operations iwm_debugfs_txq_fops = { | 373 | static const struct file_operations iwm_debugfs_txq_fops = { |
294 | .owner = THIS_MODULE, | 374 | .owner = THIS_MODULE, |
295 | .open = iwm_txrx_open, | 375 | .open = iwm_generic_open, |
296 | .read = iwm_debugfs_txq_read, | 376 | .read = iwm_debugfs_txq_read, |
297 | }; | 377 | }; |
298 | 378 | ||
299 | static const struct file_operations iwm_debugfs_tx_credit_fops = { | 379 | static const struct file_operations iwm_debugfs_tx_credit_fops = { |
300 | .owner = THIS_MODULE, | 380 | .owner = THIS_MODULE, |
301 | .open = iwm_txrx_open, | 381 | .open = iwm_generic_open, |
302 | .read = iwm_debugfs_tx_credit_read, | 382 | .read = iwm_debugfs_tx_credit_read, |
303 | }; | 383 | }; |
304 | 384 | ||
305 | static const struct file_operations iwm_debugfs_rx_ticket_fops = { | 385 | static const struct file_operations iwm_debugfs_rx_ticket_fops = { |
306 | .owner = THIS_MODULE, | 386 | .owner = THIS_MODULE, |
307 | .open = iwm_txrx_open, | 387 | .open = iwm_generic_open, |
308 | .read = iwm_debugfs_rx_ticket_read, | 388 | .read = iwm_debugfs_rx_ticket_read, |
309 | }; | 389 | }; |
310 | 390 | ||
391 | static const struct file_operations iwm_debugfs_fw_err_fops = { | ||
392 | .owner = THIS_MODULE, | ||
393 | .open = iwm_generic_open, | ||
394 | .read = iwm_debugfs_fw_err_read, | ||
395 | }; | ||
396 | |||
311 | int iwm_debugfs_init(struct iwm_priv *iwm) | 397 | int iwm_debugfs_init(struct iwm_priv *iwm) |
312 | { | 398 | { |
313 | int i, result; | 399 | int i, result; |
@@ -423,6 +509,16 @@ int iwm_debugfs_init(struct iwm_priv *iwm) | |||
423 | goto error; | 509 | goto error; |
424 | } | 510 | } |
425 | 511 | ||
512 | iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200, | ||
513 | iwm->dbg.dbgdir, iwm, | ||
514 | &iwm_debugfs_fw_err_fops); | ||
515 | result = PTR_ERR(iwm->dbg.fw_err_dentry); | ||
516 | if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) { | ||
517 | IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result); | ||
518 | goto error; | ||
519 | } | ||
520 | |||
521 | |||
426 | return 0; | 522 | return 0; |
427 | 523 | ||
428 | error: | 524 | error: |
@@ -441,6 +537,7 @@ void iwm_debugfs_exit(struct iwm_priv *iwm) | |||
441 | debugfs_remove(iwm->dbg.txq_dentry); | 537 | debugfs_remove(iwm->dbg.txq_dentry); |
442 | debugfs_remove(iwm->dbg.tx_credit_dentry); | 538 | debugfs_remove(iwm->dbg.tx_credit_dentry); |
443 | debugfs_remove(iwm->dbg.rx_ticket_dentry); | 539 | debugfs_remove(iwm->dbg.rx_ticket_dentry); |
540 | debugfs_remove(iwm->dbg.fw_err_dentry); | ||
444 | if (iwm->bus_ops->debugfs_exit) | 541 | if (iwm->bus_ops->debugfs_exit) |
445 | iwm->bus_ops->debugfs_exit(iwm); | 542 | iwm->bus_ops->debugfs_exit(iwm); |
446 | 543 | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index f5c2d6f3fd43..1b02a4e2a1ac 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h | |||
@@ -289,6 +289,8 @@ struct iwm_priv { | |||
289 | u8 *resp_ie; | 289 | u8 *resp_ie; |
290 | int resp_ie_len; | 290 | int resp_ie_len; |
291 | 291 | ||
292 | struct iwm_fw_error_hdr *last_fw_err; | ||
293 | |||
292 | char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); | 294 | char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); |
293 | }; | 295 | }; |
294 | 296 | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 6a5b76acb645..d668e4756324 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c | |||
@@ -260,6 +260,11 @@ int iwm_priv_init(struct iwm_priv *iwm) | |||
260 | iwm->watchdog.data = (unsigned long)iwm; | 260 | iwm->watchdog.data = (unsigned long)iwm; |
261 | mutex_init(&iwm->mutex); | 261 | mutex_init(&iwm->mutex); |
262 | 262 | ||
263 | iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr), | ||
264 | GFP_KERNEL); | ||
265 | if (iwm->last_fw_err == NULL) | ||
266 | return -ENOMEM; | ||
267 | |||
263 | return 0; | 268 | return 0; |
264 | } | 269 | } |
265 | 270 | ||
@@ -271,6 +276,7 @@ void iwm_priv_deinit(struct iwm_priv *iwm) | |||
271 | destroy_workqueue(iwm->txq[i].wq); | 276 | destroy_workqueue(iwm->txq[i].wq); |
272 | 277 | ||
273 | destroy_workqueue(iwm->rx_wq); | 278 | destroy_workqueue(iwm->rx_wq); |
279 | kfree(iwm->last_fw_err); | ||
274 | } | 280 | } |
275 | 281 | ||
276 | /* | 282 | /* |
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 14950b147f91..40dbcbc16593 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c | |||
@@ -102,6 +102,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, | |||
102 | error = (struct iwm_umac_notif_error *)buf; | 102 | error = (struct iwm_umac_notif_error *)buf; |
103 | fw_err = &error->err; | 103 | fw_err = &error->err; |
104 | 104 | ||
105 | memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr)); | ||
106 | |||
105 | IWM_ERR(iwm, "%cMAC FW ERROR:\n", | 107 | IWM_ERR(iwm, "%cMAC FW ERROR:\n", |
106 | (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); | 108 | (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); |
107 | IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); | 109 | IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); |