From 863981e96738983919de841ec669e157e6bdaeb0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sun, 11 Sep 2016 04:34:46 -0300 Subject: Linux-libre 4.7.1-gnu --- drivers/net/wireless/ath/wcn36xx/smd.c | 228 ++++++++++++++++++++++----------- 1 file changed, 153 insertions(+), 75 deletions(-) (limited to 'drivers/net/wireless/ath/wcn36xx/smd.c') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 936938c74..06c5ddcd3 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -104,11 +104,11 @@ static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn, struct ieee80211_sta *sta, struct wcn36xx_hal_config_bss_params *bss_params) { - if (IEEE80211_BAND_5GHZ == WCN36XX_BAND(wcn)) + if (NL80211_BAND_5GHZ == WCN36XX_BAND(wcn)) bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE; else if (sta && sta->ht_cap.ht_supported) bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE; - else if (sta && (sta->supp_rates[IEEE80211_BAND_2GHZ] & 0x7f)) + else if (sta && (sta->supp_rates[NL80211_BAND_2GHZ] & 0x7f)) bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE; else bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE; @@ -191,16 +191,16 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, struct ieee80211_sta *sta, struct wcn36xx_hal_config_sta_params *sta_params) { - struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; - struct wcn36xx_sta *priv_sta = NULL; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_sta *sta_priv = NULL; if (vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT) { sta_params->type = 1; - sta_params->sta_index = 0xFF; + sta_params->sta_index = WCN36XX_HAL_STA_INVALID_IDX; } else { sta_params->type = 0; - sta_params->sta_index = 1; + sta_params->sta_index = vif_priv->self_sta_index; } sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); @@ -215,7 +215,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, else memcpy(&sta_params->bssid, vif->addr, ETH_ALEN); - sta_params->encrypt_type = priv_vif->encrypt_type; + sta_params->encrypt_type = vif_priv->encrypt_type; sta_params->short_preamble_supported = true; sta_params->rifs_mode = 0; @@ -224,21 +224,21 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, sta_params->uapsd = 0; sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC; sta_params->max_ampdu_duration = 0; - sta_params->bssid_index = priv_vif->bss_index; + sta_params->bssid_index = vif_priv->bss_index; sta_params->p2p = 0; if (sta) { - priv_sta = (struct wcn36xx_sta *)sta->drv_priv; + sta_priv = wcn36xx_sta_to_priv(sta); if (NL80211_IFTYPE_STATION == vif->type) memcpy(&sta_params->bssid, sta->addr, ETH_ALEN); else memcpy(&sta_params->mac, sta->addr, ETH_ALEN); sta_params->wmm_enabled = sta->wme; sta_params->max_sp_len = sta->max_sp; - sta_params->aid = priv_sta->aid; + sta_params->aid = sta_priv->aid; wcn36xx_smd_set_sta_ht_params(sta, sta_params); - memcpy(&sta_params->supported_rates, &priv_sta->supported_rates, - sizeof(priv_sta->supported_rates)); + memcpy(&sta_params->supported_rates, &sta_priv->supported_rates, + sizeof(sta_priv->supported_rates)); } else { wcn36xx_set_default_rates(&sta_params->supported_rates); wcn36xx_smd_set_sta_default_ht_params(sta_params); @@ -271,6 +271,16 @@ out: return ret; } +static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr, + enum wcn36xx_hal_host_msg_type msg_type, + size_t msg_size) +{ + memset(hdr, 0, msg_size + sizeof(*hdr)); + hdr->msg_type = msg_type; + hdr->msg_version = WCN36XX_HAL_MSG_VERSION0; + hdr->len = msg_size + sizeof(*hdr); +} + #define INIT_HAL_MSG(msg_body, type) \ do { \ memset(&msg_body, 0, sizeof(msg_body)); \ @@ -302,22 +312,6 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) return 0; } -static int wcn36xx_smd_rsp_status_check_v2(struct wcn36xx *wcn, void *buf, - size_t len) -{ - struct wcn36xx_fw_msg_status_rsp_v2 *rsp; - - if (len < sizeof(struct wcn36xx_hal_msg_header) + sizeof(*rsp)) - return wcn36xx_smd_rsp_status_check(buf, len); - - rsp = buf + sizeof(struct wcn36xx_hal_msg_header); - - if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) - return rsp->status; - - return 0; -} - int wcn36xx_smd_load_nv(struct wcn36xx *wcn) { struct nv_data *nv_d; @@ -726,7 +720,7 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, size_t len) { struct wcn36xx_hal_add_sta_self_rsp_msg *rsp; - struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); if (len < sizeof(*rsp)) return -EINVAL; @@ -743,8 +737,8 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, "hal add sta self status %d self_sta_index %d dpu_index %d\n", rsp->status, rsp->self_sta_index, rsp->dpu_index); - priv_vif->self_sta_index = rsp->self_sta_index; - priv_vif->self_dpu_desc_index = rsp->dpu_index; + vif_priv->self_sta_index = rsp->self_sta_index; + vif_priv->self_dpu_desc_index = rsp->dpu_index; return 0; } @@ -949,17 +943,32 @@ static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn, memcpy(&v1->mac, orig->mac, ETH_ALEN); v1->aid = orig->aid; v1->type = orig->type; + v1->short_preamble_supported = orig->short_preamble_supported; v1->listen_interval = orig->listen_interval; + v1->wmm_enabled = orig->wmm_enabled; v1->ht_capable = orig->ht_capable; - + v1->tx_channel_width_set = orig->tx_channel_width_set; + v1->rifs_mode = orig->rifs_mode; + v1->lsig_txop_protection = orig->lsig_txop_protection; v1->max_ampdu_size = orig->max_ampdu_size; v1->max_ampdu_density = orig->max_ampdu_density; v1->sgi_40mhz = orig->sgi_40mhz; v1->sgi_20Mhz = orig->sgi_20Mhz; - + v1->rmf = orig->rmf; + v1->encrypt_type = orig->encrypt_type; + v1->action = orig->action; + v1->uapsd = orig->uapsd; + v1->max_sp_len = orig->max_sp_len; + v1->green_field_capable = orig->green_field_capable; + v1->mimo_ps = orig->mimo_ps; + v1->delayed_ba_support = orig->delayed_ba_support; + v1->max_ampdu_duration = orig->max_ampdu_duration; + v1->dsss_cck_mode_40mhz = orig->dsss_cck_mode_40mhz; memcpy(&v1->supported_rates, &orig->supported_rates, sizeof(orig->supported_rates)); v1->sta_index = orig->sta_index; + v1->bssid_index = orig->bssid_index; + v1->p2p = orig->p2p; } static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, @@ -969,7 +978,7 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, { struct wcn36xx_hal_config_sta_rsp_msg *rsp; struct config_sta_rsp_params *params; - struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; + struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); if (len < sizeof(*rsp)) return -EINVAL; @@ -1170,12 +1179,13 @@ static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn, static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *buf, size_t len) { struct wcn36xx_hal_config_bss_rsp_msg *rsp; struct wcn36xx_hal_config_bss_rsp_params *params; - struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); if (len < sizeof(*rsp)) return -EINVAL; @@ -1198,14 +1208,15 @@ static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, params->bss_bcast_sta_idx, params->mac, params->tx_mgmt_power, params->ucast_dpu_signature); - priv_vif->bss_index = params->bss_index; + vif_priv->bss_index = params->bss_index; - if (priv_vif->sta) { - priv_vif->sta->bss_sta_index = params->bss_sta_index; - priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index; + if (sta) { + struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); + sta_priv->bss_sta_index = params->bss_sta_index; + sta_priv->bss_dpu_desc_index = params->dpu_desc_index; } - priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature; + vif_priv->self_ucast_dpu_sign = params->ucast_dpu_signature; return 0; } @@ -1217,7 +1228,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, struct wcn36xx_hal_config_bss_req_msg msg; struct wcn36xx_hal_config_bss_params *bss; struct wcn36xx_hal_config_sta_params *sta_params; - struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); int ret = 0; mutex_lock(&wcn->hal_mutex); @@ -1329,6 +1340,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, } ret = wcn36xx_smd_config_bss_rsp(wcn, vif, + sta, wcn->hal_buf, wcn->hal_rsp_len); if (ret) { @@ -1343,13 +1355,13 @@ out: int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif) { struct wcn36xx_hal_delete_bss_req_msg msg_body; - struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); int ret = 0; mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ); - msg_body.bss_index = priv_vif->bss_index; + msg_body.bss_index = vif_priv->bss_index; PREPARE_HAL_BUF(wcn->hal_buf, msg_body); @@ -1375,26 +1387,47 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, u16 p2p_off) { struct wcn36xx_hal_send_beacon_req_msg msg_body; - int ret = 0; + int ret = 0, pad, pvm_len; mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ); - /* TODO need to find out why this is needed? */ - msg_body.beacon_length = skb_beacon->len + 6; + pvm_len = skb_beacon->data[tim_off + 1] - 3; + pad = TIM_MIN_PVM_SIZE - pvm_len; - if (BEACON_TEMPLATE_SIZE > msg_body.beacon_length) { - memcpy(&msg_body.beacon, &skb_beacon->len, sizeof(u32)); - memcpy(&(msg_body.beacon[4]), skb_beacon->data, - skb_beacon->len); - } else { + /* Padding is irrelevant to mesh mode since tim_off is always 0. */ + if (vif->type == NL80211_IFTYPE_MESH_POINT) + pad = 0; + + msg_body.beacon_length = skb_beacon->len + pad; + /* TODO need to find out why + 6 is needed */ + msg_body.beacon_length6 = msg_body.beacon_length + 6; + + if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) { wcn36xx_err("Beacon is to big: beacon size=%d\n", msg_body.beacon_length); ret = -ENOMEM; goto out; } + memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len); memcpy(msg_body.bssid, vif->addr, ETH_ALEN); + if (pad > 0) { + /* + * The wcn36xx FW has a fixed size for the PVM in the TIM. If + * given the beacon template from mac80211 with a PVM shorter + * than the FW expectes it will overwrite the data after the + * TIM. + */ + wcn36xx_dbg(WCN36XX_DBG_HAL, "Pad TIM PVM. %d bytes at %d\n", + pad, pvm_len); + memmove(&msg_body.beacon[tim_off + 5 + pvm_len + pad], + &msg_body.beacon[tim_off + 5 + pvm_len], + skb_beacon->len - (tim_off + 5 + pvm_len)); + memset(&msg_body.beacon[tim_off + 5 + pvm_len], 0, pad); + msg_body.beacon[tim_off + 1] += pad; + } + /* TODO need to find out why this is needed? */ if (vif->type == NL80211_IFTYPE_MESH_POINT) /* mesh beacon don't need this, so push further down */ @@ -1598,8 +1631,7 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, wcn36xx_err("Sending hal_remove_bsskey failed\n"); goto out; } - ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf, - wcn->hal_rsp_len); + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); if (ret) { wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret); goto out; @@ -1612,7 +1644,7 @@ out: int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) { struct wcn36xx_hal_enter_bmps_req_msg msg_body; - struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); int ret = 0; mutex_lock(&wcn->hal_mutex); @@ -1641,8 +1673,8 @@ out: int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) { - struct wcn36xx_hal_enter_bmps_req_msg msg_body; - struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; + struct wcn36xx_hal_exit_bmps_req_msg msg_body; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); int ret = 0; mutex_lock(&wcn->hal_mutex); @@ -1703,7 +1735,7 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int packet_type) { struct wcn36xx_hal_keep_alive_req_msg msg_body; - struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); int ret = 0; mutex_lock(&wcn->hal_mutex); @@ -1944,6 +1976,17 @@ out: return ret; } +static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len) +{ + struct wcn36xx_hal_trigger_ba_rsp_msg *rsp; + + if (len < sizeof(*rsp)) + return -EINVAL; + + rsp = (struct wcn36xx_hal_trigger_ba_rsp_msg *) buf; + return rsp->status; +} + int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) { struct wcn36xx_hal_trigger_ba_req_msg msg_body; @@ -1968,8 +2011,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) wcn36xx_err("Sending hal_trigger_ba failed\n"); goto out; } - ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf, - wcn->hal_rsp_len); + ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len); if (ret) { wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret); goto out; @@ -2006,9 +2048,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, list_for_each_entry(tmp, &wcn->vif_list, list) { wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", tmp->bss_index); - vif = container_of((void *)tmp, - struct ieee80211_vif, - drv_priv); + vif = wcn36xx_priv_to_vif(tmp); ieee80211_connection_loss(vif); } return 0; @@ -2023,9 +2063,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, if (tmp->bss_index == rsp->bss_index) { wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", rsp->bss_index); - vif = container_of((void *)tmp, - struct ieee80211_vif, - drv_priv); + vif = wcn36xx_priv_to_vif(tmp); ieee80211_connection_loss(vif); return 0; } @@ -2041,25 +2079,24 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn, { struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf; struct wcn36xx_vif *tmp; - struct ieee80211_sta *sta = NULL; + struct ieee80211_sta *sta; if (len != sizeof(*rsp)) { wcn36xx_warn("Corrupted delete sta indication\n"); return -EIO; } + wcn36xx_dbg(WCN36XX_DBG_HAL, "delete station indication %pM index %d\n", + rsp->addr2, rsp->sta_id); + list_for_each_entry(tmp, &wcn->vif_list, list) { - if (sta && (tmp->sta->sta_index == rsp->sta_id)) { - sta = container_of((void *)tmp->sta, - struct ieee80211_sta, - drv_priv); - wcn36xx_dbg(WCN36XX_DBG_HAL, - "delete station indication %pM index %d\n", - rsp->addr2, - rsp->sta_id); + rcu_read_lock(); + sta = ieee80211_find_sta(wcn36xx_priv_to_vif(tmp), rsp->addr2); + if (sta) ieee80211_report_low_ack(sta, 0); + rcu_read_unlock(); + if (sta) return 0; - } } wcn36xx_warn("STA with addr %pM and index %d not found\n", @@ -2100,6 +2137,46 @@ out: mutex_unlock(&wcn->hal_mutex); return ret; } + +int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, + struct ieee80211_vif *vif, + struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *msg_body = NULL; + int ret = 0; + + mutex_lock(&wcn->hal_mutex); + + msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *) + wcn->hal_buf; + init_hal_msg(&msg_body->header, WCN36XX_HAL_8023_MULTICAST_LIST_REQ, + sizeof(msg_body->mc_addr_list)); + + /* An empty list means all mc traffic will be received */ + if (fp) + memcpy(&msg_body->mc_addr_list, fp, + sizeof(msg_body->mc_addr_list)); + else + msg_body->mc_addr_list.mc_addr_count = 0; + + msg_body->mc_addr_list.bss_index = vif_priv->bss_index; + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len); + if (ret) { + wcn36xx_err("Sending HAL_8023_MULTICAST_LIST failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("HAL_8023_MULTICAST_LIST rsp failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) { struct wcn36xx_hal_msg_header *msg_header = buf; @@ -2141,6 +2218,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP: case WCN36XX_HAL_CH_SWITCH_RSP: case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP: + case WCN36XX_HAL_8023_MULTICAST_LIST_RSP: memcpy(wcn->hal_buf, buf, len); wcn->hal_rsp_len = len; complete(&wcn->hal_rsp_compl); -- cgit v1.2.3-54-g00ecf