aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-12-10 17:37:26 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-21 18:56:16 -0500
commita9e1cb6a78ea8a74c49bf76726a2942f636a833b (patch)
treee1f4f083c7154f322b2a65c90a04da817403fcba /drivers
parent696bdee3ba216186e21997d20a839b76158346e6 (diff)
iwlwifi: add continuous uCode event log capability
In order to help uCode debugging, adding the capability to provide continuous uCode event logging function. uCode events is located in round-robin event queue and filled by uCode, by enable continuous event logging, driver check the write pointer and log the newly added events in iwl_bg_ucode_trace() timer function. There is still possibility of missing events if event queue being wrapped before next event dump; but with this capability, we can have much better understanding of the uCode behavior during runtime; it can help to debug the uCode related issues. Methods to enable/disable the continuous event log: step 1: enable ucode trace timer "echo 1 > /sys/kernel/debug/ieee80211/phyX/iwlagn/debug/ucode_tracing" step 2: start ftrace sudo ./trace-cmd record -e iwlwifi_ucode:* sleep 1d step 3: stop ftrace sudo ./trace-cmd report trace.dat step 4: disable ucode trace timer "echo 0 > /sys/kernel/debug/ieee80211/phyX/iwlagn/debug/ucode_tracing" use "ucode_tracing" debugfs file to display number of event queue wrapped when driver attempt the continuous event logging. If event queue being wrapped more than once when driver has opportunity to log the event; it indicated there are events missing in the event log trace. This continuous event log function only available for 4965 and newer NICs. 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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c130
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c56
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h29
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h44
6 files changed, 262 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 954b8ae2c880..4d85c28e38e2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -657,6 +657,131 @@ static void iwl_bg_statistics_periodic(unsigned long data)
657 iwl_send_statistics_request(priv, CMD_ASYNC, false); 657 iwl_send_statistics_request(priv, CMD_ASYNC, false);
658} 658}
659 659
660
661static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
662 u32 start_idx, u32 num_events,
663 u32 mode)
664{
665 u32 i;
666 u32 ptr; /* SRAM byte address of log data */
667 u32 ev, time, data; /* event log data */
668 unsigned long reg_flags;
669
670 if (mode == 0)
671 ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
672 else
673 ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
674
675 /* Make sure device is powered up for SRAM reads */
676 spin_lock_irqsave(&priv->reg_lock, reg_flags);
677 if (iwl_grab_nic_access(priv)) {
678 spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
679 return;
680 }
681
682 /* Set starting address; reads will auto-increment */
683 _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
684 rmb();
685
686 /*
687 * "time" is actually "data" for mode 0 (no timestamp).
688 * place event id # at far right for easier visual parsing.
689 */
690 for (i = 0; i < num_events; i++) {
691 ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
692 time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
693 if (mode == 0) {
694 trace_iwlwifi_dev_ucode_cont_event(priv,
695 0, time, ev);
696 } else {
697 data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
698 trace_iwlwifi_dev_ucode_cont_event(priv,
699 time, data, ev);
700 }
701 }
702 /* Allow device to power down */
703 iwl_release_nic_access(priv);
704 spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
705}
706
707void iwl_continuous_event_trace(struct iwl_priv *priv)
708{
709 u32 capacity; /* event log capacity in # entries */
710 u32 base; /* SRAM byte address of event log header */
711 u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
712 u32 num_wraps; /* # times uCode wrapped to top of log */
713 u32 next_entry; /* index of next entry to be written by uCode */
714
715 if (priv->ucode_type == UCODE_INIT)
716 base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
717 else
718 base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
719 if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
720 capacity = iwl_read_targ_mem(priv, base);
721 num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
722 mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
723 next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
724 } else
725 return;
726
727 if (num_wraps == priv->event_log.num_wraps) {
728 iwl_print_cont_event_trace(priv,
729 base, priv->event_log.next_entry,
730 next_entry - priv->event_log.next_entry,
731 mode);
732 priv->event_log.non_wraps_count++;
733 } else {
734 if ((num_wraps - priv->event_log.num_wraps) > 1)
735 priv->event_log.wraps_more_count++;
736 else
737 priv->event_log.wraps_once_count++;
738 trace_iwlwifi_dev_ucode_wrap_event(priv,
739 num_wraps - priv->event_log.num_wraps,
740 next_entry, priv->event_log.next_entry);
741 if (next_entry < priv->event_log.next_entry) {
742 iwl_print_cont_event_trace(priv, base,
743 priv->event_log.next_entry,
744 capacity - priv->event_log.next_entry,
745 mode);
746
747 iwl_print_cont_event_trace(priv, base, 0,
748 next_entry, mode);
749 } else {
750 iwl_print_cont_event_trace(priv, base,
751 next_entry, capacity - next_entry,
752 mode);
753
754 iwl_print_cont_event_trace(priv, base, 0,
755 next_entry, mode);
756 }
757 }
758 priv->event_log.num_wraps = num_wraps;
759 priv->event_log.next_entry = next_entry;
760}
761
762/**
763 * iwl_bg_ucode_trace - Timer callback to log ucode event
764 *
765 * The timer is continually set to execute every
766 * UCODE_TRACE_PERIOD milliseconds after the last timer expired
767 * this function is to perform continuous uCode event logging operation
768 * if enabled
769 */
770static void iwl_bg_ucode_trace(unsigned long data)
771{
772 struct iwl_priv *priv = (struct iwl_priv *)data;
773
774 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
775 return;
776
777 if (priv->event_log.ucode_trace) {
778 iwl_continuous_event_trace(priv);
779 /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
780 mod_timer(&priv->ucode_trace,
781 jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
782 }
783}
784
660static void iwl_rx_beacon_notif(struct iwl_priv *priv, 785static void iwl_rx_beacon_notif(struct iwl_priv *priv,
661 struct iwl_rx_mem_buffer *rxb) 786 struct iwl_rx_mem_buffer *rxb)
662{ 787{
@@ -3128,6 +3253,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
3128 priv->statistics_periodic.data = (unsigned long)priv; 3253 priv->statistics_periodic.data = (unsigned long)priv;
3129 priv->statistics_periodic.function = iwl_bg_statistics_periodic; 3254 priv->statistics_periodic.function = iwl_bg_statistics_periodic;
3130 3255
3256 init_timer(&priv->ucode_trace);
3257 priv->ucode_trace.data = (unsigned long)priv;
3258 priv->ucode_trace.function = iwl_bg_ucode_trace;
3259
3131 if (!priv->cfg->use_isr_legacy) 3260 if (!priv->cfg->use_isr_legacy)
3132 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) 3261 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
3133 iwl_irq_tasklet, (unsigned long)priv); 3262 iwl_irq_tasklet, (unsigned long)priv);
@@ -3146,6 +3275,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
3146 cancel_delayed_work(&priv->alive_start); 3275 cancel_delayed_work(&priv->alive_start);
3147 cancel_work_sync(&priv->beacon_update); 3276 cancel_work_sync(&priv->beacon_update);
3148 del_timer_sync(&priv->statistics_periodic); 3277 del_timer_sync(&priv->statistics_periodic);
3278 del_timer_sync(&priv->ucode_trace);
3149} 3279}
3150 3280
3151static void iwl_init_hw_rates(struct iwl_priv *priv, 3281static void iwl_init_hw_rates(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 86a67672598d..58e0462cafa3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -110,6 +110,7 @@ struct iwl_debugfs {
110 struct dentry *file_clear_ucode_statistics; 110 struct dentry *file_clear_ucode_statistics;
111 struct dentry *file_clear_traffic_statistics; 111 struct dentry *file_clear_traffic_statistics;
112 struct dentry *file_csr; 112 struct dentry *file_csr;
113 struct dentry *file_ucode_tracing;
113 } dbgfs_debug_files; 114 } dbgfs_debug_files;
114 u32 sram_offset; 115 u32 sram_offset;
115 u32 sram_len; 116 u32 sram_len;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 2be3549be01d..822de46e4f34 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -1867,6 +1867,58 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file,
1867 return count; 1867 return count;
1868} 1868}
1869 1869
1870static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
1871 char __user *user_buf,
1872 size_t count, loff_t *ppos) {
1873
1874 struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
1875 int pos = 0;
1876 char buf[128];
1877 const size_t bufsz = sizeof(buf);
1878 ssize_t ret;
1879
1880 pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
1881 priv->event_log.ucode_trace ? "On" : "Off");
1882 pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
1883 priv->event_log.non_wraps_count);
1884 pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
1885 priv->event_log.wraps_once_count);
1886 pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
1887 priv->event_log.wraps_more_count);
1888
1889 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1890 return ret;
1891}
1892
1893static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
1894 const char __user *user_buf,
1895 size_t count, loff_t *ppos)
1896{
1897 struct iwl_priv *priv = file->private_data;
1898 char buf[8];
1899 int buf_size;
1900 int trace;
1901
1902 memset(buf, 0, sizeof(buf));
1903 buf_size = min(count, sizeof(buf) - 1);
1904 if (copy_from_user(buf, user_buf, buf_size))
1905 return -EFAULT;
1906 if (sscanf(buf, "%d", &trace) != 1)
1907 return -EFAULT;
1908
1909 if (trace) {
1910 priv->event_log.ucode_trace = true;
1911 /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
1912 mod_timer(&priv->ucode_trace,
1913 jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
1914 } else {
1915 priv->event_log.ucode_trace = false;
1916 del_timer_sync(&priv->ucode_trace);
1917 }
1918
1919 return count;
1920}
1921
1870DEBUGFS_READ_FILE_OPS(rx_statistics); 1922DEBUGFS_READ_FILE_OPS(rx_statistics);
1871DEBUGFS_READ_FILE_OPS(tx_statistics); 1923DEBUGFS_READ_FILE_OPS(tx_statistics);
1872DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); 1924DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1882,6 +1934,7 @@ DEBUGFS_READ_FILE_OPS(power_save_status);
1882DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); 1934DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
1883DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); 1935DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
1884DEBUGFS_WRITE_FILE_OPS(csr); 1936DEBUGFS_WRITE_FILE_OPS(csr);
1937DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
1885 1938
1886/* 1939/*
1887 * Create the debugfs files and directories 1940 * Create the debugfs files and directories
@@ -1939,6 +1992,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
1939 DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR); 1992 DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
1940 DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR); 1993 DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
1941 DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR); 1994 DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
1995 DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR);
1942 } 1996 }
1943 DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); 1997 DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
1944 DEBUGFS_ADD_BOOL(disable_chain_noise, rf, 1998 DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
@@ -2002,6 +2056,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
2002 file_sensitivity); 2056 file_sensitivity);
2003 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. 2057 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
2004 file_chain_noise); 2058 file_chain_noise);
2059 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
2060 file_ucode_tracing);
2005 } 2061 }
2006 DEBUGFS_REMOVE(priv->dbgfs->dir_debug); 2062 DEBUGFS_REMOVE(priv->dbgfs->dir_debug);
2007 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); 2063 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 2673e9a4db92..b3a29c7cdbc0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -984,6 +984,32 @@ struct iwl_switch_rxon {
984 __le16 channel; 984 __le16 channel;
985}; 985};
986 986
987/*
988 * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
989 * to perform continuous uCode event logging operation if enabled
990 */
991#define UCODE_TRACE_PERIOD (100)
992
993/*
994 * iwl_event_log: current uCode event log position
995 *
996 * @ucode_trace: enable/disable ucode continuous trace timer
997 * @num_wraps: how many times the event buffer wraps
998 * @next_entry: the entry just before the next one that uCode would fill
999 * @non_wraps_count: counter for no wrap detected when dump ucode events
1000 * @wraps_once_count: counter for wrap once detected when dump ucode events
1001 * @wraps_more_count: counter for wrap more than once detected
1002 * when dump ucode events
1003 */
1004struct iwl_event_log {
1005 bool ucode_trace;
1006 u32 num_wraps;
1007 u32 next_entry;
1008 int non_wraps_count;
1009 int wraps_once_count;
1010 int wraps_more_count;
1011};
1012
987struct iwl_priv { 1013struct iwl_priv {
988 1014
989 /* ieee device used by generic ieee processing code */ 1015 /* ieee device used by generic ieee processing code */
@@ -1261,6 +1287,7 @@ struct iwl_priv {
1261 u32 disable_tx_power_cal; 1287 u32 disable_tx_power_cal;
1262 struct work_struct run_time_calib_work; 1288 struct work_struct run_time_calib_work;
1263 struct timer_list statistics_periodic; 1289 struct timer_list statistics_periodic;
1290 struct timer_list ucode_trace;
1264 bool hw_ready; 1291 bool hw_ready;
1265 /*For 3945*/ 1292 /*For 3945*/
1266#define IWL_DEFAULT_TX_POWER 0x0F 1293#define IWL_DEFAULT_TX_POWER 0x0F
@@ -1268,6 +1295,8 @@ struct iwl_priv {
1268 struct iwl3945_notif_statistics statistics_39; 1295 struct iwl3945_notif_statistics statistics_39;
1269 1296
1270 u32 sta_supp_rates; 1297 u32 sta_supp_rates;
1298
1299 struct iwl_event_log event_log;
1271}; /*iwl_priv */ 1300}; /*iwl_priv */
1272 1301
1273static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) 1302static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index e7d88d1da15d..bf46308b17fa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -11,4 +11,6 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
11EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); 11EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
12EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); 12EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
13EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); 13EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
14EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
15EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
14#endif 16#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 21361968ab7e..0819f990be6c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -65,6 +65,50 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
65); 65);
66 66
67#undef TRACE_SYSTEM 67#undef TRACE_SYSTEM
68#define TRACE_SYSTEM iwlwifi_ucode
69
70TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
71 TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
72 TP_ARGS(priv, time, data, ev),
73 TP_STRUCT__entry(
74 PRIV_ENTRY
75
76 __field(u32, time)
77 __field(u32, data)
78 __field(u32, ev)
79 ),
80 TP_fast_assign(
81 PRIV_ASSIGN;
82 __entry->time = time;
83 __entry->data = data;
84 __entry->ev = ev;
85 ),
86 TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
87 __entry->priv, __entry->time, __entry->data, __entry->ev)
88);
89
90TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
91 TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
92 TP_ARGS(priv, wraps, n_entry, p_entry),
93 TP_STRUCT__entry(
94 PRIV_ENTRY
95
96 __field(u32, wraps)
97 __field(u32, n_entry)
98 __field(u32, p_entry)
99 ),
100 TP_fast_assign(
101 PRIV_ASSIGN;
102 __entry->wraps = wraps;
103 __entry->n_entry = n_entry;
104 __entry->p_entry = p_entry;
105 ),
106 TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X",
107 __entry->priv, __entry->wraps, __entry->n_entry,
108 __entry->p_entry)
109);
110
111#undef TRACE_SYSTEM
68#define TRACE_SYSTEM iwlwifi 112#define TRACE_SYSTEM iwlwifi
69 113
70TRACE_EVENT(iwlwifi_dev_hcmd, 114TRACE_EVENT(iwlwifi_dev_hcmd,