diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 481 |
1 files changed, 303 insertions, 178 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index e4867b895c43..2a864b24291d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of wl1271 | 2 | * This file is part of wl1271 |
3 | * | 3 | * |
4 | * Copyright (C) 2008-2009 Nokia Corporation | 4 | * Copyright (C) 2008-2010 Nokia Corporation |
5 | * | 5 | * |
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | 6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> |
7 | * | 7 | * |
@@ -38,6 +38,7 @@ | |||
38 | #include "wl12xx_80211.h" | 38 | #include "wl12xx_80211.h" |
39 | #include "wl1271_reg.h" | 39 | #include "wl1271_reg.h" |
40 | #include "wl1271_spi.h" | 40 | #include "wl1271_spi.h" |
41 | #include "wl1271_io.h" | ||
41 | #include "wl1271_event.h" | 42 | #include "wl1271_event.h" |
42 | #include "wl1271_tx.h" | 43 | #include "wl1271_tx.h" |
43 | #include "wl1271_rx.h" | 44 | #include "wl1271_rx.h" |
@@ -46,6 +47,7 @@ | |||
46 | #include "wl1271_debugfs.h" | 47 | #include "wl1271_debugfs.h" |
47 | #include "wl1271_cmd.h" | 48 | #include "wl1271_cmd.h" |
48 | #include "wl1271_boot.h" | 49 | #include "wl1271_boot.h" |
50 | #include "wl1271_testmode.h" | ||
49 | 51 | ||
50 | #define WL1271_BOOT_RETRIES 3 | 52 | #define WL1271_BOOT_RETRIES 3 |
51 | 53 | ||
@@ -229,93 +231,8 @@ static struct conf_drv_settings default_conf = { | |||
229 | .psm_entry_retries = 3 | 231 | .psm_entry_retries = 3 |
230 | }, | 232 | }, |
231 | .init = { | 233 | .init = { |
232 | .genparam = { | ||
233 | .ref_clk = CONF_REF_CLK_38_4_E, | ||
234 | .settling_time = 5, | ||
235 | .clk_valid_on_wakeup = 0, | ||
236 | .dc2dcmode = 0, | ||
237 | .single_dual_band = CONF_SINGLE_BAND, | ||
238 | .tx_bip_fem_autodetect = 1, | ||
239 | .tx_bip_fem_manufacturer = 1, | ||
240 | .settings = 1, | ||
241 | .sr_state = 1, | ||
242 | .srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, | ||
243 | 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
244 | .srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, | ||
245 | 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
246 | .srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, | ||
247 | 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
248 | .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0, | ||
249 | 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
250 | .sr_sen_n_p = 0, | ||
251 | .sr_sen_n_p_gain = 0, | ||
252 | .sr_sen_nrn = 0, | ||
253 | .sr_sen_prn = 0, | ||
254 | }, | ||
255 | .radioparam = { | 234 | .radioparam = { |
256 | .rx_trace_loss = 0x24, | 235 | .fem = 1, |
257 | .tx_trace_loss = 0x0, | ||
258 | .rx_rssi_and_proc_compens = { | ||
259 | 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, | ||
260 | 0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8, | ||
261 | 0x00, 0x0a, 0x14 }, | ||
262 | .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, | ||
263 | .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, | ||
264 | .rx_rssi_and_proc_compens_5 = { | ||
265 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
266 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
267 | 0x00, 0x00, 0x00 }, | ||
268 | .tx_ref_pd_voltage = 0x1a9, | ||
269 | .tx_ref_power = 0x80, | ||
270 | .tx_offset_db = 0x0, | ||
271 | .tx_rate_limits_normal = { | ||
272 | 0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 }, | ||
273 | .tx_rate_limits_degraded = { | ||
274 | 0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 }, | ||
275 | .tx_rate_limits_extreme = { | ||
276 | 0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, | ||
277 | .tx_channel_limits_11b = { | ||
278 | 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, | ||
279 | 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, | ||
280 | 0x22, 0x50 }, | ||
281 | .tx_channel_limits_ofdm = { | ||
282 | 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, | ||
283 | 0x50, 0x50, 0x50, 0x50, 0x20, 0x50, | ||
284 | 0x20, 0x50 }, | ||
285 | .tx_pdv_rate_offsets = { | ||
286 | 0x07, 0x08, 0x04, 0x02, 0x02, 0x00 }, | ||
287 | .tx_ibias = { | ||
288 | 0x11, 0x11, 0x15, 0x11, 0x15, 0x0f }, | ||
289 | .rx_fem_insertion_loss = 0x0e, | ||
290 | .degraded_low_to_normal_threshold = 0x1e, | ||
291 | .degraded_normal_to_high_threshold = 0x2d, | ||
292 | .tx_ref_pd_voltage_5 = { | ||
293 | 0x0190, 0x01a4, 0x01c3, 0x01d8, | ||
294 | 0x020a, 0x021c }, | ||
295 | .tx_ref_power_5 = { | ||
296 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, | ||
297 | .tx_offset_db_5 = { | ||
298 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | ||
299 | .tx_rate_limits_normal_5 = { | ||
300 | 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, | ||
301 | .tx_rate_limits_degraded_5 = { | ||
302 | 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, | ||
303 | .tx_rate_limits_extreme_5 = { | ||
304 | 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, | ||
305 | .tx_channel_limits_ofdm_5 = { | ||
306 | 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, | ||
307 | 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, | ||
308 | 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, | ||
309 | 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, | ||
310 | 0x50, 0x50, 0x50 }, | ||
311 | .tx_pdv_rate_offsets_5 = { | ||
312 | 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 }, | ||
313 | .tx_ibias_5 = { | ||
314 | 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, | ||
315 | .rx_fem_insertion_loss_5 = { | ||
316 | 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, | ||
317 | .degraded_low_to_normal_threshold_5 = 0x00, | ||
318 | .degraded_normal_to_high_threshold_5 = 0x00 | ||
319 | } | 236 | } |
320 | }, | 237 | }, |
321 | .itrim = { | 238 | .itrim = { |
@@ -345,15 +262,14 @@ static void wl1271_conf_init(struct wl1271 *wl) | |||
345 | 262 | ||
346 | /* apply driver default configuration */ | 263 | /* apply driver default configuration */ |
347 | memcpy(&wl->conf, &default_conf, sizeof(default_conf)); | 264 | memcpy(&wl->conf, &default_conf, sizeof(default_conf)); |
348 | |||
349 | if (wl1271_11a_enabled()) | ||
350 | wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND; | ||
351 | } | 265 | } |
352 | 266 | ||
353 | 267 | ||
354 | static int wl1271_plt_init(struct wl1271 *wl) | 268 | static int wl1271_plt_init(struct wl1271 *wl) |
355 | { | 269 | { |
356 | int ret; | 270 | struct conf_tx_ac_category *conf_ac; |
271 | struct conf_tx_tid *conf_tid; | ||
272 | int ret, i; | ||
357 | 273 | ||
358 | ret = wl1271_cmd_general_parms(wl); | 274 | ret = wl1271_cmd_general_parms(wl); |
359 | if (ret < 0) | 275 | if (ret < 0) |
@@ -363,15 +279,89 @@ static int wl1271_plt_init(struct wl1271 *wl) | |||
363 | if (ret < 0) | 279 | if (ret < 0) |
364 | return ret; | 280 | return ret; |
365 | 281 | ||
282 | ret = wl1271_init_templates_config(wl); | ||
283 | if (ret < 0) | ||
284 | return ret; | ||
285 | |||
366 | ret = wl1271_acx_init_mem_config(wl); | 286 | ret = wl1271_acx_init_mem_config(wl); |
367 | if (ret < 0) | 287 | if (ret < 0) |
368 | return ret; | 288 | return ret; |
369 | 289 | ||
290 | /* PHY layer config */ | ||
291 | ret = wl1271_init_phy_config(wl); | ||
292 | if (ret < 0) | ||
293 | goto out_free_memmap; | ||
294 | |||
295 | ret = wl1271_acx_dco_itrim_params(wl); | ||
296 | if (ret < 0) | ||
297 | goto out_free_memmap; | ||
298 | |||
299 | /* Initialize connection monitoring thresholds */ | ||
300 | ret = wl1271_acx_conn_monit_params(wl); | ||
301 | if (ret < 0) | ||
302 | goto out_free_memmap; | ||
303 | |||
304 | /* Bluetooth WLAN coexistence */ | ||
305 | ret = wl1271_init_pta(wl); | ||
306 | if (ret < 0) | ||
307 | goto out_free_memmap; | ||
308 | |||
309 | /* Energy detection */ | ||
310 | ret = wl1271_init_energy_detection(wl); | ||
311 | if (ret < 0) | ||
312 | goto out_free_memmap; | ||
313 | |||
314 | /* Default fragmentation threshold */ | ||
315 | ret = wl1271_acx_frag_threshold(wl); | ||
316 | if (ret < 0) | ||
317 | goto out_free_memmap; | ||
318 | |||
319 | /* Default TID configuration */ | ||
320 | for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { | ||
321 | conf_tid = &wl->conf.tx.tid_conf[i]; | ||
322 | ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, | ||
323 | conf_tid->channel_type, | ||
324 | conf_tid->tsid, | ||
325 | conf_tid->ps_scheme, | ||
326 | conf_tid->ack_policy, | ||
327 | conf_tid->apsd_conf[0], | ||
328 | conf_tid->apsd_conf[1]); | ||
329 | if (ret < 0) | ||
330 | goto out_free_memmap; | ||
331 | } | ||
332 | |||
333 | /* Default AC configuration */ | ||
334 | for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { | ||
335 | conf_ac = &wl->conf.tx.ac_conf[i]; | ||
336 | ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, | ||
337 | conf_ac->cw_max, conf_ac->aifsn, | ||
338 | conf_ac->tx_op_limit); | ||
339 | if (ret < 0) | ||
340 | goto out_free_memmap; | ||
341 | } | ||
342 | |||
343 | /* Enable data path */ | ||
370 | ret = wl1271_cmd_data_path(wl, 1); | 344 | ret = wl1271_cmd_data_path(wl, 1); |
371 | if (ret < 0) | 345 | if (ret < 0) |
372 | return ret; | 346 | goto out_free_memmap; |
347 | |||
348 | /* Configure for CAM power saving (ie. always active) */ | ||
349 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
350 | if (ret < 0) | ||
351 | goto out_free_memmap; | ||
352 | |||
353 | /* configure PM */ | ||
354 | ret = wl1271_acx_pm_config(wl); | ||
355 | if (ret < 0) | ||
356 | goto out_free_memmap; | ||
373 | 357 | ||
374 | return 0; | 358 | return 0; |
359 | |||
360 | out_free_memmap: | ||
361 | kfree(wl->target_mem_map); | ||
362 | wl->target_mem_map = NULL; | ||
363 | |||
364 | return ret; | ||
375 | } | 365 | } |
376 | 366 | ||
377 | static void wl1271_disable_interrupts(struct wl1271 *wl) | 367 | static void wl1271_disable_interrupts(struct wl1271 *wl) |
@@ -397,8 +387,7 @@ static void wl1271_fw_status(struct wl1271 *wl, | |||
397 | u32 total = 0; | 387 | u32 total = 0; |
398 | int i; | 388 | int i; |
399 | 389 | ||
400 | wl1271_spi_read(wl, FW_STATUS_ADDR, status, | 390 | wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); |
401 | sizeof(*status), false); | ||
402 | 391 | ||
403 | wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " | 392 | wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " |
404 | "drv_rx_counter = %d, tx_results_counter = %d)", | 393 | "drv_rx_counter = %d, tx_results_counter = %d)", |
@@ -445,7 +434,7 @@ static void wl1271_irq_work(struct work_struct *work) | |||
445 | if (ret < 0) | 434 | if (ret < 0) |
446 | goto out; | 435 | goto out; |
447 | 436 | ||
448 | wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | 437 | wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); |
449 | 438 | ||
450 | wl1271_fw_status(wl, wl->fw_status); | 439 | wl1271_fw_status(wl, wl->fw_status); |
451 | intr = le32_to_cpu(wl->fw_status->intr); | 440 | intr = le32_to_cpu(wl->fw_status->intr); |
@@ -487,8 +476,8 @@ static void wl1271_irq_work(struct work_struct *work) | |||
487 | } | 476 | } |
488 | 477 | ||
489 | out_sleep: | 478 | out_sleep: |
490 | wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, | 479 | wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, |
491 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | 480 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); |
492 | wl1271_ps_elp_sleep(wl); | 481 | wl1271_ps_elp_sleep(wl); |
493 | 482 | ||
494 | out: | 483 | out: |
@@ -555,6 +544,40 @@ out: | |||
555 | return ret; | 544 | return ret; |
556 | } | 545 | } |
557 | 546 | ||
547 | static int wl1271_update_mac_addr(struct wl1271 *wl) | ||
548 | { | ||
549 | int ret = 0; | ||
550 | u8 *nvs_ptr = (u8 *)wl->nvs->nvs; | ||
551 | |||
552 | /* get mac address from the NVS */ | ||
553 | wl->mac_addr[0] = nvs_ptr[11]; | ||
554 | wl->mac_addr[1] = nvs_ptr[10]; | ||
555 | wl->mac_addr[2] = nvs_ptr[6]; | ||
556 | wl->mac_addr[3] = nvs_ptr[5]; | ||
557 | wl->mac_addr[4] = nvs_ptr[4]; | ||
558 | wl->mac_addr[5] = nvs_ptr[3]; | ||
559 | |||
560 | /* FIXME: if it is a zero-address, we should bail out. Now, instead, | ||
561 | we randomize an address */ | ||
562 | if (is_zero_ether_addr(wl->mac_addr)) { | ||
563 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
564 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
565 | get_random_bytes(wl->mac_addr + 3, 3); | ||
566 | |||
567 | /* update this address to the NVS */ | ||
568 | nvs_ptr[11] = wl->mac_addr[0]; | ||
569 | nvs_ptr[10] = wl->mac_addr[1]; | ||
570 | nvs_ptr[6] = wl->mac_addr[2]; | ||
571 | nvs_ptr[5] = wl->mac_addr[3]; | ||
572 | nvs_ptr[4] = wl->mac_addr[4]; | ||
573 | nvs_ptr[3] = wl->mac_addr[5]; | ||
574 | } | ||
575 | |||
576 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
577 | |||
578 | return ret; | ||
579 | } | ||
580 | |||
558 | static int wl1271_fetch_nvs(struct wl1271 *wl) | 581 | static int wl1271_fetch_nvs(struct wl1271 *wl) |
559 | { | 582 | { |
560 | const struct firmware *fw; | 583 | const struct firmware *fw; |
@@ -567,15 +590,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) | |||
567 | return ret; | 590 | return ret; |
568 | } | 591 | } |
569 | 592 | ||
570 | if (fw->size % 4) { | 593 | if (fw->size != sizeof(struct wl1271_nvs_file)) { |
571 | wl1271_error("nvs size is not multiple of 32 bits: %zu", | 594 | wl1271_error("nvs size is not as expected: %zu != %zu", |
572 | fw->size); | 595 | fw->size, sizeof(struct wl1271_nvs_file)); |
573 | ret = -EILSEQ; | 596 | ret = -EILSEQ; |
574 | goto out; | 597 | goto out; |
575 | } | 598 | } |
576 | 599 | ||
577 | wl->nvs_len = fw->size; | 600 | wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); |
578 | wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); | ||
579 | 601 | ||
580 | if (!wl->nvs) { | 602 | if (!wl->nvs) { |
581 | wl1271_error("could not allocate memory for the nvs file"); | 603 | wl1271_error("could not allocate memory for the nvs file"); |
@@ -583,9 +605,9 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) | |||
583 | goto out; | 605 | goto out; |
584 | } | 606 | } |
585 | 607 | ||
586 | memcpy(wl->nvs, fw->data, wl->nvs_len); | 608 | memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); |
587 | 609 | ||
588 | ret = 0; | 610 | ret = wl1271_update_mac_addr(wl); |
589 | 611 | ||
590 | out: | 612 | out: |
591 | release_firmware(fw); | 613 | release_firmware(fw); |
@@ -626,8 +648,8 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) | |||
626 | msleep(WL1271_PRE_POWER_ON_SLEEP); | 648 | msleep(WL1271_PRE_POWER_ON_SLEEP); |
627 | wl1271_power_on(wl); | 649 | wl1271_power_on(wl); |
628 | msleep(WL1271_POWER_ON_SLEEP); | 650 | msleep(WL1271_POWER_ON_SLEEP); |
629 | wl1271_spi_reset(wl); | 651 | wl1271_io_reset(wl); |
630 | wl1271_spi_init(wl); | 652 | wl1271_io_init(wl); |
631 | 653 | ||
632 | /* We don't need a real memory partition here, because we only want | 654 | /* We don't need a real memory partition here, because we only want |
633 | * to use the registers at this point. */ | 655 | * to use the registers at this point. */ |
@@ -642,7 +664,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) | |||
642 | /* whal_FwCtrl_BootSm() */ | 664 | /* whal_FwCtrl_BootSm() */ |
643 | 665 | ||
644 | /* 0. read chip id from CHIP_ID */ | 666 | /* 0. read chip id from CHIP_ID */ |
645 | wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B); | 667 | wl->chip.id = wl1271_read32(wl, CHIP_ID_B); |
646 | 668 | ||
647 | /* 1. check if chip id is valid */ | 669 | /* 1. check if chip id is valid */ |
648 | 670 | ||
@@ -716,11 +738,6 @@ int wl1271_plt_start(struct wl1271 *wl) | |||
716 | if (ret < 0) | 738 | if (ret < 0) |
717 | goto irq_disable; | 739 | goto irq_disable; |
718 | 740 | ||
719 | /* Make sure power saving is disabled */ | ||
720 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
721 | if (ret < 0) | ||
722 | goto irq_disable; | ||
723 | |||
724 | wl->state = WL1271_STATE_PLT; | 741 | wl->state = WL1271_STATE_PLT; |
725 | wl1271_notice("firmware booted in PLT mode (%s)", | 742 | wl1271_notice("firmware booted in PLT mode (%s)", |
726 | wl->chip.fw_ver); | 743 | wl->chip.fw_ver); |
@@ -1234,8 +1251,16 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1234 | } | 1251 | } |
1235 | 1252 | ||
1236 | /* if the channel changes while joined, join again */ | 1253 | /* if the channel changes while joined, join again */ |
1237 | if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags)) | 1254 | if (channel != wl->channel && |
1238 | wl1271_join_channel(wl, channel); | 1255 | test_bit(WL1271_FLAG_JOINED, &wl->flags)) { |
1256 | wl->channel = channel; | ||
1257 | /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */ | ||
1258 | ret = wl1271_cmd_join(wl); | ||
1259 | if (ret < 0) | ||
1260 | wl1271_warning("cmd join to update channel failed %d", | ||
1261 | ret); | ||
1262 | } else | ||
1263 | wl->channel = channel; | ||
1239 | 1264 | ||
1240 | if (conf->flags & IEEE80211_CONF_PS && | 1265 | if (conf->flags & IEEE80211_CONF_PS && |
1241 | !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { | 1266 | !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { |
@@ -1248,7 +1273,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1248 | */ | 1273 | */ |
1249 | if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { | 1274 | if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { |
1250 | wl1271_info("psm enabled"); | 1275 | wl1271_info("psm enabled"); |
1251 | ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | 1276 | ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, |
1277 | true); | ||
1252 | } | 1278 | } |
1253 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | 1279 | } else if (!(conf->flags & IEEE80211_CONF_PS) && |
1254 | test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { | 1280 | test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { |
@@ -1257,7 +1283,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1257 | clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); | 1283 | clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); |
1258 | 1284 | ||
1259 | if (test_bit(WL1271_FLAG_PSM, &wl->flags)) | 1285 | if (test_bit(WL1271_FLAG_PSM, &wl->flags)) |
1260 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); | 1286 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, |
1287 | true); | ||
1261 | } | 1288 | } |
1262 | 1289 | ||
1263 | if (conf->power_level != wl->power_level) { | 1290 | if (conf->power_level != wl->power_level) { |
@@ -1449,9 +1476,24 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
1449 | wl1271_error("Could not add or replace key"); | 1476 | wl1271_error("Could not add or replace key"); |
1450 | goto out_sleep; | 1477 | goto out_sleep; |
1451 | } | 1478 | } |
1479 | |||
1480 | /* the default WEP key needs to be configured at least once */ | ||
1481 | if (key_type == KEY_WEP) { | ||
1482 | ret = wl1271_cmd_set_default_wep_key(wl, | ||
1483 | wl->default_key); | ||
1484 | if (ret < 0) | ||
1485 | goto out_sleep; | ||
1486 | } | ||
1452 | break; | 1487 | break; |
1453 | 1488 | ||
1454 | case DISABLE_KEY: | 1489 | case DISABLE_KEY: |
1490 | /* The wl1271 does not allow to remove unicast keys - they | ||
1491 | will be cleared automatically on next CMD_JOIN. Ignore the | ||
1492 | request silently, as we dont want the mac80211 to emit | ||
1493 | an error message. */ | ||
1494 | if (!is_broadcast_ether_addr(addr)) | ||
1495 | break; | ||
1496 | |||
1455 | ret = wl1271_cmd_set_key(wl, KEY_REMOVE, | 1497 | ret = wl1271_cmd_set_key(wl, KEY_REMOVE, |
1456 | key_conf->keyidx, key_type, | 1498 | key_conf->keyidx, key_type, |
1457 | key_conf->keylen, key_conf->key, | 1499 | key_conf->keylen, key_conf->key, |
@@ -1539,6 +1581,23 @@ out: | |||
1539 | return ret; | 1581 | return ret; |
1540 | } | 1582 | } |
1541 | 1583 | ||
1584 | static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon) | ||
1585 | { | ||
1586 | u8 *ptr = beacon->data + | ||
1587 | offsetof(struct ieee80211_mgmt, u.beacon.variable); | ||
1588 | |||
1589 | /* find the location of the ssid in the beacon */ | ||
1590 | while (ptr < beacon->data + beacon->len) { | ||
1591 | if (ptr[0] == WLAN_EID_SSID) { | ||
1592 | wl->ssid_len = ptr[1]; | ||
1593 | memcpy(wl->ssid, ptr+2, wl->ssid_len); | ||
1594 | return; | ||
1595 | } | ||
1596 | ptr += ptr[1]; | ||
1597 | } | ||
1598 | wl1271_error("ad-hoc beacon template has no SSID!\n"); | ||
1599 | } | ||
1600 | |||
1542 | static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | 1601 | static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, |
1543 | struct ieee80211_vif *vif, | 1602 | struct ieee80211_vif *vif, |
1544 | struct ieee80211_bss_conf *bss_conf, | 1603 | struct ieee80211_bss_conf *bss_conf, |
@@ -1546,6 +1605,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1546 | { | 1605 | { |
1547 | enum wl1271_cmd_ps_mode mode; | 1606 | enum wl1271_cmd_ps_mode mode; |
1548 | struct wl1271 *wl = hw->priv; | 1607 | struct wl1271 *wl = hw->priv; |
1608 | bool do_join = false; | ||
1549 | int ret; | 1609 | int ret; |
1550 | 1610 | ||
1551 | wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | 1611 | wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); |
@@ -1556,40 +1616,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1556 | if (ret < 0) | 1616 | if (ret < 0) |
1557 | goto out; | 1617 | goto out; |
1558 | 1618 | ||
1559 | if ((changed & BSS_CHANGED_BSSID) && | ||
1560 | /* | ||
1561 | * Now we know the correct bssid, so we send a new join command | ||
1562 | * and enable the BSSID filter | ||
1563 | */ | ||
1564 | memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { | ||
1565 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
1566 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | ||
1567 | ret = wl1271_cmd_build_null_data(wl); | ||
1568 | if (ret < 0) { | ||
1569 | wl1271_warning("cmd buld null data failed %d", | ||
1570 | ret); | ||
1571 | goto out_sleep; | ||
1572 | } | ||
1573 | ret = wl1271_cmd_join(wl); | ||
1574 | if (ret < 0) { | ||
1575 | wl1271_warning("cmd join failed %d", ret); | ||
1576 | goto out_sleep; | ||
1577 | } | ||
1578 | set_bit(WL1271_FLAG_JOINED, &wl->flags); | ||
1579 | } | ||
1580 | |||
1581 | if (wl->bss_type == BSS_TYPE_IBSS) { | 1619 | if (wl->bss_type == BSS_TYPE_IBSS) { |
1582 | /* FIXME: This implements rudimentary ad-hoc support - | 1620 | /* FIXME: This implements rudimentary ad-hoc support - |
1583 | proper templates are on the wish list and notification | 1621 | proper templates are on the wish list and notification |
1584 | on when they change. This patch will update the templates | 1622 | on when they change. This patch will update the templates |
1585 | on every call to this function. Also, the firmware will not | 1623 | on every call to this function. */ |
1586 | answer to probe-requests as it does not have the proper | ||
1587 | SSID set in the JOIN command. The probe-response template | ||
1588 | is set nevertheless, as the FW will ASSERT without it */ | ||
1589 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); | 1624 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); |
1590 | 1625 | ||
1591 | if (beacon) { | 1626 | if (beacon) { |
1592 | struct ieee80211_hdr *hdr; | 1627 | struct ieee80211_hdr *hdr; |
1628 | |||
1629 | wl1271_ssid_set(wl, beacon); | ||
1593 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, | 1630 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, |
1594 | beacon->data, | 1631 | beacon->data, |
1595 | beacon->len); | 1632 | beacon->len); |
@@ -1611,9 +1648,31 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1611 | dev_kfree_skb(beacon); | 1648 | dev_kfree_skb(beacon); |
1612 | if (ret < 0) | 1649 | if (ret < 0) |
1613 | goto out_sleep; | 1650 | goto out_sleep; |
1651 | |||
1652 | /* Need to update the SSID (for filtering etc) */ | ||
1653 | do_join = true; | ||
1614 | } | 1654 | } |
1615 | } | 1655 | } |
1616 | 1656 | ||
1657 | if ((changed & BSS_CHANGED_BSSID) && | ||
1658 | /* | ||
1659 | * Now we know the correct bssid, so we send a new join command | ||
1660 | * and enable the BSSID filter | ||
1661 | */ | ||
1662 | memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { | ||
1663 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
1664 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | ||
1665 | ret = wl1271_cmd_build_null_data(wl); | ||
1666 | if (ret < 0) { | ||
1667 | wl1271_warning("cmd buld null data failed %d", | ||
1668 | ret); | ||
1669 | goto out_sleep; | ||
1670 | } | ||
1671 | |||
1672 | /* Need to update the BSSID (for filtering etc) */ | ||
1673 | do_join = true; | ||
1674 | } | ||
1675 | |||
1617 | if (changed & BSS_CHANGED_ASSOC) { | 1676 | if (changed & BSS_CHANGED_ASSOC) { |
1618 | if (bss_conf->assoc) { | 1677 | if (bss_conf->assoc) { |
1619 | wl->aid = bss_conf->aid; | 1678 | wl->aid = bss_conf->aid; |
@@ -1637,7 +1696,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1637 | if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && | 1696 | if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && |
1638 | !test_bit(WL1271_FLAG_PSM, &wl->flags)) { | 1697 | !test_bit(WL1271_FLAG_PSM, &wl->flags)) { |
1639 | mode = STATION_POWER_SAVE_MODE; | 1698 | mode = STATION_POWER_SAVE_MODE; |
1640 | ret = wl1271_ps_set_mode(wl, mode); | 1699 | ret = wl1271_ps_set_mode(wl, mode, true); |
1641 | if (ret < 0) | 1700 | if (ret < 0) |
1642 | goto out_sleep; | 1701 | goto out_sleep; |
1643 | } | 1702 | } |
@@ -1678,11 +1737,57 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1678 | } | 1737 | } |
1679 | } | 1738 | } |
1680 | 1739 | ||
1740 | if (do_join) { | ||
1741 | ret = wl1271_cmd_join(wl); | ||
1742 | if (ret < 0) { | ||
1743 | wl1271_warning("cmd join failed %d", ret); | ||
1744 | goto out_sleep; | ||
1745 | } | ||
1746 | set_bit(WL1271_FLAG_JOINED, &wl->flags); | ||
1747 | } | ||
1748 | |||
1749 | out_sleep: | ||
1750 | wl1271_ps_elp_sleep(wl); | ||
1751 | |||
1752 | out: | ||
1753 | mutex_unlock(&wl->mutex); | ||
1754 | } | ||
1755 | |||
1756 | static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
1757 | const struct ieee80211_tx_queue_params *params) | ||
1758 | { | ||
1759 | struct wl1271 *wl = hw->priv; | ||
1760 | int ret; | ||
1761 | |||
1762 | mutex_lock(&wl->mutex); | ||
1763 | |||
1764 | wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); | ||
1765 | |||
1766 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
1767 | if (ret < 0) | ||
1768 | goto out; | ||
1769 | |||
1770 | ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), | ||
1771 | params->cw_min, params->cw_max, | ||
1772 | params->aifs, params->txop); | ||
1773 | if (ret < 0) | ||
1774 | goto out_sleep; | ||
1775 | |||
1776 | ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), | ||
1777 | CONF_CHANNEL_TYPE_EDCF, | ||
1778 | wl1271_tx_get_queue(queue), | ||
1779 | CONF_PS_SCHEME_LEGACY_PSPOLL, | ||
1780 | CONF_ACK_POLICY_LEGACY, 0, 0); | ||
1781 | if (ret < 0) | ||
1782 | goto out_sleep; | ||
1783 | |||
1681 | out_sleep: | 1784 | out_sleep: |
1682 | wl1271_ps_elp_sleep(wl); | 1785 | wl1271_ps_elp_sleep(wl); |
1683 | 1786 | ||
1684 | out: | 1787 | out: |
1685 | mutex_unlock(&wl->mutex); | 1788 | mutex_unlock(&wl->mutex); |
1789 | |||
1790 | return ret; | ||
1686 | } | 1791 | } |
1687 | 1792 | ||
1688 | 1793 | ||
@@ -1850,6 +1955,8 @@ static const struct ieee80211_ops wl1271_ops = { | |||
1850 | .hw_scan = wl1271_op_hw_scan, | 1955 | .hw_scan = wl1271_op_hw_scan, |
1851 | .bss_info_changed = wl1271_op_bss_info_changed, | 1956 | .bss_info_changed = wl1271_op_bss_info_changed, |
1852 | .set_rts_threshold = wl1271_op_set_rts_threshold, | 1957 | .set_rts_threshold = wl1271_op_set_rts_threshold, |
1958 | .conf_tx = wl1271_op_conf_tx, | ||
1959 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | ||
1853 | }; | 1960 | }; |
1854 | 1961 | ||
1855 | static int wl1271_register_hw(struct wl1271 *wl) | 1962 | static int wl1271_register_hw(struct wl1271 *wl) |
@@ -1918,24 +2025,17 @@ static struct platform_device wl1271_device = { | |||
1918 | }; | 2025 | }; |
1919 | 2026 | ||
1920 | #define WL1271_DEFAULT_CHANNEL 0 | 2027 | #define WL1271_DEFAULT_CHANNEL 0 |
1921 | static int __devinit wl1271_probe(struct spi_device *spi) | 2028 | |
2029 | static struct ieee80211_hw *wl1271_alloc_hw(void) | ||
1922 | { | 2030 | { |
1923 | struct wl12xx_platform_data *pdata; | ||
1924 | struct ieee80211_hw *hw; | 2031 | struct ieee80211_hw *hw; |
1925 | struct wl1271 *wl; | 2032 | struct wl1271 *wl; |
1926 | int ret, i; | 2033 | int i; |
1927 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
1928 | |||
1929 | pdata = spi->dev.platform_data; | ||
1930 | if (!pdata) { | ||
1931 | wl1271_error("no platform data"); | ||
1932 | return -ENODEV; | ||
1933 | } | ||
1934 | 2034 | ||
1935 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | 2035 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); |
1936 | if (!hw) { | 2036 | if (!hw) { |
1937 | wl1271_error("could not alloc ieee80211_hw"); | 2037 | wl1271_error("could not alloc ieee80211_hw"); |
1938 | return -ENOMEM; | 2038 | return ERR_PTR(-ENOMEM); |
1939 | } | 2039 | } |
1940 | 2040 | ||
1941 | wl = hw->priv; | 2041 | wl = hw->priv; |
@@ -1944,8 +2044,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) | |||
1944 | INIT_LIST_HEAD(&wl->list); | 2044 | INIT_LIST_HEAD(&wl->list); |
1945 | 2045 | ||
1946 | wl->hw = hw; | 2046 | wl->hw = hw; |
1947 | dev_set_drvdata(&spi->dev, wl); | ||
1948 | wl->spi = spi; | ||
1949 | 2047 | ||
1950 | skb_queue_head_init(&wl->tx_queue); | 2048 | skb_queue_head_init(&wl->tx_queue); |
1951 | 2049 | ||
@@ -1969,16 +2067,57 @@ static int __devinit wl1271_probe(struct spi_device *spi) | |||
1969 | 2067 | ||
1970 | spin_lock_init(&wl->wl_lock); | 2068 | spin_lock_init(&wl->wl_lock); |
1971 | 2069 | ||
1972 | /* | ||
1973 | * In case our MAC address is not correctly set, | ||
1974 | * we use a random but Nokia MAC. | ||
1975 | */ | ||
1976 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
1977 | get_random_bytes(wl->mac_addr + 3, 3); | ||
1978 | |||
1979 | wl->state = WL1271_STATE_OFF; | 2070 | wl->state = WL1271_STATE_OFF; |
1980 | mutex_init(&wl->mutex); | 2071 | mutex_init(&wl->mutex); |
1981 | 2072 | ||
2073 | /* Apply default driver configuration. */ | ||
2074 | wl1271_conf_init(wl); | ||
2075 | |||
2076 | return hw; | ||
2077 | } | ||
2078 | |||
2079 | int wl1271_free_hw(struct wl1271 *wl) | ||
2080 | { | ||
2081 | ieee80211_unregister_hw(wl->hw); | ||
2082 | |||
2083 | wl1271_debugfs_exit(wl); | ||
2084 | |||
2085 | kfree(wl->target_mem_map); | ||
2086 | vfree(wl->fw); | ||
2087 | wl->fw = NULL; | ||
2088 | kfree(wl->nvs); | ||
2089 | wl->nvs = NULL; | ||
2090 | |||
2091 | kfree(wl->fw_status); | ||
2092 | kfree(wl->tx_res_if); | ||
2093 | |||
2094 | ieee80211_free_hw(wl->hw); | ||
2095 | |||
2096 | return 0; | ||
2097 | } | ||
2098 | |||
2099 | static int __devinit wl1271_probe(struct spi_device *spi) | ||
2100 | { | ||
2101 | struct wl12xx_platform_data *pdata; | ||
2102 | struct ieee80211_hw *hw; | ||
2103 | struct wl1271 *wl; | ||
2104 | int ret; | ||
2105 | |||
2106 | pdata = spi->dev.platform_data; | ||
2107 | if (!pdata) { | ||
2108 | wl1271_error("no platform data"); | ||
2109 | return -ENODEV; | ||
2110 | } | ||
2111 | |||
2112 | hw = wl1271_alloc_hw(); | ||
2113 | if (IS_ERR(hw)) | ||
2114 | return PTR_ERR(hw); | ||
2115 | |||
2116 | wl = hw->priv; | ||
2117 | |||
2118 | dev_set_drvdata(&spi->dev, wl); | ||
2119 | wl->spi = spi; | ||
2120 | |||
1982 | /* This is the only SPI value that we need to set here, the rest | 2121 | /* This is the only SPI value that we need to set here, the rest |
1983 | * comes from the board-peripherals file */ | 2122 | * comes from the board-peripherals file */ |
1984 | spi->bits_per_word = 32; | 2123 | spi->bits_per_word = 32; |
@@ -2020,9 +2159,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) | |||
2020 | } | 2159 | } |
2021 | dev_set_drvdata(&wl1271_device.dev, wl); | 2160 | dev_set_drvdata(&wl1271_device.dev, wl); |
2022 | 2161 | ||
2023 | /* Apply default driver configuration. */ | ||
2024 | wl1271_conf_init(wl); | ||
2025 | |||
2026 | ret = wl1271_init_ieee80211(wl); | 2162 | ret = wl1271_init_ieee80211(wl); |
2027 | if (ret) | 2163 | if (ret) |
2028 | goto out_platform; | 2164 | goto out_platform; |
@@ -2053,21 +2189,10 @@ static int __devexit wl1271_remove(struct spi_device *spi) | |||
2053 | { | 2189 | { |
2054 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); | 2190 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); |
2055 | 2191 | ||
2056 | ieee80211_unregister_hw(wl->hw); | ||
2057 | |||
2058 | wl1271_debugfs_exit(wl); | ||
2059 | platform_device_unregister(&wl1271_device); | 2192 | platform_device_unregister(&wl1271_device); |
2060 | free_irq(wl->irq, wl); | 2193 | free_irq(wl->irq, wl); |
2061 | kfree(wl->target_mem_map); | ||
2062 | vfree(wl->fw); | ||
2063 | wl->fw = NULL; | ||
2064 | kfree(wl->nvs); | ||
2065 | wl->nvs = NULL; | ||
2066 | |||
2067 | kfree(wl->fw_status); | ||
2068 | kfree(wl->tx_res_if); | ||
2069 | 2194 | ||
2070 | ieee80211_free_hw(wl->hw); | 2195 | wl1271_free_hw(wl); |
2071 | 2196 | ||
2072 | return 0; | 2197 | return 0; |
2073 | } | 2198 | } |