diff options
author | Kalle Valo <kalle.valo@nokia.com> | 2009-04-29 16:33:31 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-06 15:14:54 -0400 |
commit | 2f01a1f58889fbfeb68b1bc1b52e4197f3333490 (patch) | |
tree | 949cf33c4e3dcdf7abcf95c9bda4d8372da04f97 /drivers/net/wireless | |
parent | d53d9e67b55f6a9fc3f836c5c392eb41ce5676f4 (diff) |
wl12xx: add driver
wl12xx is a driver for TI wl1251 802.11 chipset designed for embedded
devices, supporting both SDIO and SPI busses. Currently the driver
supports only SPI. Adding support 1253 (the 5 GHz version) should be
relatively easy. More information here:
http://focus.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?contentId=4711&navigationId=12494&templateId=6123
(Collapsed original sequence of pre-merge patches into single commit for
initial merge. -- JWL)
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
30 files changed, 9232 insertions, 0 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 2d8434f409b6..91be3e7bf133 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -500,5 +500,6 @@ source "drivers/net/wireless/b43legacy/Kconfig" | |||
500 | source "drivers/net/wireless/zd1211rw/Kconfig" | 500 | source "drivers/net/wireless/zd1211rw/Kconfig" |
501 | source "drivers/net/wireless/rt2x00/Kconfig" | 501 | source "drivers/net/wireless/rt2x00/Kconfig" |
502 | source "drivers/net/wireless/orinoco/Kconfig" | 502 | source "drivers/net/wireless/orinoco/Kconfig" |
503 | source "drivers/net/wireless/wl12xx/Kconfig" | ||
503 | 504 | ||
504 | endmenu | 505 | endmenu |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 0625e91b5995..f2b1861e6bcb 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -58,3 +58,5 @@ obj-$(CONFIG_P54_COMMON) += p54/ | |||
58 | obj-$(CONFIG_ATH_COMMON) += ath/ | 58 | obj-$(CONFIG_ATH_COMMON) += ath/ |
59 | 59 | ||
60 | obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o | 60 | obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o |
61 | |||
62 | obj-$(CONFIG_WL12XX) += wl12xx/ | ||
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig new file mode 100644 index 000000000000..20a9633569f2 --- /dev/null +++ b/drivers/net/wireless/wl12xx/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | config WL12XX | ||
2 | tristate "TI wl1251/wl1271 support" | ||
3 | depends on MAC80211 && WLAN_80211 && SPI_MASTER && EXPERIMENTAL | ||
4 | select FW_LOADER | ||
5 | select CRC7 | ||
6 | ---help--- | ||
7 | This module adds support for wireless adapters based on | ||
8 | TI wl1251/wl1271 chipsets. | ||
9 | |||
10 | If you choose to build a module, it'll be called wl12xx. Say N if | ||
11 | unsure. | ||
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile new file mode 100644 index 000000000000..d43de27dc54c --- /dev/null +++ b/drivers/net/wireless/wl12xx/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | wl12xx-objs = main.o spi.o event.o tx.o rx.o \ | ||
2 | ps.o cmd.o acx.o boot.o init.o wl1251.o \ | ||
3 | debugfs.o | ||
4 | obj-$(CONFIG_WL12XX) += wl12xx.o | ||
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c new file mode 100644 index 000000000000..1cfd458ad5ab --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.c | |||
@@ -0,0 +1,689 @@ | |||
1 | #include "acx.h" | ||
2 | |||
3 | #include <linux/module.h> | ||
4 | #include <linux/crc7.h> | ||
5 | #include <linux/spi/spi.h> | ||
6 | |||
7 | #include "wl12xx.h" | ||
8 | #include "wl12xx_80211.h" | ||
9 | #include "reg.h" | ||
10 | #include "spi.h" | ||
11 | #include "ps.h" | ||
12 | |||
13 | int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, | ||
14 | u8 mgt_rate, u8 mgt_mod) | ||
15 | { | ||
16 | int ret; | ||
17 | struct acx_fw_gen_frame_rates rates; | ||
18 | |||
19 | wl12xx_debug(DEBUG_ACX, "acx frame rates"); | ||
20 | |||
21 | rates.header.id = ACX_FW_GEN_FRAME_RATES; | ||
22 | rates.header.len = sizeof(struct acx_fw_gen_frame_rates) - | ||
23 | sizeof(struct acx_header); | ||
24 | |||
25 | rates.tx_ctrl_frame_rate = ctrl_rate; | ||
26 | rates.tx_ctrl_frame_mod = ctrl_mod; | ||
27 | rates.tx_mgt_frame_rate = mgt_rate; | ||
28 | rates.tx_mgt_frame_mod = mgt_mod; | ||
29 | |||
30 | ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates)); | ||
31 | if (ret < 0) { | ||
32 | wl12xx_error("Failed to set FW rates and modulation"); | ||
33 | return ret; | ||
34 | } | ||
35 | |||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | |||
40 | int wl12xx_acx_station_id(struct wl12xx *wl) | ||
41 | { | ||
42 | int ret, i; | ||
43 | struct dot11_station_id mac; | ||
44 | |||
45 | wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); | ||
46 | |||
47 | mac.header.id = DOT11_STATION_ID; | ||
48 | mac.header.len = sizeof(mac) - sizeof(struct acx_header); | ||
49 | |||
50 | for (i = 0; i < ETH_ALEN; i++) | ||
51 | mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; | ||
52 | |||
53 | ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac)); | ||
54 | if (ret < 0) | ||
55 | return ret; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) | ||
61 | { | ||
62 | struct acx_dot11_default_key default_key; | ||
63 | int ret; | ||
64 | |||
65 | wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); | ||
66 | |||
67 | default_key.header.id = DOT11_DEFAULT_KEY; | ||
68 | default_key.header.len = sizeof(default_key) - | ||
69 | sizeof(struct acx_header); | ||
70 | |||
71 | default_key.id = key_id; | ||
72 | |||
73 | ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key)); | ||
74 | if (ret < 0) { | ||
75 | wl12xx_error("Couldnt set default key"); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | wl->default_key = key_id; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) | ||
85 | { | ||
86 | struct acx_wake_up_condition wake_up; | ||
87 | |||
88 | wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); | ||
89 | |||
90 | wake_up.header.id = ACX_WAKE_UP_CONDITIONS; | ||
91 | wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header); | ||
92 | |||
93 | wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; | ||
94 | wake_up.listen_interval = listen_interval; | ||
95 | |||
96 | return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up)); | ||
97 | } | ||
98 | |||
99 | int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) | ||
100 | { | ||
101 | int ret; | ||
102 | struct acx_sleep_auth auth; | ||
103 | |||
104 | wl12xx_debug(DEBUG_ACX, "acx sleep auth"); | ||
105 | |||
106 | auth.header.id = ACX_SLEEP_AUTH; | ||
107 | auth.header.len = sizeof(auth) - sizeof(struct acx_header); | ||
108 | |||
109 | auth.sleep_auth = sleep_auth; | ||
110 | |||
111 | ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth)); | ||
112 | if (ret < 0) | ||
113 | return ret; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) | ||
119 | { | ||
120 | struct wl12xx_command cmd; | ||
121 | struct acx_revision *rev; | ||
122 | int ret; | ||
123 | |||
124 | wl12xx_debug(DEBUG_ACX, "acx fw rev"); | ||
125 | |||
126 | memset(&cmd, 0, sizeof(cmd)); | ||
127 | |||
128 | ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd); | ||
129 | if (ret < 0) { | ||
130 | wl12xx_warning("ACX_FW_REV interrogate failed"); | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | rev = (struct acx_revision *) &cmd.parameters; | ||
135 | |||
136 | /* be careful with the buffer sizes */ | ||
137 | strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); | ||
138 | |||
139 | /* | ||
140 | * if the firmware version string is exactly | ||
141 | * sizeof(rev->fw_version) long or fw_len is less than | ||
142 | * sizeof(rev->fw_version) it won't be null terminated | ||
143 | */ | ||
144 | buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | int wl12xx_acx_tx_power(struct wl12xx *wl, int power) | ||
150 | { | ||
151 | struct acx_current_tx_power ie; | ||
152 | int ret; | ||
153 | |||
154 | wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); | ||
155 | |||
156 | if (power < 0 || power > 25) | ||
157 | return -EINVAL; | ||
158 | |||
159 | memset(&ie, 0, sizeof(ie)); | ||
160 | |||
161 | ie.header.id = DOT11_CUR_TX_PWR; | ||
162 | ie.header.len = sizeof(ie) - sizeof(struct acx_header); | ||
163 | ie.current_tx_power = power * 10; | ||
164 | |||
165 | ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); | ||
166 | if (ret < 0) { | ||
167 | wl12xx_warning("configure of tx power failed: %d", ret); | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | int wl12xx_acx_feature_cfg(struct wl12xx *wl) | ||
175 | { | ||
176 | struct acx_feature_config feature; | ||
177 | int ret; | ||
178 | |||
179 | wl12xx_debug(DEBUG_ACX, "acx feature cfg"); | ||
180 | |||
181 | memset(&feature, 0, sizeof(feature)); | ||
182 | |||
183 | feature.header.id = ACX_FEATURE_CFG; | ||
184 | feature.header.len = sizeof(feature) - sizeof(struct acx_header); | ||
185 | |||
186 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ | ||
187 | feature.data_flow_options = 0; | ||
188 | feature.options = 0; | ||
189 | |||
190 | ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature)); | ||
191 | if (ret < 0) | ||
192 | wl12xx_error("Couldnt set HW encryption"); | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len) | ||
198 | { | ||
199 | struct wl12xx_command cmd; | ||
200 | int ret; | ||
201 | |||
202 | wl12xx_debug(DEBUG_ACX, "acx mem map"); | ||
203 | |||
204 | ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd); | ||
205 | if (ret < 0) | ||
206 | return ret; | ||
207 | else if (cmd.status != CMD_STATUS_SUCCESS) | ||
208 | return -EIO; | ||
209 | |||
210 | memcpy(mem_map, &cmd.parameters, len); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | int wl12xx_acx_data_path_params(struct wl12xx *wl, | ||
216 | struct acx_data_path_params_resp *data_path) | ||
217 | { | ||
218 | struct acx_data_path_params params; | ||
219 | struct wl12xx_command cmd; | ||
220 | int ret; | ||
221 | |||
222 | wl12xx_debug(DEBUG_ACX, "acx data path params"); | ||
223 | |||
224 | params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; | ||
225 | params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; | ||
226 | |||
227 | params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; | ||
228 | params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; | ||
229 | |||
230 | params.tx_complete_threshold = 1; | ||
231 | |||
232 | params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; | ||
233 | |||
234 | params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; | ||
235 | |||
236 | params.header.id = ACX_DATA_PATH_PARAMS; | ||
237 | params.header.len = sizeof(params) - sizeof(struct acx_header); | ||
238 | |||
239 | ret = wl12xx_cmd_configure(wl, ¶ms, sizeof(params)); | ||
240 | if (ret < 0) | ||
241 | return ret; | ||
242 | |||
243 | |||
244 | ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, | ||
245 | sizeof(struct acx_data_path_params_resp), | ||
246 | &cmd); | ||
247 | |||
248 | if (ret < 0) { | ||
249 | wl12xx_warning("failed to read data path parameters: %d", ret); | ||
250 | return ret; | ||
251 | } else if (cmd.status != CMD_STATUS_SUCCESS) { | ||
252 | wl12xx_warning("data path parameter acx status failed"); | ||
253 | return -EIO; | ||
254 | } | ||
255 | |||
256 | memcpy(data_path, &cmd.parameters, sizeof(*data_path)); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) | ||
262 | { | ||
263 | struct rx_msdu_lifetime msdu_lifetime; | ||
264 | int ret; | ||
265 | |||
266 | wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); | ||
267 | |||
268 | msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME; | ||
269 | msdu_lifetime.header.len = sizeof(msdu_lifetime) - | ||
270 | sizeof(struct acx_header); | ||
271 | msdu_lifetime.lifetime = life_time; | ||
272 | |||
273 | ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime)); | ||
274 | if (ret < 0) { | ||
275 | wl12xx_warning("failed to set rx msdu life time: %d", ret); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) | ||
283 | { | ||
284 | struct acx_rx_config rx_config; | ||
285 | int ret; | ||
286 | |||
287 | wl12xx_debug(DEBUG_ACX, "acx rx config"); | ||
288 | |||
289 | rx_config.header.id = ACX_RX_CFG; | ||
290 | rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header); | ||
291 | rx_config.config_options = config; | ||
292 | rx_config.filter_options = filter; | ||
293 | |||
294 | ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config)); | ||
295 | if (ret < 0) { | ||
296 | wl12xx_warning("failed to set rx config: %d", ret); | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | int wl12xx_acx_pd_threshold(struct wl12xx *wl) | ||
304 | { | ||
305 | struct acx_packet_detection packet_detection; | ||
306 | int ret; | ||
307 | |||
308 | wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); | ||
309 | |||
310 | /* FIXME: threshold value not set */ | ||
311 | packet_detection.header.id = ACX_PD_THRESHOLD; | ||
312 | packet_detection.header.len = sizeof(packet_detection) - | ||
313 | sizeof(struct acx_header); | ||
314 | |||
315 | ret = wl12xx_cmd_configure(wl, &packet_detection, | ||
316 | sizeof(packet_detection)); | ||
317 | if (ret < 0) { | ||
318 | wl12xx_warning("failed to set pd threshold: %d", ret); | ||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) | ||
326 | { | ||
327 | struct acx_slot slot; | ||
328 | int ret; | ||
329 | |||
330 | wl12xx_debug(DEBUG_ACX, "acx slot"); | ||
331 | |||
332 | slot.header.id = ACX_SLOT; | ||
333 | slot.header.len = sizeof(slot) - sizeof(struct acx_header); | ||
334 | |||
335 | slot.wone_index = STATION_WONE_INDEX; | ||
336 | slot.slot_time = slot_time; | ||
337 | |||
338 | ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot)); | ||
339 | if (ret < 0) { | ||
340 | wl12xx_warning("failed to set slot time: %d", ret); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | int wl12xx_acx_group_address_tbl(struct wl12xx *wl) | ||
348 | { | ||
349 | struct multicast_grp_addr_start multicast; | ||
350 | int ret; | ||
351 | |||
352 | wl12xx_debug(DEBUG_ACX, "acx group address tbl"); | ||
353 | |||
354 | /* MAC filtering */ | ||
355 | multicast.header.id = DOT11_GROUP_ADDRESS_TBL; | ||
356 | multicast.header.len = sizeof(multicast) - sizeof(struct acx_header); | ||
357 | |||
358 | multicast.enabled = 0; | ||
359 | multicast.num_groups = 0; | ||
360 | memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN); | ||
361 | |||
362 | ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast)); | ||
363 | if (ret < 0) { | ||
364 | wl12xx_warning("failed to set group addr table: %d", ret); | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | int wl12xx_acx_service_period_timeout(struct wl12xx *wl) | ||
372 | { | ||
373 | struct acx_rx_timeout rx_timeout; | ||
374 | int ret; | ||
375 | |||
376 | wl12xx_debug(DEBUG_ACX, "acx service period timeout"); | ||
377 | |||
378 | /* RX timeout */ | ||
379 | rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT; | ||
380 | rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header); | ||
381 | |||
382 | rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; | ||
383 | rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF; | ||
384 | |||
385 | ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout)); | ||
386 | if (ret < 0) { | ||
387 | wl12xx_warning("failed to set service period timeout: %d", | ||
388 | ret); | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) | ||
396 | { | ||
397 | struct acx_rts_threshold rts; | ||
398 | int ret; | ||
399 | |||
400 | wl12xx_debug(DEBUG_ACX, "acx rts threshold"); | ||
401 | |||
402 | rts.header.id = DOT11_RTS_THRESHOLD; | ||
403 | rts.header.len = sizeof(rts) - sizeof(struct acx_header); | ||
404 | |||
405 | rts.threshold = rts_threshold; | ||
406 | |||
407 | ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts)); | ||
408 | if (ret < 0) { | ||
409 | wl12xx_warning("failed to set rts threshold: %d", ret); | ||
410 | return ret; | ||
411 | } | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) | ||
417 | { | ||
418 | struct acx_beacon_filter_option beacon_filter; | ||
419 | int ret; | ||
420 | |||
421 | wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); | ||
422 | |||
423 | beacon_filter.header.id = ACX_BEACON_FILTER_OPT; | ||
424 | beacon_filter.header.len = sizeof(beacon_filter) - | ||
425 | sizeof(struct acx_header); | ||
426 | |||
427 | beacon_filter.enable = 0; | ||
428 | beacon_filter.max_num_beacons = 0; | ||
429 | |||
430 | ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter)); | ||
431 | if (ret < 0) { | ||
432 | wl12xx_warning("failed to set beacon filter opt: %d", ret); | ||
433 | return ret; | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) | ||
440 | { | ||
441 | struct acx_beacon_filter_ie_table ie_table; | ||
442 | int ret; | ||
443 | |||
444 | wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); | ||
445 | |||
446 | ie_table.header.id = ACX_BEACON_FILTER_TABLE; | ||
447 | ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header); | ||
448 | |||
449 | ie_table.num_ie = 0; | ||
450 | memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE); | ||
451 | |||
452 | ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table)); | ||
453 | if (ret < 0) { | ||
454 | wl12xx_warning("failed to set beacon filter table: %d", ret); | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | int wl12xx_acx_sg_enable(struct wl12xx *wl) | ||
462 | { | ||
463 | struct acx_bt_wlan_coex pta; | ||
464 | int ret; | ||
465 | |||
466 | wl12xx_debug(DEBUG_ACX, "acx sg enable"); | ||
467 | |||
468 | pta.header.id = ACX_SG_ENABLE; | ||
469 | pta.header.len = sizeof(pta) - sizeof(struct acx_header); | ||
470 | |||
471 | pta.enable = SG_ENABLE; | ||
472 | |||
473 | ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta)); | ||
474 | if (ret < 0) { | ||
475 | wl12xx_warning("failed to set softgemini enable: %d", ret); | ||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | int wl12xx_acx_sg_cfg(struct wl12xx *wl) | ||
483 | { | ||
484 | struct acx_bt_wlan_coex_param param; | ||
485 | int ret; | ||
486 | |||
487 | wl12xx_debug(DEBUG_ACX, "acx sg cfg"); | ||
488 | |||
489 | /* BT-WLAN coext parameters */ | ||
490 | param.header.id = ACX_SG_CFG; | ||
491 | param.header.len = sizeof(param) - sizeof(struct acx_header); | ||
492 | |||
493 | param.min_rate = RATE_INDEX_24MBPS; | ||
494 | param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; | ||
495 | param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; | ||
496 | param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; | ||
497 | param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; | ||
498 | param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; | ||
499 | param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; | ||
500 | param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; | ||
501 | param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; | ||
502 | param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; | ||
503 | param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; | ||
504 | param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; | ||
505 | param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; | ||
506 | param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; | ||
507 | param.antenna_type = PTA_ANTENNA_TYPE_DEF; | ||
508 | param.signal_type = PTA_SIGNALING_TYPE_DEF; | ||
509 | param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; | ||
510 | param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; | ||
511 | param.max_cts = PTA_MAX_NUM_CTS_DEF; | ||
512 | param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; | ||
513 | param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; | ||
514 | param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; | ||
515 | param.wlan_elp_hp = PTA_ELP_HP_DEF; | ||
516 | param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; | ||
517 | param.ack_mode_dual_ant = PTA_ACK_MODE_DEF; | ||
518 | param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF; | ||
519 | param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; | ||
520 | param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; | ||
521 | |||
522 | ret = wl12xx_cmd_configure(wl, ¶m, sizeof(param)); | ||
523 | if (ret < 0) { | ||
524 | wl12xx_warning("failed to set sg config: %d", ret); | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | int wl12xx_acx_cca_threshold(struct wl12xx *wl) | ||
532 | { | ||
533 | struct acx_energy_detection detection; | ||
534 | int ret; | ||
535 | |||
536 | wl12xx_debug(DEBUG_ACX, "acx cca threshold"); | ||
537 | |||
538 | detection.header.id = ACX_CCA_THRESHOLD; | ||
539 | detection.header.len = sizeof(detection) - sizeof(struct acx_header); | ||
540 | |||
541 | detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; | ||
542 | detection.tx_energy_detection = 0; | ||
543 | |||
544 | ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection)); | ||
545 | if (ret < 0) { | ||
546 | wl12xx_warning("failed to set cca threshold: %d", ret); | ||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) | ||
554 | { | ||
555 | struct acx_beacon_broadcast bb; | ||
556 | int ret; | ||
557 | |||
558 | wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); | ||
559 | |||
560 | bb.header.id = ACX_BCN_DTIM_OPTIONS; | ||
561 | bb.header.len = sizeof(bb) - sizeof(struct acx_header); | ||
562 | |||
563 | bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; | ||
564 | bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; | ||
565 | bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; | ||
566 | bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; | ||
567 | |||
568 | ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb)); | ||
569 | if (ret < 0) { | ||
570 | wl12xx_warning("failed to set rx config: %d", ret); | ||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) | ||
578 | { | ||
579 | struct acx_aid acx_aid; | ||
580 | int ret; | ||
581 | |||
582 | wl12xx_debug(DEBUG_ACX, "acx aid"); | ||
583 | |||
584 | acx_aid.header.id = ACX_AID; | ||
585 | acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header); | ||
586 | |||
587 | acx_aid.aid = aid; | ||
588 | |||
589 | ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid)); | ||
590 | if (ret < 0) { | ||
591 | wl12xx_warning("failed to set aid: %d", ret); | ||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) | ||
599 | { | ||
600 | struct acx_event_mask mask; | ||
601 | int ret; | ||
602 | |||
603 | wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); | ||
604 | |||
605 | mask.header.id = ACX_EVENT_MBOX_MASK; | ||
606 | mask.header.len = sizeof(mask) - sizeof(struct acx_header); | ||
607 | |||
608 | /* high event mask is unused */ | ||
609 | mask.high_event_mask = 0xffffffff; | ||
610 | |||
611 | mask.event_mask = event_mask; | ||
612 | |||
613 | ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask)); | ||
614 | if (ret < 0) { | ||
615 | wl12xx_warning("failed to set aid: %d", ret); | ||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) | ||
623 | { | ||
624 | struct acx_preamble ie; | ||
625 | int ret; | ||
626 | |||
627 | wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); | ||
628 | |||
629 | memset(&ie, 0, sizeof(ie)); | ||
630 | |||
631 | ie.header.id = ACX_PREAMBLE_TYPE; | ||
632 | ie.header.len = sizeof(ie) - sizeof(struct acx_header); | ||
633 | ie.preamble = preamble; | ||
634 | ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); | ||
635 | if (ret < 0) { | ||
636 | wl12xx_warning("Setting of preamble failed: %d", ret); | ||
637 | return ret; | ||
638 | } | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | int wl12xx_acx_cts_protect(struct wl12xx *wl, | ||
643 | enum acx_ctsprotect_type ctsprotect) | ||
644 | { | ||
645 | struct acx_ctsprotect ie; | ||
646 | int ret; | ||
647 | |||
648 | wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); | ||
649 | |||
650 | memset(&ie, 0, sizeof(ie)); | ||
651 | |||
652 | ie.header.id = ACX_CTS_PROTECTION; | ||
653 | ie.header.len = sizeof(ie) - sizeof(struct acx_header); | ||
654 | ie.ctsprotect = ctsprotect; | ||
655 | ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); | ||
656 | if (ret < 0) { | ||
657 | wl12xx_warning("Setting of ctsprotect failed: %d", ret); | ||
658 | return ret; | ||
659 | } | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) | ||
664 | { | ||
665 | struct wl12xx_command *answer; | ||
666 | int ret; | ||
667 | |||
668 | wl12xx_debug(DEBUG_ACX, "acx statistics"); | ||
669 | |||
670 | answer = kmalloc(sizeof(*answer), GFP_KERNEL); | ||
671 | if (!answer) { | ||
672 | wl12xx_warning("could not allocate memory for acx statistics"); | ||
673 | ret = -ENOMEM; | ||
674 | goto out; | ||
675 | } | ||
676 | |||
677 | ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer), | ||
678 | answer); | ||
679 | if (ret < 0) { | ||
680 | wl12xx_warning("acx statistics failed: %d", ret); | ||
681 | goto out; | ||
682 | } | ||
683 | |||
684 | memcpy(stats, answer->parameters, sizeof(*stats)); | ||
685 | |||
686 | out: | ||
687 | kfree(answer); | ||
688 | return ret; | ||
689 | } | ||
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h new file mode 100644 index 000000000000..fb2d2340993c --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.h | |||
@@ -0,0 +1,1245 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_ACX_H__ | ||
26 | #define __WL12XX_ACX_H__ | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | |||
30 | /* Target's information element */ | ||
31 | struct acx_header { | ||
32 | u16 id; | ||
33 | u16 len; | ||
34 | }; | ||
35 | |||
36 | struct acx_error_counter { | ||
37 | struct acx_header header; | ||
38 | |||
39 | /* The number of PLCP errors since the last time this */ | ||
40 | /* information element was interrogated. This field is */ | ||
41 | /* automatically cleared when it is interrogated.*/ | ||
42 | u32 PLCP_error; | ||
43 | |||
44 | /* The number of FCS errors since the last time this */ | ||
45 | /* information element was interrogated. This field is */ | ||
46 | /* automatically cleared when it is interrogated.*/ | ||
47 | u32 FCS_error; | ||
48 | |||
49 | /* The number of MPDUs without PLCP header errors received*/ | ||
50 | /* since the last time this information element was interrogated. */ | ||
51 | /* This field is automatically cleared when it is interrogated.*/ | ||
52 | u32 valid_frame; | ||
53 | |||
54 | /* the number of missed sequence numbers in the squentially */ | ||
55 | /* values of frames seq numbers */ | ||
56 | u32 seq_num_miss; | ||
57 | } __attribute__ ((packed)); | ||
58 | |||
59 | struct acx_revision { | ||
60 | struct acx_header header; | ||
61 | |||
62 | /* | ||
63 | * The WiLink firmware version, an ASCII string x.x.x.x, | ||
64 | * that uniquely identifies the current firmware. | ||
65 | * The left most digit is incremented each time a | ||
66 | * significant change is made to the firmware, such as | ||
67 | * code redesign or new platform support. | ||
68 | * The second digit is incremented when major enhancements | ||
69 | * are added or major fixes are made. | ||
70 | * The third digit is incremented for each GA release. | ||
71 | * The fourth digit is incremented for each build. | ||
72 | * The first two digits identify a firmware release version, | ||
73 | * in other words, a unique set of features. | ||
74 | * The first three digits identify a GA release. | ||
75 | */ | ||
76 | char fw_version[20]; | ||
77 | |||
78 | /* | ||
79 | * This 4 byte field specifies the WiLink hardware version. | ||
80 | * bits 0 - 15: Reserved. | ||
81 | * bits 16 - 23: Version ID - The WiLink version ID | ||
82 | * (1 = first spin, 2 = second spin, and so on). | ||
83 | * bits 24 - 31: Chip ID - The WiLink chip ID. | ||
84 | */ | ||
85 | u32 hw_version; | ||
86 | } __attribute__ ((packed)); | ||
87 | |||
88 | enum wl12xx_psm_mode { | ||
89 | /* Active mode */ | ||
90 | WL12XX_PSM_CAM = 0, | ||
91 | |||
92 | /* Power save mode */ | ||
93 | WL12XX_PSM_PS = 1, | ||
94 | |||
95 | /* Extreme low power */ | ||
96 | WL12XX_PSM_ELP = 2, | ||
97 | }; | ||
98 | |||
99 | struct acx_sleep_auth { | ||
100 | struct acx_header header; | ||
101 | |||
102 | /* The sleep level authorization of the device. */ | ||
103 | /* 0 - Always active*/ | ||
104 | /* 1 - Power down mode: light / fast sleep*/ | ||
105 | /* 2 - ELP mode: Deep / Max sleep*/ | ||
106 | u8 sleep_auth; | ||
107 | u8 padding[3]; | ||
108 | } __attribute__ ((packed)); | ||
109 | |||
110 | #define TIM_ELE_ID 5 | ||
111 | #define PARTIAL_VBM_MAX 251 | ||
112 | |||
113 | struct tim { | ||
114 | u8 identity; | ||
115 | u8 length; | ||
116 | u8 dtim_count; | ||
117 | u8 dtim_period; | ||
118 | u8 bitmap_ctrl; | ||
119 | u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ | ||
120 | } __attribute__ ((packed)); | ||
121 | |||
122 | /* Virtual Bit Map update */ | ||
123 | struct vbm_update_request { | ||
124 | __le16 len; | ||
125 | u8 padding[2]; | ||
126 | struct tim tim; | ||
127 | } __attribute__ ((packed)); | ||
128 | |||
129 | enum { | ||
130 | HOSTIF_PCI_MASTER_HOST_INDIRECT, | ||
131 | HOSTIF_PCI_MASTER_HOST_DIRECT, | ||
132 | HOSTIF_SLAVE, | ||
133 | HOSTIF_PKT_RING, | ||
134 | HOSTIF_DONTCARE = 0xFF | ||
135 | }; | ||
136 | |||
137 | #define DEFAULT_UCAST_PRIORITY 0 | ||
138 | #define DEFAULT_RX_Q_PRIORITY 0 | ||
139 | #define DEFAULT_NUM_STATIONS 1 | ||
140 | #define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ | ||
141 | #define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ | ||
142 | #define TRACE_BUFFER_MAX_SIZE 256 | ||
143 | |||
144 | #define DP_RX_PACKET_RING_CHUNK_SIZE 1600 | ||
145 | #define DP_TX_PACKET_RING_CHUNK_SIZE 1600 | ||
146 | #define DP_RX_PACKET_RING_CHUNK_NUM 2 | ||
147 | #define DP_TX_PACKET_RING_CHUNK_NUM 2 | ||
148 | #define DP_TX_COMPLETE_TIME_OUT 20 | ||
149 | #define FW_TX_CMPLT_BLOCK_SIZE 16 | ||
150 | |||
151 | struct acx_data_path_params { | ||
152 | struct acx_header header; | ||
153 | |||
154 | u16 rx_packet_ring_chunk_size; | ||
155 | u16 tx_packet_ring_chunk_size; | ||
156 | |||
157 | u8 rx_packet_ring_chunk_num; | ||
158 | u8 tx_packet_ring_chunk_num; | ||
159 | |||
160 | /* | ||
161 | * Maximum number of packets that can be gathered | ||
162 | * in the TX complete ring before an interrupt | ||
163 | * is generated. | ||
164 | */ | ||
165 | u8 tx_complete_threshold; | ||
166 | |||
167 | /* Number of pending TX complete entries in cyclic ring.*/ | ||
168 | u8 tx_complete_ring_depth; | ||
169 | |||
170 | /* | ||
171 | * Max num microseconds since a packet enters the TX | ||
172 | * complete ring until an interrupt is generated. | ||
173 | */ | ||
174 | u32 tx_complete_timeout; | ||
175 | } __attribute__ ((packed)); | ||
176 | |||
177 | |||
178 | struct acx_data_path_params_resp { | ||
179 | struct acx_header header; | ||
180 | |||
181 | u16 rx_packet_ring_chunk_size; | ||
182 | u16 tx_packet_ring_chunk_size; | ||
183 | |||
184 | u8 rx_packet_ring_chunk_num; | ||
185 | u8 tx_packet_ring_chunk_num; | ||
186 | |||
187 | u8 pad[2]; | ||
188 | |||
189 | u32 rx_packet_ring_addr; | ||
190 | u32 tx_packet_ring_addr; | ||
191 | |||
192 | u32 rx_control_addr; | ||
193 | u32 tx_control_addr; | ||
194 | |||
195 | u32 tx_complete_addr; | ||
196 | } __attribute__ ((packed)); | ||
197 | |||
198 | #define TX_MSDU_LIFETIME_MIN 0 | ||
199 | #define TX_MSDU_LIFETIME_MAX 3000 | ||
200 | #define TX_MSDU_LIFETIME_DEF 512 | ||
201 | #define RX_MSDU_LIFETIME_MIN 0 | ||
202 | #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF | ||
203 | #define RX_MSDU_LIFETIME_DEF 512000 | ||
204 | |||
205 | struct rx_msdu_lifetime { | ||
206 | struct acx_header header; | ||
207 | |||
208 | /* | ||
209 | * The maximum amount of time, in TU, before the | ||
210 | * firmware discards the MSDU. | ||
211 | */ | ||
212 | u32 lifetime; | ||
213 | } __attribute__ ((packed)); | ||
214 | |||
215 | /* | ||
216 | * RX Config Options Table | ||
217 | * Bit Definition | ||
218 | * === ========== | ||
219 | * 31:14 Reserved | ||
220 | * 13 Copy RX Status - when set, write three receive status words | ||
221 | * to top of rx'd MPDUs. | ||
222 | * When cleared, do not write three status words (added rev 1.5) | ||
223 | * 12 Reserved | ||
224 | * 11 RX Complete upon FCS error - when set, give rx complete | ||
225 | * interrupt for FCS errors, after the rx filtering, e.g. unicast | ||
226 | * frames not to us with FCS error will not generate an interrupt. | ||
227 | * 10 SSID Filter Enable - When set, the WiLink discards all beacon, | ||
228 | * probe request, and probe response frames with an SSID that does | ||
229 | * not match the SSID specified by the host in the START/JOIN | ||
230 | * command. | ||
231 | * When clear, the WiLink receives frames with any SSID. | ||
232 | * 9 Broadcast Filter Enable - When set, the WiLink discards all | ||
233 | * broadcast frames. When clear, the WiLink receives all received | ||
234 | * broadcast frames. | ||
235 | * 8:6 Reserved | ||
236 | * 5 BSSID Filter Enable - When set, the WiLink discards any frames | ||
237 | * with a BSSID that does not match the BSSID specified by the | ||
238 | * host. | ||
239 | * When clear, the WiLink receives frames from any BSSID. | ||
240 | * 4 MAC Addr Filter - When set, the WiLink discards any frames | ||
241 | * with a destination address that does not match the MAC address | ||
242 | * of the adaptor. | ||
243 | * When clear, the WiLink receives frames destined to any MAC | ||
244 | * address. | ||
245 | * 3 Promiscuous - When set, the WiLink receives all valid frames | ||
246 | * (i.e., all frames that pass the FCS check). | ||
247 | * When clear, only frames that pass the other filters specified | ||
248 | * are received. | ||
249 | * 2 FCS - When set, the WiLink includes the FCS with the received | ||
250 | * frame. | ||
251 | * When cleared, the FCS is discarded. | ||
252 | * 1 PLCP header - When set, write all data from baseband to frame | ||
253 | * buffer including PHY header. | ||
254 | * 0 Reserved - Always equal to 0. | ||
255 | * | ||
256 | * RX Filter Options Table | ||
257 | * Bit Definition | ||
258 | * === ========== | ||
259 | * 31:12 Reserved - Always equal to 0. | ||
260 | * 11 Association - When set, the WiLink receives all association | ||
261 | * related frames (association request/response, reassocation | ||
262 | * request/response, and disassociation). When clear, these frames | ||
263 | * are discarded. | ||
264 | * 10 Auth/De auth - When set, the WiLink receives all authentication | ||
265 | * and de-authentication frames. When clear, these frames are | ||
266 | * discarded. | ||
267 | * 9 Beacon - When set, the WiLink receives all beacon frames. | ||
268 | * When clear, these frames are discarded. | ||
269 | * 8 Contention Free - When set, the WiLink receives all contention | ||
270 | * free frames. | ||
271 | * When clear, these frames are discarded. | ||
272 | * 7 Control - When set, the WiLink receives all control frames. | ||
273 | * When clear, these frames are discarded. | ||
274 | * 6 Data - When set, the WiLink receives all data frames. | ||
275 | * When clear, these frames are discarded. | ||
276 | * 5 FCS Error - When set, the WiLink receives frames that have FCS | ||
277 | * errors. | ||
278 | * When clear, these frames are discarded. | ||
279 | * 4 Management - When set, the WiLink receives all management | ||
280 | * frames. | ||
281 | * When clear, these frames are discarded. | ||
282 | * 3 Probe Request - When set, the WiLink receives all probe request | ||
283 | * frames. | ||
284 | * When clear, these frames are discarded. | ||
285 | * 2 Probe Response - When set, the WiLink receives all probe | ||
286 | * response frames. | ||
287 | * When clear, these frames are discarded. | ||
288 | * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK | ||
289 | * frames. | ||
290 | * When clear, these frames are discarded. | ||
291 | * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames | ||
292 | * that have reserved frame types and sub types as defined by the | ||
293 | * 802.11 specification. | ||
294 | * When clear, these frames are discarded. | ||
295 | */ | ||
296 | struct acx_rx_config { | ||
297 | struct acx_header header; | ||
298 | |||
299 | u32 config_options; | ||
300 | u32 filter_options; | ||
301 | } __attribute__ ((packed)); | ||
302 | |||
303 | enum { | ||
304 | QOS_AC_BE = 0, | ||
305 | QOS_AC_BK, | ||
306 | QOS_AC_VI, | ||
307 | QOS_AC_VO, | ||
308 | QOS_HIGHEST_AC_INDEX = QOS_AC_VO, | ||
309 | }; | ||
310 | |||
311 | #define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) | ||
312 | #define FIRST_AC_INDEX QOS_AC_BE | ||
313 | #define MAX_NUM_OF_802_1d_TAGS 8 | ||
314 | #define AC_PARAMS_MAX_TSID 15 | ||
315 | #define MAX_APSD_CONF 0xffff | ||
316 | |||
317 | #define QOS_TX_HIGH_MIN (0) | ||
318 | #define QOS_TX_HIGH_MAX (100) | ||
319 | |||
320 | #define QOS_TX_HIGH_BK_DEF (25) | ||
321 | #define QOS_TX_HIGH_BE_DEF (35) | ||
322 | #define QOS_TX_HIGH_VI_DEF (35) | ||
323 | #define QOS_TX_HIGH_VO_DEF (35) | ||
324 | |||
325 | #define QOS_TX_LOW_BK_DEF (15) | ||
326 | #define QOS_TX_LOW_BE_DEF (25) | ||
327 | #define QOS_TX_LOW_VI_DEF (25) | ||
328 | #define QOS_TX_LOW_VO_DEF (25) | ||
329 | |||
330 | struct acx_tx_queue_qos_config { | ||
331 | struct acx_header header; | ||
332 | |||
333 | u8 qid; | ||
334 | u8 pad[3]; | ||
335 | |||
336 | /* Max number of blocks allowd in the queue */ | ||
337 | u16 high_threshold; | ||
338 | |||
339 | /* Lowest memory blocks guaranteed for this queue */ | ||
340 | u16 low_threshold; | ||
341 | } __attribute__ ((packed)); | ||
342 | |||
343 | struct acx_packet_detection { | ||
344 | struct acx_header header; | ||
345 | |||
346 | u32 threshold; | ||
347 | } __attribute__ ((packed)); | ||
348 | |||
349 | |||
350 | enum acx_slot_type { | ||
351 | SLOT_TIME_LONG = 0, | ||
352 | SLOT_TIME_SHORT = 1, | ||
353 | DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, | ||
354 | MAX_SLOT_TIMES = 0xFF | ||
355 | }; | ||
356 | |||
357 | #define STATION_WONE_INDEX 0 | ||
358 | |||
359 | struct acx_slot { | ||
360 | struct acx_header header; | ||
361 | |||
362 | u8 wone_index; /* Reserved */ | ||
363 | u8 slot_time; | ||
364 | u8 reserved[6]; | ||
365 | } __attribute__ ((packed)); | ||
366 | |||
367 | |||
368 | #define ADDRESS_GROUP_MAX (8) | ||
369 | #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) | ||
370 | |||
371 | struct multicast_grp_addr_start { | ||
372 | struct acx_header header; | ||
373 | |||
374 | u8 enabled; | ||
375 | u8 num_groups; | ||
376 | u8 pad[2]; | ||
377 | u8 mac_table[ADDRESS_GROUP_MAX_LEN]; | ||
378 | } __attribute__ ((packed)); | ||
379 | |||
380 | |||
381 | #define RX_TIMEOUT_PS_POLL_MIN 0 | ||
382 | #define RX_TIMEOUT_PS_POLL_MAX (200000) | ||
383 | #define RX_TIMEOUT_PS_POLL_DEF (15) | ||
384 | #define RX_TIMEOUT_UPSD_MIN 0 | ||
385 | #define RX_TIMEOUT_UPSD_MAX (200000) | ||
386 | #define RX_TIMEOUT_UPSD_DEF (15) | ||
387 | |||
388 | struct acx_rx_timeout { | ||
389 | struct acx_header header; | ||
390 | |||
391 | /* | ||
392 | * The longest time the STA will wait to receive | ||
393 | * traffic from the AP after a PS-poll has been | ||
394 | * transmitted. | ||
395 | */ | ||
396 | u16 ps_poll_timeout; | ||
397 | |||
398 | /* | ||
399 | * The longest time the STA will wait to receive | ||
400 | * traffic from the AP after a frame has been sent | ||
401 | * from an UPSD enabled queue. | ||
402 | */ | ||
403 | u16 upsd_timeout; | ||
404 | } __attribute__ ((packed)); | ||
405 | |||
406 | #define RTS_THRESHOLD_MIN 0 | ||
407 | #define RTS_THRESHOLD_MAX 4096 | ||
408 | #define RTS_THRESHOLD_DEF 2347 | ||
409 | |||
410 | struct acx_rts_threshold { | ||
411 | struct acx_header header; | ||
412 | |||
413 | u16 threshold; | ||
414 | u8 pad[2]; | ||
415 | } __attribute__ ((packed)); | ||
416 | |||
417 | struct acx_beacon_filter_option { | ||
418 | struct acx_header header; | ||
419 | |||
420 | u8 enable; | ||
421 | |||
422 | /* | ||
423 | * The number of beacons without the unicast TIM | ||
424 | * bit set that the firmware buffers before | ||
425 | * signaling the host about ready frames. | ||
426 | * When set to 0 and the filter is enabled, beacons | ||
427 | * without the unicast TIM bit set are dropped. | ||
428 | */ | ||
429 | u8 max_num_beacons; | ||
430 | u8 pad[2]; | ||
431 | } __attribute__ ((packed)); | ||
432 | |||
433 | /* | ||
434 | * ACXBeaconFilterEntry (not 221) | ||
435 | * Byte Offset Size (Bytes) Definition | ||
436 | * =========== ============ ========== | ||
437 | * 0 1 IE identifier | ||
438 | * 1 1 Treatment bit mask | ||
439 | * | ||
440 | * ACXBeaconFilterEntry (221) | ||
441 | * Byte Offset Size (Bytes) Definition | ||
442 | * =========== ============ ========== | ||
443 | * 0 1 IE identifier | ||
444 | * 1 1 Treatment bit mask | ||
445 | * 2 3 OUI | ||
446 | * 5 1 Type | ||
447 | * 6 2 Version | ||
448 | * | ||
449 | * | ||
450 | * Treatment bit mask - The information element handling: | ||
451 | * bit 0 - The information element is compared and transferred | ||
452 | * in case of change. | ||
453 | * bit 1 - The information element is transferred to the host | ||
454 | * with each appearance or disappearance. | ||
455 | * Note that both bits can be set at the same time. | ||
456 | */ | ||
457 | #define BEACON_FILTER_TABLE_MAX_IE_NUM (32) | ||
458 | #define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) | ||
459 | #define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) | ||
460 | #define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) | ||
461 | #define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ | ||
462 | BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ | ||
463 | (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ | ||
464 | BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) | ||
465 | |||
466 | struct acx_beacon_filter_ie_table { | ||
467 | struct acx_header header; | ||
468 | |||
469 | u8 num_ie; | ||
470 | u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; | ||
471 | u8 pad[3]; | ||
472 | } __attribute__ ((packed)); | ||
473 | |||
474 | enum { | ||
475 | SG_ENABLE = 0, | ||
476 | SG_DISABLE, | ||
477 | SG_SENSE_NO_ACTIVITY, | ||
478 | SG_SENSE_ACTIVE | ||
479 | }; | ||
480 | |||
481 | struct acx_bt_wlan_coex { | ||
482 | struct acx_header header; | ||
483 | |||
484 | /* | ||
485 | * 0 -> PTA enabled | ||
486 | * 1 -> PTA disabled | ||
487 | * 2 -> sense no active mode, i.e. | ||
488 | * an interrupt is sent upon | ||
489 | * BT activity. | ||
490 | * 3 -> PTA is switched on in response | ||
491 | * to the interrupt sending. | ||
492 | */ | ||
493 | u8 enable; | ||
494 | u8 pad[3]; | ||
495 | } __attribute__ ((packed)); | ||
496 | |||
497 | #define PTA_ANTENNA_TYPE_DEF (0) | ||
498 | #define PTA_BT_HP_MAXTIME_DEF (2000) | ||
499 | #define PTA_WLAN_HP_MAX_TIME_DEF (5000) | ||
500 | #define PTA_SENSE_DISABLE_TIMER_DEF (1350) | ||
501 | #define PTA_PROTECTIVE_RX_TIME_DEF (1500) | ||
502 | #define PTA_PROTECTIVE_TX_TIME_DEF (1500) | ||
503 | #define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) | ||
504 | #define PTA_SIGNALING_TYPE_DEF (1) | ||
505 | #define PTA_AFH_LEVERAGE_ON_DEF (0) | ||
506 | #define PTA_NUMBER_QUIET_CYCLE_DEF (0) | ||
507 | #define PTA_MAX_NUM_CTS_DEF (3) | ||
508 | #define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) | ||
509 | #define PTA_NUMBER_OF_BT_PACKETS_DEF (2) | ||
510 | #define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) | ||
511 | #define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) | ||
512 | #define PTA_CYCLE_TIME_FAST_DEF (8700) | ||
513 | #define PTA_RX_FOR_AVALANCHE_DEF (5) | ||
514 | #define PTA_ELP_HP_DEF (0) | ||
515 | #define PTA_ANTI_STARVE_PERIOD_DEF (500) | ||
516 | #define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) | ||
517 | #define PTA_ALLOW_PA_SD_DEF (1) | ||
518 | #define PTA_TIME_BEFORE_BEACON_DEF (6300) | ||
519 | #define PTA_HPDM_MAX_TIME_DEF (1600) | ||
520 | #define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) | ||
521 | #define PTA_AUTO_MODE_NO_CTS_DEF (0) | ||
522 | #define PTA_BT_HP_RESPECTED_DEF (3) | ||
523 | #define PTA_WLAN_RX_MIN_RATE_DEF (24) | ||
524 | #define PTA_ACK_MODE_DEF (1) | ||
525 | |||
526 | struct acx_bt_wlan_coex_param { | ||
527 | struct acx_header header; | ||
528 | |||
529 | /* | ||
530 | * The minimum rate of a received WLAN packet in the STA, | ||
531 | * during protective mode, of which a new BT-HP request | ||
532 | * during this Rx will always be respected and gain the antenna. | ||
533 | */ | ||
534 | u32 min_rate; | ||
535 | |||
536 | /* Max time the BT HP will be respected. */ | ||
537 | u16 bt_hp_max_time; | ||
538 | |||
539 | /* Max time the WLAN HP will be respected. */ | ||
540 | u16 wlan_hp_max_time; | ||
541 | |||
542 | /* | ||
543 | * The time between the last BT activity | ||
544 | * and the moment when the sense mode returns | ||
545 | * to SENSE_INACTIVE. | ||
546 | */ | ||
547 | u16 sense_disable_timer; | ||
548 | |||
549 | /* Time before the next BT HP instance */ | ||
550 | u16 rx_time_bt_hp; | ||
551 | u16 tx_time_bt_hp; | ||
552 | |||
553 | /* range: 10-20000 default: 1500 */ | ||
554 | u16 rx_time_bt_hp_fast; | ||
555 | u16 tx_time_bt_hp_fast; | ||
556 | |||
557 | /* range: 2000-65535 default: 8700 */ | ||
558 | u16 wlan_cycle_fast; | ||
559 | |||
560 | /* range: 0 - 15000 (Msec) default: 1000 */ | ||
561 | u16 bt_anti_starvation_period; | ||
562 | |||
563 | /* range 400-10000(Usec) default: 3000 */ | ||
564 | u16 next_bt_lp_packet; | ||
565 | |||
566 | /* Deafult: worst case for BT DH5 traffic */ | ||
567 | u16 wake_up_beacon; | ||
568 | |||
569 | /* range: 0-50000(Usec) default: 1050 */ | ||
570 | u16 hp_dm_max_guard_time; | ||
571 | |||
572 | /* | ||
573 | * This is to prevent both BT & WLAN antenna | ||
574 | * starvation. | ||
575 | * Range: 100-50000(Usec) default:2550 | ||
576 | */ | ||
577 | u16 next_wlan_packet; | ||
578 | |||
579 | /* 0 -> shared antenna */ | ||
580 | u8 antenna_type; | ||
581 | |||
582 | /* | ||
583 | * 0 -> TI legacy | ||
584 | * 1 -> Palau | ||
585 | */ | ||
586 | u8 signal_type; | ||
587 | |||
588 | /* | ||
589 | * BT AFH status | ||
590 | * 0 -> no AFH | ||
591 | * 1 -> from dedicated GPIO | ||
592 | * 2 -> AFH on (from host) | ||
593 | */ | ||
594 | u8 afh_leverage_on; | ||
595 | |||
596 | /* | ||
597 | * The number of cycles during which no | ||
598 | * TX will be sent after 1 cycle of RX | ||
599 | * transaction in protective mode | ||
600 | */ | ||
601 | u8 quiet_cycle_num; | ||
602 | |||
603 | /* | ||
604 | * The maximum number of CTSs that will | ||
605 | * be sent for receiving RX packet in | ||
606 | * protective mode | ||
607 | */ | ||
608 | u8 max_cts; | ||
609 | |||
610 | /* | ||
611 | * The number of WLAN packets | ||
612 | * transferred in common mode before | ||
613 | * switching to BT. | ||
614 | */ | ||
615 | u8 wlan_packets_num; | ||
616 | |||
617 | /* | ||
618 | * The number of BT packets | ||
619 | * transferred in common mode before | ||
620 | * switching to WLAN. | ||
621 | */ | ||
622 | u8 bt_packets_num; | ||
623 | |||
624 | /* range: 1-255 default: 5 */ | ||
625 | u8 missed_rx_avalanche; | ||
626 | |||
627 | /* range: 0-1 default: 1 */ | ||
628 | u8 wlan_elp_hp; | ||
629 | |||
630 | /* range: 0 - 15 default: 4 */ | ||
631 | u8 bt_anti_starvation_cycles; | ||
632 | |||
633 | u8 ack_mode_dual_ant; | ||
634 | |||
635 | /* | ||
636 | * Allow PA_SD assertion/de-assertion | ||
637 | * during enabled BT activity. | ||
638 | */ | ||
639 | u8 pa_sd_enable; | ||
640 | |||
641 | /* | ||
642 | * Enable/Disable PTA in auto mode: | ||
643 | * Support Both Active & P.S modes | ||
644 | */ | ||
645 | u8 pta_auto_mode_enable; | ||
646 | |||
647 | /* range: 0 - 20 default: 1 */ | ||
648 | u8 bt_hp_respected_num; | ||
649 | } __attribute__ ((packed)); | ||
650 | |||
651 | #define CCA_THRSH_ENABLE_ENERGY_D 0x140A | ||
652 | #define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF | ||
653 | |||
654 | struct acx_energy_detection { | ||
655 | struct acx_header header; | ||
656 | |||
657 | /* The RX Clear Channel Assessment threshold in the PHY */ | ||
658 | u16 rx_cca_threshold; | ||
659 | u8 tx_energy_detection; | ||
660 | u8 pad; | ||
661 | } __attribute__ ((packed)); | ||
662 | |||
663 | #define BCN_RX_TIMEOUT_DEF_VALUE 10000 | ||
664 | #define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 | ||
665 | #define RX_BROADCAST_IN_PS_DEF_VALUE 1 | ||
666 | #define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 | ||
667 | |||
668 | struct acx_beacon_broadcast { | ||
669 | struct acx_header header; | ||
670 | |||
671 | u16 beacon_rx_timeout; | ||
672 | u16 broadcast_timeout; | ||
673 | |||
674 | /* Enables receiving of broadcast packets in PS mode */ | ||
675 | u8 rx_broadcast_in_ps; | ||
676 | |||
677 | /* Consecutive PS Poll failures before updating the host */ | ||
678 | u8 ps_poll_threshold; | ||
679 | u8 pad[2]; | ||
680 | } __attribute__ ((packed)); | ||
681 | |||
682 | struct acx_event_mask { | ||
683 | struct acx_header header; | ||
684 | |||
685 | u32 event_mask; | ||
686 | u32 high_event_mask; /* Unused */ | ||
687 | } __attribute__ ((packed)); | ||
688 | |||
689 | #define CFG_RX_FCS BIT(2) | ||
690 | #define CFG_RX_ALL_GOOD BIT(3) | ||
691 | #define CFG_UNI_FILTER_EN BIT(4) | ||
692 | #define CFG_BSSID_FILTER_EN BIT(5) | ||
693 | #define CFG_MC_FILTER_EN BIT(6) | ||
694 | #define CFG_MC_ADDR0_EN BIT(7) | ||
695 | #define CFG_MC_ADDR1_EN BIT(8) | ||
696 | #define CFG_BC_REJECT_EN BIT(9) | ||
697 | #define CFG_SSID_FILTER_EN BIT(10) | ||
698 | #define CFG_RX_INT_FCS_ERROR BIT(11) | ||
699 | #define CFG_RX_INT_ENCRYPTED BIT(12) | ||
700 | #define CFG_RX_WR_RX_STATUS BIT(13) | ||
701 | #define CFG_RX_FILTER_NULTI BIT(14) | ||
702 | #define CFG_RX_RESERVE BIT(15) | ||
703 | #define CFG_RX_TIMESTAMP_TSF BIT(16) | ||
704 | |||
705 | #define CFG_RX_RSV_EN BIT(0) | ||
706 | #define CFG_RX_RCTS_ACK BIT(1) | ||
707 | #define CFG_RX_PRSP_EN BIT(2) | ||
708 | #define CFG_RX_PREQ_EN BIT(3) | ||
709 | #define CFG_RX_MGMT_EN BIT(4) | ||
710 | #define CFG_RX_FCS_ERROR BIT(5) | ||
711 | #define CFG_RX_DATA_EN BIT(6) | ||
712 | #define CFG_RX_CTL_EN BIT(7) | ||
713 | #define CFG_RX_CF_EN BIT(8) | ||
714 | #define CFG_RX_BCN_EN BIT(9) | ||
715 | #define CFG_RX_AUTH_EN BIT(10) | ||
716 | #define CFG_RX_ASSOC_EN BIT(11) | ||
717 | |||
718 | #define SCAN_PASSIVE BIT(0) | ||
719 | #define SCAN_5GHZ_BAND BIT(1) | ||
720 | #define SCAN_TRIGGERED BIT(2) | ||
721 | #define SCAN_PRIORITY_HIGH BIT(3) | ||
722 | |||
723 | struct acx_fw_gen_frame_rates { | ||
724 | struct acx_header header; | ||
725 | |||
726 | u8 tx_ctrl_frame_rate; /* RATE_* */ | ||
727 | u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ | ||
728 | u8 tx_mgt_frame_rate; | ||
729 | u8 tx_mgt_frame_mod; | ||
730 | } __attribute__ ((packed)); | ||
731 | |||
732 | /* STA MAC */ | ||
733 | struct dot11_station_id { | ||
734 | struct acx_header header; | ||
735 | |||
736 | u8 mac[ETH_ALEN]; | ||
737 | u8 pad[2]; | ||
738 | } __attribute__ ((packed)); | ||
739 | |||
740 | /* HW encryption keys */ | ||
741 | #define NUM_ACCESS_CATEGORIES_COPY 4 | ||
742 | #define MAX_KEY_SIZE 32 | ||
743 | |||
744 | /* When set, disable HW encryption */ | ||
745 | #define DF_ENCRYPTION_DISABLE 0x01 | ||
746 | /* When set, disable HW decryption */ | ||
747 | #define DF_SNIFF_MODE_ENABLE 0x80 | ||
748 | |||
749 | struct acx_feature_config { | ||
750 | struct acx_header header; | ||
751 | |||
752 | u32 options; | ||
753 | u32 data_flow_options; | ||
754 | } __attribute__ ((packed)); | ||
755 | |||
756 | enum acx_key_action { | ||
757 | KEY_ADD_OR_REPLACE = 1, | ||
758 | KEY_REMOVE = 2, | ||
759 | KEY_SET_ID = 3, | ||
760 | MAX_KEY_ACTION = 0xffff, | ||
761 | }; | ||
762 | |||
763 | enum acx_key_type { | ||
764 | KEY_WEP_DEFAULT = 0, | ||
765 | KEY_WEP_ADDR = 1, | ||
766 | KEY_AES_GROUP = 4, | ||
767 | KEY_AES_PAIRWISE = 5, | ||
768 | KEY_WEP_GROUP = 6, | ||
769 | KEY_TKIP_MIC_GROUP = 10, | ||
770 | KEY_TKIP_MIC_PAIRWISE = 11, | ||
771 | }; | ||
772 | |||
773 | /* | ||
774 | * | ||
775 | * key_type_e key size key format | ||
776 | * ---------- --------- ---------- | ||
777 | * 0x00 5, 13, 29 Key data | ||
778 | * 0x01 5, 13, 29 Key data | ||
779 | * 0x04 16 16 bytes of key data | ||
780 | * 0x05 16 16 bytes of key data | ||
781 | * 0x0a 32 16 bytes of TKIP key data | ||
782 | * 8 bytes of RX MIC key data | ||
783 | * 8 bytes of TX MIC key data | ||
784 | * 0x0b 32 16 bytes of TKIP key data | ||
785 | * 8 bytes of RX MIC key data | ||
786 | * 8 bytes of TX MIC key data | ||
787 | * | ||
788 | */ | ||
789 | |||
790 | struct acx_set_key { | ||
791 | /* Ignored for default WEP key */ | ||
792 | u8 addr[ETH_ALEN]; | ||
793 | |||
794 | /* key_action_e */ | ||
795 | u16 key_action; | ||
796 | |||
797 | u16 reserved_1; | ||
798 | |||
799 | /* key size in bytes */ | ||
800 | u8 key_size; | ||
801 | |||
802 | /* key_type_e */ | ||
803 | u8 key_type; | ||
804 | u8 ssid_profile; | ||
805 | |||
806 | /* | ||
807 | * TKIP, AES: frame's key id field. | ||
808 | * For WEP default key: key id; | ||
809 | */ | ||
810 | u8 id; | ||
811 | u8 reserved_2[6]; | ||
812 | u8 key[MAX_KEY_SIZE]; | ||
813 | u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; | ||
814 | u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; | ||
815 | } __attribute__ ((packed)); | ||
816 | |||
817 | struct acx_current_tx_power { | ||
818 | struct acx_header header; | ||
819 | |||
820 | u8 current_tx_power; | ||
821 | u8 padding[3]; | ||
822 | } __attribute__ ((packed)); | ||
823 | |||
824 | struct acx_dot11_default_key { | ||
825 | struct acx_header header; | ||
826 | |||
827 | u8 id; | ||
828 | u8 pad[3]; | ||
829 | } __attribute__ ((packed)); | ||
830 | |||
831 | struct acx_tsf_info { | ||
832 | struct acx_header header; | ||
833 | |||
834 | u32 current_tsf_msb; | ||
835 | u32 current_tsf_lsb; | ||
836 | u32 last_TBTT_msb; | ||
837 | u32 last_TBTT_lsb; | ||
838 | u8 last_dtim_count; | ||
839 | u8 pad[3]; | ||
840 | } __attribute__ ((packed)); | ||
841 | |||
842 | /* 802.11 PS */ | ||
843 | enum acx_ps_mode { | ||
844 | STATION_ACTIVE_MODE, | ||
845 | STATION_POWER_SAVE_MODE | ||
846 | }; | ||
847 | |||
848 | struct acx_ps_params { | ||
849 | u8 ps_mode; /* STATION_* */ | ||
850 | u8 send_null_data; /* Do we have to send NULL data packet ? */ | ||
851 | u8 retries; /* Number of retires for the initial NULL data packet */ | ||
852 | |||
853 | /* | ||
854 | * TUs during which the target stays awake after switching | ||
855 | * to power save mode. | ||
856 | */ | ||
857 | u8 hang_over_period; | ||
858 | u16 null_data_rate; | ||
859 | u8 pad[2]; | ||
860 | } __attribute__ ((packed)); | ||
861 | |||
862 | enum acx_wake_up_event { | ||
863 | WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ | ||
864 | WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ | ||
865 | WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ | ||
866 | WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ | ||
867 | WAKE_UP_EVENT_BITS_MASK = 0x0F | ||
868 | }; | ||
869 | |||
870 | struct acx_wake_up_condition { | ||
871 | struct acx_header header; | ||
872 | |||
873 | u8 wake_up_event; /* Only one bit can be set */ | ||
874 | u8 listen_interval; | ||
875 | u8 pad[2]; | ||
876 | } __attribute__ ((packed)); | ||
877 | |||
878 | struct acx_aid { | ||
879 | struct acx_header header; | ||
880 | |||
881 | /* | ||
882 | * To be set when associated with an AP. | ||
883 | */ | ||
884 | u16 aid; | ||
885 | u8 pad[2]; | ||
886 | } __attribute__ ((packed)); | ||
887 | |||
888 | enum acx_preamble_type { | ||
889 | ACX_PREAMBLE_LONG = 0, | ||
890 | ACX_PREAMBLE_SHORT = 1 | ||
891 | }; | ||
892 | |||
893 | struct acx_preamble { | ||
894 | struct acx_header header; | ||
895 | /* | ||
896 | * When set, the WiLink transmits the frames with a short preamble and | ||
897 | * when cleared, the WiLink transmits the frames with a long preamble. | ||
898 | */ | ||
899 | u8 preamble; | ||
900 | u8 padding[3]; | ||
901 | } __attribute__ ((packed)); | ||
902 | |||
903 | enum acx_ctsprotect_type { | ||
904 | CTSPROTECT_DISABLE = 0, | ||
905 | CTSPROTECT_ENABLE = 1 | ||
906 | }; | ||
907 | |||
908 | struct acx_ctsprotect { | ||
909 | struct acx_header header; | ||
910 | u8 ctsprotect; | ||
911 | u8 padding[3]; | ||
912 | } __attribute__ ((packed)); | ||
913 | |||
914 | struct acx_tx_statistics { | ||
915 | u32 internal_desc_overflow; | ||
916 | } __attribute__ ((packed)); | ||
917 | |||
918 | struct acx_rx_statistics { | ||
919 | u32 out_of_mem; | ||
920 | u32 hdr_overflow; | ||
921 | u32 hw_stuck; | ||
922 | u32 dropped; | ||
923 | u32 fcs_err; | ||
924 | u32 xfr_hint_trig; | ||
925 | u32 path_reset; | ||
926 | u32 reset_counter; | ||
927 | } __attribute__ ((packed)); | ||
928 | |||
929 | struct acx_dma_statistics { | ||
930 | u32 rx_requested; | ||
931 | u32 rx_errors; | ||
932 | u32 tx_requested; | ||
933 | u32 tx_errors; | ||
934 | } __attribute__ ((packed)); | ||
935 | |||
936 | struct acx_isr_statistics { | ||
937 | /* host command complete */ | ||
938 | u32 cmd_cmplt; | ||
939 | |||
940 | /* fiqisr() */ | ||
941 | u32 fiqs; | ||
942 | |||
943 | /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ | ||
944 | u32 rx_headers; | ||
945 | |||
946 | /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ | ||
947 | u32 rx_completes; | ||
948 | |||
949 | /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ | ||
950 | u32 rx_mem_overflow; | ||
951 | |||
952 | /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ | ||
953 | u32 rx_rdys; | ||
954 | |||
955 | /* irqisr() */ | ||
956 | u32 irqs; | ||
957 | |||
958 | /* (INT_STS_ND & INT_TRIG_TX_PROC) */ | ||
959 | u32 tx_procs; | ||
960 | |||
961 | /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ | ||
962 | u32 decrypt_done; | ||
963 | |||
964 | /* (INT_STS_ND & INT_TRIG_DMA0) */ | ||
965 | u32 dma0_done; | ||
966 | |||
967 | /* (INT_STS_ND & INT_TRIG_DMA1) */ | ||
968 | u32 dma1_done; | ||
969 | |||
970 | /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ | ||
971 | u32 tx_exch_complete; | ||
972 | |||
973 | /* (INT_STS_ND & INT_TRIG_COMMAND) */ | ||
974 | u32 commands; | ||
975 | |||
976 | /* (INT_STS_ND & INT_TRIG_RX_PROC) */ | ||
977 | u32 rx_procs; | ||
978 | |||
979 | /* (INT_STS_ND & INT_TRIG_PM_802) */ | ||
980 | u32 hw_pm_mode_changes; | ||
981 | |||
982 | /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ | ||
983 | u32 host_acknowledges; | ||
984 | |||
985 | /* (INT_STS_ND & INT_TRIG_PM_PCI) */ | ||
986 | u32 pci_pm; | ||
987 | |||
988 | /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ | ||
989 | u32 wakeups; | ||
990 | |||
991 | /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ | ||
992 | u32 low_rssi; | ||
993 | } __attribute__ ((packed)); | ||
994 | |||
995 | struct acx_wep_statistics { | ||
996 | /* WEP address keys configured */ | ||
997 | u32 addr_key_count; | ||
998 | |||
999 | /* default keys configured */ | ||
1000 | u32 default_key_count; | ||
1001 | |||
1002 | u32 reserved; | ||
1003 | |||
1004 | /* number of times that WEP key not found on lookup */ | ||
1005 | u32 key_not_found; | ||
1006 | |||
1007 | /* number of times that WEP key decryption failed */ | ||
1008 | u32 decrypt_fail; | ||
1009 | |||
1010 | /* WEP packets decrypted */ | ||
1011 | u32 packets; | ||
1012 | |||
1013 | /* WEP decrypt interrupts */ | ||
1014 | u32 interrupt; | ||
1015 | } __attribute__ ((packed)); | ||
1016 | |||
1017 | #define ACX_MISSED_BEACONS_SPREAD 10 | ||
1018 | |||
1019 | struct acx_pwr_statistics { | ||
1020 | /* the amount of enters into power save mode (both PD & ELP) */ | ||
1021 | u32 ps_enter; | ||
1022 | |||
1023 | /* the amount of enters into ELP mode */ | ||
1024 | u32 elp_enter; | ||
1025 | |||
1026 | /* the amount of missing beacon interrupts to the host */ | ||
1027 | u32 missing_bcns; | ||
1028 | |||
1029 | /* the amount of wake on host-access times */ | ||
1030 | u32 wake_on_host; | ||
1031 | |||
1032 | /* the amount of wake on timer-expire */ | ||
1033 | u32 wake_on_timer_exp; | ||
1034 | |||
1035 | /* the number of packets that were transmitted with PS bit set */ | ||
1036 | u32 tx_with_ps; | ||
1037 | |||
1038 | /* the number of packets that were transmitted with PS bit clear */ | ||
1039 | u32 tx_without_ps; | ||
1040 | |||
1041 | /* the number of received beacons */ | ||
1042 | u32 rcvd_beacons; | ||
1043 | |||
1044 | /* the number of entering into PowerOn (power save off) */ | ||
1045 | u32 power_save_off; | ||
1046 | |||
1047 | /* the number of entries into power save mode */ | ||
1048 | u16 enable_ps; | ||
1049 | |||
1050 | /* | ||
1051 | * the number of exits from power save, not including failed PS | ||
1052 | * transitions | ||
1053 | */ | ||
1054 | u16 disable_ps; | ||
1055 | |||
1056 | /* | ||
1057 | * the number of times the TSF counter was adjusted because | ||
1058 | * of drift | ||
1059 | */ | ||
1060 | u32 fix_tsf_ps; | ||
1061 | |||
1062 | /* Gives statistics about the spread continuous missed beacons. | ||
1063 | * The 16 LSB are dedicated for the PS mode. | ||
1064 | * The 16 MSB are dedicated for the PS mode. | ||
1065 | * cont_miss_bcns_spread[0] - single missed beacon. | ||
1066 | * cont_miss_bcns_spread[1] - two continuous missed beacons. | ||
1067 | * cont_miss_bcns_spread[2] - three continuous missed beacons. | ||
1068 | * ... | ||
1069 | * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. | ||
1070 | */ | ||
1071 | u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; | ||
1072 | |||
1073 | /* the number of beacons in awake mode */ | ||
1074 | u32 rcvd_awake_beacons; | ||
1075 | } __attribute__ ((packed)); | ||
1076 | |||
1077 | struct acx_mic_statistics { | ||
1078 | u32 rx_pkts; | ||
1079 | u32 calc_failure; | ||
1080 | } __attribute__ ((packed)); | ||
1081 | |||
1082 | struct acx_aes_statistics { | ||
1083 | u32 encrypt_fail; | ||
1084 | u32 decrypt_fail; | ||
1085 | u32 encrypt_packets; | ||
1086 | u32 decrypt_packets; | ||
1087 | u32 encrypt_interrupt; | ||
1088 | u32 decrypt_interrupt; | ||
1089 | } __attribute__ ((packed)); | ||
1090 | |||
1091 | struct acx_event_statistics { | ||
1092 | u32 heart_beat; | ||
1093 | u32 calibration; | ||
1094 | u32 rx_mismatch; | ||
1095 | u32 rx_mem_empty; | ||
1096 | u32 rx_pool; | ||
1097 | u32 oom_late; | ||
1098 | u32 phy_transmit_error; | ||
1099 | u32 tx_stuck; | ||
1100 | } __attribute__ ((packed)); | ||
1101 | |||
1102 | struct acx_ps_statistics { | ||
1103 | u32 pspoll_timeouts; | ||
1104 | u32 upsd_timeouts; | ||
1105 | u32 upsd_max_sptime; | ||
1106 | u32 upsd_max_apturn; | ||
1107 | u32 pspoll_max_apturn; | ||
1108 | u32 pspoll_utilization; | ||
1109 | u32 upsd_utilization; | ||
1110 | } __attribute__ ((packed)); | ||
1111 | |||
1112 | struct acx_rxpipe_statistics { | ||
1113 | u32 rx_prep_beacon_drop; | ||
1114 | u32 descr_host_int_trig_rx_data; | ||
1115 | u32 beacon_buffer_thres_host_int_trig_rx_data; | ||
1116 | u32 missed_beacon_host_int_trig_rx_data; | ||
1117 | u32 tx_xfr_host_int_trig_rx_data; | ||
1118 | } __attribute__ ((packed)); | ||
1119 | |||
1120 | struct acx_statistics { | ||
1121 | struct acx_header header; | ||
1122 | |||
1123 | struct acx_tx_statistics tx; | ||
1124 | struct acx_rx_statistics rx; | ||
1125 | struct acx_dma_statistics dma; | ||
1126 | struct acx_isr_statistics isr; | ||
1127 | struct acx_wep_statistics wep; | ||
1128 | struct acx_pwr_statistics pwr; | ||
1129 | struct acx_aes_statistics aes; | ||
1130 | struct acx_mic_statistics mic; | ||
1131 | struct acx_event_statistics event; | ||
1132 | struct acx_ps_statistics ps; | ||
1133 | struct acx_rxpipe_statistics rxpipe; | ||
1134 | } __attribute__ ((packed)); | ||
1135 | |||
1136 | enum { | ||
1137 | ACX_WAKE_UP_CONDITIONS = 0x0002, | ||
1138 | ACX_MEM_CFG = 0x0003, | ||
1139 | ACX_SLOT = 0x0004, | ||
1140 | ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ | ||
1141 | ACX_AC_CFG = 0x0007, | ||
1142 | ACX_MEM_MAP = 0x0008, | ||
1143 | ACX_AID = 0x000A, | ||
1144 | ACX_RADIO_PARAM = 0x000B, /* Not used */ | ||
1145 | ACX_CFG = 0x000C, /* Not used */ | ||
1146 | ACX_FW_REV = 0x000D, | ||
1147 | ACX_MEDIUM_USAGE = 0x000F, | ||
1148 | ACX_RX_CFG = 0x0010, | ||
1149 | ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ | ||
1150 | ACX_BSS_IN_PS = 0x0012, /* for AP only */ | ||
1151 | ACX_STATISTICS = 0x0013, /* Debug API */ | ||
1152 | ACX_FEATURE_CFG = 0x0015, | ||
1153 | ACX_MISC_CFG = 0x0017, /* Not used */ | ||
1154 | ACX_TID_CFG = 0x001A, | ||
1155 | ACX_BEACON_FILTER_OPT = 0x001F, | ||
1156 | ACX_LOW_RSSI = 0x0020, | ||
1157 | ACX_NOISE_HIST = 0x0021, | ||
1158 | ACX_HDK_VERSION = 0x0022, /* ??? */ | ||
1159 | ACX_PD_THRESHOLD = 0x0023, | ||
1160 | ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ | ||
1161 | ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ | ||
1162 | ACX_CCA_THRESHOLD = 0x0025, | ||
1163 | ACX_EVENT_MBOX_MASK = 0x0026, | ||
1164 | #ifdef FW_RUNNING_AS_AP | ||
1165 | ACX_DTIM_PERIOD = 0x0027, /* for AP only */ | ||
1166 | #else | ||
1167 | ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ | ||
1168 | #endif | ||
1169 | ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ | ||
1170 | ACX_GPIO_CFG = 0x002A, /* Not used */ | ||
1171 | ACX_GPIO_SET = 0x002B, /* Not used */ | ||
1172 | ACX_PM_CFG = 0x002C, /* To Be Documented */ | ||
1173 | ACX_CONN_MONIT_PARAMS = 0x002D, | ||
1174 | ACX_AVERAGE_RSSI = 0x002E, /* Not used */ | ||
1175 | ACX_CONS_TX_FAILURE = 0x002F, | ||
1176 | ACX_BCN_DTIM_OPTIONS = 0x0031, | ||
1177 | ACX_SG_ENABLE = 0x0032, | ||
1178 | ACX_SG_CFG = 0x0033, | ||
1179 | ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ | ||
1180 | ACX_LOW_SNR = 0x0037, /* To Be Documented */ | ||
1181 | ACX_BEACON_FILTER_TABLE = 0x0038, | ||
1182 | ACX_ARP_IP_FILTER = 0x0039, | ||
1183 | ACX_ROAMING_STATISTICS_TBL = 0x003B, | ||
1184 | ACX_RATE_POLICY = 0x003D, | ||
1185 | ACX_CTS_PROTECTION = 0x003E, | ||
1186 | ACX_SLEEP_AUTH = 0x003F, | ||
1187 | ACX_PREAMBLE_TYPE = 0x0040, | ||
1188 | ACX_ERROR_CNT = 0x0041, | ||
1189 | ACX_FW_GEN_FRAME_RATES = 0x0042, | ||
1190 | ACX_IBSS_FILTER = 0x0044, | ||
1191 | ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, | ||
1192 | ACX_TSF_INFO = 0x0046, | ||
1193 | ACX_CONFIG_PS_WMM = 0x0049, | ||
1194 | ACX_ENABLE_RX_DATA_FILTER = 0x004A, | ||
1195 | ACX_SET_RX_DATA_FILTER = 0x004B, | ||
1196 | ACX_GET_DATA_FILTER_STATISTICS = 0x004C, | ||
1197 | ACX_POWER_LEVEL_TABLE = 0x004D, | ||
1198 | ACX_BET_ENABLE = 0x0050, | ||
1199 | DOT11_STATION_ID = 0x1001, | ||
1200 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, | ||
1201 | DOT11_CUR_TX_PWR = 0x100D, | ||
1202 | DOT11_DEFAULT_KEY = 0x1010, | ||
1203 | DOT11_RX_DOT11_MODE = 0x1012, | ||
1204 | DOT11_RTS_THRESHOLD = 0x1013, | ||
1205 | DOT11_GROUP_ADDRESS_TBL = 0x1014, | ||
1206 | |||
1207 | MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, | ||
1208 | |||
1209 | MAX_IE = 0xFFFF | ||
1210 | }; | ||
1211 | |||
1212 | |||
1213 | int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, | ||
1214 | u8 mgt_rate, u8 mgt_mod); | ||
1215 | int wl12xx_acx_station_id(struct wl12xx *wl); | ||
1216 | int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); | ||
1217 | int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval); | ||
1218 | int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); | ||
1219 | int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); | ||
1220 | int wl12xx_acx_tx_power(struct wl12xx *wl, int power); | ||
1221 | int wl12xx_acx_feature_cfg(struct wl12xx *wl); | ||
1222 | int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len); | ||
1223 | int wl12xx_acx_data_path_params(struct wl12xx *wl, | ||
1224 | struct acx_data_path_params_resp *data_path); | ||
1225 | int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); | ||
1226 | int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); | ||
1227 | int wl12xx_acx_pd_threshold(struct wl12xx *wl); | ||
1228 | int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); | ||
1229 | int wl12xx_acx_group_address_tbl(struct wl12xx *wl); | ||
1230 | int wl12xx_acx_service_period_timeout(struct wl12xx *wl); | ||
1231 | int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); | ||
1232 | int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); | ||
1233 | int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); | ||
1234 | int wl12xx_acx_sg_enable(struct wl12xx *wl); | ||
1235 | int wl12xx_acx_sg_cfg(struct wl12xx *wl); | ||
1236 | int wl12xx_acx_cca_threshold(struct wl12xx *wl); | ||
1237 | int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); | ||
1238 | int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); | ||
1239 | int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); | ||
1240 | int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); | ||
1241 | int wl12xx_acx_cts_protect(struct wl12xx *wl, | ||
1242 | enum acx_ctsprotect_type ctsprotect); | ||
1243 | int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); | ||
1244 | |||
1245 | #endif /* __WL12XX_ACX_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c new file mode 100644 index 000000000000..48ac08c429bd --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/gpio.h> | ||
25 | |||
26 | #include "reg.h" | ||
27 | #include "boot.h" | ||
28 | #include "spi.h" | ||
29 | #include "event.h" | ||
30 | |||
31 | static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) | ||
32 | { | ||
33 | enable_irq(wl->irq); | ||
34 | } | ||
35 | |||
36 | void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) | ||
37 | { | ||
38 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
39 | wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); | ||
40 | } | ||
41 | |||
42 | int wl12xx_boot_soft_reset(struct wl12xx *wl) | ||
43 | { | ||
44 | unsigned long timeout; | ||
45 | u32 boot_data; | ||
46 | |||
47 | /* perform soft reset */ | ||
48 | wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); | ||
49 | |||
50 | /* SOFT_RESET is self clearing */ | ||
51 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | ||
52 | while (1) { | ||
53 | boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); | ||
54 | wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | ||
55 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) | ||
56 | break; | ||
57 | |||
58 | if (time_after(jiffies, timeout)) { | ||
59 | /* 1.2 check pWhalBus->uSelfClearTime if the | ||
60 | * timeout was reached */ | ||
61 | wl12xx_error("soft reset timeout"); | ||
62 | return -1; | ||
63 | } | ||
64 | |||
65 | udelay(SOFT_RESET_STALL_TIME); | ||
66 | } | ||
67 | |||
68 | /* disable Rx/Tx */ | ||
69 | wl12xx_reg_write32(wl, ENABLE, 0x0); | ||
70 | |||
71 | /* disable auto calibration on start*/ | ||
72 | wl12xx_reg_write32(wl, SPARE_A2, 0xffff); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | int wl12xx_boot_init_seq(struct wl12xx *wl) | ||
78 | { | ||
79 | u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; | ||
80 | |||
81 | /* | ||
82 | * col #1: INTEGER_DIVIDER | ||
83 | * col #2: FRACTIONAL_DIVIDER | ||
84 | * col #3: ATTN_BB | ||
85 | * col #4: ALPHA_BB | ||
86 | * col #5: STOP_TIME_BB | ||
87 | * col #6: BB_PLL_LOOP_FILTER | ||
88 | */ | ||
89 | static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { | ||
90 | |||
91 | { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ | ||
92 | { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ | ||
93 | { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ | ||
94 | { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ | ||
95 | { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ | ||
96 | }; | ||
97 | |||
98 | /* read NVS params */ | ||
99 | scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); | ||
100 | wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); | ||
101 | |||
102 | /* read ELP_CMD */ | ||
103 | elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); | ||
104 | wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); | ||
105 | |||
106 | /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ | ||
107 | ref_freq = scr_pad6 & 0x000000FF; | ||
108 | wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); | ||
109 | |||
110 | wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); | ||
111 | |||
112 | /* | ||
113 | * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) | ||
114 | */ | ||
115 | wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); | ||
116 | |||
117 | /* | ||
118 | * set the clock detect feature to work in the restart wu procedure | ||
119 | * (ELP_CFG_MODE[14]) and Select the clock source type | ||
120 | * (ELP_CFG_MODE[13:12]) | ||
121 | */ | ||
122 | tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; | ||
123 | wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); | ||
124 | |||
125 | /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ | ||
126 | elp_cmd |= 0x00000040; | ||
127 | wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); | ||
128 | |||
129 | /* PG 1.2: Set the BB PLL stable time to be 1000usec | ||
130 | * (PLL_STABLE_TIME) */ | ||
131 | wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); | ||
132 | |||
133 | /* PG 1.2: read clock request time */ | ||
134 | init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); | ||
135 | |||
136 | /* | ||
137 | * PG 1.2: set the clock request time to be ref_clk_settling_time - | ||
138 | * 1ms = 4ms | ||
139 | */ | ||
140 | if (init_data > 0x21) | ||
141 | tmp = init_data - 0x21; | ||
142 | else | ||
143 | tmp = 0; | ||
144 | wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); | ||
145 | |||
146 | /* set BB PLL configurations in RF AFE */ | ||
147 | wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); | ||
148 | |||
149 | /* set RF_AFE_REG_5 */ | ||
150 | wl12xx_reg_write32(wl, 0x003058d4, 0x50); | ||
151 | |||
152 | /* set RF_AFE_CTRL_REG_2 */ | ||
153 | wl12xx_reg_write32(wl, 0x00305948, 0x11c001); | ||
154 | |||
155 | /* | ||
156 | * change RF PLL and BB PLL divider for VCO clock and adjust VCO | ||
157 | * bais current(RF_AFE_REG_13) | ||
158 | */ | ||
159 | wl12xx_reg_write32(wl, 0x003058f4, 0x1e); | ||
160 | |||
161 | /* set BB PLL configurations */ | ||
162 | tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; | ||
163 | wl12xx_reg_write32(wl, 0x00305840, tmp); | ||
164 | |||
165 | /* set fractional divider according to Appendix C-BB PLL | ||
166 | * Calculations | ||
167 | */ | ||
168 | tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; | ||
169 | wl12xx_reg_write32(wl, 0x00305844, tmp); | ||
170 | |||
171 | /* set the initial data for the sigma delta */ | ||
172 | wl12xx_reg_write32(wl, 0x00305848, 0x3039); | ||
173 | |||
174 | /* | ||
175 | * set the accumulator attenuation value, calibration loop1 | ||
176 | * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and | ||
177 | * the VCO gain | ||
178 | */ | ||
179 | tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | | ||
180 | (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; | ||
181 | wl12xx_reg_write32(wl, 0x00305854, tmp); | ||
182 | |||
183 | /* | ||
184 | * set the calibration stop time after holdoff time expires and set | ||
185 | * settling time HOLD_OFF_TIME_BB | ||
186 | */ | ||
187 | tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; | ||
188 | wl12xx_reg_write32(wl, 0x00305858, tmp); | ||
189 | |||
190 | /* | ||
191 | * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL | ||
192 | * constant leakage current to linearize PFD to 0uA - | ||
193 | * BB_ILOOPF[7:3] | ||
194 | */ | ||
195 | tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; | ||
196 | wl12xx_reg_write32(wl, 0x003058f8, tmp); | ||
197 | |||
198 | /* | ||
199 | * set regulator output voltage for n divider to | ||
200 | * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], | ||
201 | * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB | ||
202 | * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] | ||
203 | */ | ||
204 | wl12xx_reg_write32(wl, 0x003058f0, 0x29); | ||
205 | |||
206 | /* enable restart wakeup sequence (ELP_CMD[0]) */ | ||
207 | wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); | ||
208 | |||
209 | /* restart sequence completed */ | ||
210 | udelay(2000); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | int wl12xx_boot_run_firmware(struct wl12xx *wl) | ||
216 | { | ||
217 | int loop, ret; | ||
218 | u32 chip_id, interrupt; | ||
219 | |||
220 | wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | ||
221 | |||
222 | chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); | ||
223 | |||
224 | wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | ||
225 | |||
226 | if (chip_id != wl->chip.id) { | ||
227 | wl12xx_error("chip id doesn't match after firmware boot"); | ||
228 | return -EIO; | ||
229 | } | ||
230 | |||
231 | /* wait for init to complete */ | ||
232 | loop = 0; | ||
233 | while (loop++ < INIT_LOOP) { | ||
234 | udelay(INIT_LOOP_DELAY); | ||
235 | interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
236 | |||
237 | if (interrupt == 0xffffffff) { | ||
238 | wl12xx_error("error reading hardware complete " | ||
239 | "init indication"); | ||
240 | return -EIO; | ||
241 | } | ||
242 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | ||
243 | else if (interrupt & wl->chip.intr_init_complete) { | ||
244 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
245 | wl->chip.intr_init_complete); | ||
246 | break; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if (loop >= INIT_LOOP) { | ||
251 | wl12xx_error("timeout waiting for the hardware to " | ||
252 | "complete initialization"); | ||
253 | return -EIO; | ||
254 | } | ||
255 | |||
256 | /* get hardware config command mail box */ | ||
257 | wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); | ||
258 | |||
259 | /* get hardware config event mail box */ | ||
260 | wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
261 | |||
262 | /* set the working partition to its "running" mode offset */ | ||
263 | wl12xx_set_partition(wl, | ||
264 | wl->chip.p_table[PART_WORK].mem.start, | ||
265 | wl->chip.p_table[PART_WORK].mem.size, | ||
266 | wl->chip.p_table[PART_WORK].reg.start, | ||
267 | wl->chip.p_table[PART_WORK].reg.size); | ||
268 | |||
269 | wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | ||
270 | wl->cmd_box_addr, wl->event_box_addr); | ||
271 | |||
272 | /* | ||
273 | * in case of full asynchronous mode the firmware event must be | ||
274 | * ready to receive event from the command mailbox | ||
275 | */ | ||
276 | |||
277 | /* enable gpio interrupts */ | ||
278 | wl12xx_boot_enable_interrupts(wl); | ||
279 | |||
280 | wl->chip.op_target_enable_interrupts(wl); | ||
281 | |||
282 | /* unmask all mbox events */ | ||
283 | wl->event_mask = 0xffffffff; | ||
284 | |||
285 | ret = wl12xx_event_unmask(wl); | ||
286 | if (ret < 0) { | ||
287 | wl12xx_error("EVENT mask setting failed"); | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | wl12xx_event_mbox_config(wl); | ||
292 | |||
293 | /* firmware startup completed */ | ||
294 | return 0; | ||
295 | } | ||
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h new file mode 100644 index 000000000000..4fa73132baae --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __BOOT_H__ | ||
25 | #define __BOOT_H__ | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | |||
29 | int wl12xx_boot_soft_reset(struct wl12xx *wl); | ||
30 | int wl12xx_boot_init_seq(struct wl12xx *wl); | ||
31 | int wl12xx_boot_run_firmware(struct wl12xx *wl); | ||
32 | void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); | ||
33 | |||
34 | /* number of times we try to read the INIT interrupt */ | ||
35 | #define INIT_LOOP 20000 | ||
36 | |||
37 | /* delay between retries */ | ||
38 | #define INIT_LOOP_DELAY 50 | ||
39 | |||
40 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c new file mode 100644 index 000000000000..f73ab602b7ae --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.c | |||
@@ -0,0 +1,353 @@ | |||
1 | #include "cmd.h" | ||
2 | |||
3 | #include <linux/module.h> | ||
4 | #include <linux/crc7.h> | ||
5 | #include <linux/spi/spi.h> | ||
6 | |||
7 | #include "wl12xx.h" | ||
8 | #include "wl12xx_80211.h" | ||
9 | #include "reg.h" | ||
10 | #include "spi.h" | ||
11 | #include "ps.h" | ||
12 | |||
13 | int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len) | ||
14 | { | ||
15 | struct wl12xx_command cmd; | ||
16 | unsigned long timeout; | ||
17 | size_t cmd_len; | ||
18 | u32 intr; | ||
19 | int ret = 0; | ||
20 | |||
21 | memset(&cmd, 0, sizeof(cmd)); | ||
22 | cmd.id = type; | ||
23 | cmd.status = 0; | ||
24 | memcpy(cmd.parameters, buf, buf_len); | ||
25 | cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN; | ||
26 | |||
27 | wl12xx_ps_elp_wakeup(wl); | ||
28 | |||
29 | wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len); | ||
30 | |||
31 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | ||
32 | |||
33 | timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); | ||
34 | |||
35 | intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
36 | while (!(intr & wl->chip.intr_cmd_complete)) { | ||
37 | if (time_after(jiffies, timeout)) { | ||
38 | wl12xx_error("command complete timeout"); | ||
39 | ret = -ETIMEDOUT; | ||
40 | goto out; | ||
41 | } | ||
42 | |||
43 | msleep(1); | ||
44 | |||
45 | intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
46 | } | ||
47 | |||
48 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
49 | wl->chip.intr_cmd_complete); | ||
50 | |||
51 | out: | ||
52 | wl12xx_ps_elp_sleep(wl); | ||
53 | |||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) | ||
58 | { | ||
59 | int ret; | ||
60 | |||
61 | wl12xx_debug(DEBUG_CMD, "cmd test"); | ||
62 | |||
63 | ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); | ||
64 | if (ret < 0) { | ||
65 | wl12xx_warning("TEST command failed"); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | if (answer) { | ||
70 | struct wl12xx_command *cmd_answer; | ||
71 | |||
72 | /* | ||
73 | * The test command got in, we can read the answer. | ||
74 | * The answer would be a wl12xx_command, where the | ||
75 | * parameter array contains the actual answer. | ||
76 | */ | ||
77 | |||
78 | wl12xx_ps_elp_wakeup(wl); | ||
79 | |||
80 | wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | ||
81 | |||
82 | wl12xx_ps_elp_sleep(wl); | ||
83 | |||
84 | cmd_answer = buf; | ||
85 | if (cmd_answer->status != CMD_STATUS_SUCCESS) | ||
86 | wl12xx_error("TEST command answer error: %d", | ||
87 | cmd_answer->status); | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | |||
94 | int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, | ||
95 | void *answer) | ||
96 | { | ||
97 | struct wl12xx_command *cmd; | ||
98 | struct acx_header header; | ||
99 | int ret; | ||
100 | |||
101 | wl12xx_debug(DEBUG_CMD, "cmd interrogate"); | ||
102 | |||
103 | header.id = ie_id; | ||
104 | header.len = ie_len - sizeof(header); | ||
105 | |||
106 | ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header)); | ||
107 | if (ret < 0) { | ||
108 | wl12xx_error("INTERROGATE command failed"); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | wl12xx_ps_elp_wakeup(wl); | ||
113 | |||
114 | /* the interrogate command got in, we can read the answer */ | ||
115 | wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer, | ||
116 | CMDMBOX_HEADER_LEN + ie_len); | ||
117 | |||
118 | wl12xx_ps_elp_sleep(wl); | ||
119 | |||
120 | cmd = answer; | ||
121 | if (cmd->status != CMD_STATUS_SUCCESS) | ||
122 | wl12xx_error("INTERROGATE command error: %d", | ||
123 | cmd->status); | ||
124 | |||
125 | return 0; | ||
126 | |||
127 | } | ||
128 | |||
129 | int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len) | ||
130 | { | ||
131 | int ret; | ||
132 | |||
133 | wl12xx_debug(DEBUG_CMD, "cmd configure"); | ||
134 | |||
135 | ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie, | ||
136 | ie_len); | ||
137 | if (ret < 0) { | ||
138 | wl12xx_warning("CONFIGURE command NOK"); | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | return 0; | ||
143 | |||
144 | } | ||
145 | |||
146 | int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, | ||
147 | void *bitmap, u16 bitmap_len, u8 bitmap_control) | ||
148 | { | ||
149 | struct vbm_update_request vbm; | ||
150 | int ret; | ||
151 | |||
152 | wl12xx_debug(DEBUG_CMD, "cmd vbm"); | ||
153 | |||
154 | /* Count and period will be filled by the target */ | ||
155 | vbm.tim.bitmap_ctrl = bitmap_control; | ||
156 | if (bitmap_len > PARTIAL_VBM_MAX) { | ||
157 | wl12xx_warning("cmd vbm len is %d B, truncating to %d", | ||
158 | bitmap_len, PARTIAL_VBM_MAX); | ||
159 | bitmap_len = PARTIAL_VBM_MAX; | ||
160 | } | ||
161 | memcpy(vbm.tim.pvb_field, bitmap, bitmap_len); | ||
162 | vbm.tim.identity = identity; | ||
163 | vbm.tim.length = bitmap_len + 3; | ||
164 | |||
165 | vbm.len = cpu_to_le16(bitmap_len + 5); | ||
166 | |||
167 | ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm)); | ||
168 | if (ret < 0) { | ||
169 | wl12xx_error("VBM command failed"); | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) | ||
177 | { | ||
178 | int ret; | ||
179 | u16 cmd_rx, cmd_tx; | ||
180 | |||
181 | wl12xx_debug(DEBUG_CMD, "cmd data path"); | ||
182 | |||
183 | if (enable) { | ||
184 | cmd_rx = CMD_ENABLE_RX; | ||
185 | cmd_tx = CMD_ENABLE_TX; | ||
186 | } else { | ||
187 | cmd_rx = CMD_DISABLE_RX; | ||
188 | cmd_tx = CMD_DISABLE_TX; | ||
189 | } | ||
190 | |||
191 | ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel)); | ||
192 | if (ret < 0) { | ||
193 | wl12xx_error("rx %s cmd for channel %d failed", | ||
194 | enable ? "start" : "stop", channel); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", | ||
199 | enable ? "start" : "stop", channel); | ||
200 | |||
201 | ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel)); | ||
202 | if (ret < 0) { | ||
203 | wl12xx_error("tx %s cmd for channel %d failed", | ||
204 | enable ? "start" : "stop", channel); | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", | ||
209 | enable ? "start" : "stop", channel); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, | ||
215 | u16 beacon_interval, u8 wait) | ||
216 | { | ||
217 | unsigned long timeout; | ||
218 | struct cmd_join join = {}; | ||
219 | int ret, i; | ||
220 | u8 *bssid; | ||
221 | |||
222 | /* FIXME: this should be in main.c */ | ||
223 | ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, | ||
224 | DEFAULT_HW_GEN_MODULATION_TYPE, | ||
225 | wl->tx_mgmt_frm_rate, | ||
226 | wl->tx_mgmt_frm_mod); | ||
227 | if (ret < 0) | ||
228 | return ret; | ||
229 | |||
230 | wl12xx_debug(DEBUG_CMD, "cmd join"); | ||
231 | |||
232 | /* Reverse order BSSID */ | ||
233 | bssid = (u8 *)&join.bssid_lsb; | ||
234 | for (i = 0; i < ETH_ALEN; i++) | ||
235 | bssid[i] = wl->bssid[ETH_ALEN - i - 1]; | ||
236 | |||
237 | join.rx_config_options = wl->rx_config; | ||
238 | join.rx_filter_options = wl->rx_filter; | ||
239 | |||
240 | join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | ||
241 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | ||
242 | |||
243 | join.beacon_interval = beacon_interval; | ||
244 | join.dtim_interval = dtim_interval; | ||
245 | join.bss_type = bss_type; | ||
246 | join.channel = wl->channel; | ||
247 | join.ctrl = JOIN_CMD_CTRL_TX_FLUSH; | ||
248 | |||
249 | ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join)); | ||
250 | if (ret < 0) { | ||
251 | wl12xx_error("failed to initiate cmd join"); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | timeout = msecs_to_jiffies(JOIN_TIMEOUT); | ||
256 | |||
257 | /* | ||
258 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | ||
259 | * simplify locking we just sleep instead, for now | ||
260 | */ | ||
261 | if (wait) | ||
262 | msleep(10); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) | ||
268 | { | ||
269 | int ret; | ||
270 | struct acx_ps_params ps_params; | ||
271 | |||
272 | /* FIXME: this should be in ps.c */ | ||
273 | ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int); | ||
274 | if (ret < 0) { | ||
275 | wl12xx_error("Couldnt set wake up conditions"); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); | ||
280 | |||
281 | ps_params.ps_mode = ps_mode; | ||
282 | ps_params.send_null_data = 1; | ||
283 | ps_params.retries = 5; | ||
284 | ps_params.hang_over_period = 128; | ||
285 | ps_params.null_data_rate = 1; /* 1 Mbps */ | ||
286 | |||
287 | ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params, | ||
288 | sizeof(ps_params)); | ||
289 | if (ret < 0) { | ||
290 | wl12xx_error("cmd set_ps_mode failed"); | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer) | ||
298 | { | ||
299 | struct cmd_read_write_memory mem_cmd, *mem_answer; | ||
300 | struct wl12xx_command cmd; | ||
301 | int ret; | ||
302 | |||
303 | wl12xx_debug(DEBUG_CMD, "cmd read memory"); | ||
304 | |||
305 | memset(&mem_cmd, 0, sizeof(mem_cmd)); | ||
306 | mem_cmd.addr = addr; | ||
307 | mem_cmd.size = len; | ||
308 | |||
309 | ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd)); | ||
310 | if (ret < 0) { | ||
311 | wl12xx_error("read memory command failed: %d", ret); | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | /* the read command got in, we can now read the answer */ | ||
316 | wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd, | ||
317 | CMDMBOX_HEADER_LEN + sizeof(mem_cmd)); | ||
318 | |||
319 | if (cmd.status != CMD_STATUS_SUCCESS) | ||
320 | wl12xx_error("error in read command result: %d", cmd.status); | ||
321 | |||
322 | mem_answer = (struct cmd_read_write_memory *) cmd.parameters; | ||
323 | memcpy(answer, mem_answer->value, len); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, | ||
329 | void *buf, size_t buf_len) | ||
330 | { | ||
331 | struct wl12xx_cmd_packet_template template; | ||
332 | int ret; | ||
333 | |||
334 | wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); | ||
335 | |||
336 | memset(&template, 0, sizeof(template)); | ||
337 | |||
338 | WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); | ||
339 | buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); | ||
340 | template.size = cpu_to_le16(buf_len); | ||
341 | |||
342 | if (buf) | ||
343 | memcpy(template.template, buf, buf_len); | ||
344 | |||
345 | ret = wl12xx_cmd_send(wl, cmd_id, &template, | ||
346 | sizeof(template.size) + buf_len); | ||
347 | if (ret < 0) { | ||
348 | wl12xx_warning("cmd set_template failed: %d", ret); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | return 0; | ||
353 | } | ||
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h new file mode 100644 index 000000000000..aa307dcd081f --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.h | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_CMD_H__ | ||
26 | #define __WL12XX_CMD_H__ | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | |||
30 | int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); | ||
31 | int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); | ||
32 | int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, | ||
33 | void *answer); | ||
34 | int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len); | ||
35 | int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, | ||
36 | void *bitmap, u16 bitmap_len, u8 bitmap_control); | ||
37 | int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable); | ||
38 | int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, | ||
39 | u16 beacon_interval, u8 wait); | ||
40 | int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); | ||
41 | int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer); | ||
42 | int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, | ||
43 | void *buf, size_t buf_len); | ||
44 | |||
45 | /* unit ms */ | ||
46 | #define WL12XX_COMMAND_TIMEOUT 2000 | ||
47 | |||
48 | #define WL12XX_MAX_TEMPLATE_SIZE 300 | ||
49 | |||
50 | struct wl12xx_cmd_packet_template { | ||
51 | __le16 size; | ||
52 | u8 template[WL12XX_MAX_TEMPLATE_SIZE]; | ||
53 | } __attribute__ ((packed)); | ||
54 | |||
55 | enum wl12xx_commands { | ||
56 | CMD_RESET = 0, | ||
57 | CMD_INTERROGATE = 1, /*use this to read information elements*/ | ||
58 | CMD_CONFIGURE = 2, /*use this to write information elements*/ | ||
59 | CMD_ENABLE_RX = 3, | ||
60 | CMD_ENABLE_TX = 4, | ||
61 | CMD_DISABLE_RX = 5, | ||
62 | CMD_DISABLE_TX = 6, | ||
63 | CMD_SCAN = 8, | ||
64 | CMD_STOP_SCAN = 9, | ||
65 | CMD_VBM = 10, | ||
66 | CMD_START_JOIN = 11, | ||
67 | CMD_SET_KEYS = 12, | ||
68 | CMD_READ_MEMORY = 13, | ||
69 | CMD_WRITE_MEMORY = 14, | ||
70 | CMD_BEACON = 19, | ||
71 | CMD_PROBE_RESP = 20, | ||
72 | CMD_NULL_DATA = 21, | ||
73 | CMD_PROBE_REQ = 22, | ||
74 | CMD_TEST = 23, | ||
75 | CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ | ||
76 | CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ | ||
77 | CMD_NOISE_HIST = 28, | ||
78 | CMD_RX_RESET = 29, | ||
79 | CMD_PS_POLL = 30, | ||
80 | CMD_QOS_NULL_DATA = 31, | ||
81 | CMD_LNA_CONTROL = 32, | ||
82 | CMD_SET_BCN_MODE = 33, | ||
83 | CMD_MEASUREMENT = 34, | ||
84 | CMD_STOP_MEASUREMENT = 35, | ||
85 | CMD_DISCONNECT = 36, | ||
86 | CMD_SET_PS_MODE = 37, | ||
87 | CMD_CHANNEL_SWITCH = 38, | ||
88 | CMD_STOP_CHANNEL_SWICTH = 39, | ||
89 | CMD_AP_DISCOVERY = 40, | ||
90 | CMD_STOP_AP_DISCOVERY = 41, | ||
91 | CMD_SPS_SCAN = 42, | ||
92 | CMD_STOP_SPS_SCAN = 43, | ||
93 | CMD_HEALTH_CHECK = 45, | ||
94 | CMD_DEBUG = 46, | ||
95 | CMD_TRIGGER_SCAN_TO = 47, | ||
96 | |||
97 | NUM_COMMANDS, | ||
98 | MAX_COMMAND_ID = 0xFFFF, | ||
99 | }; | ||
100 | |||
101 | #define MAX_CMD_PARAMS 572 | ||
102 | |||
103 | struct wl12xx_command { | ||
104 | u16 id; | ||
105 | u16 status; | ||
106 | u8 parameters[MAX_CMD_PARAMS]; | ||
107 | }; | ||
108 | |||
109 | enum { | ||
110 | CMD_MAILBOX_IDLE = 0, | ||
111 | CMD_STATUS_SUCCESS = 1, | ||
112 | CMD_STATUS_UNKNOWN_CMD = 2, | ||
113 | CMD_STATUS_UNKNOWN_IE = 3, | ||
114 | CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, | ||
115 | CMD_STATUS_RX_BUSY = 13, | ||
116 | CMD_STATUS_INVALID_PARAM = 14, | ||
117 | CMD_STATUS_TEMPLATE_TOO_LARGE = 15, | ||
118 | CMD_STATUS_OUT_OF_MEMORY = 16, | ||
119 | CMD_STATUS_STA_TABLE_FULL = 17, | ||
120 | CMD_STATUS_RADIO_ERROR = 18, | ||
121 | CMD_STATUS_WRONG_NESTING = 19, | ||
122 | CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ | ||
123 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ | ||
124 | MAX_COMMAND_STATUS = 0xff | ||
125 | }; | ||
126 | |||
127 | |||
128 | /* | ||
129 | * CMD_READ_MEMORY | ||
130 | * | ||
131 | * The host issues this command to read the WiLink device memory/registers. | ||
132 | * | ||
133 | * Note: The Base Band address has special handling (16 bits registers and | ||
134 | * addresses). For more information, see the hardware specification. | ||
135 | */ | ||
136 | /* | ||
137 | * CMD_WRITE_MEMORY | ||
138 | * | ||
139 | * The host issues this command to write the WiLink device memory/registers. | ||
140 | * | ||
141 | * The Base Band address has special handling (16 bits registers and | ||
142 | * addresses). For more information, see the hardware specification. | ||
143 | */ | ||
144 | #define MAX_READ_SIZE 256 | ||
145 | |||
146 | struct cmd_read_write_memory { | ||
147 | /* The address of the memory to read from or write to.*/ | ||
148 | u32 addr; | ||
149 | |||
150 | /* The amount of data in bytes to read from or write to the WiLink | ||
151 | * device.*/ | ||
152 | u32 size; | ||
153 | |||
154 | /* The actual value read from or written to the Wilink. The source | ||
155 | of this field is the Host in WRITE command or the Wilink in READ | ||
156 | command. */ | ||
157 | u8 value[MAX_READ_SIZE]; | ||
158 | }; | ||
159 | |||
160 | #define CMDMBOX_HEADER_LEN 4 | ||
161 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | ||
162 | |||
163 | |||
164 | struct basic_scan_parameters { | ||
165 | u32 rx_config_options; | ||
166 | u32 rx_filter_options; | ||
167 | |||
168 | /* | ||
169 | * Scan options: | ||
170 | * bit 0: When this bit is set, passive scan. | ||
171 | * bit 1: Band, when this bit is set we scan | ||
172 | * in the 5Ghz band. | ||
173 | * bit 2: voice mode, 0 for normal scan. | ||
174 | * bit 3: scan priority, 1 for high priority. | ||
175 | */ | ||
176 | u16 scan_options; | ||
177 | |||
178 | /* Number of channels to scan */ | ||
179 | u8 num_channels; | ||
180 | |||
181 | /* Number opf probe requests to send, per channel */ | ||
182 | u8 num_probe_requests; | ||
183 | |||
184 | /* Rate and modulation for probe requests */ | ||
185 | u16 tx_rate; | ||
186 | |||
187 | u8 tid_trigger; | ||
188 | u8 ssid_len; | ||
189 | u32 ssid[8]; | ||
190 | |||
191 | } __attribute__ ((packed)); | ||
192 | |||
193 | struct basic_scan_channel_parameters { | ||
194 | u32 min_duration; /* in TU */ | ||
195 | u32 max_duration; /* in TU */ | ||
196 | u32 bssid_lsb; | ||
197 | u16 bssid_msb; | ||
198 | |||
199 | /* | ||
200 | * bits 0-3: Early termination count. | ||
201 | * bits 4-5: Early termination condition. | ||
202 | */ | ||
203 | u8 early_termination; | ||
204 | |||
205 | u8 tx_power_att; | ||
206 | u8 channel; | ||
207 | u8 pad[3]; | ||
208 | } __attribute__ ((packed)); | ||
209 | |||
210 | /* SCAN parameters */ | ||
211 | #define SCAN_MAX_NUM_OF_CHANNELS 16 | ||
212 | |||
213 | struct cmd_scan { | ||
214 | struct basic_scan_parameters params; | ||
215 | struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; | ||
216 | } __attribute__ ((packed)); | ||
217 | |||
218 | enum { | ||
219 | BSS_TYPE_IBSS = 0, | ||
220 | BSS_TYPE_STA_BSS = 2, | ||
221 | BSS_TYPE_AP_BSS = 3, | ||
222 | MAX_BSS_TYPE = 0xFF | ||
223 | }; | ||
224 | |||
225 | #define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ | ||
226 | #define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ | ||
227 | |||
228 | |||
229 | struct cmd_join { | ||
230 | u32 bssid_lsb; | ||
231 | u16 bssid_msb; | ||
232 | u16 beacon_interval; /* in TBTTs */ | ||
233 | u32 rx_config_options; | ||
234 | u32 rx_filter_options; | ||
235 | |||
236 | /* | ||
237 | * The target uses this field to determine the rate at | ||
238 | * which to transmit control frame responses (such as | ||
239 | * ACK or CTS frames). | ||
240 | */ | ||
241 | u16 basic_rate_set; | ||
242 | u8 dtim_interval; | ||
243 | u8 tx_ctrl_frame_rate; /* OBSOLETE */ | ||
244 | u8 tx_ctrl_frame_mod; /* OBSOLETE */ | ||
245 | /* | ||
246 | * bits 0-2: This bitwise field specifies the type | ||
247 | * of BSS to start or join (BSS_TYPE_*). | ||
248 | * bit 4: Band - The radio band in which to join | ||
249 | * or start. | ||
250 | * 0 - 2.4GHz band | ||
251 | * 1 - 5GHz band | ||
252 | * bits 3, 5-7: Reserved | ||
253 | */ | ||
254 | u8 bss_type; | ||
255 | u8 channel; | ||
256 | u8 ssid_len; | ||
257 | u8 ssid[IW_ESSID_MAX_SIZE]; | ||
258 | u8 ctrl; /* JOIN_CMD_CTRL_* */ | ||
259 | u8 tx_mgt_frame_rate; /* OBSOLETE */ | ||
260 | u8 tx_mgt_frame_mod; /* OBSOLETE */ | ||
261 | u8 reserved; | ||
262 | } __attribute__ ((packed)); | ||
263 | |||
264 | |||
265 | #endif /* __WL12XX_CMD_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c new file mode 100644 index 000000000000..cdb368ce4dae --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.c | |||
@@ -0,0 +1,508 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "debugfs.h" | ||
25 | |||
26 | #include <linux/skbuff.h> | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "acx.h" | ||
30 | |||
31 | /* ms */ | ||
32 | #define WL12XX_DEBUGFS_STATS_LIFETIME 1000 | ||
33 | |||
34 | /* debugfs macros idea from mac80211 */ | ||
35 | |||
36 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
37 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
38 | size_t count, loff_t *ppos) \ | ||
39 | { \ | ||
40 | struct wl12xx *wl = file->private_data; \ | ||
41 | char buf[buflen]; \ | ||
42 | int res; \ | ||
43 | \ | ||
44 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
45 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
46 | } \ | ||
47 | \ | ||
48 | static const struct file_operations name## _ops = { \ | ||
49 | .read = name## _read, \ | ||
50 | .open = wl12xx_open_file_generic, \ | ||
51 | }; | ||
52 | |||
53 | #define DEBUGFS_ADD(name, parent) \ | ||
54 | wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ | ||
55 | wl, &name## _ops); \ | ||
56 | if (IS_ERR(wl->debugfs.name)) { \ | ||
57 | ret = PTR_ERR(wl->debugfs.name); \ | ||
58 | wl->debugfs.name = NULL; \ | ||
59 | goto out; \ | ||
60 | } | ||
61 | |||
62 | #define DEBUGFS_DEL(name) \ | ||
63 | do { \ | ||
64 | debugfs_remove(wl->debugfs.name); \ | ||
65 | wl->debugfs.name = NULL; \ | ||
66 | } while (0) | ||
67 | |||
68 | #define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ | ||
69 | static ssize_t sub## _ ##name## _read(struct file *file, \ | ||
70 | char __user *userbuf, \ | ||
71 | size_t count, loff_t *ppos) \ | ||
72 | { \ | ||
73 | struct wl12xx *wl = file->private_data; \ | ||
74 | char buf[buflen]; \ | ||
75 | int res; \ | ||
76 | \ | ||
77 | wl12xx_debugfs_update_stats(wl); \ | ||
78 | \ | ||
79 | res = scnprintf(buf, buflen, fmt "\n", \ | ||
80 | wl->stats.fw_stats->sub.name); \ | ||
81 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
82 | } \ | ||
83 | \ | ||
84 | static const struct file_operations sub## _ ##name## _ops = { \ | ||
85 | .read = sub## _ ##name## _read, \ | ||
86 | .open = wl12xx_open_file_generic, \ | ||
87 | }; | ||
88 | |||
89 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ | ||
90 | DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) | ||
91 | |||
92 | #define DEBUGFS_FWSTATS_DEL(sub, name) \ | ||
93 | DEBUGFS_DEL(sub## _ ##name) | ||
94 | |||
95 | static void wl12xx_debugfs_update_stats(struct wl12xx *wl) | ||
96 | { | ||
97 | mutex_lock(&wl->mutex); | ||
98 | |||
99 | if (wl->state == WL12XX_STATE_ON && | ||
100 | time_after(jiffies, wl->stats.fw_stats_update + | ||
101 | msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { | ||
102 | wl12xx_acx_statistics(wl, wl->stats.fw_stats); | ||
103 | wl->stats.fw_stats_update = jiffies; | ||
104 | } | ||
105 | |||
106 | mutex_unlock(&wl->mutex); | ||
107 | } | ||
108 | |||
109 | static int wl12xx_open_file_generic(struct inode *inode, struct file *file) | ||
110 | { | ||
111 | file->private_data = inode->i_private; | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); | ||
116 | |||
117 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); | ||
118 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); | ||
119 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); | ||
120 | DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); | ||
121 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); | ||
122 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); | ||
123 | DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); | ||
124 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); | ||
125 | |||
126 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); | ||
127 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); | ||
128 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); | ||
129 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); | ||
130 | |||
131 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); | ||
132 | DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); | ||
133 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); | ||
134 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); | ||
135 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); | ||
136 | DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); | ||
137 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); | ||
138 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); | ||
139 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); | ||
140 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); | ||
141 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); | ||
142 | DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); | ||
143 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); | ||
144 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); | ||
145 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); | ||
146 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); | ||
147 | DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); | ||
148 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); | ||
149 | |||
150 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); | ||
151 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); | ||
152 | /* skipping wep.reserved */ | ||
153 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); | ||
154 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); | ||
155 | DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); | ||
156 | DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); | ||
157 | |||
158 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); | ||
159 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); | ||
160 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); | ||
161 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); | ||
162 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); | ||
163 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); | ||
164 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); | ||
165 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); | ||
166 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); | ||
167 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); | ||
168 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); | ||
169 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); | ||
170 | /* skipping cont_miss_bcns_spread for now */ | ||
171 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); | ||
172 | |||
173 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); | ||
174 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); | ||
175 | |||
176 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); | ||
177 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); | ||
178 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); | ||
179 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); | ||
180 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); | ||
181 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); | ||
182 | |||
183 | DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); | ||
184 | DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); | ||
185 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); | ||
186 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); | ||
187 | DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); | ||
188 | DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); | ||
189 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); | ||
190 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); | ||
191 | |||
192 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); | ||
193 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); | ||
194 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); | ||
195 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); | ||
196 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); | ||
197 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); | ||
198 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); | ||
199 | |||
200 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); | ||
201 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); | ||
202 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, | ||
203 | 20, "%u"); | ||
204 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); | ||
205 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); | ||
206 | |||
207 | DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); | ||
208 | DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", | ||
209 | wl->stats.excessive_retries); | ||
210 | |||
211 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | ||
212 | size_t count, loff_t *ppos) | ||
213 | { | ||
214 | struct wl12xx *wl = file->private_data; | ||
215 | u32 queue_len; | ||
216 | char buf[20]; | ||
217 | int res; | ||
218 | |||
219 | queue_len = skb_queue_len(&wl->tx_queue); | ||
220 | |||
221 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); | ||
222 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
223 | } | ||
224 | |||
225 | static const struct file_operations tx_queue_len_ops = { | ||
226 | .read = tx_queue_len_read, | ||
227 | .open = wl12xx_open_file_generic, | ||
228 | }; | ||
229 | |||
230 | static void wl12xx_debugfs_delete_files(struct wl12xx *wl) | ||
231 | { | ||
232 | DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); | ||
233 | |||
234 | DEBUGFS_FWSTATS_DEL(rx, out_of_mem); | ||
235 | DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); | ||
236 | DEBUGFS_FWSTATS_DEL(rx, hw_stuck); | ||
237 | DEBUGFS_FWSTATS_DEL(rx, dropped); | ||
238 | DEBUGFS_FWSTATS_DEL(rx, fcs_err); | ||
239 | DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); | ||
240 | DEBUGFS_FWSTATS_DEL(rx, path_reset); | ||
241 | DEBUGFS_FWSTATS_DEL(rx, reset_counter); | ||
242 | |||
243 | DEBUGFS_FWSTATS_DEL(dma, rx_requested); | ||
244 | DEBUGFS_FWSTATS_DEL(dma, rx_errors); | ||
245 | DEBUGFS_FWSTATS_DEL(dma, tx_requested); | ||
246 | DEBUGFS_FWSTATS_DEL(dma, tx_errors); | ||
247 | |||
248 | DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); | ||
249 | DEBUGFS_FWSTATS_DEL(isr, fiqs); | ||
250 | DEBUGFS_FWSTATS_DEL(isr, rx_headers); | ||
251 | DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); | ||
252 | DEBUGFS_FWSTATS_DEL(isr, rx_rdys); | ||
253 | DEBUGFS_FWSTATS_DEL(isr, irqs); | ||
254 | DEBUGFS_FWSTATS_DEL(isr, tx_procs); | ||
255 | DEBUGFS_FWSTATS_DEL(isr, decrypt_done); | ||
256 | DEBUGFS_FWSTATS_DEL(isr, dma0_done); | ||
257 | DEBUGFS_FWSTATS_DEL(isr, dma1_done); | ||
258 | DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); | ||
259 | DEBUGFS_FWSTATS_DEL(isr, commands); | ||
260 | DEBUGFS_FWSTATS_DEL(isr, rx_procs); | ||
261 | DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); | ||
262 | DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); | ||
263 | DEBUGFS_FWSTATS_DEL(isr, pci_pm); | ||
264 | DEBUGFS_FWSTATS_DEL(isr, wakeups); | ||
265 | DEBUGFS_FWSTATS_DEL(isr, low_rssi); | ||
266 | |||
267 | DEBUGFS_FWSTATS_DEL(wep, addr_key_count); | ||
268 | DEBUGFS_FWSTATS_DEL(wep, default_key_count); | ||
269 | /* skipping wep.reserved */ | ||
270 | DEBUGFS_FWSTATS_DEL(wep, key_not_found); | ||
271 | DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); | ||
272 | DEBUGFS_FWSTATS_DEL(wep, packets); | ||
273 | DEBUGFS_FWSTATS_DEL(wep, interrupt); | ||
274 | |||
275 | DEBUGFS_FWSTATS_DEL(pwr, ps_enter); | ||
276 | DEBUGFS_FWSTATS_DEL(pwr, elp_enter); | ||
277 | DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); | ||
278 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); | ||
279 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); | ||
280 | DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); | ||
281 | DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); | ||
282 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); | ||
283 | DEBUGFS_FWSTATS_DEL(pwr, power_save_off); | ||
284 | DEBUGFS_FWSTATS_DEL(pwr, enable_ps); | ||
285 | DEBUGFS_FWSTATS_DEL(pwr, disable_ps); | ||
286 | DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); | ||
287 | /* skipping cont_miss_bcns_spread for now */ | ||
288 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); | ||
289 | |||
290 | DEBUGFS_FWSTATS_DEL(mic, rx_pkts); | ||
291 | DEBUGFS_FWSTATS_DEL(mic, calc_failure); | ||
292 | |||
293 | DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); | ||
294 | DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); | ||
295 | DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); | ||
296 | DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); | ||
297 | DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); | ||
298 | DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); | ||
299 | |||
300 | DEBUGFS_FWSTATS_DEL(event, heart_beat); | ||
301 | DEBUGFS_FWSTATS_DEL(event, calibration); | ||
302 | DEBUGFS_FWSTATS_DEL(event, rx_mismatch); | ||
303 | DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); | ||
304 | DEBUGFS_FWSTATS_DEL(event, rx_pool); | ||
305 | DEBUGFS_FWSTATS_DEL(event, oom_late); | ||
306 | DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); | ||
307 | DEBUGFS_FWSTATS_DEL(event, tx_stuck); | ||
308 | |||
309 | DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); | ||
310 | DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); | ||
311 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); | ||
312 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); | ||
313 | DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); | ||
314 | DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); | ||
315 | DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); | ||
316 | |||
317 | DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); | ||
318 | DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); | ||
319 | DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
320 | DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
321 | DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
322 | |||
323 | DEBUGFS_DEL(tx_queue_len); | ||
324 | DEBUGFS_DEL(retry_count); | ||
325 | DEBUGFS_DEL(excessive_retries); | ||
326 | } | ||
327 | |||
328 | static int wl12xx_debugfs_add_files(struct wl12xx *wl) | ||
329 | { | ||
330 | int ret = 0; | ||
331 | |||
332 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); | ||
333 | |||
334 | DEBUGFS_FWSTATS_ADD(rx, out_of_mem); | ||
335 | DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); | ||
336 | DEBUGFS_FWSTATS_ADD(rx, hw_stuck); | ||
337 | DEBUGFS_FWSTATS_ADD(rx, dropped); | ||
338 | DEBUGFS_FWSTATS_ADD(rx, fcs_err); | ||
339 | DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); | ||
340 | DEBUGFS_FWSTATS_ADD(rx, path_reset); | ||
341 | DEBUGFS_FWSTATS_ADD(rx, reset_counter); | ||
342 | |||
343 | DEBUGFS_FWSTATS_ADD(dma, rx_requested); | ||
344 | DEBUGFS_FWSTATS_ADD(dma, rx_errors); | ||
345 | DEBUGFS_FWSTATS_ADD(dma, tx_requested); | ||
346 | DEBUGFS_FWSTATS_ADD(dma, tx_errors); | ||
347 | |||
348 | DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); | ||
349 | DEBUGFS_FWSTATS_ADD(isr, fiqs); | ||
350 | DEBUGFS_FWSTATS_ADD(isr, rx_headers); | ||
351 | DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); | ||
352 | DEBUGFS_FWSTATS_ADD(isr, rx_rdys); | ||
353 | DEBUGFS_FWSTATS_ADD(isr, irqs); | ||
354 | DEBUGFS_FWSTATS_ADD(isr, tx_procs); | ||
355 | DEBUGFS_FWSTATS_ADD(isr, decrypt_done); | ||
356 | DEBUGFS_FWSTATS_ADD(isr, dma0_done); | ||
357 | DEBUGFS_FWSTATS_ADD(isr, dma1_done); | ||
358 | DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); | ||
359 | DEBUGFS_FWSTATS_ADD(isr, commands); | ||
360 | DEBUGFS_FWSTATS_ADD(isr, rx_procs); | ||
361 | DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); | ||
362 | DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); | ||
363 | DEBUGFS_FWSTATS_ADD(isr, pci_pm); | ||
364 | DEBUGFS_FWSTATS_ADD(isr, wakeups); | ||
365 | DEBUGFS_FWSTATS_ADD(isr, low_rssi); | ||
366 | |||
367 | DEBUGFS_FWSTATS_ADD(wep, addr_key_count); | ||
368 | DEBUGFS_FWSTATS_ADD(wep, default_key_count); | ||
369 | /* skipping wep.reserved */ | ||
370 | DEBUGFS_FWSTATS_ADD(wep, key_not_found); | ||
371 | DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); | ||
372 | DEBUGFS_FWSTATS_ADD(wep, packets); | ||
373 | DEBUGFS_FWSTATS_ADD(wep, interrupt); | ||
374 | |||
375 | DEBUGFS_FWSTATS_ADD(pwr, ps_enter); | ||
376 | DEBUGFS_FWSTATS_ADD(pwr, elp_enter); | ||
377 | DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); | ||
378 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); | ||
379 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); | ||
380 | DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); | ||
381 | DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); | ||
382 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); | ||
383 | DEBUGFS_FWSTATS_ADD(pwr, power_save_off); | ||
384 | DEBUGFS_FWSTATS_ADD(pwr, enable_ps); | ||
385 | DEBUGFS_FWSTATS_ADD(pwr, disable_ps); | ||
386 | DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); | ||
387 | /* skipping cont_miss_bcns_spread for now */ | ||
388 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); | ||
389 | |||
390 | DEBUGFS_FWSTATS_ADD(mic, rx_pkts); | ||
391 | DEBUGFS_FWSTATS_ADD(mic, calc_failure); | ||
392 | |||
393 | DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); | ||
394 | DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); | ||
395 | DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); | ||
396 | DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); | ||
397 | DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); | ||
398 | DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); | ||
399 | |||
400 | DEBUGFS_FWSTATS_ADD(event, heart_beat); | ||
401 | DEBUGFS_FWSTATS_ADD(event, calibration); | ||
402 | DEBUGFS_FWSTATS_ADD(event, rx_mismatch); | ||
403 | DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); | ||
404 | DEBUGFS_FWSTATS_ADD(event, rx_pool); | ||
405 | DEBUGFS_FWSTATS_ADD(event, oom_late); | ||
406 | DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); | ||
407 | DEBUGFS_FWSTATS_ADD(event, tx_stuck); | ||
408 | |||
409 | DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); | ||
410 | DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); | ||
411 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); | ||
412 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); | ||
413 | DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); | ||
414 | DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); | ||
415 | DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); | ||
416 | |||
417 | DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); | ||
418 | DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); | ||
419 | DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
420 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
421 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
422 | |||
423 | DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); | ||
424 | DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); | ||
425 | DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); | ||
426 | |||
427 | out: | ||
428 | if (ret < 0) | ||
429 | wl12xx_debugfs_delete_files(wl); | ||
430 | |||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | void wl12xx_debugfs_reset(struct wl12xx *wl) | ||
435 | { | ||
436 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); | ||
437 | wl->stats.retry_count = 0; | ||
438 | wl->stats.excessive_retries = 0; | ||
439 | } | ||
440 | |||
441 | int wl12xx_debugfs_init(struct wl12xx *wl) | ||
442 | { | ||
443 | int ret; | ||
444 | |||
445 | wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
446 | |||
447 | if (IS_ERR(wl->debugfs.rootdir)) { | ||
448 | ret = PTR_ERR(wl->debugfs.rootdir); | ||
449 | wl->debugfs.rootdir = NULL; | ||
450 | goto err; | ||
451 | } | ||
452 | |||
453 | wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", | ||
454 | wl->debugfs.rootdir); | ||
455 | |||
456 | if (IS_ERR(wl->debugfs.fw_statistics)) { | ||
457 | ret = PTR_ERR(wl->debugfs.fw_statistics); | ||
458 | wl->debugfs.fw_statistics = NULL; | ||
459 | goto err_root; | ||
460 | } | ||
461 | |||
462 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), | ||
463 | GFP_KERNEL); | ||
464 | |||
465 | if (!wl->stats.fw_stats) { | ||
466 | ret = -ENOMEM; | ||
467 | goto err_fw; | ||
468 | } | ||
469 | |||
470 | wl->stats.fw_stats_update = jiffies; | ||
471 | |||
472 | ret = wl12xx_debugfs_add_files(wl); | ||
473 | |||
474 | if (ret < 0) | ||
475 | goto err_file; | ||
476 | |||
477 | return 0; | ||
478 | |||
479 | err_file: | ||
480 | kfree(wl->stats.fw_stats); | ||
481 | wl->stats.fw_stats = NULL; | ||
482 | |||
483 | err_fw: | ||
484 | debugfs_remove(wl->debugfs.fw_statistics); | ||
485 | wl->debugfs.fw_statistics = NULL; | ||
486 | |||
487 | err_root: | ||
488 | debugfs_remove(wl->debugfs.rootdir); | ||
489 | wl->debugfs.rootdir = NULL; | ||
490 | |||
491 | err: | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | void wl12xx_debugfs_exit(struct wl12xx *wl) | ||
496 | { | ||
497 | wl12xx_debugfs_delete_files(wl); | ||
498 | |||
499 | kfree(wl->stats.fw_stats); | ||
500 | wl->stats.fw_stats = NULL; | ||
501 | |||
502 | debugfs_remove(wl->debugfs.fw_statistics); | ||
503 | wl->debugfs.fw_statistics = NULL; | ||
504 | |||
505 | debugfs_remove(wl->debugfs.rootdir); | ||
506 | wl->debugfs.rootdir = NULL; | ||
507 | |||
508 | } | ||
diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/debugfs.h new file mode 100644 index 000000000000..562cdcbcc874 --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef WL12XX_DEBUGFS_H | ||
25 | #define WL12XX_DEBUGFS_H | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | |||
29 | int wl12xx_debugfs_init(struct wl12xx *wl); | ||
30 | void wl12xx_debugfs_exit(struct wl12xx *wl); | ||
31 | void wl12xx_debugfs_reset(struct wl12xx *wl); | ||
32 | |||
33 | #endif /* WL12XX_DEBUGFS_H */ | ||
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c new file mode 100644 index 000000000000..99529ca89a7e --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "wl12xx.h" | ||
26 | #include "reg.h" | ||
27 | #include "spi.h" | ||
28 | #include "event.h" | ||
29 | #include "ps.h" | ||
30 | |||
31 | static int wl12xx_event_scan_complete(struct wl12xx *wl, | ||
32 | struct event_mailbox *mbox) | ||
33 | { | ||
34 | wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", | ||
35 | mbox->scheduled_scan_status, | ||
36 | mbox->scheduled_scan_channels); | ||
37 | |||
38 | if (wl->scanning) { | ||
39 | mutex_unlock(&wl->mutex); | ||
40 | ieee80211_scan_completed(wl->hw, false); | ||
41 | mutex_lock(&wl->mutex); | ||
42 | wl->scanning = false; | ||
43 | } | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) | ||
49 | { | ||
50 | wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); | ||
51 | wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); | ||
52 | wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); | ||
53 | } | ||
54 | |||
55 | static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) | ||
56 | { | ||
57 | int ret; | ||
58 | u32 vector; | ||
59 | |||
60 | wl12xx_event_mbox_dump(mbox); | ||
61 | |||
62 | vector = mbox->events_vector & ~(mbox->events_mask); | ||
63 | wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); | ||
64 | |||
65 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
66 | ret = wl12xx_event_scan_complete(wl, mbox); | ||
67 | if (ret < 0) | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | if (vector & BSS_LOSE_EVENT_ID) { | ||
72 | wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | ||
73 | |||
74 | if (wl->psm_requested && wl->psm) { | ||
75 | ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
76 | if (ret < 0) | ||
77 | return ret; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | int wl12xx_event_unmask(struct wl12xx *wl) | ||
85 | { | ||
86 | int ret; | ||
87 | |||
88 | ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); | ||
89 | if (ret < 0) | ||
90 | return ret; | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | void wl12xx_event_mbox_config(struct wl12xx *wl) | ||
96 | { | ||
97 | wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
98 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | ||
99 | |||
100 | wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", | ||
101 | wl->mbox_ptr[0], wl->mbox_ptr[1]); | ||
102 | } | ||
103 | |||
104 | int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) | ||
105 | { | ||
106 | struct event_mailbox mbox; | ||
107 | int ret; | ||
108 | |||
109 | wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); | ||
110 | |||
111 | if (mbox_num > 1) | ||
112 | return -EINVAL; | ||
113 | |||
114 | /* first we read the mbox descriptor */ | ||
115 | wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | ||
116 | sizeof(struct event_mailbox)); | ||
117 | |||
118 | /* process the descriptor */ | ||
119 | ret = wl12xx_event_process(wl, &mbox); | ||
120 | if (ret < 0) | ||
121 | return ret; | ||
122 | |||
123 | /* then we let the firmware know it can go on...*/ | ||
124 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h new file mode 100644 index 000000000000..1f4c2f7438a7 --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.h | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_EVENT_H__ | ||
26 | #define __WL12XX_EVENT_H__ | ||
27 | |||
28 | /* | ||
29 | * Mbox events | ||
30 | * | ||
31 | * The event mechanism is based on a pair of event buffers (buffers A and | ||
32 | * B) at fixed locations in the target's memory. The host processes one | ||
33 | * buffer while the other buffer continues to collect events. If the host | ||
34 | * is not processing events, an interrupt is issued to signal that a buffer | ||
35 | * is ready. Once the host is done with processing events from one buffer, | ||
36 | * it signals the target (with an ACK interrupt) that the event buffer is | ||
37 | * free. | ||
38 | */ | ||
39 | |||
40 | enum { | ||
41 | RESERVED1_EVENT_ID = BIT(0), | ||
42 | RESERVED2_EVENT_ID = BIT(1), | ||
43 | MEASUREMENT_START_EVENT_ID = BIT(2), | ||
44 | SCAN_COMPLETE_EVENT_ID = BIT(3), | ||
45 | CALIBRATION_COMPLETE_EVENT_ID = BIT(4), | ||
46 | ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), | ||
47 | PS_REPORT_EVENT_ID = BIT(6), | ||
48 | SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), | ||
49 | HEALTH_REPORT_EVENT_ID = BIT(8), | ||
50 | ACI_DETECTION_EVENT_ID = BIT(9), | ||
51 | DEBUG_REPORT_EVENT_ID = BIT(10), | ||
52 | MAC_STATUS_EVENT_ID = BIT(11), | ||
53 | DISCONNECT_EVENT_COMPLETE_ID = BIT(12), | ||
54 | JOIN_EVENT_COMPLETE_ID = BIT(13), | ||
55 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), | ||
56 | BSS_LOSE_EVENT_ID = BIT(15), | ||
57 | ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), | ||
58 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), | ||
59 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), | ||
60 | SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), | ||
61 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), | ||
62 | RESET_BSS_EVENT_ID = BIT(21), | ||
63 | REGAINED_BSS_EVENT_ID = BIT(22), | ||
64 | ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), | ||
65 | ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), | ||
66 | ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), | ||
67 | |||
68 | DBG_EVENT_ID = BIT(26), | ||
69 | BT_PTA_SENSE_EVENT_ID = BIT(27), | ||
70 | BT_PTA_PREDICTION_EVENT_ID = BIT(28), | ||
71 | BT_PTA_AVALANCHE_EVENT_ID = BIT(29), | ||
72 | |||
73 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), | ||
74 | |||
75 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, | ||
76 | }; | ||
77 | |||
78 | struct event_debug_report { | ||
79 | u8 debug_event_id; | ||
80 | u8 num_params; | ||
81 | u16 pad; | ||
82 | u32 report_1; | ||
83 | u32 report_2; | ||
84 | u32 report_3; | ||
85 | } __attribute__ ((packed)); | ||
86 | |||
87 | struct event_mailbox { | ||
88 | u32 events_vector; | ||
89 | u32 events_mask; | ||
90 | u32 reserved_1; | ||
91 | u32 reserved_2; | ||
92 | |||
93 | char average_rssi_level; | ||
94 | u8 ps_status; | ||
95 | u8 channel_switch_status; | ||
96 | u8 scheduled_scan_status; | ||
97 | |||
98 | /* Channels scanned by the scheduled scan */ | ||
99 | u16 scheduled_scan_channels; | ||
100 | |||
101 | /* If bit 0 is set -> target's fatal error */ | ||
102 | u16 health_report; | ||
103 | u16 bad_fft_counter; | ||
104 | u8 bt_pta_sense_info; | ||
105 | u8 bt_pta_protective_info; | ||
106 | u32 reserved; | ||
107 | u32 debug_report[2]; | ||
108 | |||
109 | /* Number of FCS errors since last event */ | ||
110 | u32 fcs_err_counter; | ||
111 | |||
112 | struct event_debug_report report; | ||
113 | u8 average_snr_level; | ||
114 | u8 padding[19]; | ||
115 | } __attribute__ ((packed)); | ||
116 | |||
117 | int wl12xx_event_unmask(struct wl12xx *wl); | ||
118 | void wl12xx_event_mbox_config(struct wl12xx *wl); | ||
119 | int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); | ||
120 | |||
121 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c new file mode 100644 index 000000000000..2a573a6010bd --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "init.h" | ||
28 | #include "wl12xx_80211.h" | ||
29 | #include "acx.h" | ||
30 | #include "cmd.h" | ||
31 | |||
32 | int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) | ||
33 | { | ||
34 | int ret; | ||
35 | |||
36 | ret = wl12xx_acx_feature_cfg(wl); | ||
37 | if (ret < 0) { | ||
38 | wl12xx_warning("couldn't set feature config"); | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | ret = wl12xx_acx_default_key(wl, wl->default_key); | ||
43 | if (ret < 0) { | ||
44 | wl12xx_warning("couldn't set default key"); | ||
45 | return ret; | ||
46 | } | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | int wl12xx_hw_init_templates_config(struct wl12xx *wl) | ||
52 | { | ||
53 | int ret; | ||
54 | u8 partial_vbm[PARTIAL_VBM_MAX]; | ||
55 | |||
56 | /* send empty templates for fw memory reservation */ | ||
57 | ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, | ||
58 | sizeof(struct wl12xx_probe_req_template)); | ||
59 | if (ret < 0) | ||
60 | return ret; | ||
61 | |||
62 | ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, | ||
63 | sizeof(struct wl12xx_null_data_template)); | ||
64 | if (ret < 0) | ||
65 | return ret; | ||
66 | |||
67 | ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, | ||
68 | sizeof(struct wl12xx_ps_poll_template)); | ||
69 | if (ret < 0) | ||
70 | return ret; | ||
71 | |||
72 | ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, | ||
73 | sizeof | ||
74 | (struct wl12xx_qos_null_data_template)); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, | ||
79 | sizeof | ||
80 | (struct wl12xx_probe_resp_template)); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | |||
84 | ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, | ||
85 | sizeof | ||
86 | (struct wl12xx_beacon_template)); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | /* tim templates, first reserve space then allocate an empty one */ | ||
91 | memset(partial_vbm, 0, PARTIAL_VBM_MAX); | ||
92 | ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); | ||
93 | if (ret < 0) | ||
94 | return ret; | ||
95 | |||
96 | ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) | ||
104 | { | ||
105 | int ret; | ||
106 | |||
107 | ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); | ||
108 | if (ret < 0) | ||
109 | return ret; | ||
110 | |||
111 | ret = wl12xx_acx_rx_config(wl, config, filter); | ||
112 | if (ret < 0) | ||
113 | return ret; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int wl12xx_hw_init_phy_config(struct wl12xx *wl) | ||
119 | { | ||
120 | int ret; | ||
121 | |||
122 | ret = wl12xx_acx_pd_threshold(wl); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); | ||
127 | if (ret < 0) | ||
128 | return ret; | ||
129 | |||
130 | ret = wl12xx_acx_group_address_tbl(wl); | ||
131 | if (ret < 0) | ||
132 | return ret; | ||
133 | |||
134 | ret = wl12xx_acx_service_period_timeout(wl); | ||
135 | if (ret < 0) | ||
136 | return ret; | ||
137 | |||
138 | ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) | ||
146 | { | ||
147 | int ret; | ||
148 | |||
149 | ret = wl12xx_acx_beacon_filter_opt(wl); | ||
150 | if (ret < 0) | ||
151 | return ret; | ||
152 | |||
153 | ret = wl12xx_acx_beacon_filter_table(wl); | ||
154 | if (ret < 0) | ||
155 | return ret; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | int wl12xx_hw_init_pta(struct wl12xx *wl) | ||
161 | { | ||
162 | int ret; | ||
163 | |||
164 | ret = wl12xx_acx_sg_enable(wl); | ||
165 | if (ret < 0) | ||
166 | return ret; | ||
167 | |||
168 | ret = wl12xx_acx_sg_cfg(wl); | ||
169 | if (ret < 0) | ||
170 | return ret; | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | int wl12xx_hw_init_energy_detection(struct wl12xx *wl) | ||
176 | { | ||
177 | int ret; | ||
178 | |||
179 | ret = wl12xx_acx_cca_threshold(wl); | ||
180 | if (ret < 0) | ||
181 | return ret; | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) | ||
187 | { | ||
188 | int ret; | ||
189 | |||
190 | ret = wl12xx_acx_bcn_dtim_options(wl); | ||
191 | if (ret < 0) | ||
192 | return ret; | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | int wl12xx_hw_init_power_auth(struct wl12xx *wl) | ||
198 | { | ||
199 | return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); | ||
200 | } | ||
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h new file mode 100644 index 000000000000..c8b6cd0b7c3e --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL12XX_INIT_H__ | ||
25 | #define __WL12XX_INIT_H__ | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | |||
29 | int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); | ||
30 | int wl12xx_hw_init_templates_config(struct wl12xx *wl); | ||
31 | int wl12xx_hw_init_mem_config(struct wl12xx *wl); | ||
32 | int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); | ||
33 | int wl12xx_hw_init_phy_config(struct wl12xx *wl); | ||
34 | int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); | ||
35 | int wl12xx_hw_init_pta(struct wl12xx *wl); | ||
36 | int wl12xx_hw_init_energy_detection(struct wl12xx *wl); | ||
37 | int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); | ||
38 | int wl12xx_hw_init_power_auth(struct wl12xx *wl); | ||
39 | |||
40 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c new file mode 100644 index 000000000000..744f4ce5993b --- /dev/null +++ b/drivers/net/wireless/wl12xx/main.c | |||
@@ -0,0 +1,1358 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/firmware.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/spi/spi.h> | ||
30 | #include <linux/crc32.h> | ||
31 | #include <linux/etherdevice.h> | ||
32 | #include <linux/spi/wl12xx.h> | ||
33 | |||
34 | #include "wl12xx.h" | ||
35 | #include "wl12xx_80211.h" | ||
36 | #include "reg.h" | ||
37 | #include "wl1251.h" | ||
38 | #include "spi.h" | ||
39 | #include "event.h" | ||
40 | #include "tx.h" | ||
41 | #include "rx.h" | ||
42 | #include "ps.h" | ||
43 | #include "init.h" | ||
44 | #include "debugfs.h" | ||
45 | |||
46 | static void wl12xx_disable_interrupts(struct wl12xx *wl) | ||
47 | { | ||
48 | disable_irq(wl->irq); | ||
49 | } | ||
50 | |||
51 | static void wl12xx_power_off(struct wl12xx *wl) | ||
52 | { | ||
53 | wl->set_power(false); | ||
54 | } | ||
55 | |||
56 | static void wl12xx_power_on(struct wl12xx *wl) | ||
57 | { | ||
58 | wl->set_power(true); | ||
59 | } | ||
60 | |||
61 | static irqreturn_t wl12xx_irq(int irq, void *cookie) | ||
62 | { | ||
63 | struct wl12xx *wl; | ||
64 | |||
65 | wl12xx_debug(DEBUG_IRQ, "IRQ"); | ||
66 | |||
67 | wl = cookie; | ||
68 | |||
69 | schedule_work(&wl->irq_work); | ||
70 | |||
71 | return IRQ_HANDLED; | ||
72 | } | ||
73 | |||
74 | static int wl12xx_fetch_firmware(struct wl12xx *wl) | ||
75 | { | ||
76 | const struct firmware *fw; | ||
77 | int ret; | ||
78 | |||
79 | ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); | ||
80 | |||
81 | if (ret < 0) { | ||
82 | wl12xx_error("could not get firmware: %d", ret); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | if (fw->size % 4) { | ||
87 | wl12xx_error("firmware size is not multiple of 32 bits: %d", | ||
88 | fw->size); | ||
89 | ret = -EILSEQ; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | wl->fw_len = fw->size; | ||
94 | wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); | ||
95 | |||
96 | if (!wl->fw) { | ||
97 | wl12xx_error("could not allocate memory for the firmware"); | ||
98 | ret = -ENOMEM; | ||
99 | goto out; | ||
100 | } | ||
101 | |||
102 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
103 | |||
104 | ret = 0; | ||
105 | |||
106 | out: | ||
107 | release_firmware(fw); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int wl12xx_fetch_nvs(struct wl12xx *wl) | ||
113 | { | ||
114 | const struct firmware *fw; | ||
115 | int ret; | ||
116 | |||
117 | ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); | ||
118 | |||
119 | if (ret < 0) { | ||
120 | wl12xx_error("could not get nvs file: %d", ret); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | if (fw->size % 4) { | ||
125 | wl12xx_error("nvs size is not multiple of 32 bits: %d", | ||
126 | fw->size); | ||
127 | ret = -EILSEQ; | ||
128 | goto out; | ||
129 | } | ||
130 | |||
131 | wl->nvs_len = fw->size; | ||
132 | wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); | ||
133 | |||
134 | if (!wl->nvs) { | ||
135 | wl12xx_error("could not allocate memory for the nvs file"); | ||
136 | ret = -ENOMEM; | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | memcpy(wl->nvs, fw->data, wl->nvs_len); | ||
141 | |||
142 | ret = 0; | ||
143 | |||
144 | out: | ||
145 | release_firmware(fw); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static void wl12xx_fw_wakeup(struct wl12xx *wl) | ||
151 | { | ||
152 | u32 elp_reg; | ||
153 | |||
154 | elp_reg = ELPCTRL_WAKE_UP; | ||
155 | wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
156 | elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
157 | |||
158 | if (!(elp_reg & ELPCTRL_WLAN_READY)) { | ||
159 | wl12xx_warning("WLAN not ready"); | ||
160 | elp_reg = ELPCTRL_WAKE_UP_WLAN_READY; | ||
161 | wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static int wl12xx_chip_wakeup(struct wl12xx *wl) | ||
166 | { | ||
167 | int ret = 0; | ||
168 | |||
169 | wl12xx_power_on(wl); | ||
170 | msleep(wl->chip.power_on_sleep); | ||
171 | wl12xx_spi_reset(wl); | ||
172 | wl12xx_spi_init(wl); | ||
173 | |||
174 | /* We don't need a real memory partition here, because we only want | ||
175 | * to use the registers at this point. */ | ||
176 | wl12xx_set_partition(wl, | ||
177 | 0x00000000, | ||
178 | 0x00000000, | ||
179 | REGISTERS_BASE, | ||
180 | REGISTERS_DOWN_SIZE); | ||
181 | |||
182 | /* ELP module wake up */ | ||
183 | wl12xx_fw_wakeup(wl); | ||
184 | |||
185 | /* whal_FwCtrl_BootSm() */ | ||
186 | |||
187 | /* 0. read chip id from CHIP_ID */ | ||
188 | wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); | ||
189 | |||
190 | /* 1. check if chip id is valid */ | ||
191 | |||
192 | switch (wl->chip.id) { | ||
193 | case CHIP_ID_1251_PG12: | ||
194 | wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", | ||
195 | wl->chip.id); | ||
196 | |||
197 | wl1251_setup(wl); | ||
198 | |||
199 | break; | ||
200 | case CHIP_ID_1271_PG10: | ||
201 | case CHIP_ID_1251_PG10: | ||
202 | case CHIP_ID_1251_PG11: | ||
203 | default: | ||
204 | wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); | ||
205 | ret = -ENODEV; | ||
206 | goto out; | ||
207 | } | ||
208 | |||
209 | if (wl->fw == NULL) { | ||
210 | ret = wl12xx_fetch_firmware(wl); | ||
211 | if (ret < 0) | ||
212 | goto out; | ||
213 | } | ||
214 | |||
215 | /* No NVS from netlink, try to get it from the filesystem */ | ||
216 | if (wl->nvs == NULL) { | ||
217 | ret = wl12xx_fetch_nvs(wl); | ||
218 | if (ret < 0) | ||
219 | goto out; | ||
220 | } | ||
221 | |||
222 | out: | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static void wl12xx_filter_work(struct work_struct *work) | ||
227 | { | ||
228 | struct wl12xx *wl = | ||
229 | container_of(work, struct wl12xx, filter_work); | ||
230 | int ret; | ||
231 | |||
232 | mutex_lock(&wl->mutex); | ||
233 | |||
234 | if (wl->state == WL12XX_STATE_OFF) | ||
235 | goto out; | ||
236 | |||
237 | ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
238 | if (ret < 0) | ||
239 | goto out; | ||
240 | |||
241 | out: | ||
242 | mutex_unlock(&wl->mutex); | ||
243 | } | ||
244 | |||
245 | int wl12xx_plt_start(struct wl12xx *wl) | ||
246 | { | ||
247 | int ret; | ||
248 | |||
249 | wl12xx_notice("power up"); | ||
250 | |||
251 | if (wl->state != WL12XX_STATE_OFF) { | ||
252 | wl12xx_error("cannot go into PLT state because not " | ||
253 | "in off state: %d", wl->state); | ||
254 | return -EBUSY; | ||
255 | } | ||
256 | |||
257 | wl->state = WL12XX_STATE_PLT; | ||
258 | |||
259 | ret = wl12xx_chip_wakeup(wl); | ||
260 | if (ret < 0) | ||
261 | return ret; | ||
262 | |||
263 | ret = wl->chip.op_boot(wl); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | |||
267 | wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); | ||
268 | |||
269 | ret = wl->chip.op_plt_init(wl); | ||
270 | if (ret < 0) | ||
271 | return ret; | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | int wl12xx_plt_stop(struct wl12xx *wl) | ||
277 | { | ||
278 | wl12xx_notice("power down"); | ||
279 | |||
280 | if (wl->state != WL12XX_STATE_PLT) { | ||
281 | wl12xx_error("cannot power down because not in PLT " | ||
282 | "state: %d", wl->state); | ||
283 | return -EBUSY; | ||
284 | } | ||
285 | |||
286 | wl12xx_disable_interrupts(wl); | ||
287 | wl12xx_power_off(wl); | ||
288 | |||
289 | wl->state = WL12XX_STATE_OFF; | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | |||
295 | static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
296 | { | ||
297 | struct wl12xx *wl = hw->priv; | ||
298 | |||
299 | skb_queue_tail(&wl->tx_queue, skb); | ||
300 | |||
301 | schedule_work(&wl->tx_work); | ||
302 | |||
303 | /* | ||
304 | * The workqueue is slow to process the tx_queue and we need stop | ||
305 | * the queue here, otherwise the queue will get too long. | ||
306 | */ | ||
307 | if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { | ||
308 | ieee80211_stop_queues(wl->hw); | ||
309 | |||
310 | /* | ||
311 | * FIXME: this is racy, the variable is not properly | ||
312 | * protected. Maybe fix this by removing the stupid | ||
313 | * variable altogether and checking the real queue state? | ||
314 | */ | ||
315 | wl->tx_queue_stopped = true; | ||
316 | } | ||
317 | |||
318 | return NETDEV_TX_OK; | ||
319 | } | ||
320 | |||
321 | static int wl12xx_op_start(struct ieee80211_hw *hw) | ||
322 | { | ||
323 | struct wl12xx *wl = hw->priv; | ||
324 | int ret = 0; | ||
325 | |||
326 | wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); | ||
327 | |||
328 | mutex_lock(&wl->mutex); | ||
329 | |||
330 | if (wl->state != WL12XX_STATE_OFF) { | ||
331 | wl12xx_error("cannot start because not in off state: %d", | ||
332 | wl->state); | ||
333 | ret = -EBUSY; | ||
334 | goto out; | ||
335 | } | ||
336 | |||
337 | ret = wl12xx_chip_wakeup(wl); | ||
338 | if (ret < 0) | ||
339 | return ret; | ||
340 | |||
341 | ret = wl->chip.op_boot(wl); | ||
342 | if (ret < 0) | ||
343 | goto out; | ||
344 | |||
345 | ret = wl->chip.op_hw_init(wl); | ||
346 | if (ret < 0) | ||
347 | goto out; | ||
348 | |||
349 | ret = wl12xx_acx_station_id(wl); | ||
350 | if (ret < 0) | ||
351 | goto out; | ||
352 | |||
353 | wl->state = WL12XX_STATE_ON; | ||
354 | |||
355 | wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); | ||
356 | |||
357 | out: | ||
358 | if (ret < 0) | ||
359 | wl12xx_power_off(wl); | ||
360 | |||
361 | mutex_unlock(&wl->mutex); | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | static void wl12xx_op_stop(struct ieee80211_hw *hw) | ||
367 | { | ||
368 | struct wl12xx *wl = hw->priv; | ||
369 | |||
370 | wl12xx_info("down"); | ||
371 | |||
372 | wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
373 | |||
374 | mutex_lock(&wl->mutex); | ||
375 | |||
376 | WARN_ON(wl->state != WL12XX_STATE_ON); | ||
377 | |||
378 | if (wl->scanning) { | ||
379 | mutex_unlock(&wl->mutex); | ||
380 | ieee80211_scan_completed(wl->hw, true); | ||
381 | mutex_lock(&wl->mutex); | ||
382 | wl->scanning = false; | ||
383 | } | ||
384 | |||
385 | wl->state = WL12XX_STATE_OFF; | ||
386 | |||
387 | wl12xx_disable_interrupts(wl); | ||
388 | |||
389 | mutex_unlock(&wl->mutex); | ||
390 | |||
391 | cancel_work_sync(&wl->irq_work); | ||
392 | cancel_work_sync(&wl->tx_work); | ||
393 | cancel_work_sync(&wl->filter_work); | ||
394 | |||
395 | mutex_lock(&wl->mutex); | ||
396 | |||
397 | /* let's notify MAC80211 about the remaining pending TX frames */ | ||
398 | wl12xx_tx_flush(wl); | ||
399 | |||
400 | wl12xx_power_off(wl); | ||
401 | |||
402 | memset(wl->bssid, 0, ETH_ALEN); | ||
403 | wl->listen_int = 1; | ||
404 | wl->bss_type = MAX_BSS_TYPE; | ||
405 | |||
406 | wl->data_in_count = 0; | ||
407 | wl->rx_counter = 0; | ||
408 | wl->rx_handled = 0; | ||
409 | wl->rx_current_buffer = 0; | ||
410 | wl->rx_last_id = 0; | ||
411 | wl->next_tx_complete = 0; | ||
412 | wl->elp = false; | ||
413 | wl->psm = 0; | ||
414 | wl->tx_queue_stopped = false; | ||
415 | wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; | ||
416 | |||
417 | wl12xx_debugfs_reset(wl); | ||
418 | |||
419 | mutex_unlock(&wl->mutex); | ||
420 | } | ||
421 | |||
422 | static int wl12xx_op_add_interface(struct ieee80211_hw *hw, | ||
423 | struct ieee80211_if_init_conf *conf) | ||
424 | { | ||
425 | struct wl12xx *wl = hw->priv; | ||
426 | DECLARE_MAC_BUF(mac); | ||
427 | int ret = 0; | ||
428 | |||
429 | wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", | ||
430 | conf->type, print_mac(mac, conf->mac_addr)); | ||
431 | |||
432 | mutex_lock(&wl->mutex); | ||
433 | |||
434 | switch (conf->type) { | ||
435 | case NL80211_IFTYPE_STATION: | ||
436 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
437 | break; | ||
438 | case NL80211_IFTYPE_ADHOC: | ||
439 | wl->bss_type = BSS_TYPE_IBSS; | ||
440 | break; | ||
441 | default: | ||
442 | ret = -EOPNOTSUPP; | ||
443 | goto out; | ||
444 | } | ||
445 | |||
446 | if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { | ||
447 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | ||
448 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
449 | ret = wl12xx_acx_station_id(wl); | ||
450 | if (ret < 0) | ||
451 | goto out; | ||
452 | } | ||
453 | |||
454 | out: | ||
455 | mutex_unlock(&wl->mutex); | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, | ||
460 | struct ieee80211_if_init_conf *conf) | ||
461 | { | ||
462 | wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
463 | } | ||
464 | |||
465 | static int wl12xx_build_null_data(struct wl12xx *wl) | ||
466 | { | ||
467 | struct wl12xx_null_data_template template; | ||
468 | |||
469 | if (!is_zero_ether_addr(wl->bssid)) { | ||
470 | memcpy(template.header.da, wl->bssid, ETH_ALEN); | ||
471 | memcpy(template.header.bssid, wl->bssid, ETH_ALEN); | ||
472 | } else { | ||
473 | memset(template.header.da, 0xff, ETH_ALEN); | ||
474 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
475 | } | ||
476 | |||
477 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
478 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
479 | IEEE80211_STYPE_NULLFUNC); | ||
480 | |||
481 | return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, | ||
482 | sizeof(template)); | ||
483 | |||
484 | } | ||
485 | |||
486 | static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) | ||
487 | { | ||
488 | struct wl12xx_ps_poll_template template; | ||
489 | |||
490 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | ||
491 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | ||
492 | template.aid = aid; | ||
493 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | ||
494 | |||
495 | return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, | ||
496 | sizeof(template)); | ||
497 | |||
498 | } | ||
499 | |||
500 | static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) | ||
501 | { | ||
502 | struct wl12xx *wl = hw->priv; | ||
503 | struct ieee80211_conf *conf = &hw->conf; | ||
504 | int channel, ret = 0; | ||
505 | |||
506 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
507 | |||
508 | wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", | ||
509 | channel, | ||
510 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||
511 | conf->power_level); | ||
512 | |||
513 | mutex_lock(&wl->mutex); | ||
514 | |||
515 | if (channel != wl->channel) { | ||
516 | /* FIXME: use beacon interval provided by mac80211 */ | ||
517 | ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
518 | if (ret < 0) | ||
519 | goto out; | ||
520 | |||
521 | wl->channel = channel; | ||
522 | } | ||
523 | |||
524 | ret = wl12xx_build_null_data(wl); | ||
525 | if (ret < 0) | ||
526 | goto out; | ||
527 | |||
528 | if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { | ||
529 | wl12xx_info("psm enabled"); | ||
530 | |||
531 | wl->psm_requested = true; | ||
532 | |||
533 | /* | ||
534 | * We enter PSM only if we're already associated. | ||
535 | * If we're not, we'll enter it when joining an SSID, | ||
536 | * through the bss_info_changed() hook. | ||
537 | */ | ||
538 | ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
539 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
540 | wl->psm_requested) { | ||
541 | wl12xx_info("psm disabled"); | ||
542 | |||
543 | wl->psm_requested = false; | ||
544 | |||
545 | if (wl->psm) | ||
546 | ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
547 | } | ||
548 | |||
549 | if (conf->power_level != wl->power_level) { | ||
550 | ret = wl12xx_acx_tx_power(wl, conf->power_level); | ||
551 | if (ret < 0) | ||
552 | goto out; | ||
553 | |||
554 | wl->power_level = conf->power_level; | ||
555 | } | ||
556 | |||
557 | out: | ||
558 | mutex_unlock(&wl->mutex); | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | #define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
563 | FIF_ALLMULTI | \ | ||
564 | FIF_FCSFAIL | \ | ||
565 | FIF_BCN_PRBRESP_PROMISC | \ | ||
566 | FIF_CONTROL | \ | ||
567 | FIF_OTHER_BSS) | ||
568 | |||
569 | static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, | ||
570 | unsigned int changed, | ||
571 | unsigned int *total, | ||
572 | int mc_count, | ||
573 | struct dev_addr_list *mc_list) | ||
574 | { | ||
575 | struct wl12xx *wl = hw->priv; | ||
576 | |||
577 | wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); | ||
578 | |||
579 | *total &= WL12XX_SUPPORTED_FILTERS; | ||
580 | changed &= WL12XX_SUPPORTED_FILTERS; | ||
581 | |||
582 | if (changed == 0) | ||
583 | /* no filters which we support changed */ | ||
584 | return; | ||
585 | |||
586 | /* FIXME: wl->rx_config and wl->rx_filter are not protected */ | ||
587 | |||
588 | wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; | ||
589 | wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; | ||
590 | |||
591 | if (*total & FIF_PROMISC_IN_BSS) { | ||
592 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
593 | wl->rx_config |= CFG_RX_ALL_GOOD; | ||
594 | } | ||
595 | if (*total & FIF_ALLMULTI) | ||
596 | /* | ||
597 | * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive | ||
598 | * all multicast frames | ||
599 | */ | ||
600 | wl->rx_config &= ~CFG_MC_FILTER_EN; | ||
601 | if (*total & FIF_FCSFAIL) | ||
602 | wl->rx_filter |= CFG_RX_FCS_ERROR; | ||
603 | if (*total & FIF_BCN_PRBRESP_PROMISC) { | ||
604 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | ||
605 | wl->rx_config &= ~CFG_SSID_FILTER_EN; | ||
606 | } | ||
607 | if (*total & FIF_CONTROL) | ||
608 | wl->rx_filter |= CFG_RX_CTL_EN; | ||
609 | if (*total & FIF_OTHER_BSS) | ||
610 | wl->rx_filter &= ~CFG_BSSID_FILTER_EN; | ||
611 | |||
612 | /* | ||
613 | * FIXME: workqueues need to be properly cancelled on stop(), for | ||
614 | * now let's just disable changing the filter settings. They will | ||
615 | * be updated any on config(). | ||
616 | */ | ||
617 | /* schedule_work(&wl->filter_work); */ | ||
618 | } | ||
619 | |||
620 | /* HW encryption */ | ||
621 | static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key, | ||
622 | enum set_key_cmd cmd, | ||
623 | struct ieee80211_key_conf *mac80211_key, | ||
624 | const u8 *addr) | ||
625 | { | ||
626 | switch (mac80211_key->alg) { | ||
627 | case ALG_WEP: | ||
628 | if (is_broadcast_ether_addr(addr)) | ||
629 | key->key_type = KEY_WEP_DEFAULT; | ||
630 | else | ||
631 | key->key_type = KEY_WEP_ADDR; | ||
632 | |||
633 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
634 | break; | ||
635 | case ALG_TKIP: | ||
636 | if (is_broadcast_ether_addr(addr)) | ||
637 | key->key_type = KEY_TKIP_MIC_GROUP; | ||
638 | else | ||
639 | key->key_type = KEY_TKIP_MIC_PAIRWISE; | ||
640 | |||
641 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
642 | break; | ||
643 | case ALG_CCMP: | ||
644 | if (is_broadcast_ether_addr(addr)) | ||
645 | key->key_type = KEY_AES_GROUP; | ||
646 | else | ||
647 | key->key_type = KEY_AES_PAIRWISE; | ||
648 | mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
649 | break; | ||
650 | default: | ||
651 | wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); | ||
652 | return -EOPNOTSUPP; | ||
653 | } | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
659 | struct ieee80211_vif *vif, | ||
660 | struct ieee80211_sta *sta, | ||
661 | struct ieee80211_key_conf *key) | ||
662 | { | ||
663 | struct wl12xx *wl = hw->priv; | ||
664 | struct acx_set_key wl_key; | ||
665 | const u8 *addr; | ||
666 | int ret; | ||
667 | |||
668 | static const u8 bcast_addr[ETH_ALEN] = | ||
669 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
670 | |||
671 | wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); | ||
672 | |||
673 | memset(&wl_key, 0, sizeof(wl_key)); | ||
674 | |||
675 | addr = sta ? sta->addr : bcast_addr; | ||
676 | |||
677 | wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); | ||
678 | wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); | ||
679 | wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", | ||
680 | key->alg, key->keyidx, key->keylen, key->flags); | ||
681 | wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); | ||
682 | |||
683 | mutex_lock(&wl->mutex); | ||
684 | |||
685 | switch (cmd) { | ||
686 | case SET_KEY: | ||
687 | wl_key.key_action = KEY_ADD_OR_REPLACE; | ||
688 | break; | ||
689 | case DISABLE_KEY: | ||
690 | wl_key.key_action = KEY_REMOVE; | ||
691 | break; | ||
692 | default: | ||
693 | wl12xx_error("Unsupported key cmd 0x%x", cmd); | ||
694 | break; | ||
695 | } | ||
696 | |||
697 | ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr); | ||
698 | if (ret < 0) { | ||
699 | wl12xx_error("Set KEY type failed"); | ||
700 | goto out; | ||
701 | } | ||
702 | |||
703 | if (wl_key.key_type != KEY_WEP_DEFAULT) | ||
704 | memcpy(wl_key.addr, addr, ETH_ALEN); | ||
705 | |||
706 | if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) || | ||
707 | (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) { | ||
708 | /* | ||
709 | * We get the key in the following form: | ||
710 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
711 | * but the target is expecting: | ||
712 | * TKIP - RX MIC - TX MIC | ||
713 | */ | ||
714 | memcpy(wl_key.key, key->key, 16); | ||
715 | memcpy(wl_key.key + 16, key->key + 24, 8); | ||
716 | memcpy(wl_key.key + 24, key->key + 16, 8); | ||
717 | |||
718 | } else { | ||
719 | memcpy(wl_key.key, key->key, key->keylen); | ||
720 | } | ||
721 | wl_key.key_size = key->keylen; | ||
722 | |||
723 | wl_key.id = key->keyidx; | ||
724 | wl_key.ssid_profile = 0; | ||
725 | |||
726 | wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key)); | ||
727 | |||
728 | if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) { | ||
729 | wl12xx_error("Set KEY failed"); | ||
730 | ret = -EOPNOTSUPP; | ||
731 | goto out; | ||
732 | } | ||
733 | |||
734 | out: | ||
735 | mutex_unlock(&wl->mutex); | ||
736 | return ret; | ||
737 | } | ||
738 | |||
739 | static int wl12xx_build_basic_rates(char *rates) | ||
740 | { | ||
741 | u8 index = 0; | ||
742 | |||
743 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
744 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
745 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
746 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
747 | |||
748 | return index; | ||
749 | } | ||
750 | |||
751 | static int wl12xx_build_extended_rates(char *rates) | ||
752 | { | ||
753 | u8 index = 0; | ||
754 | |||
755 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | ||
756 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | ||
757 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | ||
758 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | ||
759 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | ||
760 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | ||
761 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | ||
762 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
763 | |||
764 | return index; | ||
765 | } | ||
766 | |||
767 | |||
768 | static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) | ||
769 | { | ||
770 | struct wl12xx_probe_req_template template; | ||
771 | struct wl12xx_ie_rates *rates; | ||
772 | char *ptr; | ||
773 | u16 size; | ||
774 | |||
775 | ptr = (char *)&template; | ||
776 | size = sizeof(struct ieee80211_header); | ||
777 | |||
778 | memset(template.header.da, 0xff, ETH_ALEN); | ||
779 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
780 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
781 | template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
782 | |||
783 | /* IEs */ | ||
784 | /* SSID */ | ||
785 | template.ssid.header.id = WLAN_EID_SSID; | ||
786 | template.ssid.header.len = ssid_len; | ||
787 | if (ssid_len && ssid) | ||
788 | memcpy(template.ssid.ssid, ssid, ssid_len); | ||
789 | size += sizeof(struct wl12xx_ie_header) + ssid_len; | ||
790 | ptr += size; | ||
791 | |||
792 | /* Basic Rates */ | ||
793 | rates = (struct wl12xx_ie_rates *)ptr; | ||
794 | rates->header.id = WLAN_EID_SUPP_RATES; | ||
795 | rates->header.len = wl12xx_build_basic_rates(rates->rates); | ||
796 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
797 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
798 | |||
799 | /* Extended rates */ | ||
800 | rates = (struct wl12xx_ie_rates *)ptr; | ||
801 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | ||
802 | rates->header.len = wl12xx_build_extended_rates(rates->rates); | ||
803 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
804 | |||
805 | wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | ||
806 | |||
807 | return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, | ||
808 | size); | ||
809 | } | ||
810 | |||
811 | static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, | ||
812 | u8 active_scan, u8 high_prio, u8 num_channels, | ||
813 | u8 probe_requests) | ||
814 | { | ||
815 | int i, ret; | ||
816 | u32 split_scan = 0; | ||
817 | u16 scan_options = 0; | ||
818 | struct cmd_scan *params; | ||
819 | struct wl12xx_command *cmd_answer; | ||
820 | |||
821 | if (wl->scanning) | ||
822 | return -EINVAL; | ||
823 | |||
824 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
825 | if (!params) | ||
826 | return -ENOMEM; | ||
827 | |||
828 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
829 | params->params.rx_filter_options = | ||
830 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
831 | |||
832 | /* High priority scan */ | ||
833 | if (!active_scan) | ||
834 | scan_options |= SCAN_PASSIVE; | ||
835 | if (high_prio) | ||
836 | scan_options |= SCAN_PRIORITY_HIGH; | ||
837 | params->params.scan_options = scan_options; | ||
838 | |||
839 | params->params.num_channels = num_channels; | ||
840 | params->params.num_probe_requests = probe_requests; | ||
841 | params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
842 | params->params.tid_trigger = 0; | ||
843 | |||
844 | for (i = 0; i < num_channels; i++) { | ||
845 | params->channels[i].min_duration = cpu_to_le32(30000); | ||
846 | params->channels[i].max_duration = cpu_to_le32(60000); | ||
847 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | ||
848 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | ||
849 | params->channels[i].early_termination = 0; | ||
850 | params->channels[i].tx_power_att = 0; | ||
851 | params->channels[i].channel = i + 1; | ||
852 | memset(params->channels[i].pad, 0, 3); | ||
853 | } | ||
854 | |||
855 | for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) | ||
856 | memset(¶ms->channels[i], 0, | ||
857 | sizeof(struct basic_scan_channel_parameters)); | ||
858 | |||
859 | if (len && ssid) { | ||
860 | params->params.ssid_len = len; | ||
861 | memcpy(params->params.ssid, ssid, len); | ||
862 | } else { | ||
863 | params->params.ssid_len = 0; | ||
864 | memset(params->params.ssid, 0, 32); | ||
865 | } | ||
866 | |||
867 | ret = wl12xx_build_probe_req(wl, ssid, len); | ||
868 | if (ret < 0) { | ||
869 | wl12xx_error("PROBE request template failed"); | ||
870 | goto out; | ||
871 | } | ||
872 | |||
873 | ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan, | ||
874 | sizeof(u32)); | ||
875 | if (ret < 0) { | ||
876 | wl12xx_error("Split SCAN failed"); | ||
877 | goto out; | ||
878 | } | ||
879 | |||
880 | wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | ||
881 | |||
882 | wl->scanning = true; | ||
883 | |||
884 | ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | ||
885 | if (ret < 0) | ||
886 | wl12xx_error("SCAN failed"); | ||
887 | |||
888 | wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | ||
889 | |||
890 | cmd_answer = (struct wl12xx_command *) params; | ||
891 | if (cmd_answer->status != CMD_STATUS_SUCCESS) { | ||
892 | wl12xx_error("TEST command answer error: %d", | ||
893 | cmd_answer->status); | ||
894 | wl->scanning = false; | ||
895 | ret = -EIO; | ||
896 | goto out; | ||
897 | } | ||
898 | |||
899 | out: | ||
900 | kfree(params); | ||
901 | return ret; | ||
902 | |||
903 | } | ||
904 | |||
905 | static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, | ||
906 | struct cfg80211_scan_request *req) | ||
907 | { | ||
908 | struct wl12xx *wl = hw->priv; | ||
909 | int ret; | ||
910 | u8 *ssid = NULL; | ||
911 | size_t ssid_len = 0; | ||
912 | |||
913 | wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
914 | |||
915 | if (req->n_ssids) { | ||
916 | ssid = req->ssids[0].ssid; | ||
917 | ssid_len = req->ssids[0].ssid_len; | ||
918 | } | ||
919 | |||
920 | mutex_lock(&wl->mutex); | ||
921 | ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); | ||
922 | mutex_unlock(&wl->mutex); | ||
923 | |||
924 | return ret; | ||
925 | } | ||
926 | |||
927 | static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
928 | { | ||
929 | struct wl12xx *wl = hw->priv; | ||
930 | int ret; | ||
931 | |||
932 | ret = wl12xx_acx_rts_threshold(wl, (u16) value); | ||
933 | |||
934 | if (ret < 0) | ||
935 | wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); | ||
936 | |||
937 | return ret; | ||
938 | } | ||
939 | |||
940 | static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, | ||
941 | struct ieee80211_vif *vif, | ||
942 | struct ieee80211_bss_conf *bss_conf, | ||
943 | u32 changed) | ||
944 | { | ||
945 | enum acx_ps_mode mode; | ||
946 | struct wl12xx *wl = hw->priv; | ||
947 | struct sk_buff *beacon; | ||
948 | int ret; | ||
949 | |||
950 | wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | ||
951 | |||
952 | mutex_lock(&wl->mutex); | ||
953 | |||
954 | if (changed & BSS_CHANGED_ASSOC) { | ||
955 | if (bss_conf->assoc) { | ||
956 | wl->aid = bss_conf->aid; | ||
957 | |||
958 | ret = wl12xx_build_ps_poll(wl, wl->aid); | ||
959 | if (ret < 0) | ||
960 | goto out; | ||
961 | |||
962 | ret = wl12xx_acx_aid(wl, wl->aid); | ||
963 | if (ret < 0) | ||
964 | goto out; | ||
965 | |||
966 | /* If we want to go in PSM but we're not there yet */ | ||
967 | if (wl->psm_requested && !wl->psm) { | ||
968 | mode = STATION_POWER_SAVE_MODE; | ||
969 | ret = wl12xx_ps_set_mode(wl, mode); | ||
970 | if (ret < 0) | ||
971 | goto out; | ||
972 | } | ||
973 | } | ||
974 | } | ||
975 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
976 | if (bss_conf->use_short_slot) | ||
977 | ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); | ||
978 | else | ||
979 | ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); | ||
980 | if (ret < 0) { | ||
981 | wl12xx_warning("Set slot time failed %d", ret); | ||
982 | goto out; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
987 | if (bss_conf->use_short_preamble) | ||
988 | wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); | ||
989 | else | ||
990 | wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); | ||
991 | } | ||
992 | |||
993 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
994 | if (bss_conf->use_cts_prot) | ||
995 | ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); | ||
996 | else | ||
997 | ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); | ||
998 | if (ret < 0) { | ||
999 | wl12xx_warning("Set ctsprotect failed %d", ret); | ||
1000 | goto out; | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | if (changed & BSS_CHANGED_BSSID) { | ||
1005 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | ||
1006 | |||
1007 | ret = wl12xx_build_null_data(wl); | ||
1008 | if (ret < 0) | ||
1009 | goto out; | ||
1010 | |||
1011 | if (wl->bss_type != BSS_TYPE_IBSS) { | ||
1012 | ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1); | ||
1013 | if (ret < 0) | ||
1014 | goto out; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | if (changed & BSS_CHANGED_BEACON) { | ||
1019 | beacon = ieee80211_beacon_get(hw, vif); | ||
1020 | ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, | ||
1021 | beacon->len); | ||
1022 | |||
1023 | if (ret < 0) { | ||
1024 | dev_kfree_skb(beacon); | ||
1025 | goto out; | ||
1026 | } | ||
1027 | |||
1028 | ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, | ||
1029 | beacon->len); | ||
1030 | |||
1031 | dev_kfree_skb(beacon); | ||
1032 | |||
1033 | if (ret < 0) | ||
1034 | goto out; | ||
1035 | |||
1036 | ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
1037 | |||
1038 | if (ret < 0) | ||
1039 | goto out; | ||
1040 | } | ||
1041 | |||
1042 | out: | ||
1043 | mutex_unlock(&wl->mutex); | ||
1044 | } | ||
1045 | |||
1046 | |||
1047 | /* can't be const, mac80211 writes to this */ | ||
1048 | static struct ieee80211_rate wl12xx_rates[] = { | ||
1049 | { .bitrate = 10, | ||
1050 | .hw_value = 0x1, | ||
1051 | .hw_value_short = 0x1, }, | ||
1052 | { .bitrate = 20, | ||
1053 | .hw_value = 0x2, | ||
1054 | .hw_value_short = 0x2, | ||
1055 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1056 | { .bitrate = 55, | ||
1057 | .hw_value = 0x4, | ||
1058 | .hw_value_short = 0x4, | ||
1059 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1060 | { .bitrate = 110, | ||
1061 | .hw_value = 0x20, | ||
1062 | .hw_value_short = 0x20, | ||
1063 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1064 | { .bitrate = 60, | ||
1065 | .hw_value = 0x8, | ||
1066 | .hw_value_short = 0x8, }, | ||
1067 | { .bitrate = 90, | ||
1068 | .hw_value = 0x10, | ||
1069 | .hw_value_short = 0x10, }, | ||
1070 | { .bitrate = 120, | ||
1071 | .hw_value = 0x40, | ||
1072 | .hw_value_short = 0x40, }, | ||
1073 | { .bitrate = 180, | ||
1074 | .hw_value = 0x80, | ||
1075 | .hw_value_short = 0x80, }, | ||
1076 | { .bitrate = 240, | ||
1077 | .hw_value = 0x200, | ||
1078 | .hw_value_short = 0x200, }, | ||
1079 | { .bitrate = 360, | ||
1080 | .hw_value = 0x400, | ||
1081 | .hw_value_short = 0x400, }, | ||
1082 | { .bitrate = 480, | ||
1083 | .hw_value = 0x800, | ||
1084 | .hw_value_short = 0x800, }, | ||
1085 | { .bitrate = 540, | ||
1086 | .hw_value = 0x1000, | ||
1087 | .hw_value_short = 0x1000, }, | ||
1088 | }; | ||
1089 | |||
1090 | /* can't be const, mac80211 writes to this */ | ||
1091 | static struct ieee80211_channel wl12xx_channels[] = { | ||
1092 | { .hw_value = 1, .center_freq = 2412}, | ||
1093 | { .hw_value = 2, .center_freq = 2417}, | ||
1094 | { .hw_value = 3, .center_freq = 2422}, | ||
1095 | { .hw_value = 4, .center_freq = 2427}, | ||
1096 | { .hw_value = 5, .center_freq = 2432}, | ||
1097 | { .hw_value = 6, .center_freq = 2437}, | ||
1098 | { .hw_value = 7, .center_freq = 2442}, | ||
1099 | { .hw_value = 8, .center_freq = 2447}, | ||
1100 | { .hw_value = 9, .center_freq = 2452}, | ||
1101 | { .hw_value = 10, .center_freq = 2457}, | ||
1102 | { .hw_value = 11, .center_freq = 2462}, | ||
1103 | { .hw_value = 12, .center_freq = 2467}, | ||
1104 | { .hw_value = 13, .center_freq = 2472}, | ||
1105 | }; | ||
1106 | |||
1107 | /* can't be const, mac80211 writes to this */ | ||
1108 | static struct ieee80211_supported_band wl12xx_band_2ghz = { | ||
1109 | .channels = wl12xx_channels, | ||
1110 | .n_channels = ARRAY_SIZE(wl12xx_channels), | ||
1111 | .bitrates = wl12xx_rates, | ||
1112 | .n_bitrates = ARRAY_SIZE(wl12xx_rates), | ||
1113 | }; | ||
1114 | |||
1115 | static const struct ieee80211_ops wl12xx_ops = { | ||
1116 | .start = wl12xx_op_start, | ||
1117 | .stop = wl12xx_op_stop, | ||
1118 | .add_interface = wl12xx_op_add_interface, | ||
1119 | .remove_interface = wl12xx_op_remove_interface, | ||
1120 | .config = wl12xx_op_config, | ||
1121 | .configure_filter = wl12xx_op_configure_filter, | ||
1122 | .tx = wl12xx_op_tx, | ||
1123 | .set_key = wl12xx_op_set_key, | ||
1124 | .hw_scan = wl12xx_op_hw_scan, | ||
1125 | .bss_info_changed = wl12xx_op_bss_info_changed, | ||
1126 | .set_rts_threshold = wl12xx_op_set_rts_threshold, | ||
1127 | }; | ||
1128 | |||
1129 | static int wl12xx_register_hw(struct wl12xx *wl) | ||
1130 | { | ||
1131 | int ret; | ||
1132 | |||
1133 | if (wl->mac80211_registered) | ||
1134 | return 0; | ||
1135 | |||
1136 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
1137 | |||
1138 | ret = ieee80211_register_hw(wl->hw); | ||
1139 | if (ret < 0) { | ||
1140 | wl12xx_error("unable to register mac80211 hw: %d", ret); | ||
1141 | return ret; | ||
1142 | } | ||
1143 | |||
1144 | wl->mac80211_registered = true; | ||
1145 | |||
1146 | wl12xx_notice("loaded"); | ||
1147 | |||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | static int wl12xx_init_ieee80211(struct wl12xx *wl) | ||
1152 | { | ||
1153 | /* The tx descriptor buffer and the TKIP space */ | ||
1154 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) | ||
1155 | + WL12XX_TKIP_IV_SPACE; | ||
1156 | |||
1157 | /* unit us */ | ||
1158 | /* FIXME: find a proper value */ | ||
1159 | wl->hw->channel_change_time = 10000; | ||
1160 | |||
1161 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
1162 | IEEE80211_HW_NOISE_DBM; | ||
1163 | |||
1164 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
1165 | wl->hw->wiphy->max_scan_ssids = 1; | ||
1166 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; | ||
1167 | |||
1168 | SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); | ||
1169 | |||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | #define WL12XX_DEFAULT_CHANNEL 1 | ||
1174 | static int __devinit wl12xx_probe(struct spi_device *spi) | ||
1175 | { | ||
1176 | struct wl12xx_platform_data *pdata; | ||
1177 | struct ieee80211_hw *hw; | ||
1178 | struct wl12xx *wl; | ||
1179 | int ret, i; | ||
1180 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
1181 | |||
1182 | pdata = spi->dev.platform_data; | ||
1183 | if (!pdata) { | ||
1184 | wl12xx_error("no platform data"); | ||
1185 | return -ENODEV; | ||
1186 | } | ||
1187 | |||
1188 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); | ||
1189 | if (!hw) { | ||
1190 | wl12xx_error("could not alloc ieee80211_hw"); | ||
1191 | return -ENOMEM; | ||
1192 | } | ||
1193 | |||
1194 | wl = hw->priv; | ||
1195 | memset(wl, 0, sizeof(*wl)); | ||
1196 | |||
1197 | wl->hw = hw; | ||
1198 | dev_set_drvdata(&spi->dev, wl); | ||
1199 | wl->spi = spi; | ||
1200 | |||
1201 | wl->data_in_count = 0; | ||
1202 | |||
1203 | skb_queue_head_init(&wl->tx_queue); | ||
1204 | |||
1205 | INIT_WORK(&wl->tx_work, wl12xx_tx_work); | ||
1206 | INIT_WORK(&wl->filter_work, wl12xx_filter_work); | ||
1207 | wl->channel = WL12XX_DEFAULT_CHANNEL; | ||
1208 | wl->scanning = false; | ||
1209 | wl->default_key = 0; | ||
1210 | wl->listen_int = 1; | ||
1211 | wl->rx_counter = 0; | ||
1212 | wl->rx_handled = 0; | ||
1213 | wl->rx_current_buffer = 0; | ||
1214 | wl->rx_last_id = 0; | ||
1215 | wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; | ||
1216 | wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; | ||
1217 | wl->elp = false; | ||
1218 | wl->psm = 0; | ||
1219 | wl->psm_requested = false; | ||
1220 | wl->tx_queue_stopped = false; | ||
1221 | wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; | ||
1222 | |||
1223 | /* We use the default power on sleep time until we know which chip | ||
1224 | * we're using */ | ||
1225 | wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; | ||
1226 | |||
1227 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
1228 | wl->tx_frames[i] = NULL; | ||
1229 | |||
1230 | wl->next_tx_complete = 0; | ||
1231 | |||
1232 | /* | ||
1233 | * In case our MAC address is not correctly set, | ||
1234 | * we use a random but Nokia MAC. | ||
1235 | */ | ||
1236 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
1237 | get_random_bytes(wl->mac_addr + 3, 3); | ||
1238 | |||
1239 | wl->state = WL12XX_STATE_OFF; | ||
1240 | mutex_init(&wl->mutex); | ||
1241 | |||
1242 | wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; | ||
1243 | wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; | ||
1244 | |||
1245 | /* This is the only SPI value that we need to set here, the rest | ||
1246 | * comes from the board-peripherals file */ | ||
1247 | spi->bits_per_word = 32; | ||
1248 | |||
1249 | ret = spi_setup(spi); | ||
1250 | if (ret < 0) { | ||
1251 | wl12xx_error("spi_setup failed"); | ||
1252 | goto out_free; | ||
1253 | } | ||
1254 | |||
1255 | wl->set_power = pdata->set_power; | ||
1256 | if (!wl->set_power) { | ||
1257 | wl12xx_error("set power function missing in platform data"); | ||
1258 | return -ENODEV; | ||
1259 | } | ||
1260 | |||
1261 | wl->irq = spi->irq; | ||
1262 | if (wl->irq < 0) { | ||
1263 | wl12xx_error("irq missing in platform data"); | ||
1264 | return -ENODEV; | ||
1265 | } | ||
1266 | |||
1267 | ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); | ||
1268 | if (ret < 0) { | ||
1269 | wl12xx_error("request_irq() failed: %d", ret); | ||
1270 | goto out_free; | ||
1271 | } | ||
1272 | |||
1273 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
1274 | |||
1275 | disable_irq(wl->irq); | ||
1276 | |||
1277 | ret = wl12xx_init_ieee80211(wl); | ||
1278 | if (ret) | ||
1279 | goto out_irq; | ||
1280 | |||
1281 | ret = wl12xx_register_hw(wl); | ||
1282 | if (ret) | ||
1283 | goto out_irq; | ||
1284 | |||
1285 | wl12xx_debugfs_init(wl); | ||
1286 | |||
1287 | wl12xx_notice("initialized"); | ||
1288 | |||
1289 | return 0; | ||
1290 | |||
1291 | out_irq: | ||
1292 | free_irq(wl->irq, wl); | ||
1293 | |||
1294 | out_free: | ||
1295 | ieee80211_free_hw(hw); | ||
1296 | |||
1297 | return ret; | ||
1298 | } | ||
1299 | |||
1300 | static int __devexit wl12xx_remove(struct spi_device *spi) | ||
1301 | { | ||
1302 | struct wl12xx *wl = dev_get_drvdata(&spi->dev); | ||
1303 | |||
1304 | ieee80211_unregister_hw(wl->hw); | ||
1305 | |||
1306 | wl12xx_debugfs_exit(wl); | ||
1307 | |||
1308 | free_irq(wl->irq, wl); | ||
1309 | kfree(wl->target_mem_map); | ||
1310 | kfree(wl->data_path); | ||
1311 | kfree(wl->fw); | ||
1312 | wl->fw = NULL; | ||
1313 | kfree(wl->nvs); | ||
1314 | wl->nvs = NULL; | ||
1315 | ieee80211_free_hw(wl->hw); | ||
1316 | |||
1317 | return 0; | ||
1318 | } | ||
1319 | |||
1320 | |||
1321 | static struct spi_driver wl12xx_spi_driver = { | ||
1322 | .driver = { | ||
1323 | .name = "wl12xx", | ||
1324 | .bus = &spi_bus_type, | ||
1325 | .owner = THIS_MODULE, | ||
1326 | }, | ||
1327 | |||
1328 | .probe = wl12xx_probe, | ||
1329 | .remove = __devexit_p(wl12xx_remove), | ||
1330 | }; | ||
1331 | |||
1332 | static int __init wl12xx_init(void) | ||
1333 | { | ||
1334 | int ret; | ||
1335 | |||
1336 | ret = spi_register_driver(&wl12xx_spi_driver); | ||
1337 | if (ret < 0) { | ||
1338 | wl12xx_error("failed to register spi driver: %d", ret); | ||
1339 | goto out; | ||
1340 | } | ||
1341 | |||
1342 | out: | ||
1343 | return ret; | ||
1344 | } | ||
1345 | |||
1346 | static void __exit wl12xx_exit(void) | ||
1347 | { | ||
1348 | spi_unregister_driver(&wl12xx_spi_driver); | ||
1349 | |||
1350 | wl12xx_notice("unloaded"); | ||
1351 | } | ||
1352 | |||
1353 | module_init(wl12xx_init); | ||
1354 | module_exit(wl12xx_exit); | ||
1355 | |||
1356 | MODULE_LICENSE("GPL"); | ||
1357 | MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, " | ||
1358 | "Luciano Coelho <luciano.coelho@nokia.com>"); | ||
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c new file mode 100644 index 000000000000..83a10117330b --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "reg.h" | ||
25 | #include "ps.h" | ||
26 | #include "spi.h" | ||
27 | |||
28 | #define WL12XX_WAKEUP_TIMEOUT 2000 | ||
29 | |||
30 | /* Routines to toggle sleep mode while in ELP */ | ||
31 | void wl12xx_ps_elp_sleep(struct wl12xx *wl) | ||
32 | { | ||
33 | if (wl->elp || !wl->psm) | ||
34 | return; | ||
35 | |||
36 | wl12xx_debug(DEBUG_PSM, "chip to elp"); | ||
37 | |||
38 | wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
39 | |||
40 | wl->elp = true; | ||
41 | } | ||
42 | |||
43 | int wl12xx_ps_elp_wakeup(struct wl12xx *wl) | ||
44 | { | ||
45 | unsigned long timeout; | ||
46 | u32 elp_reg; | ||
47 | |||
48 | if (!wl->elp) | ||
49 | return 0; | ||
50 | |||
51 | wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); | ||
52 | |||
53 | timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); | ||
54 | |||
55 | wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | ||
56 | |||
57 | elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
58 | |||
59 | /* | ||
60 | * FIXME: we should wait for irq from chip but, as a temporary | ||
61 | * solution to simplify locking, let's poll instead | ||
62 | */ | ||
63 | while (!(elp_reg & ELPCTRL_WLAN_READY)) { | ||
64 | if (time_after(jiffies, timeout)) { | ||
65 | wl12xx_error("elp wakeup timeout"); | ||
66 | return -ETIMEDOUT; | ||
67 | } | ||
68 | msleep(1); | ||
69 | elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
70 | } | ||
71 | |||
72 | wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", | ||
73 | jiffies_to_msecs(jiffies) - | ||
74 | (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); | ||
75 | |||
76 | wl->elp = false; | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) | ||
82 | { | ||
83 | int ret; | ||
84 | |||
85 | if (enable) { | ||
86 | wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); | ||
87 | |||
88 | /* | ||
89 | * FIXME: we should PSM_ELP, but because of firmware wakeup | ||
90 | * problems let's use only PSM_PS | ||
91 | */ | ||
92 | ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS); | ||
93 | if (ret < 0) | ||
94 | return ret; | ||
95 | |||
96 | wl12xx_ps_elp_sleep(wl); | ||
97 | } else { | ||
98 | wl12xx_debug(DEBUG_PSM, "sleep auth cam"); | ||
99 | |||
100 | /* | ||
101 | * When the target is in ELP, we can only | ||
102 | * access the ELP control register. Thus, | ||
103 | * we have to wake the target up before | ||
104 | * changing the power authorization. | ||
105 | */ | ||
106 | |||
107 | wl12xx_ps_elp_wakeup(wl); | ||
108 | |||
109 | ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); | ||
110 | if (ret < 0) | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode) | ||
118 | { | ||
119 | int ret; | ||
120 | |||
121 | switch (mode) { | ||
122 | case STATION_POWER_SAVE_MODE: | ||
123 | wl12xx_debug(DEBUG_PSM, "entering psm"); | ||
124 | ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | ret = wl12xx_ps_set_elp(wl, true); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | wl->psm = 1; | ||
133 | break; | ||
134 | case STATION_ACTIVE_MODE: | ||
135 | default: | ||
136 | wl12xx_debug(DEBUG_PSM, "leaving psm"); | ||
137 | ret = wl12xx_ps_set_elp(wl, false); | ||
138 | if (ret < 0) | ||
139 | return ret; | ||
140 | |||
141 | ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); | ||
142 | if (ret < 0) | ||
143 | return ret; | ||
144 | |||
145 | wl->psm = 0; | ||
146 | break; | ||
147 | } | ||
148 | |||
149 | return ret; | ||
150 | } | ||
151 | |||
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h new file mode 100644 index 000000000000..5d7c52553830 --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.h | |||
@@ -0,0 +1,36 @@ | |||
1 | #ifndef __WL12XX_PS_H__ | ||
2 | #define __WL12XX_PS_H__ | ||
3 | |||
4 | /* | ||
5 | * This file is part of wl12xx | ||
6 | * | ||
7 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
8 | * Copyright (C) 2008 Nokia Corporation | ||
9 | * | ||
10 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * version 2 as published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but | ||
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
24 | * 02110-1301 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "acx.h" | ||
30 | |||
31 | int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode); | ||
32 | void wl12xx_ps_elp_sleep(struct wl12xx *wl); | ||
33 | int wl12xx_ps_elp_wakeup(struct wl12xx *wl); | ||
34 | |||
35 | |||
36 | #endif /* __WL12XX_PS_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h new file mode 100644 index 000000000000..e421643215cd --- /dev/null +++ b/drivers/net/wireless/wl12xx/reg.h | |||
@@ -0,0 +1,745 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __REG_H__ | ||
26 | #define __REG_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | #include "wl12xx.h" | ||
30 | |||
31 | #define REGISTERS_BASE 0x00300000 | ||
32 | #define DRPW_BASE 0x00310000 | ||
33 | |||
34 | #define REGISTERS_DOWN_SIZE 0x00008800 | ||
35 | #define REGISTERS_WORK_SIZE 0x0000b000 | ||
36 | |||
37 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | ||
38 | |||
39 | /* ELP register commands */ | ||
40 | #define ELPCTRL_WAKE_UP 0x1 | ||
41 | #define ELPCTRL_WAKE_UP_WLAN_READY 0x5 | ||
42 | #define ELPCTRL_SLEEP 0x0 | ||
43 | /* ELP WLAN_READY bit */ | ||
44 | #define ELPCTRL_WLAN_READY 0x2 | ||
45 | |||
46 | /* | ||
47 | * Interrupt registers. | ||
48 | * 64 bit interrupt sources registers ws ced. | ||
49 | * sme interupts were removed and new ones were added. | ||
50 | * Order was changed. | ||
51 | */ | ||
52 | #define FIQ_MASK (REGISTERS_BASE + 0x0400) | ||
53 | #define FIQ_MASK_L (REGISTERS_BASE + 0x0400) | ||
54 | #define FIQ_MASK_H (REGISTERS_BASE + 0x0404) | ||
55 | #define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) | ||
56 | #define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) | ||
57 | #define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) | ||
58 | #define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) | ||
59 | #define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) | ||
60 | #define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) | ||
61 | #define IRQ_MASK (REGISTERS_BASE + 0x0418) | ||
62 | #define IRQ_MASK_L (REGISTERS_BASE + 0x0418) | ||
63 | #define IRQ_MASK_H (REGISTERS_BASE + 0x041C) | ||
64 | #define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) | ||
65 | #define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) | ||
66 | #define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) | ||
67 | #define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) | ||
68 | #define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) | ||
69 | #define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) | ||
70 | #define ECPU_MASK (REGISTERS_BASE + 0x0448) | ||
71 | #define FIQ_STS_L (REGISTERS_BASE + 0x044C) | ||
72 | #define FIQ_STS_H (REGISTERS_BASE + 0x0450) | ||
73 | #define IRQ_STS_L (REGISTERS_BASE + 0x0454) | ||
74 | #define IRQ_STS_H (REGISTERS_BASE + 0x0458) | ||
75 | #define INT_STS_ND (REGISTERS_BASE + 0x0464) | ||
76 | #define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) | ||
77 | #define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) | ||
78 | #define INT_STS_CLR (REGISTERS_BASE + 0x04B4) | ||
79 | #define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) | ||
80 | #define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) | ||
81 | #define INT_ACK (REGISTERS_BASE + 0x046C) | ||
82 | #define INT_ACK_L (REGISTERS_BASE + 0x046C) | ||
83 | #define INT_ACK_H (REGISTERS_BASE + 0x0470) | ||
84 | #define INT_TRIG (REGISTERS_BASE + 0x0474) | ||
85 | #define INT_TRIG_L (REGISTERS_BASE + 0x0474) | ||
86 | #define INT_TRIG_H (REGISTERS_BASE + 0x0478) | ||
87 | #define HOST_STS_L (REGISTERS_BASE + 0x045C) | ||
88 | #define HOST_STS_H (REGISTERS_BASE + 0x0460) | ||
89 | #define HOST_MASK (REGISTERS_BASE + 0x0430) | ||
90 | #define HOST_MASK_L (REGISTERS_BASE + 0x0430) | ||
91 | #define HOST_MASK_H (REGISTERS_BASE + 0x0434) | ||
92 | #define HOST_MASK_SET (REGISTERS_BASE + 0x0438) | ||
93 | #define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) | ||
94 | #define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) | ||
95 | #define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) | ||
96 | #define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) | ||
97 | #define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) | ||
98 | |||
99 | /* Host Interrupts*/ | ||
100 | #define HINT_MASK (REGISTERS_BASE + 0x0494) | ||
101 | #define HINT_MASK_SET (REGISTERS_BASE + 0x0498) | ||
102 | #define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) | ||
103 | #define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) | ||
104 | /*1150 spec calls this HINT_STS_RAW*/ | ||
105 | #define HINT_STS_ND (REGISTERS_BASE + 0x04B0) | ||
106 | #define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) | ||
107 | #define HINT_ACK (REGISTERS_BASE + 0x04A8) | ||
108 | #define HINT_TRIG (REGISTERS_BASE + 0x04AC) | ||
109 | |||
110 | /* Device Configuration registers*/ | ||
111 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
112 | #define ECPU_CTRL (REGISTERS_BASE + 0x0804) | ||
113 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
114 | #define EE_START (REGISTERS_BASE + 0x080C) | ||
115 | |||
116 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
117 | |||
118 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
119 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
120 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
121 | |||
122 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
123 | |||
124 | /* Power Management registers */ | ||
125 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
126 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
127 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
128 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
129 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
130 | |||
131 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
132 | |||
133 | /* Scratch Pad registers*/ | ||
134 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
135 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
136 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
137 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
138 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
139 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
140 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
141 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
142 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
143 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
144 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
145 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
146 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
147 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
148 | |||
149 | /* Spare registers*/ | ||
150 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
151 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
152 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
153 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
154 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
155 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
156 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
157 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
158 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
159 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
160 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
161 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
162 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
163 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
164 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
165 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
166 | |||
167 | enum wl12xx_acx_int_reg { | ||
168 | ACX_REG_INTERRUPT_TRIG, | ||
169 | ACX_REG_INTERRUPT_TRIG_H, | ||
170 | |||
171 | /*============================================= | ||
172 | Host Interrupt Mask Register - 32bit (RW) | ||
173 | ------------------------------------------ | ||
174 | Setting a bit in this register masks the | ||
175 | corresponding interrupt to the host. | ||
176 | 0 - RX0 - Rx first dubble buffer Data Interrupt | ||
177 | 1 - TXD - Tx Data Interrupt | ||
178 | 2 - TXXFR - Tx Transfer Interrupt | ||
179 | 3 - RX1 - Rx second dubble buffer Data Interrupt | ||
180 | 4 - RXXFR - Rx Transfer Interrupt | ||
181 | 5 - EVENT_A - Event Mailbox interrupt | ||
182 | 6 - EVENT_B - Event Mailbox interrupt | ||
183 | 7 - WNONHST - Wake On Host Interrupt | ||
184 | 8 - TRACE_A - Debug Trace interrupt | ||
185 | 9 - TRACE_B - Debug Trace interrupt | ||
186 | 10 - CDCMP - Command Complete Interrupt | ||
187 | 11 - | ||
188 | 12 - | ||
189 | 13 - | ||
190 | 14 - ICOMP - Initialization Complete Interrupt | ||
191 | 16 - SG SE - Soft Gemini - Sense enable interrupt | ||
192 | 17 - SG SD - Soft Gemini - Sense disable interrupt | ||
193 | 18 - - | ||
194 | 19 - - | ||
195 | 20 - - | ||
196 | 21- - | ||
197 | Default: 0x0001 | ||
198 | *==============================================*/ | ||
199 | ACX_REG_INTERRUPT_MASK, | ||
200 | |||
201 | /*============================================= | ||
202 | Host Interrupt Mask Set 16bit, (Write only) | ||
203 | ------------------------------------------ | ||
204 | Setting a bit in this register sets | ||
205 | the corresponding bin in ACX_HINT_MASK register | ||
206 | without effecting the mask | ||
207 | state of other bits (0 = no effect). | ||
208 | ==============================================*/ | ||
209 | ACX_REG_HINT_MASK_SET, | ||
210 | |||
211 | /*============================================= | ||
212 | Host Interrupt Mask Clear 16bit,(Write only) | ||
213 | ------------------------------------------ | ||
214 | Setting a bit in this register clears | ||
215 | the corresponding bin in ACX_HINT_MASK register | ||
216 | without effecting the mask | ||
217 | state of other bits (0 = no effect). | ||
218 | =============================================*/ | ||
219 | ACX_REG_HINT_MASK_CLR, | ||
220 | |||
221 | /*============================================= | ||
222 | Host Interrupt Status Nondestructive Read | ||
223 | 16bit,(Read only) | ||
224 | ------------------------------------------ | ||
225 | The host can read this register to determine | ||
226 | which interrupts are active. | ||
227 | Reading this register doesn't | ||
228 | effect its content. | ||
229 | =============================================*/ | ||
230 | ACX_REG_INTERRUPT_NO_CLEAR, | ||
231 | |||
232 | /*============================================= | ||
233 | Host Interrupt Status Clear on Read Register | ||
234 | 16bit,(Read only) | ||
235 | ------------------------------------------ | ||
236 | The host can read this register to determine | ||
237 | which interrupts are active. | ||
238 | Reading this register clears it, | ||
239 | thus making all interrupts inactive. | ||
240 | ==============================================*/ | ||
241 | ACX_REG_INTERRUPT_CLEAR, | ||
242 | |||
243 | /*============================================= | ||
244 | Host Interrupt Acknowledge Register | ||
245 | 16bit,(Write only) | ||
246 | ------------------------------------------ | ||
247 | The host can set individual bits in this | ||
248 | register to clear (acknowledge) the corresp. | ||
249 | interrupt status bits in the HINT_STS_CLR and | ||
250 | HINT_STS_ND registers, thus making the | ||
251 | assotiated interrupt inactive. (0-no effect) | ||
252 | ==============================================*/ | ||
253 | ACX_REG_INTERRUPT_ACK, | ||
254 | |||
255 | /*=============================================== | ||
256 | Host Software Reset - 32bit RW | ||
257 | ------------------------------------------ | ||
258 | [31:1] Reserved | ||
259 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
260 | it holds the Wlan hardware in a soft reset state. | ||
261 | This reset disables all MAC and baseband processor | ||
262 | clocks except the CardBus/PCI interface clock. | ||
263 | It also initializes all MAC state machines except | ||
264 | the host interface. It does not reload the | ||
265 | contents of the EEPROM. When this bit is cleared | ||
266 | (not self-clearing), the Wlan hardware | ||
267 | exits the software reset state. | ||
268 | ===============================================*/ | ||
269 | ACX_REG_SLV_SOFT_RESET, | ||
270 | |||
271 | /*=============================================== | ||
272 | EEPROM Burst Read Start - 32bit RW | ||
273 | ------------------------------------------ | ||
274 | [31:1] Reserved | ||
275 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
276 | Setting this bit starts a burst read from | ||
277 | the external EEPROM. | ||
278 | If this bit is set (after reset) before an EEPROM read/write, | ||
279 | the burst read starts at EEPROM address 0. | ||
280 | Otherwise, it starts at the address | ||
281 | following the address of the previous access. | ||
282 | TheWlan hardware hardware clears this bit automatically. | ||
283 | |||
284 | Default: 0x00000000 | ||
285 | *================================================*/ | ||
286 | ACX_REG_EE_START, | ||
287 | |||
288 | /* Embedded ARM CPU Control */ | ||
289 | |||
290 | /*=============================================== | ||
291 | Halt eCPU - 32bit RW | ||
292 | ------------------------------------------ | ||
293 | 0 HALT_ECPU Halt Embedded CPU - This bit is the | ||
294 | compliment of bit 1 (MDATA2) in the SOR_CFG register. | ||
295 | During a hardware reset, this bit holds | ||
296 | the inverse of MDATA2. | ||
297 | When downloading firmware from the host, | ||
298 | set this bit (pull down MDATA2). | ||
299 | The host clears this bit after downloading the firmware into | ||
300 | zero-wait-state SSRAM. | ||
301 | When loading firmware from Flash, clear this bit (pull up MDATA2) | ||
302 | so that the eCPU can run the bootloader code in Flash | ||
303 | HALT_ECPU eCPU State | ||
304 | -------------------- | ||
305 | 1 halt eCPU | ||
306 | 0 enable eCPU | ||
307 | ===============================================*/ | ||
308 | ACX_REG_ECPU_CONTROL, | ||
309 | |||
310 | ACX_REG_TABLE_LEN | ||
311 | }; | ||
312 | |||
313 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) | ||
314 | #define ACX_REG_EEPROM_START_BIT BIT(1) | ||
315 | |||
316 | /* Command/Information Mailbox Pointers */ | ||
317 | |||
318 | /*=============================================== | ||
319 | Command Mailbox Pointer - 32bit RW | ||
320 | ------------------------------------------ | ||
321 | This register holds the start address of | ||
322 | the command mailbox located in the Wlan hardware memory. | ||
323 | The host must read this pointer after a reset to | ||
324 | find the location of the command mailbox. | ||
325 | The Wlan hardware initializes the command mailbox | ||
326 | pointer with the default address of the command mailbox. | ||
327 | The command mailbox pointer is not valid until after | ||
328 | the host receives the Init Complete interrupt from | ||
329 | the Wlan hardware. | ||
330 | ===============================================*/ | ||
331 | #define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) | ||
332 | |||
333 | /*=============================================== | ||
334 | Information Mailbox Pointer - 32bit RW | ||
335 | ------------------------------------------ | ||
336 | This register holds the start address of | ||
337 | the information mailbox located in the Wlan hardware memory. | ||
338 | The host must read this pointer after a reset to find | ||
339 | the location of the information mailbox. | ||
340 | The Wlan hardware initializes the information mailbox pointer | ||
341 | with the default address of the information mailbox. | ||
342 | The information mailbox pointer is not valid | ||
343 | until after the host receives the Init Complete interrupt from | ||
344 | the Wlan hardware. | ||
345 | ===============================================*/ | ||
346 | #define REG_EVENT_MAILBOX_PTR (SCR_PAD1) | ||
347 | |||
348 | |||
349 | /* Misc */ | ||
350 | |||
351 | #define REG_ENABLE_TX_RX (ENABLE) | ||
352 | /* | ||
353 | * Rx configuration (filter) information element | ||
354 | * --------------------------------------------- | ||
355 | */ | ||
356 | #define REG_RX_CONFIG (RX_CFG) | ||
357 | #define REG_RX_FILTER (RX_FILTER_CFG) | ||
358 | |||
359 | |||
360 | #define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 | ||
361 | |||
362 | /* promiscuous - receives all valid frames */ | ||
363 | #define RX_CFG_PROMISCUOUS 0x0008 | ||
364 | |||
365 | /* receives frames from any BSSID */ | ||
366 | #define RX_CFG_BSSID 0x0020 | ||
367 | |||
368 | /* receives frames destined to any MAC address */ | ||
369 | #define RX_CFG_MAC 0x0010 | ||
370 | |||
371 | #define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 | ||
372 | #define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 | ||
373 | #define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 | ||
374 | #define RX_CFG_ENABLE_ANY_BSSID 0x0000 | ||
375 | |||
376 | /* discards all broadcast frames */ | ||
377 | #define RX_CFG_DISABLE_BCAST 0x0200 | ||
378 | |||
379 | #define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 | ||
380 | #define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 | ||
381 | #define RX_CFG_COPY_RX_STATUS 0x2000 | ||
382 | #define RX_CFG_TSF 0x10000 | ||
383 | |||
384 | #define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
385 | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
386 | |||
387 | #define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
388 | | RX_CFG_ENABLE_ANY_BSSID) | ||
389 | |||
390 | #define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
391 | RX_CFG_ENABLE_ANY_BSSID) | ||
392 | |||
393 | #define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
394 | | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
395 | |||
396 | #define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ | ||
397 | | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ | ||
398 | | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) | ||
399 | |||
400 | #define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) | ||
401 | |||
402 | #define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ | ||
403 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
404 | |||
405 | #define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ | ||
406 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
407 | |||
408 | #define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
409 | | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ | ||
410 | | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||
411 | |||
412 | #define RX_FILTER_OPTION_FILTER_ALL 0 | ||
413 | |||
414 | #define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ | ||
415 | | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) | ||
416 | |||
417 | #define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
418 | | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ | ||
419 | | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ | ||
420 | | CFG_RX_PRSP_EN) | ||
421 | |||
422 | |||
423 | /*=============================================== | ||
424 | Phy regs | ||
425 | ===============================================*/ | ||
426 | #define ACX_PHY_ADDR_REG SBB_ADDR | ||
427 | #define ACX_PHY_DATA_REG SBB_DATA | ||
428 | #define ACX_PHY_CTRL_REG SBB_CTL | ||
429 | #define ACX_PHY_REG_WR_MASK 0x00000001ul | ||
430 | #define ACX_PHY_REG_RD_MASK 0x00000002ul | ||
431 | |||
432 | |||
433 | /*=============================================== | ||
434 | EEPROM Read/Write Request 32bit RW | ||
435 | ------------------------------------------ | ||
436 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit | ||
437 | loads a single byte of data into the EE_DATA | ||
438 | register from the EEPROM location specified in | ||
439 | the EE_ADDR register. | ||
440 | The Wlan hardware hardware clears this bit automatically. | ||
441 | EE_DATA is valid when this bit is cleared. | ||
442 | |||
443 | 0 EE_WRITE - EEPROM Write Request - Setting this bit | ||
444 | writes a single byte of data from the EE_DATA register into the | ||
445 | EEPROM location specified in the EE_ADDR register. | ||
446 | The Wlan hardware hardware clears this bit automatically. | ||
447 | *===============================================*/ | ||
448 | #define ACX_EE_CTL_REG EE_CTL | ||
449 | #define EE_WRITE 0x00000001ul | ||
450 | #define EE_READ 0x00000002ul | ||
451 | |||
452 | /*=============================================== | ||
453 | EEPROM Address - 32bit RW | ||
454 | ------------------------------------------ | ||
455 | This register specifies the address | ||
456 | within the EEPROM from/to which to read/write data. | ||
457 | ===============================================*/ | ||
458 | #define ACX_EE_ADDR_REG EE_ADDR | ||
459 | |||
460 | /*=============================================== | ||
461 | EEPROM Data - 32bit RW | ||
462 | ------------------------------------------ | ||
463 | This register either holds the read 8 bits of | ||
464 | data from the EEPROM or the write data | ||
465 | to be written to the EEPROM. | ||
466 | ===============================================*/ | ||
467 | #define ACX_EE_DATA_REG EE_DATA | ||
468 | |||
469 | /*=============================================== | ||
470 | EEPROM Base Address - 32bit RW | ||
471 | ------------------------------------------ | ||
472 | This register holds the upper nine bits | ||
473 | [23:15] of the 24-bit Wlan hardware memory | ||
474 | address for burst reads from EEPROM accesses. | ||
475 | The EEPROM provides the lower 15 bits of this address. | ||
476 | The MSB of the address from the EEPROM is ignored. | ||
477 | ===============================================*/ | ||
478 | #define ACX_EE_CFG EE_CFG | ||
479 | |||
480 | /*=============================================== | ||
481 | GPIO Output Values -32bit, RW | ||
482 | ------------------------------------------ | ||
483 | [31:16] Reserved | ||
484 | [15: 0] Specify the output values (at the output driver inputs) for | ||
485 | GPIO[15:0], respectively. | ||
486 | ===============================================*/ | ||
487 | #define ACX_GPIO_OUT_REG GPIO_OUT | ||
488 | #define ACX_MAX_GPIO_LINES 15 | ||
489 | |||
490 | /*=============================================== | ||
491 | Contention window -32bit, RW | ||
492 | ------------------------------------------ | ||
493 | [31:26] Reserved | ||
494 | [25:16] Max (0x3ff) | ||
495 | [15:07] Reserved | ||
496 | [06:00] Current contention window value - default is 0x1F | ||
497 | ===============================================*/ | ||
498 | #define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG | ||
499 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f | ||
500 | #define ACX_CONT_WIND_MAX 0x03ff0000 | ||
501 | |||
502 | /* | ||
503 | * Indirect slave register/memory registers | ||
504 | * ---------------------------------------- | ||
505 | */ | ||
506 | #define HW_SLAVE_REG_ADDR_REG 0x00000004 | ||
507 | #define HW_SLAVE_REG_DATA_REG 0x00000008 | ||
508 | #define HW_SLAVE_REG_CTRL_REG 0x0000000c | ||
509 | |||
510 | #define SLAVE_AUTO_INC 0x00010000 | ||
511 | #define SLAVE_NO_AUTO_INC 0x00000000 | ||
512 | #define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 | ||
513 | |||
514 | #define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR | ||
515 | #define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA | ||
516 | #define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL | ||
517 | #define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL | ||
518 | |||
519 | #define HW_FUNC_EVENT_INT_EN 0x8000 | ||
520 | #define HW_FUNC_EVENT_MASK_REG 0x00000034 | ||
521 | |||
522 | #define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) | ||
523 | |||
524 | /*=============================================== | ||
525 | HI_CFG Interface Configuration Register Values | ||
526 | ------------------------------------------ | ||
527 | ===============================================*/ | ||
528 | #define HI_CFG_UART_ENABLE 0x00000004 | ||
529 | #define HI_CFG_RST232_ENABLE 0x00000008 | ||
530 | #define HI_CFG_CLOCK_REQ_SELECT 0x00000010 | ||
531 | #define HI_CFG_HOST_INT_ENABLE 0x00000020 | ||
532 | #define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 | ||
533 | #define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 | ||
534 | #define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 | ||
535 | #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 | ||
536 | #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 | ||
537 | |||
538 | /* | ||
539 | * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile | ||
540 | * for platforms using active high interrupt level | ||
541 | */ | ||
542 | #ifdef USE_ACTIVE_HIGH | ||
543 | #define HI_CFG_DEF_VAL \ | ||
544 | (HI_CFG_UART_ENABLE | \ | ||
545 | HI_CFG_RST232_ENABLE | \ | ||
546 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
547 | HI_CFG_HOST_INT_ENABLE) | ||
548 | #else | ||
549 | #define HI_CFG_DEF_VAL \ | ||
550 | (HI_CFG_UART_ENABLE | \ | ||
551 | HI_CFG_RST232_ENABLE | \ | ||
552 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
553 | HI_CFG_HOST_INT_ENABLE) | ||
554 | |||
555 | #endif | ||
556 | |||
557 | #define REF_FREQ_19_2 0 | ||
558 | #define REF_FREQ_26_0 1 | ||
559 | #define REF_FREQ_38_4 2 | ||
560 | #define REF_FREQ_40_0 3 | ||
561 | #define REF_FREQ_33_6 4 | ||
562 | #define REF_FREQ_NUM 5 | ||
563 | |||
564 | #define LUT_PARAM_INTEGER_DIVIDER 0 | ||
565 | #define LUT_PARAM_FRACTIONAL_DIVIDER 1 | ||
566 | #define LUT_PARAM_ATTN_BB 2 | ||
567 | #define LUT_PARAM_ALPHA_BB 3 | ||
568 | #define LUT_PARAM_STOP_TIME_BB 4 | ||
569 | #define LUT_PARAM_BB_PLL_LOOP_FILTER 5 | ||
570 | #define LUT_PARAM_NUM 6 | ||
571 | |||
572 | #define ACX_EEPROMLESS_IND_REG (SCR_PAD4) | ||
573 | #define USE_EEPROM 0 | ||
574 | #define SOFT_RESET_MAX_TIME 1000000 | ||
575 | #define SOFT_RESET_STALL_TIME 1000 | ||
576 | #define NVS_DATA_BUNDARY_ALIGNMENT 4 | ||
577 | |||
578 | |||
579 | /* Firmware image load chunk size */ | ||
580 | #define CHUNK_SIZE 512 | ||
581 | |||
582 | /* Firmware image header size */ | ||
583 | #define FW_HDR_SIZE 8 | ||
584 | |||
585 | #define ECPU_CONTROL_HALT 0x00000101 | ||
586 | |||
587 | |||
588 | /****************************************************************************** | ||
589 | |||
590 | CHANNELS, BAND & REG DOMAINS definitions | ||
591 | |||
592 | ******************************************************************************/ | ||
593 | |||
594 | |||
595 | enum { | ||
596 | RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ | ||
597 | RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ | ||
598 | RADIO_BAND_JAPAN_4_9_GHZ = 2, | ||
599 | DEFAULT_BAND = RADIO_BAND_2_4GHZ, | ||
600 | INVALID_BAND = 0xFE, | ||
601 | MAX_RADIO_BANDS = 0xFF | ||
602 | }; | ||
603 | |||
604 | enum { | ||
605 | NO_RATE = 0, | ||
606 | RATE_1MBPS = 0x0A, | ||
607 | RATE_2MBPS = 0x14, | ||
608 | RATE_5_5MBPS = 0x37, | ||
609 | RATE_6MBPS = 0x0B, | ||
610 | RATE_9MBPS = 0x0F, | ||
611 | RATE_11MBPS = 0x6E, | ||
612 | RATE_12MBPS = 0x0A, | ||
613 | RATE_18MBPS = 0x0E, | ||
614 | RATE_22MBPS = 0xDC, | ||
615 | RATE_24MBPS = 0x09, | ||
616 | RATE_36MBPS = 0x0D, | ||
617 | RATE_48MBPS = 0x08, | ||
618 | RATE_54MBPS = 0x0C | ||
619 | }; | ||
620 | |||
621 | enum { | ||
622 | RATE_INDEX_1MBPS = 0, | ||
623 | RATE_INDEX_2MBPS = 1, | ||
624 | RATE_INDEX_5_5MBPS = 2, | ||
625 | RATE_INDEX_6MBPS = 3, | ||
626 | RATE_INDEX_9MBPS = 4, | ||
627 | RATE_INDEX_11MBPS = 5, | ||
628 | RATE_INDEX_12MBPS = 6, | ||
629 | RATE_INDEX_18MBPS = 7, | ||
630 | RATE_INDEX_22MBPS = 8, | ||
631 | RATE_INDEX_24MBPS = 9, | ||
632 | RATE_INDEX_36MBPS = 10, | ||
633 | RATE_INDEX_48MBPS = 11, | ||
634 | RATE_INDEX_54MBPS = 12, | ||
635 | RATE_INDEX_MAX = RATE_INDEX_54MBPS, | ||
636 | MAX_RATE_INDEX, | ||
637 | INVALID_RATE_INDEX = MAX_RATE_INDEX, | ||
638 | RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF | ||
639 | }; | ||
640 | |||
641 | enum { | ||
642 | RATE_MASK_1MBPS = 0x1, | ||
643 | RATE_MASK_2MBPS = 0x2, | ||
644 | RATE_MASK_5_5MBPS = 0x4, | ||
645 | RATE_MASK_11MBPS = 0x20, | ||
646 | }; | ||
647 | |||
648 | #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ | ||
649 | #define OFDM_RATE_BIT BIT(6) | ||
650 | #define PBCC_RATE_BIT BIT(7) | ||
651 | |||
652 | enum { | ||
653 | CCK_LONG = 0, | ||
654 | CCK_SHORT = SHORT_PREAMBLE_BIT, | ||
655 | PBCC_LONG = PBCC_RATE_BIT, | ||
656 | PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, | ||
657 | OFDM = OFDM_RATE_BIT | ||
658 | }; | ||
659 | |||
660 | /****************************************************************************** | ||
661 | |||
662 | Transmit-Descriptor RATE-SET field definitions... | ||
663 | |||
664 | Define a new "Rate-Set" for TX path that incorporates the | ||
665 | Rate & Modulation info into a single 16-bit field. | ||
666 | |||
667 | TxdRateSet_t: | ||
668 | b15 - Indicates Preamble type (1=SHORT, 0=LONG). | ||
669 | Notes: | ||
670 | Must be LONG (0) for 1Mbps rate. | ||
671 | Does not apply (set to 0) for RevG-OFDM rates. | ||
672 | b14 - Indicates PBCC encoding (1=PBCC, 0=not). | ||
673 | Notes: | ||
674 | Does not apply (set to 0) for rates 1 and 2 Mbps. | ||
675 | Does not apply (set to 0) for RevG-OFDM rates. | ||
676 | b13 - Unused (set to 0). | ||
677 | b12-b0 - Supported Rate indicator bits as defined below. | ||
678 | |||
679 | ******************************************************************************/ | ||
680 | |||
681 | |||
682 | #define TNETW1251_CHIP_ID_PG1_0 0x07010101 | ||
683 | #define TNETW1251_CHIP_ID_PG1_1 0x07020101 | ||
684 | #define TNETW1251_CHIP_ID_PG1_2 0x07030101 | ||
685 | |||
686 | /************************************************************************* | ||
687 | |||
688 | Interrupt Trigger Register (Host -> WiLink) | ||
689 | |||
690 | **************************************************************************/ | ||
691 | |||
692 | /* Hardware to Embedded CPU Interrupts - first 32-bit register set */ | ||
693 | |||
694 | /* | ||
695 | * Host Command Interrupt. Setting this bit masks | ||
696 | * the interrupt that the host issues to inform | ||
697 | * the FW that it has sent a command | ||
698 | * to the Wlan hardware Command Mailbox. | ||
699 | */ | ||
700 | #define INTR_TRIG_CMD BIT(0) | ||
701 | |||
702 | /* | ||
703 | * Host Event Acknowlegde Interrupt. The host | ||
704 | * sets this bit to acknowledge that it received | ||
705 | * the unsolicited information from the event | ||
706 | * mailbox. | ||
707 | */ | ||
708 | #define INTR_TRIG_EVENT_ACK BIT(1) | ||
709 | |||
710 | /* | ||
711 | * The host sets this bit to inform the Wlan | ||
712 | * FW that a TX packet is in the XFER | ||
713 | * Buffer #0. | ||
714 | */ | ||
715 | #define INTR_TRIG_TX_PROC0 BIT(2) | ||
716 | |||
717 | /* | ||
718 | * The host sets this bit to inform the FW | ||
719 | * that it read a packet from RX XFER | ||
720 | * Buffer #0. | ||
721 | */ | ||
722 | #define INTR_TRIG_RX_PROC0 BIT(3) | ||
723 | |||
724 | #define INTR_TRIG_DEBUG_ACK BIT(4) | ||
725 | |||
726 | #define INTR_TRIG_STATE_CHANGED BIT(5) | ||
727 | |||
728 | |||
729 | /* Hardware to Embedded CPU Interrupts - second 32-bit register set */ | ||
730 | |||
731 | /* | ||
732 | * The host sets this bit to inform the FW | ||
733 | * that it read a packet from RX XFER | ||
734 | * Buffer #1. | ||
735 | */ | ||
736 | #define INTR_TRIG_RX_PROC1 BIT(17) | ||
737 | |||
738 | /* | ||
739 | * The host sets this bit to inform the Wlan | ||
740 | * hardware that a TX packet is in the XFER | ||
741 | * Buffer #1. | ||
742 | */ | ||
743 | #define INTR_TRIG_TX_PROC1 BIT(18) | ||
744 | |||
745 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c new file mode 100644 index 000000000000..981ea259eb89 --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/skbuff.h> | ||
26 | #include <net/mac80211.h> | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "reg.h" | ||
30 | #include "spi.h" | ||
31 | #include "rx.h" | ||
32 | |||
33 | static void wl12xx_rx_header(struct wl12xx *wl, | ||
34 | struct wl12xx_rx_descriptor *desc) | ||
35 | { | ||
36 | u32 rx_packet_ring_addr; | ||
37 | |||
38 | rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; | ||
39 | if (wl->rx_current_buffer) | ||
40 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | ||
41 | |||
42 | wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, | ||
43 | sizeof(struct wl12xx_rx_descriptor)); | ||
44 | } | ||
45 | |||
46 | static void wl12xx_rx_status(struct wl12xx *wl, | ||
47 | struct wl12xx_rx_descriptor *desc, | ||
48 | struct ieee80211_rx_status *status, | ||
49 | u8 beacon) | ||
50 | { | ||
51 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | ||
52 | |||
53 | status->band = IEEE80211_BAND_2GHZ; | ||
54 | status->mactime = desc->timestamp; | ||
55 | |||
56 | /* | ||
57 | * The rx status timestamp is a 32 bits value while the TSF is a | ||
58 | * 64 bits one. | ||
59 | * For IBSS merging, TSF is mandatory, so we have to get it | ||
60 | * somehow, so we ask for ACX_TSF_INFO. | ||
61 | * That could be moved to the get_tsf() hook, but unfortunately, | ||
62 | * this one must be atomic, while our SPI routines can sleep. | ||
63 | */ | ||
64 | if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { | ||
65 | u64 mactime; | ||
66 | int ret; | ||
67 | struct wl12xx_command cmd; | ||
68 | struct acx_tsf_info *tsf_info; | ||
69 | |||
70 | memset(&cmd, 0, sizeof(cmd)); | ||
71 | |||
72 | ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, | ||
73 | sizeof(struct acx_tsf_info), | ||
74 | &cmd); | ||
75 | if (ret < 0) { | ||
76 | wl12xx_warning("ACX_FW_REV interrogate failed"); | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | tsf_info = (struct acx_tsf_info *)&(cmd.parameters); | ||
81 | |||
82 | mactime = tsf_info->current_tsf_lsb | | ||
83 | (tsf_info->current_tsf_msb << 31); | ||
84 | |||
85 | status->mactime = mactime; | ||
86 | } | ||
87 | |||
88 | status->signal = desc->rssi; | ||
89 | status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / | ||
90 | (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); | ||
91 | status->qual = min(status->qual, 100); | ||
92 | status->qual = max(status->qual, 0); | ||
93 | |||
94 | /* | ||
95 | * FIXME: guessing that snr needs to be divided by two, otherwise | ||
96 | * the values don't make any sense | ||
97 | */ | ||
98 | status->noise = desc->rssi - desc->snr / 2; | ||
99 | |||
100 | status->freq = ieee80211_channel_to_frequency(desc->channel); | ||
101 | |||
102 | status->flag |= RX_FLAG_TSFT; | ||
103 | |||
104 | if (desc->flags & RX_DESC_ENCRYPTION_MASK) { | ||
105 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; | ||
106 | |||
107 | if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) | ||
108 | status->flag |= RX_FLAG_DECRYPTED; | ||
109 | |||
110 | if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) | ||
111 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
112 | } | ||
113 | |||
114 | if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) | ||
115 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
116 | |||
117 | |||
118 | /* FIXME: set status->rate_idx */ | ||
119 | } | ||
120 | |||
121 | static void wl12xx_rx_body(struct wl12xx *wl, | ||
122 | struct wl12xx_rx_descriptor *desc) | ||
123 | { | ||
124 | struct sk_buff *skb; | ||
125 | struct ieee80211_rx_status status; | ||
126 | u8 *rx_buffer, beacon = 0; | ||
127 | u16 length, *fc; | ||
128 | u32 curr_id, last_id_inc, rx_packet_ring_addr; | ||
129 | |||
130 | length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); | ||
131 | curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; | ||
132 | last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); | ||
133 | |||
134 | if (last_id_inc != curr_id) { | ||
135 | wl12xx_warning("curr ID:%d, last ID inc:%d", | ||
136 | curr_id, last_id_inc); | ||
137 | wl->rx_last_id = curr_id; | ||
138 | } else { | ||
139 | wl->rx_last_id = last_id_inc; | ||
140 | } | ||
141 | |||
142 | rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + | ||
143 | sizeof(struct wl12xx_rx_descriptor) + 20; | ||
144 | if (wl->rx_current_buffer) | ||
145 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | ||
146 | |||
147 | skb = dev_alloc_skb(length); | ||
148 | if (!skb) { | ||
149 | wl12xx_error("Couldn't allocate RX frame"); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | rx_buffer = skb_put(skb, length); | ||
154 | wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); | ||
155 | |||
156 | /* The actual lenght doesn't include the target's alignment */ | ||
157 | skb->len = desc->length - PLCP_HEADER_LENGTH; | ||
158 | |||
159 | fc = (u16 *)skb->data; | ||
160 | |||
161 | if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) | ||
162 | beacon = 1; | ||
163 | |||
164 | wl12xx_rx_status(wl, desc, &status, beacon); | ||
165 | |||
166 | wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, | ||
167 | beacon ? "beacon" : ""); | ||
168 | |||
169 | ieee80211_rx(wl->hw, skb, &status); | ||
170 | } | ||
171 | |||
172 | static void wl12xx_rx_ack(struct wl12xx *wl) | ||
173 | { | ||
174 | u32 data, addr; | ||
175 | |||
176 | if (wl->rx_current_buffer) { | ||
177 | addr = ACX_REG_INTERRUPT_TRIG_H; | ||
178 | data = INTR_TRIG_RX_PROC1; | ||
179 | } else { | ||
180 | addr = ACX_REG_INTERRUPT_TRIG; | ||
181 | data = INTR_TRIG_RX_PROC0; | ||
182 | } | ||
183 | |||
184 | wl12xx_reg_write32(wl, addr, data); | ||
185 | |||
186 | /* Toggle buffer ring */ | ||
187 | wl->rx_current_buffer = !wl->rx_current_buffer; | ||
188 | } | ||
189 | |||
190 | |||
191 | void wl12xx_rx(struct wl12xx *wl) | ||
192 | { | ||
193 | struct wl12xx_rx_descriptor rx_desc; | ||
194 | |||
195 | if (wl->state != WL12XX_STATE_ON) | ||
196 | return; | ||
197 | |||
198 | /* We first read the frame's header */ | ||
199 | wl12xx_rx_header(wl, &rx_desc); | ||
200 | |||
201 | /* Now we can read the body */ | ||
202 | wl12xx_rx_body(wl, &rx_desc); | ||
203 | |||
204 | /* Finally, we need to ACK the RX */ | ||
205 | wl12xx_rx_ack(wl); | ||
206 | |||
207 | return; | ||
208 | } | ||
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h new file mode 100644 index 000000000000..8a23fdea5016 --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_RX_H__ | ||
26 | #define __WL12XX_RX_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | /* | ||
31 | * RX PATH | ||
32 | * | ||
33 | * The Rx path uses a double buffer and an rx_contro structure, each located | ||
34 | * at a fixed address in the device memory. The host keeps track of which | ||
35 | * buffer is available and alternates between them on a per packet basis. | ||
36 | * The size of each of the two buffers is large enough to hold the longest | ||
37 | * 802.3 packet. | ||
38 | * The RX path goes like that: | ||
39 | * 1) The target generates an interrupt each time a new packet is received. | ||
40 | * There are 2 RX interrupts, one for each buffer. | ||
41 | * 2) The host reads the received packet from one of the double buffers. | ||
42 | * 3) The host triggers a target interrupt. | ||
43 | * 4) The target prepares the next RX packet. | ||
44 | */ | ||
45 | |||
46 | #define WL12XX_RX_MAX_RSSI -30 | ||
47 | #define WL12XX_RX_MIN_RSSI -95 | ||
48 | |||
49 | #define WL12XX_RX_ALIGN_TO 4 | ||
50 | #define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ | ||
51 | ~(WL12XX_RX_ALIGN_TO - 1)) | ||
52 | |||
53 | #define SHORT_PREAMBLE_BIT BIT(0) | ||
54 | #define OFDM_RATE_BIT BIT(6) | ||
55 | #define PBCC_RATE_BIT BIT(7) | ||
56 | |||
57 | #define PLCP_HEADER_LENGTH 8 | ||
58 | #define RX_DESC_PACKETID_SHIFT 11 | ||
59 | #define RX_MAX_PACKET_ID 3 | ||
60 | |||
61 | #define RX_DESC_VALID_FCS 0x0001 | ||
62 | #define RX_DESC_MATCH_RXADDR1 0x0002 | ||
63 | #define RX_DESC_MCAST 0x0004 | ||
64 | #define RX_DESC_STAINTIM 0x0008 | ||
65 | #define RX_DESC_VIRTUAL_BM 0x0010 | ||
66 | #define RX_DESC_BCAST 0x0020 | ||
67 | #define RX_DESC_MATCH_SSID 0x0040 | ||
68 | #define RX_DESC_MATCH_BSSID 0x0080 | ||
69 | #define RX_DESC_ENCRYPTION_MASK 0x0300 | ||
70 | #define RX_DESC_MEASURMENT 0x0400 | ||
71 | #define RX_DESC_SEQNUM_MASK 0x1800 | ||
72 | #define RX_DESC_MIC_FAIL 0x2000 | ||
73 | #define RX_DESC_DECRYPT_FAIL 0x4000 | ||
74 | |||
75 | struct wl12xx_rx_descriptor { | ||
76 | u32 timestamp; /* In microseconds */ | ||
77 | u16 length; /* Paylod length, including headers */ | ||
78 | u16 flags; | ||
79 | |||
80 | /* | ||
81 | * 0 - 802.11 | ||
82 | * 1 - 802.3 | ||
83 | * 2 - IP | ||
84 | * 3 - Raw Codec | ||
85 | */ | ||
86 | u8 type; | ||
87 | |||
88 | /* | ||
89 | * Recevied Rate: | ||
90 | * 0x0A - 1MBPS | ||
91 | * 0x14 - 2MBPS | ||
92 | * 0x37 - 5_5MBPS | ||
93 | * 0x0B - 6MBPS | ||
94 | * 0x0F - 9MBPS | ||
95 | * 0x6E - 11MBPS | ||
96 | * 0x0A - 12MBPS | ||
97 | * 0x0E - 18MBPS | ||
98 | * 0xDC - 22MBPS | ||
99 | * 0x09 - 24MBPS | ||
100 | * 0x0D - 36MBPS | ||
101 | * 0x08 - 48MBPS | ||
102 | * 0x0C - 54MBPS | ||
103 | */ | ||
104 | u8 rate; | ||
105 | |||
106 | u8 mod_pre; /* Modulation and preamble */ | ||
107 | u8 channel; | ||
108 | |||
109 | /* | ||
110 | * 0 - 2.4 Ghz | ||
111 | * 1 - 5 Ghz | ||
112 | */ | ||
113 | u8 band; | ||
114 | |||
115 | s8 rssi; /* in dB */ | ||
116 | u8 rcpi; /* in dB */ | ||
117 | u8 snr; /* in dB */ | ||
118 | } __attribute__ ((packed)); | ||
119 | |||
120 | void wl12xx_rx(struct wl12xx *wl); | ||
121 | |||
122 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c new file mode 100644 index 000000000000..abdf171a47e7 --- /dev/null +++ b/drivers/net/wireless/wl12xx/spi.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/crc7.h> | ||
26 | #include <linux/spi/spi.h> | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "wl12xx_80211.h" | ||
30 | #include "reg.h" | ||
31 | #include "spi.h" | ||
32 | #include "ps.h" | ||
33 | |||
34 | static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) | ||
35 | { | ||
36 | /* If the address is lower than REGISTERS_BASE, it means that this is | ||
37 | * a chip-specific register address, so look it up in the registers | ||
38 | * table */ | ||
39 | if (addr < REGISTERS_BASE) { | ||
40 | /* Make sure we don't go over the table */ | ||
41 | if (addr >= ACX_REG_TABLE_LEN) { | ||
42 | wl12xx_error("address out of range (%d)", addr); | ||
43 | return -EINVAL; | ||
44 | } | ||
45 | addr = wl->chip.acx_reg_table[addr]; | ||
46 | } | ||
47 | |||
48 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | ||
49 | } | ||
50 | |||
51 | static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) | ||
52 | { | ||
53 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | ||
54 | } | ||
55 | |||
56 | |||
57 | void wl12xx_spi_reset(struct wl12xx *wl) | ||
58 | { | ||
59 | u8 *cmd; | ||
60 | struct spi_transfer t; | ||
61 | struct spi_message m; | ||
62 | |||
63 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
64 | if (!cmd) { | ||
65 | wl12xx_error("could not allocate cmd for spi reset"); | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | memset(&t, 0, sizeof(t)); | ||
70 | spi_message_init(&m); | ||
71 | |||
72 | memset(cmd, 0xff, WSPI_INIT_CMD_LEN); | ||
73 | |||
74 | t.tx_buf = cmd; | ||
75 | t.len = WSPI_INIT_CMD_LEN; | ||
76 | spi_message_add_tail(&t, &m); | ||
77 | |||
78 | spi_sync(wl->spi, &m); | ||
79 | |||
80 | wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | ||
81 | } | ||
82 | |||
83 | void wl12xx_spi_init(struct wl12xx *wl) | ||
84 | { | ||
85 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | ||
86 | struct spi_transfer t; | ||
87 | struct spi_message m; | ||
88 | |||
89 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
90 | if (!cmd) { | ||
91 | wl12xx_error("could not allocate cmd for spi init"); | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | memset(crc, 0, sizeof(crc)); | ||
96 | memset(&t, 0, sizeof(t)); | ||
97 | spi_message_init(&m); | ||
98 | |||
99 | /* | ||
100 | * Set WSPI_INIT_COMMAND | ||
101 | * the data is being send from the MSB to LSB | ||
102 | */ | ||
103 | cmd[2] = 0xff; | ||
104 | cmd[3] = 0xff; | ||
105 | cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; | ||
106 | cmd[0] = 0; | ||
107 | cmd[7] = 0; | ||
108 | cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; | ||
109 | cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; | ||
110 | |||
111 | if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) | ||
112 | cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; | ||
113 | else | ||
114 | cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; | ||
115 | |||
116 | cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS | ||
117 | | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; | ||
118 | |||
119 | crc[0] = cmd[1]; | ||
120 | crc[1] = cmd[0]; | ||
121 | crc[2] = cmd[7]; | ||
122 | crc[3] = cmd[6]; | ||
123 | crc[4] = cmd[5]; | ||
124 | |||
125 | cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; | ||
126 | cmd[4] |= WSPI_INIT_CMD_END; | ||
127 | |||
128 | t.tx_buf = cmd; | ||
129 | t.len = WSPI_INIT_CMD_LEN; | ||
130 | spi_message_add_tail(&t, &m); | ||
131 | |||
132 | spi_sync(wl->spi, &m); | ||
133 | |||
134 | wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | ||
135 | } | ||
136 | |||
137 | /* Set the SPI partitions to access the chip addresses | ||
138 | * | ||
139 | * There are two VIRTUAL (SPI) partitions (the memory partition and the | ||
140 | * registers partition), which are mapped to two different areas of the | ||
141 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
142 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
143 | * memory partition comes before the register partition, but the opposite is | ||
144 | * also supported. | ||
145 | * | ||
146 | * PHYSICAL address | ||
147 | * space | ||
148 | * | ||
149 | * | | | ||
150 | * ...+----+--> mem_start | ||
151 | * VIRTUAL address ... | | | ||
152 | * space ... | | [PART_0] | ||
153 | * ... | | | ||
154 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
155 | * | | ... | | | ||
156 | * |MEM | ... | | | ||
157 | * | | ... | | | ||
158 | * part_size <--+----+... | | {unused area) | ||
159 | * | | ... | | | ||
160 | * |REG | ... | | | ||
161 | * part_size | | ... | | | ||
162 | * + <--+----+... ...+----+--> reg_start | ||
163 | * reg_size ... | | | ||
164 | * ... | | [PART_1] | ||
165 | * ... | | | ||
166 | * ...+----+--> reg_start + reg_size | ||
167 | * | | | ||
168 | * | ||
169 | */ | ||
170 | void wl12xx_set_partition(struct wl12xx *wl, | ||
171 | u32 mem_start, u32 mem_size, | ||
172 | u32 reg_start, u32 reg_size) | ||
173 | { | ||
174 | u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)]; | ||
175 | struct wl12xx_partition *partition; | ||
176 | struct spi_transfer t; | ||
177 | struct spi_message m; | ||
178 | u32 *cmd; | ||
179 | size_t len; | ||
180 | int addr; | ||
181 | |||
182 | spi_message_init(&m); | ||
183 | memset(&t, 0, sizeof(t)); | ||
184 | memset(tx_buf, 0, sizeof(tx_buf)); | ||
185 | |||
186 | cmd = (u32 *) tx_buf; | ||
187 | partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32)); | ||
188 | addr = HW_ACCESS_PART0_SIZE_ADDR; | ||
189 | len = 2 * sizeof(struct wl12xx_partition); | ||
190 | |||
191 | *cmd |= WSPI_CMD_WRITE; | ||
192 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
193 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
194 | |||
195 | wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
196 | mem_start, mem_size); | ||
197 | wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
198 | reg_start, reg_size); | ||
199 | |||
200 | /* Make sure that the two partitions together don't exceed the | ||
201 | * address range */ | ||
202 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
203 | wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
204 | " address range. Truncating partition[0]."); | ||
205 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
206 | wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
207 | mem_start, mem_size); | ||
208 | wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
209 | reg_start, reg_size); | ||
210 | } | ||
211 | |||
212 | if ((mem_start < reg_start) && | ||
213 | ((mem_start + mem_size) > reg_start)) { | ||
214 | /* Guarantee that the memory partition doesn't overlap the | ||
215 | * registers partition */ | ||
216 | wl12xx_debug(DEBUG_SPI, "End of partition[0] is " | ||
217 | "overlapping partition[1]. Adjusted."); | ||
218 | mem_size = reg_start - mem_start; | ||
219 | wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
220 | mem_start, mem_size); | ||
221 | wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
222 | reg_start, reg_size); | ||
223 | } else if ((reg_start < mem_start) && | ||
224 | ((reg_start + reg_size) > mem_start)) { | ||
225 | /* Guarantee that the register partition doesn't overlap the | ||
226 | * memory partition */ | ||
227 | wl12xx_debug(DEBUG_SPI, "End of partition[1] is" | ||
228 | " overlapping partition[0]. Adjusted."); | ||
229 | reg_size = mem_start - reg_start; | ||
230 | wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
231 | mem_start, mem_size); | ||
232 | wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
233 | reg_start, reg_size); | ||
234 | } | ||
235 | |||
236 | partition[0].start = mem_start; | ||
237 | partition[0].size = mem_size; | ||
238 | partition[1].start = reg_start; | ||
239 | partition[1].size = reg_size; | ||
240 | |||
241 | wl->physical_mem_addr = mem_start; | ||
242 | wl->physical_reg_addr = reg_start; | ||
243 | |||
244 | wl->virtual_mem_addr = 0; | ||
245 | wl->virtual_reg_addr = mem_size; | ||
246 | |||
247 | t.tx_buf = tx_buf; | ||
248 | t.len = sizeof(tx_buf); | ||
249 | spi_message_add_tail(&t, &m); | ||
250 | |||
251 | spi_sync(wl->spi, &m); | ||
252 | } | ||
253 | |||
254 | void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, | ||
255 | size_t len) | ||
256 | { | ||
257 | struct spi_transfer t[3]; | ||
258 | struct spi_message m; | ||
259 | char busy_buf[TNETWIF_READ_OFFSET_BYTES]; | ||
260 | u32 cmd; | ||
261 | |||
262 | cmd = 0; | ||
263 | cmd |= WSPI_CMD_READ; | ||
264 | cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
265 | cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
266 | |||
267 | spi_message_init(&m); | ||
268 | memset(t, 0, sizeof(t)); | ||
269 | |||
270 | t[0].tx_buf = &cmd; | ||
271 | t[0].len = 4; | ||
272 | spi_message_add_tail(&t[0], &m); | ||
273 | |||
274 | /* Busy and non busy words read */ | ||
275 | t[1].rx_buf = busy_buf; | ||
276 | t[1].len = TNETWIF_READ_OFFSET_BYTES; | ||
277 | spi_message_add_tail(&t[1], &m); | ||
278 | |||
279 | t[2].rx_buf = buf; | ||
280 | t[2].len = len; | ||
281 | spi_message_add_tail(&t[2], &m); | ||
282 | |||
283 | spi_sync(wl->spi, &m); | ||
284 | |||
285 | /* FIXME: check busy words */ | ||
286 | |||
287 | wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd)); | ||
288 | wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | ||
289 | } | ||
290 | |||
291 | void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, | ||
292 | size_t len) | ||
293 | { | ||
294 | struct spi_transfer t[2]; | ||
295 | struct spi_message m; | ||
296 | u32 cmd; | ||
297 | |||
298 | cmd = 0; | ||
299 | cmd |= WSPI_CMD_WRITE; | ||
300 | cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
301 | cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
302 | |||
303 | spi_message_init(&m); | ||
304 | memset(t, 0, sizeof(t)); | ||
305 | |||
306 | t[0].tx_buf = &cmd; | ||
307 | t[0].len = sizeof(cmd); | ||
308 | spi_message_add_tail(&t[0], &m); | ||
309 | |||
310 | t[1].tx_buf = buf; | ||
311 | t[1].len = len; | ||
312 | spi_message_add_tail(&t[1], &m); | ||
313 | |||
314 | spi_sync(wl->spi, &m); | ||
315 | |||
316 | wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd)); | ||
317 | wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | ||
318 | } | ||
319 | |||
320 | void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, | ||
321 | size_t len) | ||
322 | { | ||
323 | int physical; | ||
324 | |||
325 | physical = wl12xx_translate_mem_addr(wl, addr); | ||
326 | |||
327 | wl12xx_spi_read(wl, physical, buf, len); | ||
328 | } | ||
329 | |||
330 | void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, | ||
331 | size_t len) | ||
332 | { | ||
333 | int physical; | ||
334 | |||
335 | physical = wl12xx_translate_mem_addr(wl, addr); | ||
336 | |||
337 | wl12xx_spi_write(wl, physical, buf, len); | ||
338 | } | ||
339 | |||
340 | u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) | ||
341 | { | ||
342 | return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); | ||
343 | } | ||
344 | |||
345 | void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) | ||
346 | { | ||
347 | wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); | ||
348 | } | ||
349 | |||
350 | u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) | ||
351 | { | ||
352 | return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); | ||
353 | } | ||
354 | |||
355 | void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) | ||
356 | { | ||
357 | wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); | ||
358 | } | ||
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h new file mode 100644 index 000000000000..fd3227e904a8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/spi.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_SPI_H__ | ||
26 | #define __WL12XX_SPI_H__ | ||
27 | |||
28 | #include "cmd.h" | ||
29 | #include "acx.h" | ||
30 | #include "reg.h" | ||
31 | |||
32 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
33 | |||
34 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
35 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
36 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
37 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
38 | |||
39 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
40 | |||
41 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
42 | |||
43 | #define WSPI_CMD_READ 0x40000000 | ||
44 | #define WSPI_CMD_WRITE 0x00000000 | ||
45 | #define WSPI_CMD_FIXED 0x20000000 | ||
46 | #define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 | ||
47 | #define WSPI_CMD_BYTE_LENGTH_OFFSET 17 | ||
48 | #define WSPI_CMD_BYTE_ADDR 0x0001FFFF | ||
49 | |||
50 | #define WSPI_INIT_CMD_CRC_LEN 5 | ||
51 | |||
52 | #define WSPI_INIT_CMD_START 0x00 | ||
53 | #define WSPI_INIT_CMD_TX 0x40 | ||
54 | /* the extra bypass bit is sampled by the TNET as '1' */ | ||
55 | #define WSPI_INIT_CMD_BYPASS_BIT 0x80 | ||
56 | #define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 | ||
57 | #define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 | ||
58 | #define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 | ||
59 | #define WSPI_INIT_CMD_IOD 0x40 | ||
60 | #define WSPI_INIT_CMD_IP 0x20 | ||
61 | #define WSPI_INIT_CMD_CS 0x10 | ||
62 | #define WSPI_INIT_CMD_WS 0x08 | ||
63 | #define WSPI_INIT_CMD_WSPI 0x01 | ||
64 | #define WSPI_INIT_CMD_END 0x01 | ||
65 | |||
66 | #define WSPI_INIT_CMD_LEN 8 | ||
67 | |||
68 | #define TNETWIF_READ_OFFSET_BYTES 8 | ||
69 | #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ | ||
70 | ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32)) | ||
71 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | ||
72 | |||
73 | |||
74 | /* Raw target IO, address is not translated */ | ||
75 | void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len); | ||
76 | void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len); | ||
77 | |||
78 | /* Memory target IO, address is tranlated to partition 0 */ | ||
79 | void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); | ||
80 | void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); | ||
81 | u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); | ||
82 | void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); | ||
83 | |||
84 | /* Registers IO */ | ||
85 | u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); | ||
86 | void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); | ||
87 | |||
88 | /* INIT and RESET words */ | ||
89 | void wl12xx_spi_reset(struct wl12xx *wl); | ||
90 | void wl12xx_spi_init(struct wl12xx *wl); | ||
91 | void wl12xx_set_partition(struct wl12xx *wl, | ||
92 | u32 part_start, u32 part_size, | ||
93 | u32 reg_start, u32 reg_size); | ||
94 | |||
95 | static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) | ||
96 | { | ||
97 | u32 response; | ||
98 | |||
99 | wl12xx_spi_read(wl, addr, &response, sizeof(u32)); | ||
100 | |||
101 | return response; | ||
102 | } | ||
103 | |||
104 | static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) | ||
105 | { | ||
106 | wl12xx_spi_write(wl, addr, &val, sizeof(u32)); | ||
107 | } | ||
108 | |||
109 | #endif /* __WL12XX_SPI_H__ */ | ||
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c new file mode 100644 index 000000000000..62145e205a8c --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.c | |||
@@ -0,0 +1,557 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "reg.h" | ||
30 | #include "spi.h" | ||
31 | #include "tx.h" | ||
32 | #include "ps.h" | ||
33 | |||
34 | static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) | ||
35 | { | ||
36 | int used, data_in_count; | ||
37 | |||
38 | data_in_count = wl->data_in_count; | ||
39 | |||
40 | if (data_in_count < data_out_count) | ||
41 | /* data_in_count has wrapped */ | ||
42 | data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; | ||
43 | |||
44 | used = data_in_count - data_out_count; | ||
45 | |||
46 | WARN_ON(used < 0); | ||
47 | WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); | ||
48 | |||
49 | if (used >= DP_TX_PACKET_RING_CHUNK_NUM) | ||
50 | return true; | ||
51 | else | ||
52 | return false; | ||
53 | } | ||
54 | |||
55 | static int wl12xx_tx_path_status(struct wl12xx *wl) | ||
56 | { | ||
57 | u32 status, addr, data_out_count; | ||
58 | bool busy; | ||
59 | |||
60 | addr = wl->data_path->tx_control_addr; | ||
61 | status = wl12xx_mem_read32(wl, addr); | ||
62 | data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; | ||
63 | busy = wl12xx_tx_double_buffer_busy(wl, data_out_count); | ||
64 | |||
65 | if (busy) | ||
66 | return -EBUSY; | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb) | ||
72 | { | ||
73 | int i; | ||
74 | |||
75 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
76 | if (wl->tx_frames[i] == NULL) { | ||
77 | wl->tx_frames[i] = skb; | ||
78 | return i; | ||
79 | } | ||
80 | |||
81 | return -EBUSY; | ||
82 | } | ||
83 | |||
84 | static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr, | ||
85 | struct ieee80211_tx_info *control, u16 fc) | ||
86 | { | ||
87 | *(u16 *)&tx_hdr->control = 0; | ||
88 | |||
89 | tx_hdr->control.rate_policy = 0; | ||
90 | |||
91 | /* 802.11 packets */ | ||
92 | tx_hdr->control.packet_type = 0; | ||
93 | |||
94 | if (control->flags & IEEE80211_TX_CTL_NO_ACK) | ||
95 | tx_hdr->control.ack_policy = 1; | ||
96 | |||
97 | tx_hdr->control.tx_complete = 1; | ||
98 | |||
99 | if ((fc & IEEE80211_FTYPE_DATA) && | ||
100 | ((fc & IEEE80211_STYPE_QOS_DATA) || | ||
101 | (fc & IEEE80211_STYPE_QOS_NULLFUNC))) | ||
102 | tx_hdr->control.qos = 1; | ||
103 | } | ||
104 | |||
105 | /* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ | ||
106 | #define MAX_MSDU_SECURITY_LENGTH 16 | ||
107 | #define MAX_MPDU_SECURITY_LENGTH 16 | ||
108 | #define WLAN_QOS_HDR_LEN 26 | ||
109 | #define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ | ||
110 | WLAN_QOS_HDR_LEN) | ||
111 | #define HW_BLOCK_SIZE 252 | ||
112 | static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) | ||
113 | { | ||
114 | u16 payload_len, frag_threshold, mem_blocks; | ||
115 | u16 num_mpdus, mem_blocks_per_frag; | ||
116 | |||
117 | frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | ||
118 | tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); | ||
119 | |||
120 | payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH; | ||
121 | |||
122 | if (payload_len > frag_threshold) { | ||
123 | mem_blocks_per_frag = | ||
124 | ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / | ||
125 | HW_BLOCK_SIZE) + 1; | ||
126 | num_mpdus = payload_len / frag_threshold; | ||
127 | mem_blocks = num_mpdus * mem_blocks_per_frag; | ||
128 | payload_len -= num_mpdus * frag_threshold; | ||
129 | num_mpdus++; | ||
130 | |||
131 | } else { | ||
132 | mem_blocks_per_frag = 0; | ||
133 | mem_blocks = 0; | ||
134 | num_mpdus = 1; | ||
135 | } | ||
136 | |||
137 | mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; | ||
138 | |||
139 | if (num_mpdus > 1) | ||
140 | mem_blocks += min(num_mpdus, mem_blocks_per_frag); | ||
141 | |||
142 | tx_hdr->num_mem_blocks = mem_blocks; | ||
143 | } | ||
144 | |||
145 | static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, | ||
146 | struct ieee80211_tx_info *control) | ||
147 | { | ||
148 | struct tx_double_buffer_desc *tx_hdr; | ||
149 | struct ieee80211_rate *rate; | ||
150 | int id; | ||
151 | u16 fc; | ||
152 | |||
153 | if (!skb) | ||
154 | return -EINVAL; | ||
155 | |||
156 | id = wl12xx_tx_id(wl, skb); | ||
157 | if (id < 0) | ||
158 | return id; | ||
159 | |||
160 | fc = *(u16 *)skb->data; | ||
161 | tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, | ||
162 | sizeof(*tx_hdr)); | ||
163 | |||
164 | tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); | ||
165 | rate = ieee80211_get_tx_rate(wl->hw, control); | ||
166 | tx_hdr->rate = cpu_to_le16(rate->hw_value); | ||
167 | tx_hdr->expiry_time = cpu_to_le32(1 << 16); | ||
168 | tx_hdr->id = id; | ||
169 | |||
170 | /* FIXME: how to get the correct queue id? */ | ||
171 | tx_hdr->xmit_queue = 0; | ||
172 | |||
173 | wl12xx_tx_control(tx_hdr, control, fc); | ||
174 | wl12xx_tx_frag_block_num(tx_hdr); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | /* We copy the packet to the target */ | ||
180 | static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, | ||
181 | struct ieee80211_tx_info *control) | ||
182 | { | ||
183 | struct tx_double_buffer_desc *tx_hdr; | ||
184 | int len; | ||
185 | u32 addr; | ||
186 | |||
187 | if (!skb) | ||
188 | return -EINVAL; | ||
189 | |||
190 | tx_hdr = (struct tx_double_buffer_desc *) skb->data; | ||
191 | |||
192 | if (control->control.hw_key && | ||
193 | control->control.hw_key->alg == ALG_TKIP) { | ||
194 | int hdrlen; | ||
195 | u16 fc; | ||
196 | u8 *pos; | ||
197 | |||
198 | fc = *(u16 *)(skb->data + sizeof(*tx_hdr)); | ||
199 | tx_hdr->length += WL12XX_TKIP_IV_SPACE; | ||
200 | |||
201 | hdrlen = ieee80211_hdrlen(fc); | ||
202 | |||
203 | pos = skb_push(skb, WL12XX_TKIP_IV_SPACE); | ||
204 | memmove(pos, pos + WL12XX_TKIP_IV_SPACE, | ||
205 | sizeof(*tx_hdr) + hdrlen); | ||
206 | } | ||
207 | |||
208 | /* Revisit. This is a workaround for getting non-aligned packets. | ||
209 | This happens at least with EAPOL packets from the user space. | ||
210 | Our DMA requires packets to be aligned on a 4-byte boundary. | ||
211 | */ | ||
212 | if (unlikely((long)skb->data & 0x03)) { | ||
213 | int offset = (4 - (long)skb->data) & 0x03; | ||
214 | wl12xx_debug(DEBUG_TX, "skb offset %d", offset); | ||
215 | |||
216 | /* check whether the current skb can be used */ | ||
217 | if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { | ||
218 | unsigned char *src = skb->data; | ||
219 | |||
220 | /* align the buffer on a 4-byte boundary */ | ||
221 | skb_reserve(skb, offset); | ||
222 | memmove(skb->data, src, skb->len); | ||
223 | } else { | ||
224 | wl12xx_info("No handler, fixme!"); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | /* Our skb->data at this point includes the HW header */ | ||
230 | len = WL12XX_TX_ALIGN(skb->len); | ||
231 | |||
232 | if (wl->data_in_count & 0x1) | ||
233 | addr = wl->data_path->tx_packet_ring_addr + | ||
234 | wl->data_path->tx_packet_ring_chunk_size; | ||
235 | else | ||
236 | addr = wl->data_path->tx_packet_ring_addr; | ||
237 | |||
238 | wl12xx_spi_mem_write(wl, addr, skb->data, len); | ||
239 | |||
240 | wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", | ||
241 | tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static void wl12xx_tx_trigger(struct wl12xx *wl) | ||
247 | { | ||
248 | u32 data, addr; | ||
249 | |||
250 | if (wl->data_in_count & 0x1) { | ||
251 | addr = ACX_REG_INTERRUPT_TRIG_H; | ||
252 | data = INTR_TRIG_TX_PROC1; | ||
253 | } else { | ||
254 | addr = ACX_REG_INTERRUPT_TRIG; | ||
255 | data = INTR_TRIG_TX_PROC0; | ||
256 | } | ||
257 | |||
258 | wl12xx_reg_write32(wl, addr, data); | ||
259 | |||
260 | /* Bumping data in */ | ||
261 | wl->data_in_count = (wl->data_in_count + 1) & | ||
262 | TX_STATUS_DATA_OUT_COUNT_MASK; | ||
263 | } | ||
264 | |||
265 | /* caller must hold wl->mutex */ | ||
266 | static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb) | ||
267 | { | ||
268 | struct ieee80211_tx_info *info; | ||
269 | int ret = 0; | ||
270 | u8 idx; | ||
271 | |||
272 | info = IEEE80211_SKB_CB(skb); | ||
273 | |||
274 | if (info->control.hw_key) { | ||
275 | idx = info->control.hw_key->hw_key_idx; | ||
276 | if (unlikely(wl->default_key != idx)) { | ||
277 | ret = wl12xx_acx_default_key(wl, idx); | ||
278 | if (ret < 0) | ||
279 | return ret; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | ret = wl12xx_tx_path_status(wl); | ||
284 | if (ret < 0) | ||
285 | return ret; | ||
286 | |||
287 | ret = wl12xx_tx_fill_hdr(wl, skb, info); | ||
288 | if (ret < 0) | ||
289 | return ret; | ||
290 | |||
291 | ret = wl12xx_tx_send_packet(wl, skb, info); | ||
292 | if (ret < 0) | ||
293 | return ret; | ||
294 | |||
295 | wl12xx_tx_trigger(wl); | ||
296 | |||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | void wl12xx_tx_work(struct work_struct *work) | ||
301 | { | ||
302 | struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); | ||
303 | struct sk_buff *skb; | ||
304 | bool woken_up = false; | ||
305 | int ret; | ||
306 | |||
307 | mutex_lock(&wl->mutex); | ||
308 | |||
309 | if (unlikely(wl->state == WL12XX_STATE_OFF)) | ||
310 | goto out; | ||
311 | |||
312 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
313 | if (!woken_up) { | ||
314 | wl12xx_ps_elp_wakeup(wl); | ||
315 | woken_up = true; | ||
316 | } | ||
317 | |||
318 | ret = wl12xx_tx_frame(wl, skb); | ||
319 | if (ret == -EBUSY) { | ||
320 | /* firmware buffer is full, stop queues */ | ||
321 | wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " | ||
322 | "stop queues"); | ||
323 | ieee80211_stop_queues(wl->hw); | ||
324 | wl->tx_queue_stopped = true; | ||
325 | skb_queue_head(&wl->tx_queue, skb); | ||
326 | goto out; | ||
327 | } else if (ret < 0) { | ||
328 | dev_kfree_skb(skb); | ||
329 | goto out; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | out: | ||
334 | if (woken_up) | ||
335 | wl12xx_ps_elp_sleep(wl); | ||
336 | |||
337 | mutex_unlock(&wl->mutex); | ||
338 | } | ||
339 | |||
340 | static const char *wl12xx_tx_parse_status(u8 status) | ||
341 | { | ||
342 | /* 8 bit status field, one character per bit plus null */ | ||
343 | static char buf[9]; | ||
344 | int i = 0; | ||
345 | |||
346 | memset(buf, 0, sizeof(buf)); | ||
347 | |||
348 | if (status & TX_DMA_ERROR) | ||
349 | buf[i++] = 'm'; | ||
350 | if (status & TX_DISABLED) | ||
351 | buf[i++] = 'd'; | ||
352 | if (status & TX_RETRY_EXCEEDED) | ||
353 | buf[i++] = 'r'; | ||
354 | if (status & TX_TIMEOUT) | ||
355 | buf[i++] = 't'; | ||
356 | if (status & TX_KEY_NOT_FOUND) | ||
357 | buf[i++] = 'k'; | ||
358 | if (status & TX_ENCRYPT_FAIL) | ||
359 | buf[i++] = 'e'; | ||
360 | if (status & TX_UNAVAILABLE_PRIORITY) | ||
361 | buf[i++] = 'p'; | ||
362 | |||
363 | /* bit 0 is unused apparently */ | ||
364 | |||
365 | return buf; | ||
366 | } | ||
367 | |||
368 | static void wl12xx_tx_packet_cb(struct wl12xx *wl, | ||
369 | struct tx_result *result) | ||
370 | { | ||
371 | struct ieee80211_tx_info *info; | ||
372 | struct sk_buff *skb; | ||
373 | int hdrlen, ret; | ||
374 | u8 *frame; | ||
375 | |||
376 | skb = wl->tx_frames[result->id]; | ||
377 | if (skb == NULL) { | ||
378 | wl12xx_error("SKB for packet %d is NULL", result->id); | ||
379 | return; | ||
380 | } | ||
381 | |||
382 | info = IEEE80211_SKB_CB(skb); | ||
383 | |||
384 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && | ||
385 | (result->status == TX_SUCCESS)) | ||
386 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
387 | |||
388 | info->status.rates[0].count = result->ack_failures + 1; | ||
389 | wl->stats.retry_count += result->ack_failures; | ||
390 | |||
391 | /* | ||
392 | * We have to remove our private TX header before pushing | ||
393 | * the skb back to mac80211. | ||
394 | */ | ||
395 | frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); | ||
396 | if (info->control.hw_key && | ||
397 | info->control.hw_key->alg == ALG_TKIP) { | ||
398 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
399 | memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen); | ||
400 | skb_pull(skb, WL12XX_TKIP_IV_SPACE); | ||
401 | } | ||
402 | |||
403 | wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | ||
404 | " status 0x%x (%s)", | ||
405 | result->id, skb, result->ack_failures, result->rate, | ||
406 | result->status, wl12xx_tx_parse_status(result->status)); | ||
407 | |||
408 | |||
409 | ieee80211_tx_status(wl->hw, skb); | ||
410 | |||
411 | wl->tx_frames[result->id] = NULL; | ||
412 | |||
413 | if (wl->tx_queue_stopped) { | ||
414 | wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); | ||
415 | |||
416 | skb = skb_dequeue(&wl->tx_queue); | ||
417 | |||
418 | /* The skb can be NULL because tx_work might have been | ||
419 | scheduled before the queue was stopped making the | ||
420 | queue empty */ | ||
421 | |||
422 | if (skb) { | ||
423 | ret = wl12xx_tx_frame(wl, skb); | ||
424 | if (ret == -EBUSY) { | ||
425 | /* firmware buffer is still full */ | ||
426 | wl12xx_debug(DEBUG_TX, "cb: fw buffer " | ||
427 | "still full"); | ||
428 | skb_queue_head(&wl->tx_queue, skb); | ||
429 | return; | ||
430 | } else if (ret < 0) { | ||
431 | dev_kfree_skb(skb); | ||
432 | return; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | wl12xx_debug(DEBUG_TX, "cb: waking queues"); | ||
437 | ieee80211_wake_queues(wl->hw); | ||
438 | wl->tx_queue_stopped = false; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | /* Called upon reception of a TX complete interrupt */ | ||
443 | void wl12xx_tx_complete(struct wl12xx *wl) | ||
444 | { | ||
445 | int i, result_index, num_complete = 0; | ||
446 | struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; | ||
447 | |||
448 | if (unlikely(wl->state != WL12XX_STATE_ON)) | ||
449 | return; | ||
450 | |||
451 | /* First we read the result */ | ||
452 | wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, | ||
453 | result, sizeof(result)); | ||
454 | |||
455 | result_index = wl->next_tx_complete; | ||
456 | |||
457 | for (i = 0; i < ARRAY_SIZE(result); i++) { | ||
458 | result_ptr = &result[result_index]; | ||
459 | |||
460 | if (result_ptr->done_1 == 1 && | ||
461 | result_ptr->done_2 == 1) { | ||
462 | wl12xx_tx_packet_cb(wl, result_ptr); | ||
463 | |||
464 | result_ptr->done_1 = 0; | ||
465 | result_ptr->done_2 = 0; | ||
466 | |||
467 | result_index = (result_index + 1) & | ||
468 | (FW_TX_CMPLT_BLOCK_SIZE - 1); | ||
469 | num_complete++; | ||
470 | } else { | ||
471 | break; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | /* Every completed frame needs to be acknowledged */ | ||
476 | if (num_complete) { | ||
477 | /* | ||
478 | * If we've wrapped, we have to clear | ||
479 | * the results in 2 steps. | ||
480 | */ | ||
481 | if (result_index > wl->next_tx_complete) { | ||
482 | /* Only 1 write is needed */ | ||
483 | wl12xx_spi_mem_write(wl, | ||
484 | wl->data_path->tx_complete_addr + | ||
485 | (wl->next_tx_complete * | ||
486 | sizeof(struct tx_result)), | ||
487 | &result[wl->next_tx_complete], | ||
488 | num_complete * | ||
489 | sizeof(struct tx_result)); | ||
490 | |||
491 | |||
492 | } else if (result_index < wl->next_tx_complete) { | ||
493 | /* 2 writes are needed */ | ||
494 | wl12xx_spi_mem_write(wl, | ||
495 | wl->data_path->tx_complete_addr + | ||
496 | (wl->next_tx_complete * | ||
497 | sizeof(struct tx_result)), | ||
498 | &result[wl->next_tx_complete], | ||
499 | (FW_TX_CMPLT_BLOCK_SIZE - | ||
500 | wl->next_tx_complete) * | ||
501 | sizeof(struct tx_result)); | ||
502 | |||
503 | wl12xx_spi_mem_write(wl, | ||
504 | wl->data_path->tx_complete_addr, | ||
505 | result, | ||
506 | (num_complete - | ||
507 | FW_TX_CMPLT_BLOCK_SIZE + | ||
508 | wl->next_tx_complete) * | ||
509 | sizeof(struct tx_result)); | ||
510 | |||
511 | } else { | ||
512 | /* We have to write the whole array */ | ||
513 | wl12xx_spi_mem_write(wl, | ||
514 | wl->data_path->tx_complete_addr, | ||
515 | result, | ||
516 | FW_TX_CMPLT_BLOCK_SIZE * | ||
517 | sizeof(struct tx_result)); | ||
518 | } | ||
519 | |||
520 | } | ||
521 | |||
522 | wl->next_tx_complete = result_index; | ||
523 | } | ||
524 | |||
525 | /* caller must hold wl->mutex */ | ||
526 | void wl12xx_tx_flush(struct wl12xx *wl) | ||
527 | { | ||
528 | int i; | ||
529 | struct sk_buff *skb; | ||
530 | struct ieee80211_tx_info *info; | ||
531 | |||
532 | /* TX failure */ | ||
533 | /* control->flags = 0; FIXME */ | ||
534 | |||
535 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
536 | info = IEEE80211_SKB_CB(skb); | ||
537 | |||
538 | wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); | ||
539 | |||
540 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
541 | continue; | ||
542 | |||
543 | ieee80211_tx_status(wl->hw, skb); | ||
544 | } | ||
545 | |||
546 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
547 | if (wl->tx_frames[i] != NULL) { | ||
548 | skb = wl->tx_frames[i]; | ||
549 | info = IEEE80211_SKB_CB(skb); | ||
550 | |||
551 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
552 | continue; | ||
553 | |||
554 | ieee80211_tx_status(wl->hw, skb); | ||
555 | wl->tx_frames[i] = NULL; | ||
556 | } | ||
557 | } | ||
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h new file mode 100644 index 000000000000..dc82691f4c14 --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.h | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_TX_H__ | ||
26 | #define __WL12XX_TX_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | /* | ||
31 | * | ||
32 | * TX PATH | ||
33 | * | ||
34 | * The Tx path uses a double buffer and a tx_control structure, each located | ||
35 | * at a fixed address in the device's memory. On startup, the host retrieves | ||
36 | * the pointers to these addresses. A double buffer allows for continuous data | ||
37 | * flow towards the device. The host keeps track of which buffer is available | ||
38 | * and alternates between these two buffers on a per packet basis. | ||
39 | * | ||
40 | * The size of each of the two buffers is large enough to hold the longest | ||
41 | * 802.3 packet - maximum size Ethernet packet + header + descriptor. | ||
42 | * TX complete indication will be received a-synchronously in a TX done cyclic | ||
43 | * buffer which is composed of 16 tx_result descriptors structures and is used | ||
44 | * in a cyclic manner. | ||
45 | * | ||
46 | * The TX (HOST) procedure is as follows: | ||
47 | * 1. Read the Tx path status, that will give the data_out_count. | ||
48 | * 2. goto 1, if not possible. | ||
49 | * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double | ||
50 | * buffer). | ||
51 | * 3. Copy the packet (preceded by double_buffer_desc), if possible. | ||
52 | * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double | ||
53 | * buffer). | ||
54 | * 4. increment data_in_count. | ||
55 | * 5. Inform the firmware by generating a firmware internal interrupt. | ||
56 | * 6. FW will increment data_out_count after it reads the buffer. | ||
57 | * | ||
58 | * The TX Complete procedure: | ||
59 | * 1. To get a TX complete indication the host enables the tx_complete flag in | ||
60 | * the TX descriptor Structure. | ||
61 | * 2. For each packet with a Tx Complete field set, the firmware adds the | ||
62 | * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 | ||
63 | * and done_2 to 1 to indicate driver ownership. | ||
64 | * 3. The firmware sends a Tx Complete interrupt to the host to trigger the | ||
65 | * host to process the new data. Note: interrupt will be send per packet if | ||
66 | * TX complete indication was requested in tx_control or per crossing | ||
67 | * aggregation threshold. | ||
68 | * 4. After receiving the Tx Complete interrupt, the host reads the | ||
69 | * TxDescriptorDone information in a cyclic manner and clears both done_1 | ||
70 | * and done_2 fields. | ||
71 | * | ||
72 | */ | ||
73 | |||
74 | #define TX_COMPLETE_REQUIRED_BIT 0x80 | ||
75 | #define TX_STATUS_DATA_OUT_COUNT_MASK 0xf | ||
76 | #define WL12XX_TX_ALIGN_TO 4 | ||
77 | #define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \ | ||
78 | ~(WL12XX_TX_ALIGN_TO - 1)) | ||
79 | #define WL12XX_TKIP_IV_SPACE 4 | ||
80 | |||
81 | struct tx_control { | ||
82 | /* Rate Policy (class) index */ | ||
83 | unsigned rate_policy:3; | ||
84 | |||
85 | /* When set, no ack policy is expected */ | ||
86 | unsigned ack_policy:1; | ||
87 | |||
88 | /* | ||
89 | * Packet type: | ||
90 | * 0 -> 802.11 | ||
91 | * 1 -> 802.3 | ||
92 | * 2 -> IP | ||
93 | * 3 -> raw codec | ||
94 | */ | ||
95 | unsigned packet_type:2; | ||
96 | |||
97 | /* If set, this is a QoS-Null or QoS-Data frame */ | ||
98 | unsigned qos:1; | ||
99 | |||
100 | /* | ||
101 | * If set, the target triggers the tx complete INT | ||
102 | * upon frame sending completion. | ||
103 | */ | ||
104 | unsigned tx_complete:1; | ||
105 | |||
106 | /* 2 bytes padding before packet header */ | ||
107 | unsigned xfer_pad:1; | ||
108 | |||
109 | unsigned reserved:7; | ||
110 | } __attribute__ ((packed)); | ||
111 | |||
112 | |||
113 | struct tx_double_buffer_desc { | ||
114 | /* Length of payload, including headers. */ | ||
115 | u16 length; | ||
116 | |||
117 | /* | ||
118 | * A bit mask that specifies the initial rate to be used | ||
119 | * Possible values are: | ||
120 | * 0x0001 - 1Mbits | ||
121 | * 0x0002 - 2Mbits | ||
122 | * 0x0004 - 5.5Mbits | ||
123 | * 0x0008 - 6Mbits | ||
124 | * 0x0010 - 9Mbits | ||
125 | * 0x0020 - 11Mbits | ||
126 | * 0x0040 - 12Mbits | ||
127 | * 0x0080 - 18Mbits | ||
128 | * 0x0100 - 22Mbits | ||
129 | * 0x0200 - 24Mbits | ||
130 | * 0x0400 - 36Mbits | ||
131 | * 0x0800 - 48Mbits | ||
132 | * 0x1000 - 54Mbits | ||
133 | */ | ||
134 | u16 rate; | ||
135 | |||
136 | /* Time in us that a packet can spend in the target */ | ||
137 | u32 expiry_time; | ||
138 | |||
139 | /* index of the TX queue used for this packet */ | ||
140 | u8 xmit_queue; | ||
141 | |||
142 | /* Used to identify a packet */ | ||
143 | u8 id; | ||
144 | |||
145 | struct tx_control control; | ||
146 | |||
147 | /* | ||
148 | * The FW should cut the packet into fragments | ||
149 | * of this size. | ||
150 | */ | ||
151 | u16 frag_threshold; | ||
152 | |||
153 | /* Numbers of HW queue blocks to be allocated */ | ||
154 | u8 num_mem_blocks; | ||
155 | |||
156 | u8 reserved; | ||
157 | } __attribute__ ((packed)); | ||
158 | |||
159 | enum { | ||
160 | TX_SUCCESS = 0, | ||
161 | TX_DMA_ERROR = BIT(7), | ||
162 | TX_DISABLED = BIT(6), | ||
163 | TX_RETRY_EXCEEDED = BIT(5), | ||
164 | TX_TIMEOUT = BIT(4), | ||
165 | TX_KEY_NOT_FOUND = BIT(3), | ||
166 | TX_ENCRYPT_FAIL = BIT(2), | ||
167 | TX_UNAVAILABLE_PRIORITY = BIT(1), | ||
168 | }; | ||
169 | |||
170 | struct tx_result { | ||
171 | /* | ||
172 | * Ownership synchronization between the host and | ||
173 | * the firmware. If done_1 and done_2 are cleared, | ||
174 | * owned by the FW (no info ready). | ||
175 | */ | ||
176 | u8 done_1; | ||
177 | |||
178 | /* same as double_buffer_desc->id */ | ||
179 | u8 id; | ||
180 | |||
181 | /* | ||
182 | * Total air access duration consumed by this | ||
183 | * packet, including all retries and overheads. | ||
184 | */ | ||
185 | u16 medium_usage; | ||
186 | |||
187 | /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ | ||
188 | u32 medium_delay; | ||
189 | |||
190 | /* Time between host xfer and tx complete */ | ||
191 | u32 fw_hnadling_time; | ||
192 | |||
193 | /* The LS-byte of the last TKIP sequence number. */ | ||
194 | u8 lsb_seq_num; | ||
195 | |||
196 | /* Retry count */ | ||
197 | u8 ack_failures; | ||
198 | |||
199 | /* At which rate we got a ACK */ | ||
200 | u16 rate; | ||
201 | |||
202 | u16 reserved; | ||
203 | |||
204 | /* TX_* */ | ||
205 | u8 status; | ||
206 | |||
207 | /* See done_1 */ | ||
208 | u8 done_2; | ||
209 | } __attribute__ ((packed)); | ||
210 | |||
211 | void wl12xx_tx_work(struct work_struct *work); | ||
212 | void wl12xx_tx_complete(struct wl12xx *wl); | ||
213 | void wl12xx_tx_flush(struct wl12xx *wl); | ||
214 | |||
215 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c new file mode 100644 index 000000000000..bd0decdcad23 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.c | |||
@@ -0,0 +1,709 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1251.h" | ||
28 | #include "reg.h" | ||
29 | #include "spi.h" | ||
30 | #include "boot.h" | ||
31 | #include "event.h" | ||
32 | #include "acx.h" | ||
33 | #include "tx.h" | ||
34 | #include "rx.h" | ||
35 | #include "ps.h" | ||
36 | #include "init.h" | ||
37 | |||
38 | static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { | ||
39 | [PART_DOWN] = { | ||
40 | .mem = { | ||
41 | .start = 0x00000000, | ||
42 | .size = 0x00016800 | ||
43 | }, | ||
44 | .reg = { | ||
45 | .start = REGISTERS_BASE, | ||
46 | .size = REGISTERS_DOWN_SIZE | ||
47 | }, | ||
48 | }, | ||
49 | |||
50 | [PART_WORK] = { | ||
51 | .mem = { | ||
52 | .start = 0x00028000, | ||
53 | .size = 0x00014000 | ||
54 | }, | ||
55 | .reg = { | ||
56 | .start = REGISTERS_BASE, | ||
57 | .size = REGISTERS_WORK_SIZE | ||
58 | }, | ||
59 | }, | ||
60 | |||
61 | /* WL1251 doesn't use the DRPW partition, so we don't set it here */ | ||
62 | }; | ||
63 | |||
64 | static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { | ||
65 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
66 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
67 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
68 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
69 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
70 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
71 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
72 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
73 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
74 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
75 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
76 | }; | ||
77 | |||
78 | static int wl1251_upload_firmware(struct wl12xx *wl) | ||
79 | { | ||
80 | struct wl12xx_partition_set *p_table = wl->chip.p_table; | ||
81 | int addr, chunk_num, partition_limit; | ||
82 | size_t fw_data_len; | ||
83 | u8 *p; | ||
84 | |||
85 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
86 | |||
87 | wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
88 | wl12xx_reg_read32(wl, CHIP_ID_B)); | ||
89 | |||
90 | /* 10.0 check firmware length and set partition */ | ||
91 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
92 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
93 | |||
94 | wl12xx_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len, | ||
95 | CHUNK_SIZE); | ||
96 | |||
97 | if ((fw_data_len % 4) != 0) { | ||
98 | wl12xx_error("firmware length not multiple of four"); | ||
99 | return -EIO; | ||
100 | } | ||
101 | |||
102 | wl12xx_set_partition(wl, | ||
103 | p_table[PART_DOWN].mem.start, | ||
104 | p_table[PART_DOWN].mem.size, | ||
105 | p_table[PART_DOWN].reg.start, | ||
106 | p_table[PART_DOWN].reg.size); | ||
107 | |||
108 | /* 10.1 set partition limit and chunk num */ | ||
109 | chunk_num = 0; | ||
110 | partition_limit = p_table[PART_DOWN].mem.size; | ||
111 | |||
112 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
113 | /* 10.2 update partition, if needed */ | ||
114 | addr = p_table[PART_DOWN].mem.start + | ||
115 | (chunk_num + 2) * CHUNK_SIZE; | ||
116 | if (addr > partition_limit) { | ||
117 | addr = p_table[PART_DOWN].mem.start + | ||
118 | chunk_num * CHUNK_SIZE; | ||
119 | partition_limit = chunk_num * CHUNK_SIZE + | ||
120 | p_table[PART_DOWN].mem.size; | ||
121 | wl12xx_set_partition(wl, | ||
122 | addr, | ||
123 | p_table[PART_DOWN].mem.size, | ||
124 | p_table[PART_DOWN].reg.start, | ||
125 | p_table[PART_DOWN].reg.size); | ||
126 | } | ||
127 | |||
128 | /* 10.3 upload the chunk */ | ||
129 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
130 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
131 | wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
132 | p, addr); | ||
133 | wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); | ||
134 | |||
135 | chunk_num++; | ||
136 | } | ||
137 | |||
138 | /* 10.4 upload the last chunk */ | ||
139 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
140 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
141 | wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x", | ||
142 | fw_data_len % CHUNK_SIZE, p, addr); | ||
143 | wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int wl1251_upload_nvs(struct wl12xx *wl) | ||
149 | { | ||
150 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
151 | int nvs_start, i; | ||
152 | u32 dest_addr, val; | ||
153 | u8 *nvs_ptr, *nvs; | ||
154 | |||
155 | nvs = wl->nvs; | ||
156 | if (nvs == NULL) | ||
157 | return -ENODEV; | ||
158 | |||
159 | nvs_ptr = nvs; | ||
160 | |||
161 | nvs_len = wl->nvs_len; | ||
162 | nvs_start = wl->fw_len; | ||
163 | |||
164 | /* | ||
165 | * Layout before the actual NVS tables: | ||
166 | * 1 byte : burst length. | ||
167 | * 2 bytes: destination address. | ||
168 | * n bytes: data to burst copy. | ||
169 | * | ||
170 | * This is ended by a 0 length, then the NVS tables. | ||
171 | */ | ||
172 | |||
173 | while (nvs_ptr[0]) { | ||
174 | burst_len = nvs_ptr[0]; | ||
175 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
176 | |||
177 | /* We move our pointer to the data */ | ||
178 | nvs_ptr += 3; | ||
179 | |||
180 | for (i = 0; i < burst_len; i++) { | ||
181 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
182 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
183 | |||
184 | wl12xx_debug(DEBUG_BOOT, | ||
185 | "nvs burst write 0x%x: 0x%x", | ||
186 | dest_addr, val); | ||
187 | wl12xx_mem_write32(wl, dest_addr, val); | ||
188 | |||
189 | nvs_ptr += 4; | ||
190 | dest_addr += 4; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * We've reached the first zero length, the first NVS table | ||
196 | * is 7 bytes further. | ||
197 | */ | ||
198 | nvs_ptr += 7; | ||
199 | nvs_len -= nvs_ptr - nvs; | ||
200 | nvs_len = ALIGN(nvs_len, 4); | ||
201 | |||
202 | /* Now we must set the partition correctly */ | ||
203 | wl12xx_set_partition(wl, nvs_start, | ||
204 | wl->chip.p_table[PART_DOWN].mem.size, | ||
205 | wl->chip.p_table[PART_DOWN].reg.start, | ||
206 | wl->chip.p_table[PART_DOWN].reg.size); | ||
207 | |||
208 | /* And finally we upload the NVS tables */ | ||
209 | nvs_bytes_written = 0; | ||
210 | while (nvs_bytes_written < nvs_len) { | ||
211 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
212 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
213 | |||
214 | val = cpu_to_le32(val); | ||
215 | |||
216 | wl12xx_debug(DEBUG_BOOT, | ||
217 | "nvs write table 0x%x: 0x%x", | ||
218 | nvs_start, val); | ||
219 | wl12xx_mem_write32(wl, nvs_start, val); | ||
220 | |||
221 | nvs_ptr += 4; | ||
222 | nvs_bytes_written += 4; | ||
223 | nvs_start += 4; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int wl1251_boot(struct wl12xx *wl) | ||
230 | { | ||
231 | int ret = 0, minor_minor_e2_ver; | ||
232 | u32 tmp, boot_data; | ||
233 | |||
234 | ret = wl12xx_boot_soft_reset(wl); | ||
235 | if (ret < 0) | ||
236 | goto out; | ||
237 | |||
238 | /* 2. start processing NVS file */ | ||
239 | ret = wl->chip.op_upload_nvs(wl); | ||
240 | if (ret < 0) | ||
241 | goto out; | ||
242 | |||
243 | /* write firmware's last address (ie. it's length) to | ||
244 | * ACX_EEPROMLESS_IND_REG */ | ||
245 | wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
246 | |||
247 | /* 6. read the EEPROM parameters */ | ||
248 | tmp = wl12xx_reg_read32(wl, SCR_PAD2); | ||
249 | |||
250 | /* 7. read bootdata */ | ||
251 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
252 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
253 | tmp = wl12xx_reg_read32(wl, SCR_PAD3); | ||
254 | |||
255 | /* 8. check bootdata and call restart sequence */ | ||
256 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
257 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
258 | |||
259 | wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
260 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
261 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
262 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
263 | |||
264 | ret = wl12xx_boot_init_seq(wl); | ||
265 | if (ret < 0) | ||
266 | goto out; | ||
267 | |||
268 | /* 9. NVS processing done */ | ||
269 | boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
270 | |||
271 | wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
272 | |||
273 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
274 | * pWhalBus->uBootData and start uploading firmware | ||
275 | */ | ||
276 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
277 | wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
278 | ret = -EIO; | ||
279 | goto out; | ||
280 | } | ||
281 | |||
282 | ret = wl->chip.op_upload_fw(wl); | ||
283 | if (ret < 0) | ||
284 | goto out; | ||
285 | |||
286 | /* 10.5 start firmware */ | ||
287 | ret = wl12xx_boot_run_firmware(wl); | ||
288 | if (ret < 0) | ||
289 | goto out; | ||
290 | |||
291 | /* Get and save the firmware version */ | ||
292 | wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); | ||
293 | |||
294 | out: | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | static int wl1251_mem_cfg(struct wl12xx *wl) | ||
299 | { | ||
300 | struct wl1251_acx_config_memory mem_conf; | ||
301 | int ret, i; | ||
302 | |||
303 | wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); | ||
304 | |||
305 | /* memory config */ | ||
306 | mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
307 | mem_conf.mem_config.rx_mem_block_num = 35; | ||
308 | mem_conf.mem_config.tx_min_mem_block_num = 64; | ||
309 | mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
310 | mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING; | ||
311 | mem_conf.mem_config.num_ssid_profiles = 1; | ||
312 | mem_conf.mem_config.debug_buffer_size = | ||
313 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
314 | |||
315 | /* RX queue config */ | ||
316 | mem_conf.rx_queue_config.dma_address = 0; | ||
317 | mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
318 | mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
319 | mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
320 | |||
321 | /* TX queue config */ | ||
322 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
323 | mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
324 | mem_conf.tx_queue_config[i].attributes = i; | ||
325 | } | ||
326 | |||
327 | mem_conf.header.id = ACX_MEM_CFG; | ||
328 | mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) - | ||
329 | sizeof(struct acx_header); | ||
330 | mem_conf.header.len -= | ||
331 | (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) * | ||
332 | sizeof(struct wl1251_acx_tx_queue_config); | ||
333 | |||
334 | ret = wl12xx_cmd_configure(wl, &mem_conf, | ||
335 | sizeof(struct wl1251_acx_config_memory)); | ||
336 | if (ret < 0) | ||
337 | wl12xx_warning("wl1251 mem config failed: %d", ret); | ||
338 | |||
339 | return ret; | ||
340 | } | ||
341 | |||
342 | static int wl1251_hw_init_mem_config(struct wl12xx *wl) | ||
343 | { | ||
344 | int ret; | ||
345 | |||
346 | ret = wl1251_mem_cfg(wl); | ||
347 | if (ret < 0) | ||
348 | return ret; | ||
349 | |||
350 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
351 | GFP_KERNEL); | ||
352 | if (!wl->target_mem_map) { | ||
353 | wl12xx_error("couldn't allocate target memory map"); | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | /* we now ask for the firmware built memory map */ | ||
358 | ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, | ||
359 | sizeof(struct wl1251_acx_mem_map)); | ||
360 | if (ret < 0) { | ||
361 | wl12xx_error("couldn't retrieve firmware memory map"); | ||
362 | kfree(wl->target_mem_map); | ||
363 | wl->target_mem_map = NULL; | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) | ||
371 | { | ||
372 | u32 cpu_ctrl; | ||
373 | |||
374 | /* 10.5.0 run the firmware (I) */ | ||
375 | cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
376 | |||
377 | /* 10.5.1 run the firmware (II) */ | ||
378 | cpu_ctrl &= ~flag; | ||
379 | wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
380 | } | ||
381 | |||
382 | static void wl1251_target_enable_interrupts(struct wl12xx *wl) | ||
383 | { | ||
384 | /* Enable target's interrupts */ | ||
385 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
386 | WL1251_ACX_INTR_RX1_DATA | | ||
387 | WL1251_ACX_INTR_TX_RESULT | | ||
388 | WL1251_ACX_INTR_EVENT_A | | ||
389 | WL1251_ACX_INTR_EVENT_B | | ||
390 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
391 | wl12xx_boot_target_enable_interrupts(wl); | ||
392 | } | ||
393 | |||
394 | static void wl1251_irq_work(struct work_struct *work) | ||
395 | { | ||
396 | u32 intr; | ||
397 | struct wl12xx *wl = | ||
398 | container_of(work, struct wl12xx, irq_work); | ||
399 | |||
400 | mutex_lock(&wl->mutex); | ||
401 | |||
402 | wl12xx_debug(DEBUG_IRQ, "IRQ work"); | ||
403 | |||
404 | if (wl->state == WL12XX_STATE_OFF) | ||
405 | goto out; | ||
406 | |||
407 | wl12xx_ps_elp_wakeup(wl); | ||
408 | |||
409 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
410 | |||
411 | intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
412 | wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
413 | |||
414 | if (wl->data_path) { | ||
415 | wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr, | ||
416 | &wl->rx_counter, sizeof(u32)); | ||
417 | |||
418 | /* We handle a frmware bug here */ | ||
419 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
420 | case 0: | ||
421 | wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); | ||
422 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
423 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
424 | break; | ||
425 | case 1: | ||
426 | wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); | ||
427 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
428 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
429 | break; | ||
430 | case 2: | ||
431 | wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); | ||
432 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
433 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
434 | break; | ||
435 | default: | ||
436 | wl12xx_warning("RX: FW and host out of sync: %d", | ||
437 | wl->rx_counter - wl->rx_handled); | ||
438 | break; | ||
439 | } | ||
440 | |||
441 | wl->rx_handled = wl->rx_counter; | ||
442 | |||
443 | |||
444 | wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); | ||
445 | } | ||
446 | |||
447 | intr &= wl->intr_mask; | ||
448 | |||
449 | if (intr == 0) { | ||
450 | wl12xx_debug(DEBUG_IRQ, "INTR is 0"); | ||
451 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
452 | ~(wl->intr_mask)); | ||
453 | |||
454 | goto out_sleep; | ||
455 | } | ||
456 | |||
457 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
458 | wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
459 | wl12xx_rx(wl); | ||
460 | } | ||
461 | |||
462 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
463 | wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
464 | wl12xx_rx(wl); | ||
465 | } | ||
466 | |||
467 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
468 | wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
469 | wl12xx_tx_complete(wl); | ||
470 | } | ||
471 | |||
472 | if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { | ||
473 | wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); | ||
474 | if (intr & WL1251_ACX_INTR_EVENT_A) | ||
475 | wl12xx_event_handle(wl, 0); | ||
476 | else | ||
477 | wl12xx_event_handle(wl, 1); | ||
478 | } | ||
479 | |||
480 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
481 | wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
482 | |||
483 | wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
484 | |||
485 | out_sleep: | ||
486 | wl12xx_ps_elp_sleep(wl); | ||
487 | out: | ||
488 | mutex_unlock(&wl->mutex); | ||
489 | } | ||
490 | |||
491 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
492 | struct acx_tx_queue_qos_config *config, | ||
493 | u32 num_blocks) | ||
494 | { | ||
495 | config->qid = qid; | ||
496 | |||
497 | switch (qid) { | ||
498 | case QOS_AC_BE: | ||
499 | config->high_threshold = | ||
500 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
501 | config->low_threshold = | ||
502 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
503 | break; | ||
504 | case QOS_AC_BK: | ||
505 | config->high_threshold = | ||
506 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
507 | config->low_threshold = | ||
508 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
509 | break; | ||
510 | case QOS_AC_VI: | ||
511 | config->high_threshold = | ||
512 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
513 | config->low_threshold = | ||
514 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
515 | break; | ||
516 | case QOS_AC_VO: | ||
517 | config->high_threshold = | ||
518 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
519 | config->low_threshold = | ||
520 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
521 | break; | ||
522 | default: | ||
523 | wl12xx_error("Invalid TX queue id: %d", qid); | ||
524 | return -EINVAL; | ||
525 | } | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) | ||
531 | { | ||
532 | struct acx_tx_queue_qos_config config; | ||
533 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
534 | int ret, i; | ||
535 | |||
536 | wl12xx_debug(DEBUG_ACX, "acx tx queue config"); | ||
537 | |||
538 | config.header.id = ACX_TX_QUEUE_CFG; | ||
539 | config.header.len = sizeof(struct acx_tx_queue_qos_config) - | ||
540 | sizeof(struct acx_header); | ||
541 | |||
542 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
543 | ret = wl1251_hw_init_txq_fill(i, &config, | ||
544 | wl_mem_map->num_tx_mem_blocks); | ||
545 | if (ret < 0) | ||
546 | return ret; | ||
547 | |||
548 | ret = wl12xx_cmd_configure(wl, &config, sizeof(config)); | ||
549 | if (ret < 0) | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static int wl1251_hw_init_data_path_config(struct wl12xx *wl) | ||
557 | { | ||
558 | int ret; | ||
559 | |||
560 | /* asking for the data path parameters */ | ||
561 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
562 | GFP_KERNEL); | ||
563 | if (!wl->data_path) { | ||
564 | wl12xx_error("Couldnt allocate data path parameters"); | ||
565 | return -ENOMEM; | ||
566 | } | ||
567 | |||
568 | ret = wl12xx_acx_data_path_params(wl, wl->data_path); | ||
569 | if (ret < 0) { | ||
570 | kfree(wl->data_path); | ||
571 | wl->data_path = NULL; | ||
572 | return ret; | ||
573 | } | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static int wl1251_hw_init(struct wl12xx *wl) | ||
579 | { | ||
580 | struct wl1251_acx_mem_map *wl_mem_map; | ||
581 | int ret; | ||
582 | |||
583 | ret = wl12xx_hw_init_hwenc_config(wl); | ||
584 | if (ret < 0) | ||
585 | return ret; | ||
586 | |||
587 | /* Template settings */ | ||
588 | ret = wl12xx_hw_init_templates_config(wl); | ||
589 | if (ret < 0) | ||
590 | return ret; | ||
591 | |||
592 | /* Default memory configuration */ | ||
593 | ret = wl1251_hw_init_mem_config(wl); | ||
594 | if (ret < 0) | ||
595 | return ret; | ||
596 | |||
597 | /* Default data path configuration */ | ||
598 | ret = wl1251_hw_init_data_path_config(wl); | ||
599 | if (ret < 0) | ||
600 | goto out_free_memmap; | ||
601 | |||
602 | /* RX config */ | ||
603 | ret = wl12xx_hw_init_rx_config(wl, | ||
604 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
605 | RX_FILTER_OPTION_DEF); | ||
606 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
607 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
608 | if (ret < 0) | ||
609 | goto out_free_data_path; | ||
610 | |||
611 | /* TX queues config */ | ||
612 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
613 | if (ret < 0) | ||
614 | goto out_free_data_path; | ||
615 | |||
616 | /* PHY layer config */ | ||
617 | ret = wl12xx_hw_init_phy_config(wl); | ||
618 | if (ret < 0) | ||
619 | goto out_free_data_path; | ||
620 | |||
621 | /* Beacon filtering */ | ||
622 | ret = wl12xx_hw_init_beacon_filter(wl); | ||
623 | if (ret < 0) | ||
624 | goto out_free_data_path; | ||
625 | |||
626 | /* Bluetooth WLAN coexistence */ | ||
627 | ret = wl12xx_hw_init_pta(wl); | ||
628 | if (ret < 0) | ||
629 | goto out_free_data_path; | ||
630 | |||
631 | /* Energy detection */ | ||
632 | ret = wl12xx_hw_init_energy_detection(wl); | ||
633 | if (ret < 0) | ||
634 | goto out_free_data_path; | ||
635 | |||
636 | /* Beacons and boradcast settings */ | ||
637 | ret = wl12xx_hw_init_beacon_broadcast(wl); | ||
638 | if (ret < 0) | ||
639 | goto out_free_data_path; | ||
640 | |||
641 | /* Enable data path */ | ||
642 | ret = wl12xx_cmd_data_path(wl, wl->channel, 1); | ||
643 | if (ret < 0) | ||
644 | goto out_free_data_path; | ||
645 | |||
646 | /* Default power state */ | ||
647 | ret = wl12xx_hw_init_power_auth(wl); | ||
648 | if (ret < 0) | ||
649 | goto out_free_data_path; | ||
650 | |||
651 | wl_mem_map = wl->target_mem_map; | ||
652 | wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
653 | wl_mem_map->num_tx_mem_blocks, | ||
654 | wl->data_path->tx_control_addr, | ||
655 | wl_mem_map->num_rx_mem_blocks, | ||
656 | wl->data_path->rx_control_addr); | ||
657 | |||
658 | return 0; | ||
659 | |||
660 | out_free_data_path: | ||
661 | kfree(wl->data_path); | ||
662 | |||
663 | out_free_memmap: | ||
664 | kfree(wl->target_mem_map); | ||
665 | |||
666 | return ret; | ||
667 | } | ||
668 | |||
669 | static int wl1251_plt_init(struct wl12xx *wl) | ||
670 | { | ||
671 | int ret; | ||
672 | |||
673 | ret = wl1251_hw_init_mem_config(wl); | ||
674 | if (ret < 0) | ||
675 | return ret; | ||
676 | |||
677 | ret = wl12xx_cmd_data_path(wl, wl->channel, 1); | ||
678 | if (ret < 0) | ||
679 | return ret; | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | void wl1251_setup(struct wl12xx *wl) | ||
685 | { | ||
686 | /* FIXME: Is it better to use strncpy here or is this ok? */ | ||
687 | wl->chip.fw_filename = WL1251_FW_NAME; | ||
688 | wl->chip.nvs_filename = WL1251_NVS_NAME; | ||
689 | |||
690 | /* Now we know what chip we're using, so adjust the power on sleep | ||
691 | * time accordingly */ | ||
692 | wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; | ||
693 | |||
694 | wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; | ||
695 | wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; | ||
696 | |||
697 | wl->chip.op_upload_nvs = wl1251_upload_nvs; | ||
698 | wl->chip.op_upload_fw = wl1251_upload_firmware; | ||
699 | wl->chip.op_boot = wl1251_boot; | ||
700 | wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; | ||
701 | wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; | ||
702 | wl->chip.op_hw_init = wl1251_hw_init; | ||
703 | wl->chip.op_plt_init = wl1251_plt_init; | ||
704 | |||
705 | wl->chip.p_table = wl1251_part_table; | ||
706 | wl->chip.acx_reg_table = wl1251_acx_reg_table; | ||
707 | |||
708 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
709 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h new file mode 100644 index 000000000000..1f4a44330394 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.h | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WL1251_H__ | ||
25 | #define __WL1251_H__ | ||
26 | |||
27 | #include <linux/bitops.h> | ||
28 | |||
29 | #include "wl12xx.h" | ||
30 | #include "acx.h" | ||
31 | |||
32 | #define WL1251_FW_NAME "wl1251-fw.bin" | ||
33 | #define WL1251_NVS_NAME "wl1251-nvs.bin" | ||
34 | |||
35 | #define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ | ||
36 | |||
37 | void wl1251_setup(struct wl12xx *wl); | ||
38 | |||
39 | |||
40 | struct wl1251_acx_memory { | ||
41 | __le16 num_stations; /* number of STAs to be supported. */ | ||
42 | u16 reserved_1; | ||
43 | |||
44 | /* | ||
45 | * Nmber of memory buffers for the RX mem pool. | ||
46 | * The actual number may be less if there are | ||
47 | * not enough blocks left for the minimum num | ||
48 | * of TX ones. | ||
49 | */ | ||
50 | u8 rx_mem_block_num; | ||
51 | u8 reserved_2; | ||
52 | u8 num_tx_queues; /* From 1 to 16 */ | ||
53 | u8 host_if_options; /* HOST_IF* */ | ||
54 | u8 tx_min_mem_block_num; | ||
55 | u8 num_ssid_profiles; | ||
56 | __le16 debug_buffer_size; | ||
57 | } __attribute__ ((packed)); | ||
58 | |||
59 | |||
60 | #define ACX_RX_DESC_MIN 1 | ||
61 | #define ACX_RX_DESC_MAX 127 | ||
62 | #define ACX_RX_DESC_DEF 32 | ||
63 | struct wl1251_acx_rx_queue_config { | ||
64 | u8 num_descs; | ||
65 | u8 pad; | ||
66 | u8 type; | ||
67 | u8 priority; | ||
68 | __le32 dma_address; | ||
69 | } __attribute__ ((packed)); | ||
70 | |||
71 | #define ACX_TX_DESC_MIN 1 | ||
72 | #define ACX_TX_DESC_MAX 127 | ||
73 | #define ACX_TX_DESC_DEF 16 | ||
74 | struct wl1251_acx_tx_queue_config { | ||
75 | u8 num_descs; | ||
76 | u8 pad[2]; | ||
77 | u8 attributes; | ||
78 | } __attribute__ ((packed)); | ||
79 | |||
80 | #define MAX_TX_QUEUE_CONFIGS 5 | ||
81 | #define MAX_TX_QUEUES 4 | ||
82 | struct wl1251_acx_config_memory { | ||
83 | struct acx_header header; | ||
84 | |||
85 | struct wl1251_acx_memory mem_config; | ||
86 | struct wl1251_acx_rx_queue_config rx_queue_config; | ||
87 | struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; | ||
88 | } __attribute__ ((packed)); | ||
89 | |||
90 | struct wl1251_acx_mem_map { | ||
91 | struct acx_header header; | ||
92 | |||
93 | void *code_start; | ||
94 | void *code_end; | ||
95 | |||
96 | void *wep_defkey_start; | ||
97 | void *wep_defkey_end; | ||
98 | |||
99 | void *sta_table_start; | ||
100 | void *sta_table_end; | ||
101 | |||
102 | void *packet_template_start; | ||
103 | void *packet_template_end; | ||
104 | |||
105 | void *queue_memory_start; | ||
106 | void *queue_memory_end; | ||
107 | |||
108 | void *packet_memory_pool_start; | ||
109 | void *packet_memory_pool_end; | ||
110 | |||
111 | void *debug_buffer1_start; | ||
112 | void *debug_buffer1_end; | ||
113 | |||
114 | void *debug_buffer2_start; | ||
115 | void *debug_buffer2_end; | ||
116 | |||
117 | /* Number of blocks FW allocated for TX packets */ | ||
118 | u32 num_tx_mem_blocks; | ||
119 | |||
120 | /* Number of blocks FW allocated for RX packets */ | ||
121 | u32 num_rx_mem_blocks; | ||
122 | } __attribute__ ((packed)); | ||
123 | |||
124 | /************************************************************************* | ||
125 | |||
126 | Host Interrupt Register (WiLink -> Host) | ||
127 | |||
128 | **************************************************************************/ | ||
129 | |||
130 | /* RX packet is ready in Xfer buffer #0 */ | ||
131 | #define WL1251_ACX_INTR_RX0_DATA BIT(0) | ||
132 | |||
133 | /* TX result(s) are in the TX complete buffer */ | ||
134 | #define WL1251_ACX_INTR_TX_RESULT BIT(1) | ||
135 | |||
136 | /* OBSOLETE */ | ||
137 | #define WL1251_ACX_INTR_TX_XFR BIT(2) | ||
138 | |||
139 | /* RX packet is ready in Xfer buffer #1 */ | ||
140 | #define WL1251_ACX_INTR_RX1_DATA BIT(3) | ||
141 | |||
142 | /* Event was entered to Event MBOX #A */ | ||
143 | #define WL1251_ACX_INTR_EVENT_A BIT(4) | ||
144 | |||
145 | /* Event was entered to Event MBOX #B */ | ||
146 | #define WL1251_ACX_INTR_EVENT_B BIT(5) | ||
147 | |||
148 | /* OBSOLETE */ | ||
149 | #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) | ||
150 | |||
151 | /* Trace meassge on MBOX #A */ | ||
152 | #define WL1251_ACX_INTR_TRACE_A BIT(7) | ||
153 | |||
154 | /* Trace meassge on MBOX #B */ | ||
155 | #define WL1251_ACX_INTR_TRACE_B BIT(8) | ||
156 | |||
157 | /* Command processing completion */ | ||
158 | #define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) | ||
159 | |||
160 | /* Init sequence is done */ | ||
161 | #define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) | ||
162 | |||
163 | #define WL1251_ACX_INTR_ALL 0xFFFFFFFF | ||
164 | |||
165 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h new file mode 100644 index 000000000000..48641437414b --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx.h | |||
@@ -0,0 +1,409 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_H__ | ||
26 | #define __WL12XX_H__ | ||
27 | |||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/bitops.h> | ||
31 | #include <net/mac80211.h> | ||
32 | |||
33 | #define DRIVER_NAME "wl12xx" | ||
34 | #define DRIVER_PREFIX DRIVER_NAME ": " | ||
35 | |||
36 | enum { | ||
37 | DEBUG_NONE = 0, | ||
38 | DEBUG_IRQ = BIT(0), | ||
39 | DEBUG_SPI = BIT(1), | ||
40 | DEBUG_BOOT = BIT(2), | ||
41 | DEBUG_MAILBOX = BIT(3), | ||
42 | DEBUG_NETLINK = BIT(4), | ||
43 | DEBUG_EVENT = BIT(5), | ||
44 | DEBUG_TX = BIT(6), | ||
45 | DEBUG_RX = BIT(7), | ||
46 | DEBUG_SCAN = BIT(8), | ||
47 | DEBUG_CRYPT = BIT(9), | ||
48 | DEBUG_PSM = BIT(10), | ||
49 | DEBUG_MAC80211 = BIT(11), | ||
50 | DEBUG_CMD = BIT(12), | ||
51 | DEBUG_ACX = BIT(13), | ||
52 | DEBUG_ALL = ~0, | ||
53 | }; | ||
54 | |||
55 | #define DEBUG_LEVEL (DEBUG_NONE) | ||
56 | |||
57 | #define DEBUG_DUMP_LIMIT 1024 | ||
58 | |||
59 | #define wl12xx_error(fmt, arg...) \ | ||
60 | printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) | ||
61 | |||
62 | #define wl12xx_warning(fmt, arg...) \ | ||
63 | printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) | ||
64 | |||
65 | #define wl12xx_notice(fmt, arg...) \ | ||
66 | printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) | ||
67 | |||
68 | #define wl12xx_info(fmt, arg...) \ | ||
69 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) | ||
70 | |||
71 | #define wl12xx_debug(level, fmt, arg...) \ | ||
72 | do { \ | ||
73 | if (level & DEBUG_LEVEL) \ | ||
74 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ | ||
75 | } while (0) | ||
76 | |||
77 | #define wl12xx_dump(level, prefix, buf, len) \ | ||
78 | do { \ | ||
79 | if (level & DEBUG_LEVEL) \ | ||
80 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
81 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
82 | buf, \ | ||
83 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
84 | 0); \ | ||
85 | } while (0) | ||
86 | |||
87 | #define wl12xx_dump_ascii(level, prefix, buf, len) \ | ||
88 | do { \ | ||
89 | if (level & DEBUG_LEVEL) \ | ||
90 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
91 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
92 | buf, \ | ||
93 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
94 | true); \ | ||
95 | } while (0) | ||
96 | |||
97 | #define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ | ||
98 | CFG_BSSID_FILTER_EN) | ||
99 | |||
100 | #define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ | ||
101 | CFG_RX_MGMT_EN | \ | ||
102 | CFG_RX_DATA_EN | \ | ||
103 | CFG_RX_CTL_EN | \ | ||
104 | CFG_RX_BCN_EN | \ | ||
105 | CFG_RX_AUTH_EN | \ | ||
106 | CFG_RX_ASSOC_EN) | ||
107 | |||
108 | |||
109 | struct boot_attr { | ||
110 | u32 radio_type; | ||
111 | u8 mac_clock; | ||
112 | u8 arm_clock; | ||
113 | int firmware_debug; | ||
114 | u32 minor; | ||
115 | u32 major; | ||
116 | u32 bugfix; | ||
117 | }; | ||
118 | |||
119 | enum wl12xx_state { | ||
120 | WL12XX_STATE_OFF, | ||
121 | WL12XX_STATE_ON, | ||
122 | WL12XX_STATE_PLT, | ||
123 | }; | ||
124 | |||
125 | enum wl12xx_partition_type { | ||
126 | PART_DOWN, | ||
127 | PART_WORK, | ||
128 | PART_DRPW, | ||
129 | |||
130 | PART_TABLE_LEN | ||
131 | }; | ||
132 | |||
133 | struct wl12xx_partition { | ||
134 | u32 size; | ||
135 | u32 start; | ||
136 | }; | ||
137 | |||
138 | struct wl12xx_partition_set { | ||
139 | struct wl12xx_partition mem; | ||
140 | struct wl12xx_partition reg; | ||
141 | }; | ||
142 | |||
143 | struct wl12xx; | ||
144 | |||
145 | /* FIXME: I'm not sure about this structure name */ | ||
146 | struct wl12xx_chip { | ||
147 | u32 id; | ||
148 | |||
149 | const char *fw_filename; | ||
150 | const char *nvs_filename; | ||
151 | |||
152 | char fw_ver[21]; | ||
153 | |||
154 | unsigned int power_on_sleep; | ||
155 | int intr_cmd_complete; | ||
156 | int intr_init_complete; | ||
157 | |||
158 | int (*op_upload_fw)(struct wl12xx *wl); | ||
159 | int (*op_upload_nvs)(struct wl12xx *wl); | ||
160 | int (*op_boot)(struct wl12xx *wl); | ||
161 | void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); | ||
162 | void (*op_target_enable_interrupts)(struct wl12xx *wl); | ||
163 | int (*op_hw_init)(struct wl12xx *wl); | ||
164 | int (*op_plt_init)(struct wl12xx *wl); | ||
165 | |||
166 | struct wl12xx_partition_set *p_table; | ||
167 | enum wl12xx_acx_int_reg *acx_reg_table; | ||
168 | }; | ||
169 | |||
170 | struct wl12xx_stats { | ||
171 | struct acx_statistics *fw_stats; | ||
172 | unsigned long fw_stats_update; | ||
173 | |||
174 | unsigned int retry_count; | ||
175 | unsigned int excessive_retries; | ||
176 | }; | ||
177 | |||
178 | struct wl12xx_debugfs { | ||
179 | struct dentry *rootdir; | ||
180 | struct dentry *fw_statistics; | ||
181 | |||
182 | struct dentry *tx_internal_desc_overflow; | ||
183 | |||
184 | struct dentry *rx_out_of_mem; | ||
185 | struct dentry *rx_hdr_overflow; | ||
186 | struct dentry *rx_hw_stuck; | ||
187 | struct dentry *rx_dropped; | ||
188 | struct dentry *rx_fcs_err; | ||
189 | struct dentry *rx_xfr_hint_trig; | ||
190 | struct dentry *rx_path_reset; | ||
191 | struct dentry *rx_reset_counter; | ||
192 | |||
193 | struct dentry *dma_rx_requested; | ||
194 | struct dentry *dma_rx_errors; | ||
195 | struct dentry *dma_tx_requested; | ||
196 | struct dentry *dma_tx_errors; | ||
197 | |||
198 | struct dentry *isr_cmd_cmplt; | ||
199 | struct dentry *isr_fiqs; | ||
200 | struct dentry *isr_rx_headers; | ||
201 | struct dentry *isr_rx_mem_overflow; | ||
202 | struct dentry *isr_rx_rdys; | ||
203 | struct dentry *isr_irqs; | ||
204 | struct dentry *isr_tx_procs; | ||
205 | struct dentry *isr_decrypt_done; | ||
206 | struct dentry *isr_dma0_done; | ||
207 | struct dentry *isr_dma1_done; | ||
208 | struct dentry *isr_tx_exch_complete; | ||
209 | struct dentry *isr_commands; | ||
210 | struct dentry *isr_rx_procs; | ||
211 | struct dentry *isr_hw_pm_mode_changes; | ||
212 | struct dentry *isr_host_acknowledges; | ||
213 | struct dentry *isr_pci_pm; | ||
214 | struct dentry *isr_wakeups; | ||
215 | struct dentry *isr_low_rssi; | ||
216 | |||
217 | struct dentry *wep_addr_key_count; | ||
218 | struct dentry *wep_default_key_count; | ||
219 | /* skipping wep.reserved */ | ||
220 | struct dentry *wep_key_not_found; | ||
221 | struct dentry *wep_decrypt_fail; | ||
222 | struct dentry *wep_packets; | ||
223 | struct dentry *wep_interrupt; | ||
224 | |||
225 | struct dentry *pwr_ps_enter; | ||
226 | struct dentry *pwr_elp_enter; | ||
227 | struct dentry *pwr_missing_bcns; | ||
228 | struct dentry *pwr_wake_on_host; | ||
229 | struct dentry *pwr_wake_on_timer_exp; | ||
230 | struct dentry *pwr_tx_with_ps; | ||
231 | struct dentry *pwr_tx_without_ps; | ||
232 | struct dentry *pwr_rcvd_beacons; | ||
233 | struct dentry *pwr_power_save_off; | ||
234 | struct dentry *pwr_enable_ps; | ||
235 | struct dentry *pwr_disable_ps; | ||
236 | struct dentry *pwr_fix_tsf_ps; | ||
237 | /* skipping cont_miss_bcns_spread for now */ | ||
238 | struct dentry *pwr_rcvd_awake_beacons; | ||
239 | |||
240 | struct dentry *mic_rx_pkts; | ||
241 | struct dentry *mic_calc_failure; | ||
242 | |||
243 | struct dentry *aes_encrypt_fail; | ||
244 | struct dentry *aes_decrypt_fail; | ||
245 | struct dentry *aes_encrypt_packets; | ||
246 | struct dentry *aes_decrypt_packets; | ||
247 | struct dentry *aes_encrypt_interrupt; | ||
248 | struct dentry *aes_decrypt_interrupt; | ||
249 | |||
250 | struct dentry *event_heart_beat; | ||
251 | struct dentry *event_calibration; | ||
252 | struct dentry *event_rx_mismatch; | ||
253 | struct dentry *event_rx_mem_empty; | ||
254 | struct dentry *event_rx_pool; | ||
255 | struct dentry *event_oom_late; | ||
256 | struct dentry *event_phy_transmit_error; | ||
257 | struct dentry *event_tx_stuck; | ||
258 | |||
259 | struct dentry *ps_pspoll_timeouts; | ||
260 | struct dentry *ps_upsd_timeouts; | ||
261 | struct dentry *ps_upsd_max_sptime; | ||
262 | struct dentry *ps_upsd_max_apturn; | ||
263 | struct dentry *ps_pspoll_max_apturn; | ||
264 | struct dentry *ps_pspoll_utilization; | ||
265 | struct dentry *ps_upsd_utilization; | ||
266 | |||
267 | struct dentry *rxpipe_rx_prep_beacon_drop; | ||
268 | struct dentry *rxpipe_descr_host_int_trig_rx_data; | ||
269 | struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; | ||
270 | struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; | ||
271 | struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; | ||
272 | |||
273 | struct dentry *tx_queue_len; | ||
274 | |||
275 | struct dentry *retry_count; | ||
276 | struct dentry *excessive_retries; | ||
277 | }; | ||
278 | |||
279 | struct wl12xx { | ||
280 | struct ieee80211_hw *hw; | ||
281 | bool mac80211_registered; | ||
282 | |||
283 | struct spi_device *spi; | ||
284 | |||
285 | void (*set_power)(bool enable); | ||
286 | int irq; | ||
287 | |||
288 | enum wl12xx_state state; | ||
289 | struct mutex mutex; | ||
290 | |||
291 | int physical_mem_addr; | ||
292 | int physical_reg_addr; | ||
293 | int virtual_mem_addr; | ||
294 | int virtual_reg_addr; | ||
295 | |||
296 | struct wl12xx_chip chip; | ||
297 | |||
298 | int cmd_box_addr; | ||
299 | int event_box_addr; | ||
300 | struct boot_attr boot_attr; | ||
301 | |||
302 | u8 *fw; | ||
303 | size_t fw_len; | ||
304 | u8 *nvs; | ||
305 | size_t nvs_len; | ||
306 | |||
307 | u8 bssid[ETH_ALEN]; | ||
308 | u8 mac_addr[ETH_ALEN]; | ||
309 | u8 bss_type; | ||
310 | u8 listen_int; | ||
311 | int channel; | ||
312 | |||
313 | void *target_mem_map; | ||
314 | struct acx_data_path_params_resp *data_path; | ||
315 | |||
316 | /* Number of TX packets transferred to the FW, modulo 16 */ | ||
317 | u32 data_in_count; | ||
318 | |||
319 | /* Frames scheduled for transmission, not handled yet */ | ||
320 | struct sk_buff_head tx_queue; | ||
321 | bool tx_queue_stopped; | ||
322 | |||
323 | struct work_struct tx_work; | ||
324 | struct work_struct filter_work; | ||
325 | |||
326 | /* Pending TX frames */ | ||
327 | struct sk_buff *tx_frames[16]; | ||
328 | |||
329 | /* | ||
330 | * Index pointing to the next TX complete entry | ||
331 | * in the cyclic XT complete array we get from | ||
332 | * the FW. | ||
333 | */ | ||
334 | u32 next_tx_complete; | ||
335 | |||
336 | /* FW Rx counter */ | ||
337 | u32 rx_counter; | ||
338 | |||
339 | /* Rx frames handled */ | ||
340 | u32 rx_handled; | ||
341 | |||
342 | /* Current double buffer */ | ||
343 | u32 rx_current_buffer; | ||
344 | u32 rx_last_id; | ||
345 | |||
346 | /* The target interrupt mask */ | ||
347 | u32 intr_mask; | ||
348 | struct work_struct irq_work; | ||
349 | |||
350 | /* The mbox event mask */ | ||
351 | u32 event_mask; | ||
352 | |||
353 | /* Mailbox pointers */ | ||
354 | u32 mbox_ptr[2]; | ||
355 | |||
356 | /* Are we currently scanning */ | ||
357 | bool scanning; | ||
358 | |||
359 | /* Our association ID */ | ||
360 | u16 aid; | ||
361 | |||
362 | /* Default key (for WEP) */ | ||
363 | u32 default_key; | ||
364 | |||
365 | unsigned int tx_mgmt_frm_rate; | ||
366 | unsigned int tx_mgmt_frm_mod; | ||
367 | |||
368 | unsigned int rx_config; | ||
369 | unsigned int rx_filter; | ||
370 | |||
371 | /* is firmware in elp mode */ | ||
372 | bool elp; | ||
373 | |||
374 | /* we can be in psm, but not in elp, we have to differentiate */ | ||
375 | bool psm; | ||
376 | |||
377 | /* PSM mode requested */ | ||
378 | bool psm_requested; | ||
379 | |||
380 | /* in dBm */ | ||
381 | int power_level; | ||
382 | |||
383 | struct wl12xx_stats stats; | ||
384 | struct wl12xx_debugfs debugfs; | ||
385 | }; | ||
386 | |||
387 | int wl12xx_plt_start(struct wl12xx *wl); | ||
388 | int wl12xx_plt_stop(struct wl12xx *wl); | ||
389 | |||
390 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ | ||
391 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS | ||
392 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | ||
393 | |||
394 | #define WL12XX_DEFAULT_POWER_LEVEL 20 | ||
395 | |||
396 | #define WL12XX_TX_QUEUE_MAX_LENGTH 20 | ||
397 | |||
398 | /* Different chips need different sleep times after power on. WL1271 needs | ||
399 | * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we | ||
400 | * know the chip ID, we change the sleep value in the wl12xx chip structure, | ||
401 | * so in subsequent power ons, we don't waste more time then needed. */ | ||
402 | #define WL12XX_DEFAULT_POWER_ON_SLEEP 200 | ||
403 | |||
404 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
405 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
406 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
407 | #define CHIP_ID_1271_PG10 (0x4030101) | ||
408 | |||
409 | #endif | ||
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h new file mode 100644 index 000000000000..657c2dbcb7d3 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h | |||
@@ -0,0 +1,156 @@ | |||
1 | #ifndef __WL12XX_80211_H__ | ||
2 | #define __WL12XX_80211_H__ | ||
3 | |||
4 | #include <linux/if_ether.h> /* ETH_ALEN */ | ||
5 | |||
6 | /* RATES */ | ||
7 | #define IEEE80211_CCK_RATE_1MB 0x02 | ||
8 | #define IEEE80211_CCK_RATE_2MB 0x04 | ||
9 | #define IEEE80211_CCK_RATE_5MB 0x0B | ||
10 | #define IEEE80211_CCK_RATE_11MB 0x16 | ||
11 | #define IEEE80211_OFDM_RATE_6MB 0x0C | ||
12 | #define IEEE80211_OFDM_RATE_9MB 0x12 | ||
13 | #define IEEE80211_OFDM_RATE_12MB 0x18 | ||
14 | #define IEEE80211_OFDM_RATE_18MB 0x24 | ||
15 | #define IEEE80211_OFDM_RATE_24MB 0x30 | ||
16 | #define IEEE80211_OFDM_RATE_36MB 0x48 | ||
17 | #define IEEE80211_OFDM_RATE_48MB 0x60 | ||
18 | #define IEEE80211_OFDM_RATE_54MB 0x6C | ||
19 | #define IEEE80211_BASIC_RATE_MASK 0x80 | ||
20 | |||
21 | #define IEEE80211_CCK_RATE_1MB_MASK (1<<0) | ||
22 | #define IEEE80211_CCK_RATE_2MB_MASK (1<<1) | ||
23 | #define IEEE80211_CCK_RATE_5MB_MASK (1<<2) | ||
24 | #define IEEE80211_CCK_RATE_11MB_MASK (1<<3) | ||
25 | #define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) | ||
26 | #define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) | ||
27 | #define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) | ||
28 | #define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) | ||
29 | #define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) | ||
30 | #define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) | ||
31 | #define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) | ||
32 | #define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) | ||
33 | |||
34 | #define IEEE80211_CCK_RATES_MASK 0x0000000F | ||
35 | #define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ | ||
36 | IEEE80211_CCK_RATE_2MB_MASK) | ||
37 | #define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ | ||
38 | IEEE80211_CCK_RATE_5MB_MASK | \ | ||
39 | IEEE80211_CCK_RATE_11MB_MASK) | ||
40 | |||
41 | #define IEEE80211_OFDM_RATES_MASK 0x00000FF0 | ||
42 | #define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ | ||
43 | IEEE80211_OFDM_RATE_12MB_MASK | \ | ||
44 | IEEE80211_OFDM_RATE_24MB_MASK) | ||
45 | #define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ | ||
46 | IEEE80211_OFDM_RATE_9MB_MASK | \ | ||
47 | IEEE80211_OFDM_RATE_18MB_MASK | \ | ||
48 | IEEE80211_OFDM_RATE_36MB_MASK | \ | ||
49 | IEEE80211_OFDM_RATE_48MB_MASK | \ | ||
50 | IEEE80211_OFDM_RATE_54MB_MASK) | ||
51 | #define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ | ||
52 | IEEE80211_CCK_DEFAULT_RATES_MASK) | ||
53 | |||
54 | |||
55 | /* This really should be 8, but not for our firmware */ | ||
56 | #define MAX_SUPPORTED_RATES 32 | ||
57 | #define COUNTRY_STRING_LEN 3 | ||
58 | #define MAX_COUNTRY_TRIPLETS 32 | ||
59 | |||
60 | /* Headers */ | ||
61 | struct ieee80211_header { | ||
62 | __le16 frame_ctl; | ||
63 | __le16 duration_id; | ||
64 | u8 da[ETH_ALEN]; | ||
65 | u8 sa[ETH_ALEN]; | ||
66 | u8 bssid[ETH_ALEN]; | ||
67 | __le16 seq_ctl; | ||
68 | u8 payload[0]; | ||
69 | } __attribute__ ((packed)); | ||
70 | |||
71 | struct wl12xx_ie_header { | ||
72 | u8 id; | ||
73 | u8 len; | ||
74 | } __attribute__ ((packed)); | ||
75 | |||
76 | /* IEs */ | ||
77 | |||
78 | struct wl12xx_ie_ssid { | ||
79 | struct wl12xx_ie_header header; | ||
80 | char ssid[IW_ESSID_MAX_SIZE]; | ||
81 | } __attribute__ ((packed)); | ||
82 | |||
83 | struct wl12xx_ie_rates { | ||
84 | struct wl12xx_ie_header header; | ||
85 | u8 rates[MAX_SUPPORTED_RATES]; | ||
86 | } __attribute__ ((packed)); | ||
87 | |||
88 | struct wl12xx_ie_ds_params { | ||
89 | struct wl12xx_ie_header header; | ||
90 | u8 channel; | ||
91 | } __attribute__ ((packed)); | ||
92 | |||
93 | struct country_triplet { | ||
94 | u8 channel; | ||
95 | u8 num_channels; | ||
96 | u8 max_tx_power; | ||
97 | } __attribute__ ((packed)); | ||
98 | |||
99 | struct wl12xx_ie_country { | ||
100 | struct wl12xx_ie_header header; | ||
101 | u8 country_string[COUNTRY_STRING_LEN]; | ||
102 | struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; | ||
103 | } __attribute__ ((packed)); | ||
104 | |||
105 | |||
106 | /* Templates */ | ||
107 | |||
108 | struct wl12xx_beacon_template { | ||
109 | struct ieee80211_header header; | ||
110 | __le32 time_stamp[2]; | ||
111 | __le16 beacon_interval; | ||
112 | __le16 capability; | ||
113 | struct wl12xx_ie_ssid ssid; | ||
114 | struct wl12xx_ie_rates rates; | ||
115 | struct wl12xx_ie_rates ext_rates; | ||
116 | struct wl12xx_ie_ds_params ds_params; | ||
117 | struct wl12xx_ie_country country; | ||
118 | } __attribute__ ((packed)); | ||
119 | |||
120 | struct wl12xx_null_data_template { | ||
121 | struct ieee80211_header header; | ||
122 | } __attribute__ ((packed)); | ||
123 | |||
124 | struct wl12xx_ps_poll_template { | ||
125 | u16 fc; | ||
126 | u16 aid; | ||
127 | u8 bssid[ETH_ALEN]; | ||
128 | u8 ta[ETH_ALEN]; | ||
129 | } __attribute__ ((packed)); | ||
130 | |||
131 | struct wl12xx_qos_null_data_template { | ||
132 | struct ieee80211_header header; | ||
133 | __le16 qos_ctl; | ||
134 | } __attribute__ ((packed)); | ||
135 | |||
136 | struct wl12xx_probe_req_template { | ||
137 | struct ieee80211_header header; | ||
138 | struct wl12xx_ie_ssid ssid; | ||
139 | struct wl12xx_ie_rates rates; | ||
140 | struct wl12xx_ie_rates ext_rates; | ||
141 | } __attribute__ ((packed)); | ||
142 | |||
143 | |||
144 | struct wl12xx_probe_resp_template { | ||
145 | struct ieee80211_header header; | ||
146 | __le32 time_stamp[2]; | ||
147 | __le16 beacon_interval; | ||
148 | __le16 capability; | ||
149 | struct wl12xx_ie_ssid ssid; | ||
150 | struct wl12xx_ie_rates rates; | ||
151 | struct wl12xx_ie_rates ext_rates; | ||
152 | struct wl12xx_ie_ds_params ds_params; | ||
153 | struct wl12xx_ie_country country; | ||
154 | } __attribute__ ((packed)); | ||
155 | |||
156 | #endif | ||