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 int cw1200_generic_open(struct inode
*inode
, struct file
*file
)
362 file
->private_data
= inode
->i_private
;
366 #ifdef CONFIG_CW1200_ETF
367 static int cw1200_etf_out_show(struct seq_file
*seq
, void *v
)
369 struct cw1200_common
*priv
= seq
->private;
373 skb
= skb_dequeue(&priv
->etf_q
);
378 seq_write(seq
, &len
, sizeof(len
));
381 seq_write(seq
, skb
->data
, len
);
388 static int cw1200_etf_out_open(struct inode
*inode
, struct file
*file
)
390 return single_open(file
, &cw1200_etf_out_show
,
394 static const struct file_operations fops_etf_out
= {
395 .open
= cw1200_etf_out_open
,
398 .release
= single_release
,
399 .owner
= THIS_MODULE
,
403 static int etf_request(struct cw1200_common
*priv
,
404 struct etf_req_msg
*msg
, u32 len
);
406 #define MAX_RX_SZE 2600
408 struct etf_in_state
{
409 struct cw1200_common
*priv
;
415 static int cw1200_etf_in_open(struct inode
*inode
, struct file
*file
)
417 struct etf_in_state
*etf
= kmalloc(sizeof(struct etf_in_state
),
425 etf
->priv
= inode
->i_private
;
427 file
->private_data
= etf
;
432 static int cw1200_etf_in_release(struct inode
*inode
, struct file
*file
)
434 kfree(file
->private_data
);
438 static ssize_t
cw1200_etf_in_write(struct file
*file
,
439 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
441 struct etf_in_state
*etf
= file
->private_data
;
445 if (!etf
->total_len
) {
446 if (count
< sizeof(etf
->total_len
)) {
447 pr_err("count < sizeof(total_len)\n");
451 if (copy_from_user(&etf
->total_len
, user_buf
,
452 sizeof(etf
->total_len
))) {
453 pr_err("copy_from_user (len) failed\n");
457 written
+= sizeof(etf
->total_len
);
458 count
-= sizeof(etf
->total_len
);
464 if (copy_from_user(etf
->buf
+ etf
->written
, user_buf
+ written
,
466 pr_err("copy_from_user (payload %zu) failed\n", count
);
471 etf
->written
+= count
;
473 if (etf
->written
>= etf
->total_len
) {
474 if (etf_request(etf
->priv
, (struct etf_req_msg
*)etf
->buf
,
476 pr_err("etf_request failed\n");
485 static const struct file_operations fops_etf_in
= {
486 .open
= cw1200_etf_in_open
,
487 .release
= cw1200_etf_in_release
,
488 .write
= cw1200_etf_in_write
,
489 .llseek
= default_llseek
,
490 .owner
= THIS_MODULE
,
492 #endif /* CONFIG_CW1200_ETF */
494 static ssize_t
cw1200_wsm_dumps(struct file
*file
,
495 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
497 struct cw1200_common
*priv
= file
->private_data
;
502 if (copy_from_user(buf
, user_buf
, 1))
506 priv
->wsm_enable_wsm_dumps
= 1;
508 priv
->wsm_enable_wsm_dumps
= 0;
513 static const struct file_operations fops_wsm_dumps
= {
514 .open
= cw1200_generic_open
,
515 .write
= cw1200_wsm_dumps
,
516 .llseek
= default_llseek
,
519 int cw1200_debug_init(struct cw1200_common
*priv
)
522 struct cw1200_debug_priv
*d
= kzalloc(sizeof(struct cw1200_debug_priv
),
528 d
->debugfs_phy
= debugfs_create_dir("cw1200",
529 priv
->hw
->wiphy
->debugfsdir
);
533 if (!debugfs_create_file("status", S_IRUSR
, d
->debugfs_phy
,
537 if (!debugfs_create_file("counters", S_IRUSR
, d
->debugfs_phy
,
538 priv
, &fops_counters
))
541 #ifdef CONFIG_CW1200_ETF
543 skb_queue_head_init(&priv
->etf_q
);
545 if (!debugfs_create_file("etf_out", S_IRUSR
, d
->debugfs_phy
,
546 priv
, &fops_etf_out
))
548 if (!debugfs_create_file("etf_in", S_IWUSR
, d
->debugfs_phy
,
552 #endif /* CONFIG_CW1200_ETF */
554 if (!debugfs_create_file("wsm_dumps", S_IWUSR
, d
->debugfs_phy
,
555 priv
, &fops_wsm_dumps
))
558 ret
= cw1200_itp_init(priv
);
566 debugfs_remove_recursive(d
->debugfs_phy
);
571 void cw1200_debug_release(struct cw1200_common
*priv
)
573 struct cw1200_debug_priv
*d
= priv
->debug
;
575 cw1200_itp_release(priv
);
581 #ifdef CONFIG_CW1200_ETF
594 static int parse_sdd_file(struct cw1200_common
*priv
, u8
*data
, u32 length
)
596 struct cw1200_sdd
*ie
;
599 ie
= (struct cw1200_sdd
*)data
;
600 if (ie
->id
== SDD_REFERENCE_FREQUENCY_ELT_ID
) {
601 priv
->hw_refclk
= cpu_to_le16(*((u16
*)ie
->data
));
602 pr_info("Using Reference clock frequency %d KHz\n",
607 length
-= ie
->len
+ sizeof(*ie
);
608 data
+= ie
->len
+ sizeof(*ie
);
615 #define ST90TDS_START_ADAPTER 0x09 /* Loads firmware too */
616 #define ST90TDS_STOP_ADAPTER 0x0A
617 #define ST90TDS_CONFIG_ADAPTER 0x0E /* Send configuration params */
618 #define ST90TDS_SBUS_READ 0x13
619 #define ST90TDS_SBUS_WRITE 0x14
620 #define ST90TDS_GET_DEVICE_OPTION 0x19
621 #define ST90TDS_SET_DEVICE_OPTION 0x1A
622 #define ST90TDS_SEND_SDD 0x1D /* SDD File used to find DPLL */
626 static int etf_request(struct cw1200_common
*priv
,
627 struct etf_req_msg
*msg
,
632 case ST90TDS_START_ADAPTER
:
633 etf_firmware
= "cw1200_etf.bin";
634 pr_info("ETF_START (len %d, '%s')\n", len
, etf_firmware
);
635 rval
= cw1200_load_firmware(priv
);
637 case ST90TDS_STOP_ADAPTER
:
638 pr_info("ETF_STOP (unhandled)\n");
640 case ST90TDS_SEND_SDD
:
641 pr_info("ETF_SDD\n");
642 rval
= parse_sdd_file(priv
, msg
->data
, msg
->len
);
644 case ST90TDS_CONFIG_ADAPTER
:
645 pr_info("ETF_CONFIG_ADAP (unhandled)\n");
647 case ST90TDS_SBUS_READ
:
648 pr_info("ETF_SBUS_READ (unhandled)\n");
650 case ST90TDS_SBUS_WRITE
:
651 pr_info("ETF_SBUS_WRITE (unhandled)\n");
653 case ST90TDS_SET_DEVICE_OPTION
:
654 pr_info("ETF_SET_DEV_OPT (unhandled)\n");
657 pr_info("ETF_PASSTHRU (0x%08x)\n", msg
->id
);
658 rval
= wsm_raw_cmd(priv
, (u8
*)msg
, len
);
664 #endif /* CONFIG_CW1200_ETF */