aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,