aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-04-08 14:39:32 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:54:44 -0400
commita83b9141b540f96dd59409c6487828e880113a29 (patch)
tree040301dd80eb0307c9dcd5208f88082b4d3922cf /drivers/net/wireless/iwlwifi
parent1620108910b07bc41f4ad462ca56e899faf7e61a (diff)
iwlwifi: adding interrupt counter in debugfs for debugging
This patch adds interrupt statistics report to debugfs, this can help to understand number of interrupts happened which including HW/SW error for easier and better debugging. in /sys/kernel/debug/ieee80211/phyN/iwlagn/data directory use "cat interrupt" to view the current interrupt counter use "echo 0 > interrupt" to clear interrupt counter Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c92
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h18
6 files changed, 141 insertions, 3 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 9dda3d547d0..12de63e9c72 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -911,6 +911,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
911 IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, 911 IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r,
912 i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); 912 i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
913 priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); 913 priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
914 priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
914 } else { 915 } else {
915 /* No handling needed */ 916 /* No handling needed */
916 IWL_DEBUG_RX(priv, 917 IWL_DEBUG_RX(priv,
@@ -1035,6 +1036,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1035 /* Tell the device to stop sending interrupts */ 1036 /* Tell the device to stop sending interrupts */
1036 iwl_disable_interrupts(priv); 1037 iwl_disable_interrupts(priv);
1037 1038
1039 priv->isr_stats.hw++;
1038 iwl_irq_handle_error(priv); 1040 iwl_irq_handle_error(priv);
1039 1041
1040 handled |= CSR_INT_BIT_HW_ERR; 1042 handled |= CSR_INT_BIT_HW_ERR;
@@ -1047,13 +1049,17 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1047#ifdef CONFIG_IWLWIFI_DEBUG 1049#ifdef CONFIG_IWLWIFI_DEBUG
1048 if (priv->debug_level & (IWL_DL_ISR)) { 1050 if (priv->debug_level & (IWL_DL_ISR)) {
1049 /* NIC fires this, but we don't use it, redundant with WAKEUP */ 1051 /* NIC fires this, but we don't use it, redundant with WAKEUP */
1050 if (inta & CSR_INT_BIT_SCD) 1052 if (inta & CSR_INT_BIT_SCD) {
1051 IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " 1053 IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
1052 "the frame/frames.\n"); 1054 "the frame/frames.\n");
1055 priv->isr_stats.sch++;
1056 }
1053 1057
1054 /* Alive notification via Rx interrupt will do the real work */ 1058 /* Alive notification via Rx interrupt will do the real work */
1055 if (inta & CSR_INT_BIT_ALIVE) 1059 if (inta & CSR_INT_BIT_ALIVE) {
1056 IWL_DEBUG_ISR(priv, "Alive interrupt\n"); 1060 IWL_DEBUG_ISR(priv, "Alive interrupt\n");
1061 priv->isr_stats.alive++;
1062 }
1057 } 1063 }
1058#endif 1064#endif
1059 /* Safely ignore these bits for debug checks below */ 1065 /* Safely ignore these bits for debug checks below */
@@ -1069,6 +1075,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1069 IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", 1075 IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
1070 hw_rf_kill ? "disable radio" : "enable radio"); 1076 hw_rf_kill ? "disable radio" : "enable radio");
1071 1077
1078 priv->isr_stats.rfkill++;
1079
1072 /* driver only loads ucode once setting the interface up. 1080 /* driver only loads ucode once setting the interface up.
1073 * the driver allows loading the ucode even if the radio 1081 * the driver allows loading the ucode even if the radio
1074 * is killed. Hence update the killswitch state here. The 1082 * is killed. Hence update the killswitch state here. The
@@ -1088,6 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1088 /* Chip got too hot and stopped itself */ 1096 /* Chip got too hot and stopped itself */
1089 if (inta & CSR_INT_BIT_CT_KILL) { 1097 if (inta & CSR_INT_BIT_CT_KILL) {
1090 IWL_ERR(priv, "Microcode CT kill error detected.\n"); 1098 IWL_ERR(priv, "Microcode CT kill error detected.\n");
1099 priv->isr_stats.ctkill++;
1091 handled |= CSR_INT_BIT_CT_KILL; 1100 handled |= CSR_INT_BIT_CT_KILL;
1092 } 1101 }
1093 1102
@@ -1095,6 +1104,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1095 if (inta & CSR_INT_BIT_SW_ERR) { 1104 if (inta & CSR_INT_BIT_SW_ERR) {
1096 IWL_ERR(priv, "Microcode SW error detected. " 1105 IWL_ERR(priv, "Microcode SW error detected. "
1097 " Restarting 0x%X.\n", inta); 1106 " Restarting 0x%X.\n", inta);
1107 priv->isr_stats.sw++;
1108 priv->isr_stats.sw_err = inta;
1098 iwl_irq_handle_error(priv); 1109 iwl_irq_handle_error(priv);
1099 handled |= CSR_INT_BIT_SW_ERR; 1110 handled |= CSR_INT_BIT_SW_ERR;
1100 } 1111 }
@@ -1110,6 +1121,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1110 iwl_txq_update_write_ptr(priv, &priv->txq[4]); 1121 iwl_txq_update_write_ptr(priv, &priv->txq[4]);
1111 iwl_txq_update_write_ptr(priv, &priv->txq[5]); 1122 iwl_txq_update_write_ptr(priv, &priv->txq[5]);
1112 1123
1124 priv->isr_stats.wakeup++;
1125
1113 handled |= CSR_INT_BIT_WAKEUP; 1126 handled |= CSR_INT_BIT_WAKEUP;
1114 } 1127 }
1115 1128
@@ -1118,19 +1131,23 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1118 * notifications from uCode come through here*/ 1131 * notifications from uCode come through here*/
1119 if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { 1132 if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
1120 iwl_rx_handle(priv); 1133 iwl_rx_handle(priv);
1134 priv->isr_stats.rx++;
1121 handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); 1135 handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
1122 } 1136 }
1123 1137
1124 if (inta & CSR_INT_BIT_FH_TX) { 1138 if (inta & CSR_INT_BIT_FH_TX) {
1125 IWL_DEBUG_ISR(priv, "Tx interrupt\n"); 1139 IWL_DEBUG_ISR(priv, "Tx interrupt\n");
1140 priv->isr_stats.tx++;
1126 handled |= CSR_INT_BIT_FH_TX; 1141 handled |= CSR_INT_BIT_FH_TX;
1127 /* FH finished to write, send event */ 1142 /* FH finished to write, send event */
1128 priv->ucode_write_complete = 1; 1143 priv->ucode_write_complete = 1;
1129 wake_up_interruptible(&priv->wait_command_queue); 1144 wake_up_interruptible(&priv->wait_command_queue);
1130 } 1145 }
1131 1146
1132 if (inta & ~handled) 1147 if (inta & ~handled) {
1133 IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); 1148 IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
1149 priv->isr_stats.unhandled++;
1150 }
1134 1151
1135 if (inta & ~CSR_INI_SET_MASK) { 1152 if (inta & ~CSR_INI_SET_MASK) {
1136 IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", 1153 IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
@@ -1155,6 +1172,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1155 spin_unlock_irqrestore(&priv->lock, flags); 1172 spin_unlock_irqrestore(&priv->lock, flags);
1156} 1173}
1157 1174
1175
1158/****************************************************************************** 1176/******************************************************************************
1159 * 1177 *
1160 * uCode download functions 1178 * uCode download functions
@@ -1983,6 +2001,8 @@ static int iwl_mac_start(struct ieee80211_hw *hw)
1983 2001
1984out: 2002out:
1985 priv->is_open = 1; 2003 priv->is_open = 1;
2004 /* default to MONITOR mode */
2005 priv->iw_mode = NL80211_IFTYPE_MONITOR;
1986 IWL_DEBUG_MAC80211(priv, "leave\n"); 2006 IWL_DEBUG_MAC80211(priv, "leave\n");
1987 return 0; 2007 return 0;
1988} 2008}
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5877293bd21..f2317524028 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2119,6 +2119,12 @@ void iwl_rx_reply_error(struct iwl_priv *priv,
2119} 2119}
2120EXPORT_SYMBOL(iwl_rx_reply_error); 2120EXPORT_SYMBOL(iwl_rx_reply_error);
2121 2121
2122void iwl_clear_isr_stats(struct iwl_priv *priv)
2123{
2124 memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
2125}
2126EXPORT_SYMBOL(iwl_clear_isr_stats);
2127
2122int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, 2128int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
2123 const struct ieee80211_tx_queue_params *params) 2129 const struct ieee80211_tx_queue_params *params)
2124{ 2130{
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index df90c261b6b..8773d733a54 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -480,6 +480,7 @@ int iwl_pci_resume(struct pci_dev *pdev);
480******************************************************/ 480******************************************************/
481void iwl_dump_nic_error_log(struct iwl_priv *priv); 481void iwl_dump_nic_error_log(struct iwl_priv *priv);
482void iwl_dump_nic_event_log(struct iwl_priv *priv); 482void iwl_dump_nic_event_log(struct iwl_priv *priv);
483void iwl_clear_isr_stats(struct iwl_priv *priv);
483 484
484/***************************************************** 485/*****************************************************
485* GEOS 486* GEOS
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 65d1a7f2db9..db069801bc4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -75,6 +75,7 @@ struct iwl_debugfs {
75 struct dentry *file_log_event; 75 struct dentry *file_log_event;
76 struct dentry *file_channels; 76 struct dentry *file_channels;
77 struct dentry *file_status; 77 struct dentry *file_status;
78 struct dentry *file_interrupt;
78 } dbgfs_data_files; 79 } dbgfs_data_files;
79 struct dir_rf_files { 80 struct dir_rf_files {
80 struct dentry *file_disable_sensitivity; 81 struct dentry *file_disable_sensitivity;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 5b8c83939bf..ffc4be3842b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -473,6 +473,95 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
473 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 473 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
474} 474}
475 475
476static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
477 char __user *user_buf,
478 size_t count, loff_t *ppos) {
479
480 struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
481 int pos = 0;
482 int cnt = 0;
483 char *buf;
484 int bufsz = 24 * 64; /* 24 items * 64 char per item */
485 ssize_t ret;
486
487 buf = kzalloc(bufsz, GFP_KERNEL);
488 if (!buf) {
489 IWL_ERR(priv, "Can not allocate Buffer\n");
490 return -ENOMEM;
491 }
492
493 pos += scnprintf(buf + pos, bufsz - pos,
494 "Interrupt Statistics Report:\n");
495
496 pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
497 priv->isr_stats.hw);
498 pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
499 priv->isr_stats.sw);
500 if (priv->isr_stats.sw > 0) {
501 pos += scnprintf(buf + pos, bufsz - pos,
502 "\tLast Restarting Code: 0x%X\n",
503 priv->isr_stats.sw_err);
504 }
505#ifdef CONFIG_IWLWIFI_DEBUG
506 pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
507 priv->isr_stats.sch);
508 pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
509 priv->isr_stats.alive);
510#endif
511 pos += scnprintf(buf + pos, bufsz - pos,
512 "HW RF KILL switch toggled:\t %u\n",
513 priv->isr_stats.rfkill);
514
515 pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
516 priv->isr_stats.ctkill);
517
518 pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
519 priv->isr_stats.wakeup);
520
521 pos += scnprintf(buf + pos, bufsz - pos,
522 "Rx command responses:\t\t %u\n",
523 priv->isr_stats.rx);
524 for (cnt = 0; cnt < REPLY_MAX; cnt++) {
525 if (priv->isr_stats.rx_handlers[cnt] > 0)
526 pos += scnprintf(buf + pos, bufsz - pos,
527 "\tRx handler[%36s]:\t\t %u\n",
528 get_cmd_string(cnt),
529 priv->isr_stats.rx_handlers[cnt]);
530 }
531
532 pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
533 priv->isr_stats.tx);
534
535 pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
536 priv->isr_stats.unhandled);
537
538 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
539 kfree(buf);
540 return ret;
541}
542
543static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
544 const char __user *user_buf,
545 size_t count, loff_t *ppos)
546{
547 struct iwl_priv *priv = file->private_data;
548 char buf[8];
549 int buf_size;
550 u32 reset_flag;
551
552 memset(buf, 0, sizeof(buf));
553 buf_size = min(count, sizeof(buf) - 1);
554 if (copy_from_user(buf, user_buf, buf_size))
555 return -EFAULT;
556 if (sscanf(buf, "%x", &reset_flag) != 1)
557 return -EFAULT;
558 if (reset_flag == 0)
559 iwl_clear_isr_stats(priv);
560
561 return count;
562}
563
564
476DEBUGFS_READ_WRITE_FILE_OPS(sram); 565DEBUGFS_READ_WRITE_FILE_OPS(sram);
477DEBUGFS_WRITE_FILE_OPS(log_event); 566DEBUGFS_WRITE_FILE_OPS(log_event);
478DEBUGFS_READ_FILE_OPS(eeprom); 567DEBUGFS_READ_FILE_OPS(eeprom);
@@ -481,6 +570,7 @@ DEBUGFS_READ_FILE_OPS(rx_statistics);
481DEBUGFS_READ_FILE_OPS(tx_statistics); 570DEBUGFS_READ_FILE_OPS(tx_statistics);
482DEBUGFS_READ_FILE_OPS(channels); 571DEBUGFS_READ_FILE_OPS(channels);
483DEBUGFS_READ_FILE_OPS(status); 572DEBUGFS_READ_FILE_OPS(status);
573DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
484 574
485/* 575/*
486 * Create the debugfs files and directories 576 * Create the debugfs files and directories
@@ -516,6 +606,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
516 DEBUGFS_ADD_FILE(tx_statistics, data); 606 DEBUGFS_ADD_FILE(tx_statistics, data);
517 DEBUGFS_ADD_FILE(channels, data); 607 DEBUGFS_ADD_FILE(channels, data);
518 DEBUGFS_ADD_FILE(status, data); 608 DEBUGFS_ADD_FILE(status, data);
609 DEBUGFS_ADD_FILE(interrupt, data);
519 DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); 610 DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
520 DEBUGFS_ADD_BOOL(disable_chain_noise, rf, 611 DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
521 &priv->disable_chain_noise_cal); 612 &priv->disable_chain_noise_cal);
@@ -546,6 +637,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
546 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); 637 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
547 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); 638 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
548 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); 639 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
640 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
549 DEBUGFS_REMOVE(priv->dbgfs->dir_data); 641 DEBUGFS_REMOVE(priv->dbgfs->dir_data);
550 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); 642 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
551 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); 643 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 59930f398f3..0922e33a7d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -819,6 +819,21 @@ enum {
819 MEASUREMENT_ACTIVE = (1 << 1), 819 MEASUREMENT_ACTIVE = (1 << 1),
820}; 820};
821 821
822/* interrupt statistics */
823struct isr_statistics {
824 u32 hw;
825 u32 sw;
826 u32 sw_err;
827 u32 sch;
828 u32 alive;
829 u32 rfkill;
830 u32 ctkill;
831 u32 wakeup;
832 u32 rx;
833 u32 rx_handlers[REPLY_MAX];
834 u32 tx;
835 u32 unhandled;
836};
822 837
823#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ 838#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
824 839
@@ -975,6 +990,9 @@ struct iwl_priv {
975 u64 bytes; 990 u64 bytes;
976 } tx_stats[3], rx_stats[3]; 991 } tx_stats[3], rx_stats[3];
977 992
993 /* counts interrupts */
994 struct isr_statistics isr_stats;
995
978 struct iwl_power_mgr power_data; 996 struct iwl_power_mgr power_data;
979 997
980 struct iwl_notif_statistics statistics; 998 struct iwl_notif_statistics statistics;