diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.c | 127 |
1 files changed, 95 insertions, 32 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 92254d0d6c4c..6b5ba8ec94c9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.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) 2009 Nokia Corporation | 4 | * Copyright (C) 2009-2010 Nokia Corporation |
5 | * | 5 | * |
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | 6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> |
7 | * | 7 | * |
@@ -35,6 +35,9 @@ | |||
35 | #include "wl1271_acx.h" | 35 | #include "wl1271_acx.h" |
36 | #include "wl12xx_80211.h" | 36 | #include "wl12xx_80211.h" |
37 | #include "wl1271_cmd.h" | 37 | #include "wl1271_cmd.h" |
38 | #include "wl1271_event.h" | ||
39 | |||
40 | #define WL1271_CMD_POLL_COUNT 5 | ||
38 | 41 | ||
39 | /* | 42 | /* |
40 | * send command to firmware | 43 | * send command to firmware |
@@ -52,6 +55,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | |||
52 | u32 intr; | 55 | u32 intr; |
53 | int ret = 0; | 56 | int ret = 0; |
54 | u16 status; | 57 | u16 status; |
58 | u16 poll_count = 0; | ||
55 | 59 | ||
56 | cmd = buf; | 60 | cmd = buf; |
57 | cmd->id = cpu_to_le16(id); | 61 | cmd->id = cpu_to_le16(id); |
@@ -73,7 +77,11 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | |||
73 | goto out; | 77 | goto out; |
74 | } | 78 | } |
75 | 79 | ||
76 | msleep(1); | 80 | udelay(10); |
81 | poll_count++; | ||
82 | if (poll_count == WL1271_CMD_POLL_COUNT) | ||
83 | wl1271_info("cmd polling took over %d cycles", | ||
84 | poll_count); | ||
77 | 85 | ||
78 | intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | 86 | intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); |
79 | } | 87 | } |
@@ -249,6 +257,35 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) | |||
249 | return ret; | 257 | return ret; |
250 | } | 258 | } |
251 | 259 | ||
260 | /* | ||
261 | * Poll the mailbox event field until any of the bits in the mask is set or a | ||
262 | * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) | ||
263 | */ | ||
264 | static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) | ||
265 | { | ||
266 | u32 events_vector, event; | ||
267 | unsigned long timeout; | ||
268 | |||
269 | timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); | ||
270 | |||
271 | do { | ||
272 | if (time_after(jiffies, timeout)) | ||
273 | return -ETIMEDOUT; | ||
274 | |||
275 | msleep(1); | ||
276 | |||
277 | /* read from both event fields */ | ||
278 | wl1271_read(wl, wl->mbox_ptr[0], &events_vector, | ||
279 | sizeof(events_vector), false); | ||
280 | event = events_vector & mask; | ||
281 | wl1271_read(wl, wl->mbox_ptr[1], &events_vector, | ||
282 | sizeof(events_vector), false); | ||
283 | event |= events_vector & mask; | ||
284 | } while (!event); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
252 | int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) | 289 | int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) |
253 | { | 290 | { |
254 | static bool do_cal = true; | 291 | static bool do_cal = true; |
@@ -281,20 +318,12 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) | |||
281 | join->rx_config_options = cpu_to_le32(wl->rx_config); | 318 | join->rx_config_options = cpu_to_le32(wl->rx_config); |
282 | join->rx_filter_options = cpu_to_le32(wl->rx_filter); | 319 | join->rx_filter_options = cpu_to_le32(wl->rx_filter); |
283 | join->bss_type = bss_type; | 320 | join->bss_type = bss_type; |
321 | join->basic_rate_set = wl->basic_rate_set; | ||
284 | 322 | ||
285 | if (wl->band == IEEE80211_BAND_2GHZ) | 323 | if (wl->band == IEEE80211_BAND_5GHZ) |
286 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS | | ||
287 | CONF_HW_BIT_RATE_2MBPS | | ||
288 | CONF_HW_BIT_RATE_5_5MBPS | | ||
289 | CONF_HW_BIT_RATE_11MBPS); | ||
290 | else { | ||
291 | join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; | 324 | join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; |
292 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS | | ||
293 | CONF_HW_BIT_RATE_12MBPS | | ||
294 | CONF_HW_BIT_RATE_24MBPS); | ||
295 | } | ||
296 | 325 | ||
297 | join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT); | 326 | join->beacon_interval = cpu_to_le16(wl->beacon_int); |
298 | join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; | 327 | join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; |
299 | 328 | ||
300 | join->channel = wl->channel; | 329 | join->channel = wl->channel; |
@@ -319,11 +348,9 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) | |||
319 | goto out_free; | 348 | goto out_free; |
320 | } | 349 | } |
321 | 350 | ||
322 | /* | 351 | ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID); |
323 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | 352 | if (ret < 0) |
324 | * simplify locking we just sleep instead, for now | 353 | wl1271_error("cmd join event completion error"); |
325 | */ | ||
326 | msleep(10); | ||
327 | 354 | ||
328 | out_free: | 355 | out_free: |
329 | kfree(join); | 356 | kfree(join); |
@@ -455,7 +482,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) | |||
455 | if (ret < 0) { | 482 | if (ret < 0) { |
456 | wl1271_error("tx %s cmd for channel %d failed", | 483 | wl1271_error("tx %s cmd for channel %d failed", |
457 | enable ? "start" : "stop", cmd->channel); | 484 | enable ? "start" : "stop", cmd->channel); |
458 | return ret; | 485 | goto out; |
459 | } | 486 | } |
460 | 487 | ||
461 | wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", | 488 | wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", |
@@ -547,17 +574,21 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | |||
547 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; | 574 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; |
548 | struct wl1271_cmd_scan *params = NULL; | 575 | struct wl1271_cmd_scan *params = NULL; |
549 | struct ieee80211_channel *channels; | 576 | struct ieee80211_channel *channels; |
577 | u32 rate; | ||
550 | int i, j, n_ch, ret; | 578 | int i, j, n_ch, ret; |
551 | u16 scan_options = 0; | 579 | u16 scan_options = 0; |
552 | u8 ieee_band; | 580 | u8 ieee_band; |
553 | 581 | ||
554 | if (band == WL1271_SCAN_BAND_2_4_GHZ) | 582 | if (band == WL1271_SCAN_BAND_2_4_GHZ) { |
555 | ieee_band = IEEE80211_BAND_2GHZ; | 583 | ieee_band = IEEE80211_BAND_2GHZ; |
556 | else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) | 584 | rate = wl->conf.tx.basic_rate; |
585 | } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) { | ||
557 | ieee_band = IEEE80211_BAND_2GHZ; | 586 | ieee_band = IEEE80211_BAND_2GHZ; |
558 | else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) | 587 | rate = wl->conf.tx.basic_rate; |
588 | } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) { | ||
559 | ieee_band = IEEE80211_BAND_5GHZ; | 589 | ieee_band = IEEE80211_BAND_5GHZ; |
560 | else | 590 | rate = wl->conf.tx.basic_rate_5; |
591 | } else | ||
561 | return -EINVAL; | 592 | return -EINVAL; |
562 | 593 | ||
563 | if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) | 594 | if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) |
@@ -584,8 +615,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | |||
584 | params->params.scan_options = cpu_to_le16(scan_options); | 615 | params->params.scan_options = cpu_to_le16(scan_options); |
585 | 616 | ||
586 | params->params.num_probe_requests = probe_requests; | 617 | params->params.num_probe_requests = probe_requests; |
587 | /* Let the fw autodetect suitable tx_rate for probes */ | 618 | params->params.tx_rate = rate; |
588 | params->params.tx_rate = 0; | ||
589 | params->params.tid_trigger = 0; | 619 | params->params.tid_trigger = 0; |
590 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | 620 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; |
591 | 621 | ||
@@ -666,11 +696,12 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | |||
666 | 696 | ||
667 | out: | 697 | out: |
668 | kfree(params); | 698 | kfree(params); |
699 | kfree(trigger); | ||
669 | return ret; | 700 | return ret; |
670 | } | 701 | } |
671 | 702 | ||
672 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | 703 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, |
673 | void *buf, size_t buf_len) | 704 | void *buf, size_t buf_len, int index, u32 rates) |
674 | { | 705 | { |
675 | struct wl1271_cmd_template_set *cmd; | 706 | struct wl1271_cmd_template_set *cmd; |
676 | int ret = 0; | 707 | int ret = 0; |
@@ -688,9 +719,10 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | |||
688 | 719 | ||
689 | cmd->len = cpu_to_le16(buf_len); | 720 | cmd->len = cpu_to_le16(buf_len); |
690 | cmd->template_type = template_id; | 721 | cmd->template_type = template_id; |
691 | cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates); | 722 | cmd->enabled_rates = cpu_to_le32(rates); |
692 | cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; | 723 | cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; |
693 | cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; | 724 | cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; |
725 | cmd->index = index; | ||
694 | 726 | ||
695 | if (buf) | 727 | if (buf) |
696 | memcpy(cmd->template_data, buf, buf_len); | 728 | memcpy(cmd->template_data, buf, buf_len); |
@@ -727,7 +759,8 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) | |||
727 | ptr = skb->data; | 759 | ptr = skb->data; |
728 | } | 760 | } |
729 | 761 | ||
730 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size); | 762 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, |
763 | WL1271_RATE_AUTOMATIC); | ||
731 | 764 | ||
732 | out: | 765 | out: |
733 | dev_kfree_skb(skb); | 766 | dev_kfree_skb(skb); |
@@ -738,6 +771,29 @@ out: | |||
738 | 771 | ||
739 | } | 772 | } |
740 | 773 | ||
774 | int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) | ||
775 | { | ||
776 | struct sk_buff *skb = NULL; | ||
777 | int ret = -ENOMEM; | ||
778 | |||
779 | skb = ieee80211_nullfunc_get(wl->hw, wl->vif); | ||
780 | if (!skb) | ||
781 | goto out; | ||
782 | |||
783 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, | ||
784 | skb->data, skb->len, | ||
785 | CMD_TEMPL_KLV_IDX_NULL_DATA, | ||
786 | WL1271_RATE_AUTOMATIC); | ||
787 | |||
788 | out: | ||
789 | dev_kfree_skb(skb); | ||
790 | if (ret) | ||
791 | wl1271_warning("cmd build klv null data failed %d", ret); | ||
792 | |||
793 | return ret; | ||
794 | |||
795 | } | ||
796 | |||
741 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) | 797 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) |
742 | { | 798 | { |
743 | struct sk_buff *skb; | 799 | struct sk_buff *skb; |
@@ -748,7 +804,7 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) | |||
748 | goto out; | 804 | goto out; |
749 | 805 | ||
750 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, | 806 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, |
751 | skb->len); | 807 | skb->len, 0, wl->basic_rate); |
752 | 808 | ||
753 | out: | 809 | out: |
754 | dev_kfree_skb(skb); | 810 | dev_kfree_skb(skb); |
@@ -773,10 +829,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, | |||
773 | 829 | ||
774 | if (band == IEEE80211_BAND_2GHZ) | 830 | if (band == IEEE80211_BAND_2GHZ) |
775 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | 831 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, |
776 | skb->data, skb->len); | 832 | skb->data, skb->len, 0, |
833 | wl->conf.tx.basic_rate); | ||
777 | else | 834 | else |
778 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, | 835 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, |
779 | skb->data, skb->len); | 836 | skb->data, skb->len, 0, |
837 | wl->conf.tx.basic_rate_5); | ||
780 | 838 | ||
781 | out: | 839 | out: |
782 | dev_kfree_skb(skb); | 840 | dev_kfree_skb(skb); |
@@ -801,7 +859,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) | |||
801 | template.qos_ctrl = cpu_to_le16(0); | 859 | template.qos_ctrl = cpu_to_le16(0); |
802 | 860 | ||
803 | return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, | 861 | return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, |
804 | sizeof(template)); | 862 | sizeof(template), 0, |
863 | WL1271_RATE_AUTOMATIC); | ||
805 | } | 864 | } |
806 | 865 | ||
807 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) | 866 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) |
@@ -914,6 +973,10 @@ int wl1271_cmd_disconnect(struct wl1271 *wl) | |||
914 | goto out_free; | 973 | goto out_free; |
915 | } | 974 | } |
916 | 975 | ||
976 | ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); | ||
977 | if (ret < 0) | ||
978 | wl1271_error("cmd disconnect event completion error"); | ||
979 | |||
917 | out_free: | 980 | out_free: |
918 | kfree(cmd); | 981 | kfree(cmd); |
919 | 982 | ||