2 * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
5 * Copyright (c) 2010, ST-Ericsson
6 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/debugfs.h>
15 #include <linux/seq_file.h>
21 static const char * const cw1200_debug_join_status
[] = {
25 "station (not authenticated yet)",
31 /* WSM_JOIN_PREAMBLE_... */
32 static const char * const cw1200_debug_preamble
[] = {
35 "long on 1 and 2 Mbps",
39 static const char * const cw1200_debug_link_id
[] = {
46 static const char *cw1200_debug_mode(int mode
)
49 case NL80211_IFTYPE_UNSPECIFIED
:
51 case NL80211_IFTYPE_MONITOR
:
53 case NL80211_IFTYPE_STATION
:
55 case NL80211_IFTYPE_ADHOC
:
57 case NL80211_IFTYPE_MESH_POINT
:
59 case NL80211_IFTYPE_AP
:
60 return "access point";
61 case NL80211_IFTYPE_P2P_CLIENT
:
63 case NL80211_IFTYPE_P2P_GO
:
70 static void cw1200_queue_status_show(struct seq_file
*seq
,
71 struct cw1200_queue
*q
)
74 seq_printf(seq
, "Queue %d:\n", q
->queue_id
);
75 seq_printf(seq
, " capacity: %zu\n", q
->capacity
);
76 seq_printf(seq
, " queued: %zu\n", q
->num_queued
);
77 seq_printf(seq
, " pending: %zu\n", q
->num_pending
);
78 seq_printf(seq
, " sent: %zu\n", q
->num_sent
);
79 seq_printf(seq
, " locked: %s\n", q
->tx_locked_cnt
? "yes" : "no");
80 seq_printf(seq
, " overfull: %s\n", q
->overfull
? "yes" : "no");
81 seq_puts(seq
, " link map: 0-> ");
82 for (i
= 0; i
< q
->stats
->map_capacity
; ++i
)
83 seq_printf(seq
, "%.2d ", q
->link_map_cache
[i
]);
84 seq_printf(seq
, "<-%zu\n", q
->stats
->map_capacity
);
87 static void cw1200_debug_print_map(struct seq_file
*seq
,
88 struct cw1200_common
*priv
,
93 seq_printf(seq
, "%s0-> ", label
);
94 for (i
= 0; i
< priv
->tx_queue_stats
.map_capacity
; ++i
)
95 seq_printf(seq
, "%s ", (map
& BIT(i
)) ? "**" : "..");
96 seq_printf(seq
, "<-%zu\n", priv
->tx_queue_stats
.map_capacity
- 1);
99 static int cw1200_status_show(struct seq_file
*seq
, void *v
)
102 struct list_head
*item
;
103 struct cw1200_common
*priv
= seq
->private;
104 struct cw1200_debug_priv
*d
= priv
->debug
;
106 seq_puts(seq
, "CW1200 Wireless LAN driver status\n");
107 seq_printf(seq
, "Hardware: %d.%d\n",
108 priv
->wsm_caps
.hw_id
,
109 priv
->wsm_caps
.hw_subid
);
110 seq_printf(seq
, "Firmware: %s %d.%d\n",
111 cw1200_fw_types
[priv
->wsm_caps
.fw_type
],
112 priv
->wsm_caps
.fw_ver
,
113 priv
->wsm_caps
.fw_build
);
114 seq_printf(seq
, "FW API: %d\n",
115 priv
->wsm_caps
.fw_api
);
116 seq_printf(seq
, "FW caps: 0x%.4X\n",
117 priv
->wsm_caps
.fw_cap
);
118 seq_printf(seq
, "FW label: '%s'\n",
119 priv
->wsm_caps
.fw_label
);
120 seq_printf(seq
, "Mode: %s%s\n",
121 cw1200_debug_mode(priv
->mode
),
122 priv
->listening
? " (listening)" : "");
123 seq_printf(seq
, "Join state: %s\n",
124 cw1200_debug_join_status
[priv
->join_status
]);
126 seq_printf(seq
, "Channel: %d%s\n",
127 priv
->channel
->hw_value
,
128 priv
->channel_switch_in_progress
?
129 " (switching)" : "");
130 if (priv
->rx_filter
.promiscuous
)
131 seq_puts(seq
, "Filter: promisc\n");
132 else if (priv
->rx_filter
.fcs
)
133 seq_puts(seq
, "Filter: fcs\n");
134 if (priv
->rx_filter
.bssid
)
135 seq_puts(seq
, "Filter: bssid\n");
136 if (!priv
->disable_beacon_filter
)
137 seq_puts(seq
, "Filter: beacons\n");
139 if (priv
->enable_beacon
||
140 priv
->mode
== NL80211_IFTYPE_AP
||
141 priv
->mode
== NL80211_IFTYPE_ADHOC
||
142 priv
->mode
== NL80211_IFTYPE_MESH_POINT
||
143 priv
->mode
== NL80211_IFTYPE_P2P_GO
)
144 seq_printf(seq
, "Beaconing: %s\n",
145 priv
->enable_beacon
?
146 "enabled" : "disabled");
148 for (i
= 0; i
< 4; ++i
)
149 seq_printf(seq
, "EDCA(%d): %d, %d, %d, %d, %d\n", i
,
150 priv
->edca
.params
[i
].cwmin
,
151 priv
->edca
.params
[i
].cwmax
,
152 priv
->edca
.params
[i
].aifns
,
153 priv
->edca
.params
[i
].txop_limit
,
154 priv
->edca
.params
[i
].max_rx_lifetime
);
156 if (priv
->join_status
== CW1200_JOIN_STATUS_STA
) {
157 static const char *pm_mode
= "unknown";
158 switch (priv
->powersave_mode
.mode
) {
165 case WSM_PSM_FAST_PS
:
169 seq_printf(seq
, "Preamble: %s\n",
170 cw1200_debug_preamble
[priv
->association_mode
.preamble
]);
171 seq_printf(seq
, "AMPDU spcn: %d\n",
172 priv
->association_mode
.mpdu_start_spacing
);
173 seq_printf(seq
, "Basic rate: 0x%.8X\n",
174 le32_to_cpu(priv
->association_mode
.basic_rate_set
));
175 seq_printf(seq
, "Bss lost: %d beacons\n",
176 priv
->bss_params
.beacon_lost_count
);
177 seq_printf(seq
, "AID: %d\n",
178 priv
->bss_params
.aid
);
179 seq_printf(seq
, "Rates: 0x%.8X\n",
180 priv
->bss_params
.operational_rate_set
);
181 seq_printf(seq
, "Powersave: %s\n", pm_mode
);
183 seq_printf(seq
, "HT: %s\n",
184 cw1200_is_ht(&priv
->ht_info
) ? "on" : "off");
185 if (cw1200_is_ht(&priv
->ht_info
)) {
186 seq_printf(seq
, "Greenfield: %s\n",
187 cw1200_ht_greenfield(&priv
->ht_info
) ? "yes" : "no");
188 seq_printf(seq
, "AMPDU dens: %d\n",
189 cw1200_ht_ampdu_density(&priv
->ht_info
));
191 seq_printf(seq
, "RSSI thold: %d\n",
192 priv
->cqm_rssi_thold
);
193 seq_printf(seq
, "RSSI hyst: %d\n",
194 priv
->cqm_rssi_hyst
);
195 seq_printf(seq
, "Long retr: %d\n",
196 priv
->long_frame_max_tx_count
);
197 seq_printf(seq
, "Short retr: %d\n",
198 priv
->short_frame_max_tx_count
);
199 spin_lock_bh(&priv
->tx_policy_cache
.lock
);
201 list_for_each(item
, &priv
->tx_policy_cache
.used
)
203 spin_unlock_bh(&priv
->tx_policy_cache
.lock
);
204 seq_printf(seq
, "RC in use: %d\n", i
);
207 for (i
= 0; i
< 4; ++i
) {
208 cw1200_queue_status_show(seq
, &priv
->tx_queue
[i
]);
212 cw1200_debug_print_map(seq
, priv
, "Link map: ",
214 cw1200_debug_print_map(seq
, priv
, "Asleep map: ",
215 priv
->sta_asleep_mask
);
216 cw1200_debug_print_map(seq
, priv
, "PSPOLL map: ",
221 for (i
= 0; i
< CW1200_MAX_STA_IN_AP_MODE
; ++i
) {
222 if (priv
->link_id_db
[i
].status
) {
223 seq_printf(seq
, "Link %d: %s, %pM\n",
225 cw1200_debug_link_id
[priv
->link_id_db
[i
].status
],
226 priv
->link_id_db
[i
].mac
);
232 seq_printf(seq
, "BH status: %s\n",
233 atomic_read(&priv
->bh_term
) ? "terminated" : "alive");
234 seq_printf(seq
, "Pending RX: %d\n",
235 atomic_read(&priv
->bh_rx
));
236 seq_printf(seq
, "Pending TX: %d\n",
237 atomic_read(&priv
->bh_tx
));
239 seq_printf(seq
, "BH errcode: %d\n",
241 seq_printf(seq
, "TX bufs: %d x %d bytes\n",
242 priv
->wsm_caps
.input_buffers
,
243 priv
->wsm_caps
.input_buffer_size
);
244 seq_printf(seq
, "Used bufs: %d\n",
246 seq_printf(seq
, "Powermgmt: %s\n",
247 priv
->powersave_enabled
? "on" : "off");
248 seq_printf(seq
, "Device: %s\n",
249 priv
->device_can_sleep
? "asleep" : "awake");
251 spin_lock(&priv
->wsm_cmd
.lock
);
252 seq_printf(seq
, "WSM status: %s\n",
253 priv
->wsm_cmd
.done
? "idle" : "active");
254 seq_printf(seq
, "WSM cmd: 0x%.4X (%td bytes)\n",
255 priv
->wsm_cmd
.cmd
, priv
->wsm_cmd
.len
);
256 seq_printf(seq
, "WSM retval: %d\n",
258 spin_unlock(&priv
->wsm_cmd
.lock
);
260 seq_printf(seq
, "Datapath: %s\n",
261 atomic_read(&priv
->tx_lock
) ? "locked" : "unlocked");
262 if (atomic_read(&priv
->tx_lock
))
263 seq_printf(seq
, "TXlock cnt: %d\n",
264 atomic_read(&priv
->tx_lock
));
266 seq_printf(seq
, "TXed: %d\n",
268 seq_printf(seq
, "AGG TXed: %d\n",
270 seq_printf(seq
, "MULTI TXed: %d (%d)\n",
271 d
->tx_multi
, d
->tx_multi_frames
);
272 seq_printf(seq
, "RXed: %d\n",
274 seq_printf(seq
, "AGG RXed: %d\n",
276 seq_printf(seq
, "TX miss: %d\n",
278 seq_printf(seq
, "TX align: %d\n",
280 seq_printf(seq
, "TX burst: %d\n",
282 seq_printf(seq
, "TX TTL: %d\n",
284 seq_printf(seq
, "Scan: %s\n",
285 atomic_read(&priv
->scan
.in_progress
) ? "active" : "idle");
290 static int cw1200_status_open(struct inode
*inode
, struct file
*file
)
292 return single_open(file
, &cw1200_status_show
,
296 static const struct file_operations fops_status
= {
297 .open
= cw1200_status_open
,
300 .release
= single_release
,
301 .owner
= THIS_MODULE
,
304 static int cw1200_counters_show(struct seq_file
*seq
, void *v
)
307 struct cw1200_common
*priv
= seq
->private;
308 struct wsm_mib_counters_table counters
;
310 ret
= wsm_get_counters_table(priv
, &counters
);
314 #define PUT_COUNTER(tab, name) \
315 seq_printf(seq, "%s:" tab "%d\n", #name, \
316 __le32_to_cpu(counters.name))
318 PUT_COUNTER("\t\t", plcp_errors
);
319 PUT_COUNTER("\t\t", fcs_errors
);
320 PUT_COUNTER("\t\t", tx_packets
);
321 PUT_COUNTER("\t\t", rx_packets
);
322 PUT_COUNTER("\t\t", rx_packet_errors
);
323 PUT_COUNTER("\t", rx_decryption_failures
);
324 PUT_COUNTER("\t\t", rx_mic_failures
);
325 PUT_COUNTER("\t", rx_no_key_failures
);
326 PUT_COUNTER("\t", tx_multicast_frames
);
327 PUT_COUNTER("\t", tx_frames_success
);
328 PUT_COUNTER("\t", tx_frame_failures
);
329 PUT_COUNTER("\t", tx_frames_retried
);
330 PUT_COUNTER("\t", tx_frames_multi_retried
);
331 PUT_COUNTER("\t", rx_frame_duplicates
);
332 PUT_COUNTER("\t\t", rts_success
);
333 PUT_COUNTER("\t\t", rts_failures
);
334 PUT_COUNTER("\t\t", ack_failures
);
335 PUT_COUNTER("\t", rx_multicast_frames
);
336 PUT_COUNTER("\t", rx_frames_success
);
337 PUT_COUNTER("\t", rx_cmac_icv_errors
);
338 PUT_COUNTER("\t\t", rx_cmac_replays
);
339 PUT_COUNTER("\t", rx_mgmt_ccmp_replays
);
346 static int cw1200_counters_open(struct inode
*inode
, struct file
*file
)
348 return single_open(file
, &cw1200_counters_show
,
352 static const struct file_operations fops_counters
= {
353 .open
= cw1200_counters_open
,
356 .release
= single_release
,
357 .owner
= THIS_MODULE
,
360 static ssize_t
cw1200_wsm_dumps(struct file
*file
,
361 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
363 struct cw1200_common
*priv
= file
->private_data
;
368 if (copy_from_user(buf
, user_buf
, 1))
372 priv
->wsm_enable_wsm_dumps
= 1;
374 priv
->wsm_enable_wsm_dumps
= 0;
379 static const struct file_operations fops_wsm_dumps
= {
381 .write
= cw1200_wsm_dumps
,
382 .llseek
= default_llseek
,
385 int cw1200_debug_init(struct cw1200_common
*priv
)
388 struct cw1200_debug_priv
*d
= kzalloc(sizeof(struct cw1200_debug_priv
),
394 d
->debugfs_phy
= debugfs_create_dir("cw1200",
395 priv
->hw
->wiphy
->debugfsdir
);
399 if (!debugfs_create_file("status", S_IRUSR
, d
->debugfs_phy
,
403 if (!debugfs_create_file("counters", S_IRUSR
, d
->debugfs_phy
,
404 priv
, &fops_counters
))
407 if (!debugfs_create_file("wsm_dumps", S_IWUSR
, d
->debugfs_phy
,
408 priv
, &fops_wsm_dumps
))
415 debugfs_remove_recursive(d
->debugfs_phy
);
420 void cw1200_debug_release(struct cw1200_common
*priv
)
422 struct cw1200_debug_priv
*d
= priv
->debug
;
424 debugfs_remove_recursive(d
->debugfs_phy
);