diff options
Diffstat (limited to 'drivers/net/wireless/ath/wcn36xx')
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/dxe.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/hal.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/main.c | 131 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/smd.c | 288 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/smd.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 14 |
6 files changed, 428 insertions, 44 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 63079231e48e..8e1dbfda6538 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -800,7 +800,7 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, (char *)ctl_skb->skb->data, ctl_skb->skb->len); /* Move the head of the ring to the next empty descriptor */ - ch->head_blk_ctl = ctl_skb->next; + ch->head_blk_ctl = ctl_skb->next; /* Commit all previous writes and set descriptors to VALID */ wmb(); diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 65ef893f2736..455143c4164e 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -3464,8 +3464,12 @@ struct wcn36xx_hal_rem_bcn_filter_req { #define WCN36XX_HAL_OFFLOAD_DISABLE 0 #define WCN36XX_HAL_OFFLOAD_ENABLE 1 #define WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE 0x2 +#define WCN36XX_HAL_OFFLOAD_MCAST_FILTER_ENABLE 0x4 +#define WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE \ + (WCN36XX_HAL_OFFLOAD_ENABLE | WCN36XX_HAL_OFFLOAD_MCAST_FILTER_ENABLE) #define WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE \ - (HAL_OFFLOAD_ENABLE|HAL_OFFLOAD_BCAST_FILTER_ENABLE) + (WCN36XX_HAL_OFFLOAD_ENABLE | WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE) +#define WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX 0x02 struct wcn36xx_hal_ns_offload_params { u8 src_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN]; @@ -3487,10 +3491,10 @@ struct wcn36xx_hal_ns_offload_params { /* slot index for this offload */ u32 slot_index; u8 bss_index; -}; +} __packed; struct wcn36xx_hal_host_offload_req { - u8 offload_Type; + u8 offload_type; /* enable or disable */ u8 enable; @@ -3499,13 +3503,13 @@ struct wcn36xx_hal_host_offload_req { u8 host_ipv4_addr[4]; u8 host_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN]; } u; -}; +} __packed; struct wcn36xx_hal_host_offload_req_msg { struct wcn36xx_hal_msg_header header; struct wcn36xx_hal_host_offload_req host_offload_params; struct wcn36xx_hal_ns_offload_params ns_offload_params; -}; +} __packed; /* Packet Types. */ #define WCN36XX_HAL_KEEP_ALIVE_NULL_PKT 1 @@ -4901,7 +4905,7 @@ struct wcn36xx_hal_gtk_offload_req_msg { u64 key_replay_counter; u8 bss_index; -}; +} __packed; struct wcn36xx_hal_gtk_offload_rsp_msg { struct wcn36xx_hal_msg_header header; @@ -4915,7 +4919,7 @@ struct wcn36xx_hal_gtk_offload_rsp_msg { struct wcn36xx_hal_gtk_offload_get_info_req_msg { struct wcn36xx_hal_msg_header header; u8 bss_index; -}; +} __packed; struct wcn36xx_hal_gtk_offload_get_info_rsp_msg { struct wcn36xx_hal_msg_header header; @@ -4939,7 +4943,7 @@ struct wcn36xx_hal_gtk_offload_get_info_rsp_msg { u32 igtk_rekey_count; u8 bss_index; -}; +} __packed; struct dhcp_info { /* Indicates the device mode which indicates about the DHCP activity */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index afb4877eaad8..d202f2128df2 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -25,6 +25,7 @@ #include <linux/rpmsg.h> #include <linux/soc/qcom/smem_state.h> #include <linux/soc/qcom/wcnss_ctrl.h> +#include <net/ipv6.h> #include "wcn36xx.h" #include "testmode.h" @@ -172,7 +173,9 @@ static struct ieee80211_supported_band wcn_band_5ghz = { #ifdef CONFIG_PM static const struct wiphy_wowlan_support wowlan_support = { - .flags = WIPHY_WOWLAN_ANY + .flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY }; #endif @@ -293,23 +296,16 @@ static int wcn36xx_start(struct ieee80211_hw *hw) goto out_free_dxe_pool; } - wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL); - if (!wcn->hal_buf) { - wcn36xx_err("Failed to allocate smd buf\n"); - ret = -ENOMEM; - goto out_free_dxe_ctl; - } - ret = wcn36xx_smd_load_nv(wcn); if (ret) { wcn36xx_err("Failed to push NV to chip\n"); - goto out_free_smd_buf; + goto out_free_dxe_ctl; } ret = wcn36xx_smd_start(wcn); if (ret) { wcn36xx_err("Failed to start chip\n"); - goto out_free_smd_buf; + goto out_free_dxe_ctl; } if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { @@ -336,8 +332,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw) out_smd_stop: wcn36xx_smd_stop(wcn); -out_free_smd_buf: - kfree(wcn->hal_buf); out_free_dxe_ctl: wcn36xx_dxe_free_ctl_blks(wcn); out_free_dxe_pool: @@ -372,8 +366,6 @@ static void wcn36xx_stop(struct ieee80211_hw *hw) wcn36xx_dxe_free_mem_pools(wcn); wcn36xx_dxe_free_ctl_blks(wcn); - - kfree(wcn->hal_buf); } static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable) @@ -1088,28 +1080,91 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw, #ifdef CONFIG_PM +static struct ieee80211_vif *wcn36xx_get_first_assoc_vif(struct wcn36xx *wcn) +{ + struct wcn36xx_vif *vif_priv = NULL; + struct ieee80211_vif *vif = NULL; + + list_for_each_entry(vif_priv, &wcn->vif_list, list) { + if (vif_priv->sta_assoc) { + vif = wcn36xx_priv_to_vif(vif_priv); + break; + } + } + return vif; +} + static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) { struct wcn36xx *wcn = hw->priv; + struct ieee80211_vif *vif = NULL; + int ret = 0; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n"); - flush_workqueue(wcn->hal_ind_wq); - wcn36xx_smd_set_power_params(wcn, true); - return 0; + mutex_lock(&wcn->conf_mutex); + + vif = wcn36xx_get_first_assoc_vif(wcn); + if (vif) { + ret = wcn36xx_smd_arp_offload(wcn, vif, true); + if (ret) + goto out; + ret = wcn36xx_smd_ipv6_ns_offload(wcn, vif, true); + if (ret) + goto out; + ret = wcn36xx_smd_gtk_offload(wcn, vif, true); + if (ret) + goto out; + ret = wcn36xx_smd_set_power_params(wcn, true); + if (ret) + goto out; + ret = wcn36xx_smd_wlan_host_suspend_ind(wcn); + } +out: + mutex_unlock(&wcn->conf_mutex); + return ret; } static int wcn36xx_resume(struct ieee80211_hw *hw) { struct wcn36xx *wcn = hw->priv; + struct ieee80211_vif *vif = NULL; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n"); - flush_workqueue(wcn->hal_ind_wq); - wcn36xx_smd_set_power_params(wcn, false); + mutex_lock(&wcn->conf_mutex); + vif = wcn36xx_get_first_assoc_vif(wcn); + if (vif) { + wcn36xx_smd_host_resume(wcn); + wcn36xx_smd_set_power_params(wcn, false); + wcn36xx_smd_gtk_offload_get_info(wcn, vif); + wcn36xx_smd_gtk_offload(wcn, vif, false); + wcn36xx_smd_ipv6_ns_offload(wcn, vif, false); + wcn36xx_smd_arp_offload(wcn, vif, false); + } + mutex_unlock(&wcn->conf_mutex); + return 0; } +static void wcn36xx_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) +{ + struct wcn36xx *wcn = hw->priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + + mutex_lock(&wcn->conf_mutex); + + memcpy(vif_priv->rekey_data.kek, data->kek, NL80211_KEK_LEN); + memcpy(vif_priv->rekey_data.kck, data->kck, NL80211_KCK_LEN); + vif_priv->rekey_data.replay_ctr = + cpu_to_le64(be64_to_cpup((__be64 *)data->replay_ctr)); + vif_priv->rekey_data.valid = true; + + mutex_unlock(&wcn->conf_mutex); +} + #endif static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, @@ -1176,6 +1231,34 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, return ret; } +#if IS_ENABLED(CONFIG_IPV6) +static void wcn36xx_ipv6_addr_change(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct inet6_dev *idev) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct inet6_ifaddr *ifa; + int idx = 0; + + memset(vif_priv->tentative_addrs, 0, sizeof(vif_priv->tentative_addrs)); + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + vif_priv->target_ipv6_addrs[idx] = ifa->addr; + if (ifa->flags & IFA_F_TENTATIVE) + __set_bit(idx, vif_priv->tentative_addrs); + idx++; + if (idx >= WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX) + break; + wcn36xx_dbg(WCN36XX_DBG_MAC, "%pI6 %s\n", &ifa->addr, + (ifa->flags & IFA_F_TENTATIVE) ? "tentative" : NULL); + } + read_unlock_bh(&idev->lock); + + vif_priv->num_target_ipv6_addrs = idx; +} +#endif + static const struct ieee80211_ops wcn36xx_ops = { .start = wcn36xx_start, .stop = wcn36xx_stop, @@ -1184,6 +1267,7 @@ static const struct ieee80211_ops wcn36xx_ops = { #ifdef CONFIG_PM .suspend = wcn36xx_suspend, .resume = wcn36xx_resume, + .set_rekey_data = wcn36xx_set_rekey_data, #endif .config = wcn36xx_config, .prepare_multicast = wcn36xx_prepare_multicast, @@ -1199,6 +1283,9 @@ static const struct ieee80211_ops wcn36xx_ops = { .sta_add = wcn36xx_sta_add, .sta_remove = wcn36xx_sta_remove, .ampdu_action = wcn36xx_ampdu_action, +#if IS_ENABLED(CONFIG_IPV6) + .ipv6_addr_change = wcn36xx_ipv6_addr_change, +#endif CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd) }; @@ -1401,6 +1488,12 @@ static int wcn36xx_probe(struct platform_device *pdev) mutex_init(&wcn->hal_mutex); mutex_init(&wcn->scan_lock); + wcn->hal_buf = devm_kmalloc(wcn->dev, WCN36XX_HAL_BUF_SIZE, GFP_KERNEL); + if (!wcn->hal_buf) { + ret = -ENOMEM; + goto out_wq; + } + ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32)); if (ret < 0) { wcn36xx_err("failed to set DMA mask: %d\n", ret); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index d0c3a1557e8d..0e3be17d8cea 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -445,22 +445,12 @@ 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, version) \ do { \ - memset(&msg_body, 0, sizeof(msg_body)); \ - msg_body.header.msg_type = type; \ - msg_body.header.msg_version = version; \ - msg_body.header.len = sizeof(msg_body); \ + memset(&(msg_body), 0, sizeof(msg_body)); \ + (msg_body).header.msg_type = type; \ + (msg_body).header.msg_version = version; \ + (msg_body).header.len = sizeof(msg_body); \ } while (0) \ #define INIT_HAL_MSG(msg_body, type) \ @@ -2729,8 +2719,7 @@ int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, 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)); + INIT_HAL_MSG(*msg_body, WCN36XX_HAL_8023_MULTICAST_LIST_REQ); /* An empty list means all mc traffic will be received */ if (fp) @@ -2756,6 +2745,269 @@ out: return ret; } +int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_host_offload_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ); + msg_body.host_offload_params.offload_type = + WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD; + if (enable) { + msg_body.host_offload_params.enable = + WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE; + memcpy(&msg_body.host_offload_params.u, + &vif->bss_conf.arp_addr_list[0], sizeof(__be32)); + } + msg_body.ns_offload_params.bss_index = vif_priv->bss_index; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending host_offload_arp failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("host_offload_arp failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + +#if IS_ENABLED(CONFIG_IPV6) +int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_host_offload_req_msg msg_body; + struct wcn36xx_hal_ns_offload_params *ns_params; + struct wcn36xx_hal_host_offload_req *ho_params; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ); + ho_params = &msg_body.host_offload_params; + ns_params = &msg_body.ns_offload_params; + + ho_params->offload_type = WCN36XX_HAL_IPV6_NS_OFFLOAD; + if (enable) { + ho_params->enable = + WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE; + if (vif_priv->num_target_ipv6_addrs) { + memcpy(&ho_params->u, + &vif_priv->target_ipv6_addrs[0].in6_u, + sizeof(struct in6_addr)); + memcpy(&ns_params->target_ipv6_addr1, + &vif_priv->target_ipv6_addrs[0].in6_u, + sizeof(struct in6_addr)); + ns_params->target_ipv6_addr1_valid = 1; + } + if (vif_priv->num_target_ipv6_addrs > 1) { + memcpy(&ns_params->target_ipv6_addr2, + &vif_priv->target_ipv6_addrs[1].in6_u, + sizeof(struct in6_addr)); + ns_params->target_ipv6_addr2_valid = 1; + } + } + memcpy(&ns_params->self_addr, vif->addr, ETH_ALEN); + ns_params->bss_index = vif_priv->bss_index; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending host_offload_arp failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("host_offload_arp failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} +#else +int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + return 0; +} +#endif + +int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_gtk_offload_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_REQ); + + if (enable) { + memcpy(&msg_body.kek, vif_priv->rekey_data.kek, NL80211_KEK_LEN); + memcpy(&msg_body.kck, vif_priv->rekey_data.kck, NL80211_KCK_LEN); + msg_body.key_replay_counter = + le64_to_cpu(vif_priv->rekey_data.replay_ctr); + msg_body.bss_index = vif_priv->bss_index; + } else { + msg_body.flags = WCN36XX_HAL_GTK_OFFLOAD_FLAGS_DISABLE; + } + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending host_offload_arp failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("host_offload_arp failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + +static int wcn36xx_smd_gtk_offload_get_info_rsp(struct wcn36xx *wcn, + struct ieee80211_vif *vif) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *rsp; + __be64 replay_ctr; + + if (wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len)) + return -EIO; + + rsp = (struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *)wcn->hal_buf; + + if (rsp->bss_index != vif_priv->bss_index) { + wcn36xx_err("gtk_offload_info invalid response bss index %d\n", + rsp->bss_index); + return -ENOENT; + } + + if (vif_priv->rekey_data.replay_ctr != cpu_to_le64(rsp->key_replay_counter)) { + replay_ctr = cpu_to_be64(rsp->key_replay_counter); + vif_priv->rekey_data.replay_ctr = + cpu_to_le64(rsp->key_replay_counter); + ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, + (void *)&replay_ctr, GFP_KERNEL); + wcn36xx_dbg(WCN36XX_DBG_HAL, + "GTK replay counter increment %llu\n", + rsp->key_replay_counter); + } + + wcn36xx_dbg(WCN36XX_DBG_HAL, + "gtk offload info status %d last_rekey_status %d " + "replay_counter %llu total_rekey_count %d gtk_rekey_count %d " + "igtk_rekey_count %d bss_index %d\n", + rsp->status, rsp->last_rekey_status, + rsp->key_replay_counter, rsp->total_rekey_count, + rsp->gtk_rekey_count, rsp->igtk_rekey_count, + rsp->bss_index); + + return 0; +} + +int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn, + struct ieee80211_vif *vif) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_gtk_offload_get_info_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_GETINFO_REQ); + + msg_body.bss_index = vif_priv->bss_index; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending gtk_offload_get_info failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("gtk_offload_get_info failed err=%d\n", ret); + goto out; + } + ret = wcn36xx_smd_gtk_offload_get_info_rsp(wcn, vif); +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + +int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn) +{ + struct wcn36xx_hal_wlan_host_suspend_ind_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_SUSPEND_IND); + msg_body.configured_mcst_bcst_filter_setting = 0; + msg_body.active_session_count = 1; + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = rpmsg_send(wcn->smd_channel, wcn->hal_buf, msg_body.header.len); + + mutex_unlock(&wcn->hal_mutex); + + return ret; +} + +int wcn36xx_smd_host_resume(struct wcn36xx *wcn) +{ + struct wcn36xx_hal_wlan_host_resume_req_msg msg_body; + struct wcn36xx_hal_host_resume_rsp_msg *rsp; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_RESUME_REQ); + msg_body.configured_mcst_bcst_filter_setting = 0; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending wlan_host_resume failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("wlan_host_resume err=%d\n", ret); + goto out; + } + + rsp = (struct wcn36xx_hal_host_resume_rsp_msg *)wcn->hal_buf; + if (rsp->status) + wcn36xx_warn("wlan_host_resume status=%d\n", rsp->status); + +out: + mutex_unlock(&wcn->hal_mutex); + + return ret; +} + int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, void *buf, int len, void *priv, u32 addr) { @@ -2804,6 +3056,10 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, case WCN36XX_HAL_8023_MULTICAST_LIST_RSP: case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP: case WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP: + case WCN36XX_HAL_HOST_OFFLOAD_RSP: + case WCN36XX_HAL_GTK_OFFLOAD_RSP: + case WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP: + case WCN36XX_HAL_HOST_RESUME_RSP: memcpy(wcn->hal_buf, buf, len); wcn->hal_rsp_len = len; complete(&wcn->hal_rsp_compl); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index 462860572e1f..d8bded03945d 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -146,4 +146,21 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, struct ieee80211_vif *vif, struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp); + +int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable); + +int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable); + +int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable); + +int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn, + struct ieee80211_vif *vif); + +int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn); + +int wcn36xx_smd_host_resume(struct wcn36xx *wcn); + #endif /* _SMD_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 71fa9992b118..6121d8a5641a 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -18,6 +18,7 @@ #define _WCN36XX_H_ #include <linux/completion.h> +#include <linux/in6.h> #include <linux/printk.h> #include <linux/spinlock.h> #include <net/mac80211.h> @@ -136,6 +137,19 @@ struct wcn36xx_vif { u8 self_dpu_desc_index; u8 self_ucast_dpu_sign; +#if IS_ENABLED(CONFIG_IPV6) + /* IPv6 addresses for WoWLAN */ + struct in6_addr target_ipv6_addrs[WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX]; + unsigned long tentative_addrs[BITS_TO_LONGS(WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX)]; + int num_target_ipv6_addrs; +#endif + /* WoWLAN GTK rekey data */ + struct { + u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; + __le64 replay_ctr; + bool valid; + } rekey_data; + struct list_head sta_list; }; |