aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2009-09-01 09:14:06 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-09-01 12:48:28 -0400
commit04e715cd46ba523806070fbf9ded009f10e107cd (patch)
treeed6f3130398a7d6e8b64d39ae87c241652348ed1 /drivers/net/wireless
parentd210176eaaed0c7883caba52665bcfb5d420c660 (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')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debug.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debugfs.c105
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c6
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c2
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
101static int iwm_txrx_open(struct inode *inode, struct file *filp) 101static 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
292static 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
368out:
369
370 return simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
371}
292 372
293static const struct file_operations iwm_debugfs_txq_fops = { 373static 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
299static const struct file_operations iwm_debugfs_tx_credit_fops = { 379static 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
305static const struct file_operations iwm_debugfs_rx_ticket_fops = { 385static 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
391static 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
311int iwm_debugfs_init(struct iwm_priv *iwm) 397int 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));