diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1251_main.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 351 |
1 files changed, 132 insertions, 219 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 2f50a256efa5..595f0f94d16e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -395,6 +395,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
395 | * the queue here, otherwise the queue will get too long. | 395 | * the queue here, otherwise the queue will get too long. |
396 | */ | 396 | */ |
397 | if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { | 397 | if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { |
398 | wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); | ||
398 | ieee80211_stop_queues(wl->hw); | 399 | ieee80211_stop_queues(wl->hw); |
399 | 400 | ||
400 | /* | 401 | /* |
@@ -510,13 +511,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) | |||
510 | } | 511 | } |
511 | 512 | ||
512 | static int wl1251_op_add_interface(struct ieee80211_hw *hw, | 513 | static int wl1251_op_add_interface(struct ieee80211_hw *hw, |
513 | struct ieee80211_if_init_conf *conf) | 514 | struct ieee80211_vif *vif) |
514 | { | 515 | { |
515 | struct wl1251 *wl = hw->priv; | 516 | struct wl1251 *wl = hw->priv; |
516 | int ret = 0; | 517 | int ret = 0; |
517 | 518 | ||
518 | wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | 519 | wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", |
519 | conf->type, conf->mac_addr); | 520 | vif->type, vif->addr); |
520 | 521 | ||
521 | mutex_lock(&wl->mutex); | 522 | mutex_lock(&wl->mutex); |
522 | if (wl->vif) { | 523 | if (wl->vif) { |
@@ -524,9 +525,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, | |||
524 | goto out; | 525 | goto out; |
525 | } | 526 | } |
526 | 527 | ||
527 | wl->vif = conf->vif; | 528 | wl->vif = vif; |
528 | 529 | ||
529 | switch (conf->type) { | 530 | switch (vif->type) { |
530 | case NL80211_IFTYPE_STATION: | 531 | case NL80211_IFTYPE_STATION: |
531 | wl->bss_type = BSS_TYPE_STA_BSS; | 532 | wl->bss_type = BSS_TYPE_STA_BSS; |
532 | break; | 533 | break; |
@@ -538,8 +539,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, | |||
538 | goto out; | 539 | goto out; |
539 | } | 540 | } |
540 | 541 | ||
541 | if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { | 542 | if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { |
542 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | 543 | memcpy(wl->mac_addr, vif->addr, ETH_ALEN); |
543 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | 544 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); |
544 | ret = wl1251_acx_station_id(wl); | 545 | ret = wl1251_acx_station_id(wl); |
545 | if (ret < 0) | 546 | if (ret < 0) |
@@ -552,7 +553,7 @@ out: | |||
552 | } | 553 | } |
553 | 554 | ||
554 | static void wl1251_op_remove_interface(struct ieee80211_hw *hw, | 555 | static void wl1251_op_remove_interface(struct ieee80211_hw *hw, |
555 | struct ieee80211_if_init_conf *conf) | 556 | struct ieee80211_vif *vif) |
556 | { | 557 | { |
557 | struct wl1251 *wl = hw->priv; | 558 | struct wl1251 *wl = hw->priv; |
558 | 559 | ||
@@ -562,43 +563,25 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw, | |||
562 | mutex_unlock(&wl->mutex); | 563 | mutex_unlock(&wl->mutex); |
563 | } | 564 | } |
564 | 565 | ||
565 | static int wl1251_build_null_data(struct wl1251 *wl) | 566 | static int wl1251_build_qos_null_data(struct wl1251 *wl) |
566 | { | 567 | { |
567 | struct wl12xx_null_data_template template; | 568 | struct ieee80211_qos_hdr template; |
568 | 569 | ||
569 | if (!is_zero_ether_addr(wl->bssid)) { | 570 | memset(&template, 0, sizeof(template)); |
570 | memcpy(template.header.da, wl->bssid, ETH_ALEN); | ||
571 | memcpy(template.header.bssid, wl->bssid, ETH_ALEN); | ||
572 | } else { | ||
573 | memset(template.header.da, 0xff, ETH_ALEN); | ||
574 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
575 | } | ||
576 | |||
577 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
578 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
579 | IEEE80211_STYPE_NULLFUNC | | ||
580 | IEEE80211_FCTL_TODS); | ||
581 | |||
582 | return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template, | ||
583 | sizeof(template)); | ||
584 | |||
585 | } | ||
586 | |||
587 | static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid) | ||
588 | { | ||
589 | struct wl12xx_ps_poll_template template; | ||
590 | 571 | ||
591 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | 572 | memcpy(template.addr1, wl->bssid, ETH_ALEN); |
592 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | 573 | memcpy(template.addr2, wl->mac_addr, ETH_ALEN); |
574 | memcpy(template.addr3, wl->bssid, ETH_ALEN); | ||
593 | 575 | ||
594 | /* aid in PS-Poll has its two MSBs each set to 1 */ | 576 | template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | |
595 | template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); | 577 | IEEE80211_STYPE_QOS_NULLFUNC | |
578 | IEEE80211_FCTL_TODS); | ||
596 | 579 | ||
597 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | 580 | /* FIXME: not sure what priority to use here */ |
581 | template.qos_ctrl = cpu_to_le16(0); | ||
598 | 582 | ||
599 | return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template, | 583 | return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, |
600 | sizeof(template)); | 584 | sizeof(template)); |
601 | |||
602 | } | 585 | } |
603 | 586 | ||
604 | static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | 587 | static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) |
@@ -640,20 +623,25 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | |||
640 | * through the bss_info_changed() hook. | 623 | * through the bss_info_changed() hook. |
641 | */ | 624 | */ |
642 | ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | 625 | ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); |
626 | if (ret < 0) | ||
627 | goto out_sleep; | ||
643 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | 628 | } else if (!(conf->flags & IEEE80211_CONF_PS) && |
644 | wl->psm_requested) { | 629 | wl->psm_requested) { |
645 | wl1251_debug(DEBUG_PSM, "psm disabled"); | 630 | wl1251_debug(DEBUG_PSM, "psm disabled"); |
646 | 631 | ||
647 | wl->psm_requested = false; | 632 | wl->psm_requested = false; |
648 | 633 | ||
649 | if (wl->psm) | 634 | if (wl->psm) { |
650 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | 635 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); |
636 | if (ret < 0) | ||
637 | goto out_sleep; | ||
638 | } | ||
651 | } | 639 | } |
652 | 640 | ||
653 | if (conf->power_level != wl->power_level) { | 641 | if (conf->power_level != wl->power_level) { |
654 | ret = wl1251_acx_tx_power(wl, conf->power_level); | 642 | ret = wl1251_acx_tx_power(wl, conf->power_level); |
655 | if (ret < 0) | 643 | if (ret < 0) |
656 | goto out; | 644 | goto out_sleep; |
657 | 645 | ||
658 | wl->power_level = conf->power_level; | 646 | wl->power_level = conf->power_level; |
659 | } | 647 | } |
@@ -864,199 +852,61 @@ out: | |||
864 | return ret; | 852 | return ret; |
865 | } | 853 | } |
866 | 854 | ||
867 | static int wl1251_build_basic_rates(char *rates) | 855 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, |
868 | { | 856 | struct cfg80211_scan_request *req) |
869 | u8 index = 0; | ||
870 | |||
871 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
872 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
873 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
874 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
875 | |||
876 | return index; | ||
877 | } | ||
878 | |||
879 | static int wl1251_build_extended_rates(char *rates) | ||
880 | { | 857 | { |
881 | u8 index = 0; | 858 | struct wl1251 *wl = hw->priv; |
882 | 859 | struct sk_buff *skb; | |
883 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | 860 | size_t ssid_len = 0; |
884 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | 861 | u8 *ssid = NULL; |
885 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | 862 | int ret; |
886 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | ||
887 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | ||
888 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | ||
889 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | ||
890 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
891 | |||
892 | return index; | ||
893 | } | ||
894 | |||
895 | 863 | ||
896 | static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) | 864 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); |
897 | { | ||
898 | struct wl12xx_probe_req_template template; | ||
899 | struct wl12xx_ie_rates *rates; | ||
900 | char *ptr; | ||
901 | u16 size; | ||
902 | |||
903 | ptr = (char *)&template; | ||
904 | size = sizeof(struct ieee80211_header); | ||
905 | |||
906 | memset(template.header.da, 0xff, ETH_ALEN); | ||
907 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
908 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
909 | template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
910 | |||
911 | /* IEs */ | ||
912 | /* SSID */ | ||
913 | template.ssid.header.id = WLAN_EID_SSID; | ||
914 | template.ssid.header.len = ssid_len; | ||
915 | if (ssid_len && ssid) | ||
916 | memcpy(template.ssid.ssid, ssid, ssid_len); | ||
917 | size += sizeof(struct wl12xx_ie_header) + ssid_len; | ||
918 | ptr += size; | ||
919 | |||
920 | /* Basic Rates */ | ||
921 | rates = (struct wl12xx_ie_rates *)ptr; | ||
922 | rates->header.id = WLAN_EID_SUPP_RATES; | ||
923 | rates->header.len = wl1251_build_basic_rates(rates->rates); | ||
924 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
925 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
926 | |||
927 | /* Extended rates */ | ||
928 | rates = (struct wl12xx_ie_rates *)ptr; | ||
929 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | ||
930 | rates->header.len = wl1251_build_extended_rates(rates->rates); | ||
931 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
932 | |||
933 | wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | ||
934 | |||
935 | return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template, | ||
936 | size); | ||
937 | } | ||
938 | 865 | ||
939 | static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, | 866 | if (req->n_ssids) { |
940 | u8 active_scan, u8 high_prio, u8 num_channels, | 867 | ssid = req->ssids[0].ssid; |
941 | u8 probe_requests) | 868 | ssid_len = req->ssids[0].ssid_len; |
942 | { | ||
943 | struct wl1251_cmd_trigger_scan_to *trigger = NULL; | ||
944 | struct cmd_scan *params = NULL; | ||
945 | int i, ret; | ||
946 | u16 scan_options = 0; | ||
947 | |||
948 | if (wl->scanning) | ||
949 | return -EINVAL; | ||
950 | |||
951 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
952 | if (!params) | ||
953 | return -ENOMEM; | ||
954 | |||
955 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
956 | params->params.rx_filter_options = | ||
957 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
958 | |||
959 | /* High priority scan */ | ||
960 | if (!active_scan) | ||
961 | scan_options |= SCAN_PASSIVE; | ||
962 | if (high_prio) | ||
963 | scan_options |= SCAN_PRIORITY_HIGH; | ||
964 | params->params.scan_options = scan_options; | ||
965 | |||
966 | params->params.num_channels = num_channels; | ||
967 | params->params.num_probe_requests = probe_requests; | ||
968 | params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
969 | params->params.tid_trigger = 0; | ||
970 | |||
971 | for (i = 0; i < num_channels; i++) { | ||
972 | params->channels[i].min_duration = cpu_to_le32(30000); | ||
973 | params->channels[i].max_duration = cpu_to_le32(60000); | ||
974 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | ||
975 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | ||
976 | params->channels[i].early_termination = 0; | ||
977 | params->channels[i].tx_power_att = 0; | ||
978 | params->channels[i].channel = i + 1; | ||
979 | memset(params->channels[i].pad, 0, 3); | ||
980 | } | 869 | } |
981 | 870 | ||
982 | for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) | 871 | mutex_lock(&wl->mutex); |
983 | memset(¶ms->channels[i], 0, | ||
984 | sizeof(struct basic_scan_channel_parameters)); | ||
985 | |||
986 | if (len && ssid) { | ||
987 | params->params.ssid_len = len; | ||
988 | memcpy(params->params.ssid, ssid, len); | ||
989 | } else { | ||
990 | params->params.ssid_len = 0; | ||
991 | memset(params->params.ssid, 0, 32); | ||
992 | } | ||
993 | 872 | ||
994 | ret = wl1251_build_probe_req(wl, ssid, len); | 873 | if (wl->scanning) { |
995 | if (ret < 0) { | 874 | wl1251_debug(DEBUG_SCAN, "scan already in progress"); |
996 | wl1251_error("PROBE request template failed"); | 875 | ret = -EINVAL; |
997 | goto out; | 876 | goto out; |
998 | } | 877 | } |
999 | 878 | ||
1000 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | 879 | ret = wl1251_ps_elp_wakeup(wl); |
1001 | if (!trigger) | 880 | if (ret < 0) |
1002 | goto out; | 881 | goto out; |
1003 | 882 | ||
1004 | trigger->timeout = 0; | 883 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, |
1005 | 884 | req->ie, req->ie_len); | |
1006 | ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | 885 | if (!skb) { |
1007 | sizeof(*trigger)); | 886 | ret = -ENOMEM; |
1008 | if (ret < 0) { | ||
1009 | wl1251_error("trigger scan to failed for hw scan"); | ||
1010 | goto out; | 887 | goto out; |
1011 | } | 888 | } |
1012 | 889 | ||
1013 | wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | 890 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, |
1014 | 891 | skb->len); | |
1015 | wl->scanning = true; | 892 | dev_kfree_skb(skb); |
893 | if (ret < 0) | ||
894 | goto out_sleep; | ||
1016 | 895 | ||
1017 | ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | 896 | ret = wl1251_cmd_trigger_scan_to(wl, 0); |
1018 | if (ret < 0) | 897 | if (ret < 0) |
1019 | wl1251_error("SCAN failed"); | 898 | goto out_sleep; |
1020 | 899 | ||
1021 | wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | 900 | wl->scanning = true; |
1022 | 901 | ||
1023 | if (params->header.status != CMD_STATUS_SUCCESS) { | 902 | ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, |
1024 | wl1251_error("TEST command answer error: %d", | 903 | req->n_channels, WL1251_SCAN_NUM_PROBES); |
1025 | params->header.status); | 904 | if (ret < 0) { |
1026 | wl->scanning = false; | 905 | wl->scanning = false; |
1027 | ret = -EIO; | 906 | goto out_sleep; |
1028 | goto out; | ||
1029 | } | ||
1030 | |||
1031 | out: | ||
1032 | kfree(params); | ||
1033 | return ret; | ||
1034 | |||
1035 | } | ||
1036 | |||
1037 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | ||
1038 | struct cfg80211_scan_request *req) | ||
1039 | { | ||
1040 | struct wl1251 *wl = hw->priv; | ||
1041 | int ret; | ||
1042 | u8 *ssid = NULL; | ||
1043 | size_t ssid_len = 0; | ||
1044 | |||
1045 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
1046 | |||
1047 | if (req->n_ssids) { | ||
1048 | ssid = req->ssids[0].ssid; | ||
1049 | ssid_len = req->ssids[0].ssid_len; | ||
1050 | } | 907 | } |
1051 | 908 | ||
1052 | mutex_lock(&wl->mutex); | 909 | out_sleep: |
1053 | |||
1054 | ret = wl1251_ps_elp_wakeup(wl); | ||
1055 | if (ret < 0) | ||
1056 | goto out; | ||
1057 | |||
1058 | ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); | ||
1059 | |||
1060 | wl1251_ps_elp_sleep(wl); | 910 | wl1251_ps_elp_sleep(wl); |
1061 | 911 | ||
1062 | out: | 912 | out: |
@@ -1095,7 +945,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1095 | { | 945 | { |
1096 | enum wl1251_cmd_ps_mode mode; | 946 | enum wl1251_cmd_ps_mode mode; |
1097 | struct wl1251 *wl = hw->priv; | 947 | struct wl1251 *wl = hw->priv; |
1098 | struct sk_buff *beacon; | 948 | struct sk_buff *beacon, *skb; |
1099 | int ret; | 949 | int ret; |
1100 | 950 | ||
1101 | wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | 951 | wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); |
@@ -1109,7 +959,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1109 | if (changed & BSS_CHANGED_BSSID) { | 959 | if (changed & BSS_CHANGED_BSSID) { |
1110 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | 960 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); |
1111 | 961 | ||
1112 | ret = wl1251_build_null_data(wl); | 962 | skb = ieee80211_nullfunc_get(wl->hw, wl->vif); |
963 | if (!skb) | ||
964 | goto out_sleep; | ||
965 | |||
966 | ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, | ||
967 | skb->data, skb->len); | ||
968 | dev_kfree_skb(skb); | ||
969 | if (ret < 0) | ||
970 | goto out_sleep; | ||
971 | |||
972 | ret = wl1251_build_qos_null_data(wl); | ||
1113 | if (ret < 0) | 973 | if (ret < 0) |
1114 | goto out; | 974 | goto out; |
1115 | 975 | ||
@@ -1130,7 +990,14 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1130 | wl->dtim_period); | 990 | wl->dtim_period); |
1131 | wl->aid = bss_conf->aid; | 991 | wl->aid = bss_conf->aid; |
1132 | 992 | ||
1133 | ret = wl1251_build_ps_poll(wl, wl->aid); | 993 | skb = ieee80211_pspoll_get(wl->hw, wl->vif); |
994 | if (!skb) | ||
995 | goto out_sleep; | ||
996 | |||
997 | ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, | ||
998 | skb->data, | ||
999 | skb->len); | ||
1000 | dev_kfree_skb(skb); | ||
1134 | if (ret < 0) | 1001 | if (ret < 0) |
1135 | goto out_sleep; | 1002 | goto out_sleep; |
1136 | 1003 | ||
@@ -1176,7 +1043,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1176 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); | 1043 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); |
1177 | if (ret < 0) { | 1044 | if (ret < 0) { |
1178 | wl1251_warning("Set ctsprotect failed %d", ret); | 1045 | wl1251_warning("Set ctsprotect failed %d", ret); |
1179 | goto out; | 1046 | goto out_sleep; |
1180 | } | 1047 | } |
1181 | } | 1048 | } |
1182 | 1049 | ||
@@ -1187,7 +1054,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1187 | 1054 | ||
1188 | if (ret < 0) { | 1055 | if (ret < 0) { |
1189 | dev_kfree_skb(beacon); | 1056 | dev_kfree_skb(beacon); |
1190 | goto out; | 1057 | goto out_sleep; |
1191 | } | 1058 | } |
1192 | 1059 | ||
1193 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, | 1060 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, |
@@ -1196,13 +1063,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1196 | dev_kfree_skb(beacon); | 1063 | dev_kfree_skb(beacon); |
1197 | 1064 | ||
1198 | if (ret < 0) | 1065 | if (ret < 0) |
1199 | goto out; | 1066 | goto out_sleep; |
1200 | 1067 | ||
1201 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, | 1068 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, |
1202 | wl->channel, wl->dtim_period); | 1069 | wl->channel, wl->dtim_period); |
1203 | 1070 | ||
1204 | if (ret < 0) | 1071 | if (ret < 0) |
1205 | goto out; | 1072 | goto out_sleep; |
1206 | } | 1073 | } |
1207 | 1074 | ||
1208 | out_sleep: | 1075 | out_sleep: |
@@ -1273,6 +1140,48 @@ static struct ieee80211_channel wl1251_channels[] = { | |||
1273 | { .hw_value = 13, .center_freq = 2472}, | 1140 | { .hw_value = 13, .center_freq = 2472}, |
1274 | }; | 1141 | }; |
1275 | 1142 | ||
1143 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
1144 | const struct ieee80211_tx_queue_params *params) | ||
1145 | { | ||
1146 | enum wl1251_acx_ps_scheme ps_scheme; | ||
1147 | struct wl1251 *wl = hw->priv; | ||
1148 | int ret; | ||
1149 | |||
1150 | mutex_lock(&wl->mutex); | ||
1151 | |||
1152 | wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); | ||
1153 | |||
1154 | ret = wl1251_ps_elp_wakeup(wl); | ||
1155 | if (ret < 0) | ||
1156 | goto out; | ||
1157 | |||
1158 | ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), | ||
1159 | params->cw_min, params->cw_max, | ||
1160 | params->aifs, params->txop); | ||
1161 | if (ret < 0) | ||
1162 | goto out_sleep; | ||
1163 | |||
1164 | if (params->uapsd) | ||
1165 | ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; | ||
1166 | else | ||
1167 | ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; | ||
1168 | |||
1169 | ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), | ||
1170 | CHANNEL_TYPE_EDCF, | ||
1171 | wl1251_tx_get_queue(queue), ps_scheme, | ||
1172 | WL1251_ACX_ACK_POLICY_LEGACY); | ||
1173 | if (ret < 0) | ||
1174 | goto out_sleep; | ||
1175 | |||
1176 | out_sleep: | ||
1177 | wl1251_ps_elp_sleep(wl); | ||
1178 | |||
1179 | out: | ||
1180 | mutex_unlock(&wl->mutex); | ||
1181 | |||
1182 | return ret; | ||
1183 | } | ||
1184 | |||
1276 | /* can't be const, mac80211 writes to this */ | 1185 | /* can't be const, mac80211 writes to this */ |
1277 | static struct ieee80211_supported_band wl1251_band_2ghz = { | 1186 | static struct ieee80211_supported_band wl1251_band_2ghz = { |
1278 | .channels = wl1251_channels, | 1187 | .channels = wl1251_channels, |
@@ -1293,6 +1202,7 @@ static const struct ieee80211_ops wl1251_ops = { | |||
1293 | .hw_scan = wl1251_op_hw_scan, | 1202 | .hw_scan = wl1251_op_hw_scan, |
1294 | .bss_info_changed = wl1251_op_bss_info_changed, | 1203 | .bss_info_changed = wl1251_op_bss_info_changed, |
1295 | .set_rts_threshold = wl1251_op_set_rts_threshold, | 1204 | .set_rts_threshold = wl1251_op_set_rts_threshold, |
1205 | .conf_tx = wl1251_op_conf_tx, | ||
1296 | }; | 1206 | }; |
1297 | 1207 | ||
1298 | static int wl1251_register_hw(struct wl1251 *wl) | 1208 | static int wl1251_register_hw(struct wl1251 *wl) |
@@ -1332,12 +1242,15 @@ int wl1251_init_ieee80211(struct wl1251 *wl) | |||
1332 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | 1242 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | |
1333 | IEEE80211_HW_NOISE_DBM | | 1243 | IEEE80211_HW_NOISE_DBM | |
1334 | IEEE80211_HW_SUPPORTS_PS | | 1244 | IEEE80211_HW_SUPPORTS_PS | |
1335 | IEEE80211_HW_BEACON_FILTER; | 1245 | IEEE80211_HW_BEACON_FILTER | |
1246 | IEEE80211_HW_SUPPORTS_UAPSD; | ||
1336 | 1247 | ||
1337 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | 1248 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); |
1338 | wl->hw->wiphy->max_scan_ssids = 1; | 1249 | wl->hw->wiphy->max_scan_ssids = 1; |
1339 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; | 1250 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; |
1340 | 1251 | ||
1252 | wl->hw->queues = 4; | ||
1253 | |||
1341 | ret = wl1251_register_hw(wl); | 1254 | ret = wl1251_register_hw(wl); |
1342 | if (ret) | 1255 | if (ret) |
1343 | goto out; | 1256 | goto out; |