2 * Copyright (c) 2008 Atheros Communications Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 static unsigned int ath9k_debug
= DBG_DEFAULT
;
20 module_param_named(debug
, ath9k_debug
, uint
, 0);
22 void DPRINTF(struct ath_softc
*sc
, int dbg_mask
, const char *fmt
, ...)
27 if (sc
->debug
.debug_mask
& dbg_mask
) {
31 printk(KERN_DEBUG
"ath9k: ");
37 static int ath9k_debugfs_open(struct inode
*inode
, struct file
*file
)
39 file
->private_data
= inode
->i_private
;
43 static ssize_t
read_file_dma(struct file
*file
, char __user
*user_buf
,
44 size_t count
, loff_t
*ppos
)
46 struct ath_softc
*sc
= file
->private_data
;
47 struct ath_hal
*ah
= sc
->sc_ah
;
50 u32 val
[ATH9K_NUM_DMA_DEBUG_REGS
];
51 int i
, qcuOffset
= 0, dcuOffset
= 0;
52 u32
*qcuBase
= &val
[0], *dcuBase
= &val
[4];
54 REG_WRITE(ah
, AR_MACMISC
,
55 ((AR_MACMISC_DMA_OBS_LINE_8
<< AR_MACMISC_DMA_OBS_S
) |
56 (AR_MACMISC_MISC_OBS_BUS_1
<<
57 AR_MACMISC_MISC_OBS_BUS_MSB_S
)));
59 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
60 "Raw DMA Debug values:\n");
62 for (i
= 0; i
< ATH9K_NUM_DMA_DEBUG_REGS
; i
++) {
64 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
, "\n");
66 val
[i
] = REG_READ(ah
, AR_DMADBG_0
+ (i
* sizeof(u32
)));
67 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
, "%d: %08x ",
71 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
, "\n\n");
72 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
73 "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
75 for (i
= 0; i
< ATH9K_NUM_QUEUES
; i
++, qcuOffset
+= 4, dcuOffset
+= 5) {
86 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
87 "%2d %2x %1x %2x %2x\n",
88 i
, (*qcuBase
& (0x7 << qcuOffset
)) >> qcuOffset
,
89 (*qcuBase
& (0x8 << qcuOffset
)) >> (qcuOffset
+ 3),
90 val
[2] & (0x7 << (i
* 3)) >> (i
* 3),
91 (*dcuBase
& (0x1f << dcuOffset
)) >> dcuOffset
);
94 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
, "\n");
96 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
97 "qcu_stitch state: %2x qcu_fetch state: %2x\n",
98 (val
[3] & 0x003c0000) >> 18, (val
[3] & 0x03c00000) >> 22);
99 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
100 "qcu_complete state: %2x dcu_complete state: %2x\n",
101 (val
[3] & 0x1c000000) >> 26, (val
[6] & 0x3));
102 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
103 "dcu_arb state: %2x dcu_fp state: %2x\n",
104 (val
[5] & 0x06000000) >> 25, (val
[5] & 0x38000000) >> 27);
105 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
106 "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n",
107 (val
[6] & 0x000003fc) >> 2, (val
[6] & 0x00000400) >> 10);
108 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
109 "txfifo_valid_0: %1d txfifo_valid_1: %1d\n",
110 (val
[6] & 0x00000800) >> 11, (val
[6] & 0x00001000) >> 12);
111 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
112 "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n",
113 (val
[6] & 0x0001e000) >> 13, (val
[6] & 0x001e0000) >> 17);
115 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
, "pcu observe: 0x%x \n",
116 REG_READ(ah
, AR_OBS_BUS_1
));
117 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
118 "AR_CR: 0x%x \n", REG_READ(ah
, AR_CR
));
120 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
123 static const struct file_operations fops_dma
= {
124 .read
= read_file_dma
,
125 .open
= ath9k_debugfs_open
,
130 void ath_debug_stat_interrupt(struct ath_softc
*sc
, enum ath9k_int status
)
133 sc
->debug
.stats
.istats
.total
++;
134 if (status
& ATH9K_INT_RX
)
135 sc
->debug
.stats
.istats
.rxok
++;
136 if (status
& ATH9K_INT_RXEOL
)
137 sc
->debug
.stats
.istats
.rxeol
++;
138 if (status
& ATH9K_INT_RXORN
)
139 sc
->debug
.stats
.istats
.rxorn
++;
140 if (status
& ATH9K_INT_TX
)
141 sc
->debug
.stats
.istats
.txok
++;
142 if (status
& ATH9K_INT_TXURN
)
143 sc
->debug
.stats
.istats
.txurn
++;
144 if (status
& ATH9K_INT_MIB
)
145 sc
->debug
.stats
.istats
.mib
++;
146 if (status
& ATH9K_INT_RXPHY
)
147 sc
->debug
.stats
.istats
.rxphyerr
++;
148 if (status
& ATH9K_INT_RXKCM
)
149 sc
->debug
.stats
.istats
.rx_keycache_miss
++;
150 if (status
& ATH9K_INT_SWBA
)
151 sc
->debug
.stats
.istats
.swba
++;
152 if (status
& ATH9K_INT_BMISS
)
153 sc
->debug
.stats
.istats
.bmiss
++;
154 if (status
& ATH9K_INT_BNR
)
155 sc
->debug
.stats
.istats
.bnr
++;
156 if (status
& ATH9K_INT_CST
)
157 sc
->debug
.stats
.istats
.cst
++;
158 if (status
& ATH9K_INT_GTT
)
159 sc
->debug
.stats
.istats
.gtt
++;
160 if (status
& ATH9K_INT_TIM
)
161 sc
->debug
.stats
.istats
.tim
++;
162 if (status
& ATH9K_INT_CABEND
)
163 sc
->debug
.stats
.istats
.cabend
++;
164 if (status
& ATH9K_INT_DTIMSYNC
)
165 sc
->debug
.stats
.istats
.dtimsync
++;
166 if (status
& ATH9K_INT_DTIM
)
167 sc
->debug
.stats
.istats
.dtim
++;
170 static ssize_t
read_file_interrupt(struct file
*file
, char __user
*user_buf
,
171 size_t count
, loff_t
*ppos
)
173 struct ath_softc
*sc
= file
->private_data
;
175 unsigned int len
= 0;
177 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
178 "%8s: %10u\n", "RX", sc
->debug
.stats
.istats
.rxok
);
179 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
180 "%8s: %10u\n", "RXEOL", sc
->debug
.stats
.istats
.rxeol
);
181 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
182 "%8s: %10u\n", "RXORN", sc
->debug
.stats
.istats
.rxorn
);
183 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
184 "%8s: %10u\n", "TX", sc
->debug
.stats
.istats
.txok
);
185 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
186 "%8s: %10u\n", "TXURN", sc
->debug
.stats
.istats
.txurn
);
187 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
188 "%8s: %10u\n", "MIB", sc
->debug
.stats
.istats
.mib
);
189 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
190 "%8s: %10u\n", "RXPHY", sc
->debug
.stats
.istats
.rxphyerr
);
191 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
192 "%8s: %10u\n", "RXKCM", sc
->debug
.stats
.istats
.rx_keycache_miss
);
193 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
194 "%8s: %10u\n", "SWBA", sc
->debug
.stats
.istats
.swba
);
195 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
196 "%8s: %10u\n", "BMISS", sc
->debug
.stats
.istats
.bmiss
);
197 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
198 "%8s: %10u\n", "BNR", sc
->debug
.stats
.istats
.bnr
);
199 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
200 "%8s: %10u\n", "CST", sc
->debug
.stats
.istats
.cst
);
201 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
202 "%8s: %10u\n", "GTT", sc
->debug
.stats
.istats
.gtt
);
203 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
204 "%8s: %10u\n", "TIM", sc
->debug
.stats
.istats
.tim
);
205 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
206 "%8s: %10u\n", "CABEND", sc
->debug
.stats
.istats
.cabend
);
207 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
208 "%8s: %10u\n", "DTIMSYNC", sc
->debug
.stats
.istats
.dtimsync
);
209 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
210 "%8s: %10u\n", "DTIM", sc
->debug
.stats
.istats
.dtim
);
211 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
212 "%8s: %10u\n", "TOTAL", sc
->debug
.stats
.istats
.total
);
214 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
217 static const struct file_operations fops_interrupt
= {
218 .read
= read_file_interrupt
,
219 .open
= ath9k_debugfs_open
,
223 static void ath_debug_stat_11n_rc(struct ath_softc
*sc
, struct sk_buff
*skb
)
225 struct ath_tx_info_priv
*tx_info_priv
= NULL
;
226 struct ieee80211_tx_info
*tx_info
= IEEE80211_SKB_CB(skb
);
227 struct ieee80211_tx_rate
*rates
= tx_info
->status
.rates
;
228 int final_ts_idx
, idx
;
230 tx_info_priv
= ATH_TX_INFO_PRIV(tx_info
);
231 final_ts_idx
= tx_info_priv
->tx
.ts_rateindex
;
232 idx
= sc
->cur_rate_table
->info
[rates
[final_ts_idx
].idx
].dot11rate
;
234 sc
->debug
.stats
.n_rcstats
[idx
].success
++;
237 static void ath_debug_stat_legacy_rc(struct ath_softc
*sc
, struct sk_buff
*skb
)
239 struct ath_tx_info_priv
*tx_info_priv
= NULL
;
240 struct ieee80211_tx_info
*tx_info
= IEEE80211_SKB_CB(skb
);
241 struct ieee80211_tx_rate
*rates
= tx_info
->status
.rates
;
242 int final_ts_idx
, idx
;
244 tx_info_priv
= ATH_TX_INFO_PRIV(tx_info
);
245 final_ts_idx
= tx_info_priv
->tx
.ts_rateindex
;
246 idx
= rates
[final_ts_idx
].idx
;
248 sc
->debug
.stats
.legacy_rcstats
[idx
].success
++;
251 void ath_debug_stat_rc(struct ath_softc
*sc
, struct sk_buff
*skb
)
253 if (conf_is_ht(&sc
->hw
->conf
))
254 ath_debug_stat_11n_rc(sc
, skb
);
256 ath_debug_stat_legacy_rc(sc
, skb
);
259 /* FIXME: legacy rates, later on .. */
260 void ath_debug_stat_retries(struct ath_softc
*sc
, int rix
,
261 int xretries
, int retries
)
263 if (conf_is_ht(&sc
->hw
->conf
)) {
264 int idx
= sc
->cur_rate_table
->info
[rix
].dot11rate
;
266 sc
->debug
.stats
.n_rcstats
[idx
].xretries
+= xretries
;
267 sc
->debug
.stats
.n_rcstats
[idx
].retries
+= retries
;
271 static ssize_t
ath_read_file_stat_11n_rc(struct file
*file
,
272 char __user
*user_buf
,
273 size_t count
, loff_t
*ppos
)
275 struct ath_softc
*sc
= file
->private_data
;
277 unsigned int len
= 0;
280 len
+= sprintf(buf
, "%7s %13s %8s %8s\n\n", "Rate", "Success",
281 "Retries", "XRetries");
283 for (i
= 0; i
<= 15; i
++) {
284 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
285 "%5s%3d: %8u %8u %8u\n", "MCS", i
,
286 sc
->debug
.stats
.n_rcstats
[i
].success
,
287 sc
->debug
.stats
.n_rcstats
[i
].retries
,
288 sc
->debug
.stats
.n_rcstats
[i
].xretries
);
291 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
294 static ssize_t
ath_read_file_stat_legacy_rc(struct file
*file
,
295 char __user
*user_buf
,
296 size_t count
, loff_t
*ppos
)
298 struct ath_softc
*sc
= file
->private_data
;
300 unsigned int len
= 0;
303 len
+= sprintf(buf
, "%7s %13s\n\n", "Rate", "Success");
305 for (i
= 0; i
< sc
->cur_rate_table
->rate_cnt
; i
++) {
306 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
, "%5u: %12u\n",
307 sc
->cur_rate_table
->info
[i
].ratekbps
/ 1000,
308 sc
->debug
.stats
.legacy_rcstats
[i
].success
);
311 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
314 static ssize_t
read_file_rcstat(struct file
*file
, char __user
*user_buf
,
315 size_t count
, loff_t
*ppos
)
317 struct ath_softc
*sc
= file
->private_data
;
319 if (conf_is_ht(&sc
->hw
->conf
))
320 return ath_read_file_stat_11n_rc(file
, user_buf
, count
, ppos
);
322 return ath_read_file_stat_legacy_rc(file
, user_buf
, count
,ppos
);
325 static const struct file_operations fops_rcstat
= {
326 .read
= read_file_rcstat
,
327 .open
= ath9k_debugfs_open
,
331 int ath9k_init_debug(struct ath_softc
*sc
)
333 sc
->debug
.debug_mask
= ath9k_debug
;
335 sc
->debug
.debugfs_root
= debugfs_create_dir(KBUILD_MODNAME
, NULL
);
336 if (!sc
->debug
.debugfs_root
)
339 sc
->debug
.debugfs_phy
= debugfs_create_dir(wiphy_name(sc
->hw
->wiphy
),
340 sc
->debug
.debugfs_root
);
341 if (!sc
->debug
.debugfs_phy
)
344 sc
->debug
.debugfs_dma
= debugfs_create_file("dma", S_IRUGO
,
345 sc
->debug
.debugfs_phy
, sc
, &fops_dma
);
346 if (!sc
->debug
.debugfs_dma
)
349 sc
->debug
.debugfs_interrupt
= debugfs_create_file("interrupt",
351 sc
->debug
.debugfs_phy
,
352 sc
, &fops_interrupt
);
353 if (!sc
->debug
.debugfs_interrupt
)
356 sc
->debug
.debugfs_rcstat
= debugfs_create_file("rcstat",
358 sc
->debug
.debugfs_phy
,
360 if (!sc
->debug
.debugfs_rcstat
)
365 ath9k_exit_debug(sc
);
369 void ath9k_exit_debug(struct ath_softc
*sc
)
371 debugfs_remove(sc
->debug
.debugfs_rcstat
);
372 debugfs_remove(sc
->debug
.debugfs_interrupt
);
373 debugfs_remove(sc
->debug
.debugfs_dma
);
374 debugfs_remove(sc
->debug
.debugfs_phy
);
375 debugfs_remove(sc
->debug
.debugfs_root
);