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
[] = {
48 static const char *cw1200_debug_mode(int mode
)
51 case NL80211_IFTYPE_UNSPECIFIED
:
53 case NL80211_IFTYPE_MONITOR
:
55 case NL80211_IFTYPE_STATION
:
57 case NL80211_IFTYPE_ADHOC
:
59 case NL80211_IFTYPE_MESH_POINT
:
61 case NL80211_IFTYPE_AP
:
62 return "access point";
63 case NL80211_IFTYPE_P2P_CLIENT
:
65 case NL80211_IFTYPE_P2P_GO
:
72 static void cw1200_queue_status_show(struct seq_file
*seq
,
73 struct cw1200_queue
*q
)
76 seq_printf(seq
, "Queue %d:\n", q
->queue_id
);
77 seq_printf(seq
, " capacity: %zu\n", q
->capacity
);
78 seq_printf(seq
, " queued: %zu\n", q
->num_queued
);
79 seq_printf(seq
, " pending: %zu\n", q
->num_pending
);
80 seq_printf(seq
, " sent: %zu\n", q
->num_sent
);
81 seq_printf(seq
, " locked: %s\n", q
->tx_locked_cnt
? "yes" : "no");
82 seq_printf(seq
, " overfull: %s\n", q
->overfull
? "yes" : "no");
83 seq_puts(seq
, " link map: 0-> ");
84 for (i
= 0; i
< q
->stats
->map_capacity
; ++i
)
85 seq_printf(seq
, "%.2d ", q
->link_map_cache
[i
]);
86 seq_printf(seq
, "<-%zu\n", q
->stats
->map_capacity
);
89 static void cw1200_debug_print_map(struct seq_file
*seq
,
90 struct cw1200_common
*priv
,
95 seq_printf(seq
, "%s0-> ", label
);
96 for (i
= 0; i
< priv
->tx_queue_stats
.map_capacity
; ++i
)
97 seq_printf(seq
, "%s ", (map
& BIT(i
)) ? "**" : "..");
98 seq_printf(seq
, "<-%zu\n", priv
->tx_queue_stats
.map_capacity
- 1);
101 static int cw1200_status_show(struct seq_file
*seq
, void *v
)
104 struct list_head
*item
;
105 struct cw1200_common
*priv
= seq
->private;
106 struct cw1200_debug_priv
*d
= priv
->debug
;
108 seq_puts(seq
, "CW1200 Wireless LAN driver status\n");
109 seq_printf(seq
, "Hardware: %d.%d\n",
110 priv
->wsm_caps
.hw_id
,
111 priv
->wsm_caps
.hw_subid
);
112 seq_printf(seq
, "Firmware: %s %d.%d\n",
113 cw1200_fw_types
[priv
->wsm_caps
.fw_type
],
114 priv
->wsm_caps
.fw_ver
,
115 priv
->wsm_caps
.fw_build
);
116 seq_printf(seq
, "FW API: %d\n",
117 priv
->wsm_caps
.fw_api
);
118 seq_printf(seq
, "FW caps: 0x%.4X\n",
119 priv
->wsm_caps
.fw_cap
);
120 seq_printf(seq
, "FW label: '%s'\n",
121 priv
->wsm_caps
.fw_label
);
122 seq_printf(seq
, "Mode: %s%s\n",
123 cw1200_debug_mode(priv
->mode
),
124 priv
->listening
? " (listening)" : "");
125 seq_printf(seq
, "Join state: %s\n",
126 cw1200_debug_join_status
[priv
->join_status
]);
128 seq_printf(seq
, "Channel: %d%s\n",
129 priv
->channel
->hw_value
,
130 priv
->channel_switch_in_progress
?
131 " (switching)" : "");
132 if (priv
->rx_filter
.promiscuous
)
133 seq_puts(seq
, "Filter: promisc\n");
134 else if (priv
->rx_filter
.fcs
)
135 seq_puts(seq
, "Filter: fcs\n");
136 if (priv
->rx_filter
.bssid
)
137 seq_puts(seq
, "Filter: bssid\n");
138 if (!priv
->disable_beacon_filter
)
139 seq_puts(seq
, "Filter: beacons\n");
141 if (priv
->enable_beacon
||
142 priv
->mode
== NL80211_IFTYPE_AP
||
143 priv
->mode
== NL80211_IFTYPE_ADHOC
||
144 priv
->mode
== NL80211_IFTYPE_MESH_POINT
||
145 priv
->mode
== NL80211_IFTYPE_P2P_GO
)
146 seq_printf(seq
, "Beaconing: %s\n",
147 priv
->enable_beacon
?
148 "enabled" : "disabled");
150 for (i
= 0; i
< 4; ++i
)
151 seq_printf(seq
, "EDCA(%d): %d, %d, %d, %d, %d\n", i
,
152 priv
->edca
.params
[i
].cwmin
,
153 priv
->edca
.params
[i
].cwmax
,
154 priv
->edca
.params
[i
].aifns
,
155 priv
->edca
.params
[i
].txop_limit
,
156 priv
->edca
.params
[i
].max_rx_lifetime
);
158 if (priv
->join_status
== CW1200_JOIN_STATUS_STA
) {
159 static const char *pm_mode
= "unknown";
160 switch (priv
->powersave_mode
.mode
) {
167 case WSM_PSM_FAST_PS
:
171 seq_printf(seq
, "Preamble: %s\n",
172 cw1200_debug_preamble
[priv
->association_mode
.preamble
]);
173 seq_printf(seq
, "AMPDU spcn: %d\n",
174 priv
->association_mode
.mpdu_start_spacing
);
175 seq_printf(seq
, "Basic rate: 0x%.8X\n",
176 le32_to_cpu(priv
->association_mode
.basic_rate_set
));
177 seq_printf(seq
, "Bss lost: %d beacons\n",
178 priv
->bss_params
.beacon_lost_count
);
179 seq_printf(seq
, "AID: %d\n",
180 priv
->bss_params
.aid
);
181 seq_printf(seq
, "Rates: 0x%.8X\n",
182 priv
->bss_params
.operational_rate_set
);
183 seq_printf(seq
, "Powersave: %s\n", pm_mode
);
185 seq_printf(seq
, "HT: %s\n",
186 cw1200_is_ht(&priv
->ht_info
) ? "on" : "off");
187 if (cw1200_is_ht(&priv
->ht_info
)) {
188 seq_printf(seq
, "Greenfield: %s\n",
189 cw1200_ht_greenfield(&priv
->ht_info
) ? "yes" : "no");
190 seq_printf(seq
, "AMPDU dens: %d\n",
191 cw1200_ht_ampdu_density(&priv
->ht_info
));
193 seq_printf(seq
, "RSSI thold: %d\n",
194 priv
->cqm_rssi_thold
);
195 seq_printf(seq
, "RSSI hyst: %d\n",
196 priv
->cqm_rssi_hyst
);
197 seq_printf(seq
, "Long retr: %d\n",
198 priv
->long_frame_max_tx_count
);
199 seq_printf(seq
, "Short retr: %d\n",
200 priv
->short_frame_max_tx_count
);
201 spin_lock_bh(&priv
->tx_policy_cache
.lock
);
203 list_for_each(item
, &priv
->tx_policy_cache
.used
)
205 spin_unlock_bh(&priv
->tx_policy_cache
.lock
);
206 seq_printf(seq
, "RC in use: %d\n", i
);
209 for (i
= 0; i
< 4; ++i
) {
210 cw1200_queue_status_show(seq
, &priv
->tx_queue
[i
]);
214 cw1200_debug_print_map(seq
, priv
, "Link map: ",
216 cw1200_debug_print_map(seq
, priv
, "Asleep map: ",
217 priv
->sta_asleep_mask
);
218 cw1200_debug_print_map(seq
, priv
, "PSPOLL map: ",
223 for (i
= 0; i
< CW1200_MAX_STA_IN_AP_MODE
; ++i
) {
224 if (priv
->link_id_db
[i
].status
) {
225 seq_printf(seq
, "Link %d: %s, %pM\n",
227 cw1200_debug_link_id
[priv
->link_id_db
[i
].status
],
228 priv
->link_id_db
[i
].mac
);
234 seq_printf(seq
, "BH status: %s\n",
235 atomic_read(&priv
->bh_term
) ? "terminated" : "alive");
236 seq_printf(seq
, "Pending RX: %d\n",
237 atomic_read(&priv
->bh_rx
));
238 seq_printf(seq
, "Pending TX: %d\n",
239 atomic_read(&priv
->bh_tx
));
241 seq_printf(seq
, "BH errcode: %d\n",
243 seq_printf(seq
, "TX bufs: %d x %d bytes\n",
244 priv
->wsm_caps
.input_buffers
,
245 priv
->wsm_caps
.input_buffer_size
);
246 seq_printf(seq
, "Used bufs: %d\n",
248 seq_printf(seq
, "Powermgmt: %s\n",
249 priv
->powersave_enabled
? "on" : "off");
250 seq_printf(seq
, "Device: %s\n",
251 priv
->device_can_sleep
? "asleep" : "awake");
253 spin_lock(&priv
->wsm_cmd
.lock
);
254 seq_printf(seq
, "WSM status: %s\n",
255 priv
->wsm_cmd
.done
? "idle" : "active");
256 seq_printf(seq
, "WSM cmd: 0x%.4X (%td bytes)\n",
257 priv
->wsm_cmd
.cmd
, priv
->wsm_cmd
.len
);
258 seq_printf(seq
, "WSM retval: %d\n",
260 spin_unlock(&priv
->wsm_cmd
.lock
);
262 seq_printf(seq
, "Datapath: %s\n",
263 atomic_read(&priv
->tx_lock
) ? "locked" : "unlocked");
264 if (atomic_read(&priv
->tx_lock
))
265 seq_printf(seq
, "TXlock cnt: %d\n",
266 atomic_read(&priv
->tx_lock
));
268 seq_printf(seq
, "TXed: %d\n",
270 seq_printf(seq
, "AGG TXed: %d\n",
272 seq_printf(seq
, "MULTI TXed: %d (%d)\n",
273 d
->tx_multi
, d
->tx_multi_frames
);
274 seq_printf(seq
, "RXed: %d\n",
276 seq_printf(seq
, "AGG RXed: %d\n",
278 seq_printf(seq
, "TX miss: %d\n",
280 seq_printf(seq
, "TX align: %d\n",
282 seq_printf(seq
, "TX burst: %d\n",
284 seq_printf(seq
, "TX TTL: %d\n",
286 seq_printf(seq
, "Scan: %s\n",
287 atomic_read(&priv
->scan
.in_progress
) ? "active" : "idle");
292 static int cw1200_status_open(struct inode
*inode
, struct file
*file
)
294 return single_open(file
, &cw1200_status_show
,
298 static const struct file_operations fops_status
= {
299 .open
= cw1200_status_open
,
302 .release
= single_release
,
303 .owner
= THIS_MODULE
,
306 static int cw1200_counters_show(struct seq_file
*seq
, void *v
)
309 struct cw1200_common
*priv
= seq
->private;
310 struct wsm_mib_counters_table counters
;
312 ret
= wsm_get_counters_table(priv
, &counters
);
316 #define PUT_COUNTER(tab, name) \
317 seq_printf(seq, "%s:" tab "%d\n", #name, \
318 __le32_to_cpu(counters.name))
320 PUT_COUNTER("\t\t", plcp_errors
);
321 PUT_COUNTER("\t\t", fcs_errors
);
322 PUT_COUNTER("\t\t", tx_packets
);
323 PUT_COUNTER("\t\t", rx_packets
);
324 PUT_COUNTER("\t\t", rx_packet_errors
);
325 PUT_COUNTER("\t", rx_decryption_failures
);
326 PUT_COUNTER("\t\t", rx_mic_failures
);
327 PUT_COUNTER("\t", rx_no_key_failures
);
328 PUT_COUNTER("\t", tx_multicast_frames
);
329 PUT_COUNTER("\t", tx_frames_success
);
330 PUT_COUNTER("\t", tx_frame_failures
);
331 PUT_COUNTER("\t", tx_frames_retried
);
332 PUT_COUNTER("\t", tx_frames_multi_retried
);
333 PUT_COUNTER("\t", rx_frame_duplicates
);
334 PUT_COUNTER("\t\t", rts_success
);
335 PUT_COUNTER("\t\t", rts_failures
);
336 PUT_COUNTER("\t\t", ack_failures
);
337 PUT_COUNTER("\t", rx_multicast_frames
);
338 PUT_COUNTER("\t", rx_frames_success
);
339 PUT_COUNTER("\t", rx_cmac_icv_errors
);
340 PUT_COUNTER("\t\t", rx_cmac_replays
);
341 PUT_COUNTER("\t", rx_mgmt_ccmp_replays
);
348 static int cw1200_counters_open(struct inode
*inode
, struct file
*file
)
350 return single_open(file
, &cw1200_counters_show
,
354 static const struct file_operations fops_counters
= {
355 .open
= cw1200_counters_open
,
358 .release
= single_release
,
359 .owner
= THIS_MODULE
,
362 static ssize_t
cw1200_wsm_dumps(struct file
*file
,
363 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
365 struct cw1200_common
*priv
= file
->private_data
;
370 if (copy_from_user(buf
, user_buf
, 1))
374 priv
->wsm_enable_wsm_dumps
= 1;
376 priv
->wsm_enable_wsm_dumps
= 0;
381 static const struct file_operations fops_wsm_dumps
= {
383 .write
= cw1200_wsm_dumps
,
384 .llseek
= default_llseek
,
387 int cw1200_debug_init(struct cw1200_common
*priv
)
390 struct cw1200_debug_priv
*d
= kzalloc(sizeof(struct cw1200_debug_priv
),
396 d
->debugfs_phy
= debugfs_create_dir("cw1200",
397 priv
->hw
->wiphy
->debugfsdir
);
401 if (!debugfs_create_file("status", 0400, d
->debugfs_phy
,
405 if (!debugfs_create_file("counters", 0400, d
->debugfs_phy
,
406 priv
, &fops_counters
))
409 if (!debugfs_create_file("wsm_dumps", 0200, d
->debugfs_phy
,
410 priv
, &fops_wsm_dumps
))
417 debugfs_remove_recursive(d
->debugfs_phy
);
422 void cw1200_debug_release(struct cw1200_common
*priv
)
424 struct cw1200_debug_priv
*d
= priv
->debug
;
426 debugfs_remove_recursive(d
->debugfs_phy
);