/****************************************************************************** * * Copyright(c) 2019 Realtek Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * ******************************************************************************/ #include "wowlan.h" static u32 wow_bk_status[4] = {0}; static u32 tgt_ind_orig; static u32 frm_tgt_ind_orig; static u32 wol_pattern_orig; static u32 wol_uc_orig; static u32 wol_magic_orig; static u8 nlo_enable_record; static u32 send_h2c_keep_alive(struct mac_ax_adapter *adapter, struct keep_alive *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_keep_alive *fwcmd_kalive; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_keep_alive)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_kalive = (struct fwcmd_keep_alive *)buf; fwcmd_kalive->dword0 = cpu_to_le32((parm->keepalive_en ? FWCMD_H2C_KEEP_ALIVE_KEEPALIVE_EN : 0) | SET_WORD(parm->packet_id, FWCMD_H2C_KEEP_ALIVE_PACKET_ID) | SET_WORD(parm->period, FWCMD_H2C_KEEP_ALIVE_PERIOD) | SET_WORD(parm->mac_id, FWCMD_H2C_KEEP_ALIVE_MAC_ID)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_KEEP_ALIVE, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_disconnect_detect(struct mac_ax_adapter *adapter, struct disconnect_detect *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_disconnect_detect *fwcmd_disconnect_det; u32 ret = 0; u32 tmp; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_disconnect_detect)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_disconnect_det = (struct fwcmd_disconnect_detect *)buf; fwcmd_disconnect_det->dword0 = cpu_to_le32((parm->disconnect_detect_en ? FWCMD_H2C_DISCONNECT_DETECT_DISCONNECT_DETECT_EN : 0) | (parm->tryok_bcnfail_count_en ? FWCMD_H2C_DISCONNECT_DETECT_TRYOK_BCNFAIL_COUNT_EN : 0) | (parm->disconnect_en ? FWCMD_H2C_DISCONNECT_DETECT_DISCONNECT_EN : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_DISCONNECT_DETECT_MAC_ID) | SET_WORD(parm->check_period, FWCMD_H2C_DISCONNECT_DETECT_CHECK_PERIOD) | SET_WORD(parm->try_pkt_count, FWCMD_H2C_DISCONNECT_DETECT_TRY_PKT_COUNT)); tmp = SET_WORD(parm->tryok_bcnfail_count_limit, FWCMD_H2C_DISCONNECT_DETECT_TRYOK_BCNFAIL_COUNT_LIMIT); fwcmd_disconnect_det->dword1 = cpu_to_le32(tmp); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_DISCONNECT_DETECT, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_wow_global(struct mac_ax_adapter *adapter, struct wow_global *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_wow_global *fwcmd_wow_glo; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_DATA); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_wow_global) + sizeof(struct mac_ax_remotectrl_info_parm_) - 4); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_wow_glo = (struct fwcmd_wow_global *)buf; fwcmd_wow_glo->dword0 = cpu_to_le32((parm->wow_en ? FWCMD_H2C_WOW_GLOBAL_WOW_EN : 0) | (parm->drop_all_pkt ? FWCMD_H2C_WOW_GLOBAL_DROP_ALL_PKT : 0) | (parm->rx_parse_after_wake ? FWCMD_H2C_WOW_GLOBAL_RX_PARSE_AFTER_WAKE : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_WOW_GLOBAL_MAC_ID) | SET_WORD(parm->pairwise_sec_algo, FWCMD_H2C_WOW_GLOBAL_PAIRWISE_SEC_ALGO) | SET_WORD(parm->group_sec_algo, FWCMD_H2C_WOW_GLOBAL_GROUP_SEC_ALGO)); //fwcmd_wow_glo->dword1 = // cpu_to_le32(parm->remotectrl_info_content); PLTFM_MEMCPY(&fwcmd_wow_glo->dword1, &parm->remotectrl_info_content, sizeof(struct mac_ax_remotectrl_info_parm_)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_WOW_GLOBAL, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_gtk_ofld(struct mac_ax_adapter *adapter, struct gtk_ofld *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_gtk_ofld *fwcmd_gtk_ofl; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_DATA); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_gtk_ofld) + sizeof(struct mac_ax_gtk_info_parm_) - 4); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_gtk_ofl = (struct fwcmd_gtk_ofld *)buf; fwcmd_gtk_ofl->dword0 = cpu_to_le32((parm->gtk_en ? FWCMD_H2C_GTK_OFLD_GTK_EN : 0) | (parm->tkip_en ? FWCMD_H2C_GTK_OFLD_TKIP_EN : 0) | (parm->ieee80211w_en ? FWCMD_H2C_GTK_OFLD_IEEE80211W_EN : 0) | (parm->pairwise_wakeup ? FWCMD_H2C_GTK_OFLD_PAIRWISE_WAKEUP : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_GTK_OFLD_MAC_ID) | SET_WORD(parm->gtk_rsp_id, FWCMD_H2C_GTK_OFLD_GTK_RSP_ID)); fwcmd_gtk_ofl->dword1 = cpu_to_le32(SET_WORD(parm->pmf_sa_query_id, FWCMD_H2C_GTK_OFLD_PMF_SA_QUERY_ID) | SET_WORD(parm->bip_sec_algo, FWCMD_H2C_GTK_OFLD_PMF_BIP_SEC_ALGO) | SET_WORD(parm->algo_akm_suit, FWCMD_H2C_GTK_OFLD_ALGO_AKM_SUIT)); PLTFM_MEMCPY(&fwcmd_gtk_ofl->dword2, &parm->gtk_info_content, sizeof(struct mac_ax_gtk_info_parm_)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_GTK_OFLD, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_arp_ofld(struct mac_ax_adapter *adapter, struct arp_ofld *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_arp_ofld *fwcmd_arp_ofl; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_arp_ofld)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_arp_ofl = (struct fwcmd_arp_ofld *)buf; fwcmd_arp_ofl->dword0 = cpu_to_le32((parm->arp_en ? FWCMD_H2C_ARP_OFLD_ARP_EN : 0) | (parm->arp_action ? FWCMD_H2C_ARP_OFLD_ARP_ACTION : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_ARP_OFLD_MAC_ID) | SET_WORD(parm->arp_rsp_id, FWCMD_H2C_ARP_OFLD_ARP_RSP_ID)); fwcmd_arp_ofl->dword1 = cpu_to_le32(parm->arp_info_content); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_ARP_OFLD, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_ndp_ofld(struct mac_ax_adapter *adapter, struct ndp_ofld *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_ndp_ofld *fwcmd_ndp_ofl; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_DATA); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_ndp_ofld) + 2 * sizeof(struct mac_ax_ndp_info_parm_) - 4); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_ndp_ofl = (struct fwcmd_ndp_ofld *)buf; fwcmd_ndp_ofl->dword0 = cpu_to_le32((parm->ndp_en ? FWCMD_H2C_NDP_OFLD_NDP_EN : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_NDP_OFLD_MAC_ID) | SET_WORD(parm->na_id, FWCMD_H2C_NDP_OFLD_NA_ID)); PLTFM_MEMCPY(&fwcmd_ndp_ofl->dword1, &parm->ndp_info_content, 2 * sizeof(struct mac_ax_ndp_info_parm_)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_NDP_OFLD, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_realwow(struct mac_ax_adapter *adapter, struct realwow *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_realwow *fwcmd_realw; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_realwow) + sizeof(struct mac_ax_realwowv2_info_parm_) - 4); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_realw = (struct fwcmd_realwow *)buf; fwcmd_realw->dword0 = cpu_to_le32((parm->realwow_en ? FWCMD_H2C_REALWOW_REALWOW_EN : 0) | (parm->auto_wakeup ? FWCMD_H2C_REALWOW_AUTO_WAKEUP : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_REALWOW_MAC_ID)); fwcmd_realw->dword1 = cpu_to_le32(SET_WORD(parm->keepalive_id, FWCMD_H2C_REALWOW_KEEPALIVE_ID) | SET_WORD(parm->wakeup_pattern_id, FWCMD_H2C_REALWOW_WAKEUP_PATTERN_ID) | SET_WORD(parm->ack_pattern_id, FWCMD_H2C_REALWOW_ACK_PATTERN_ID)); fwcmd_realw->dword2 = cpu_to_le32(parm->realwow_info_content); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_REALWOW, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_nlo(struct mac_ax_adapter *adapter, struct nlo *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif u32 ret = 0; u32 *h2cb_u32; u32 *nlo_parm_u32; u8 sh; h2cb = h2cb_alloc(adapter, H2CB_CLASS_LONG_DATA); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_nlo) + sizeof(struct mac_ax_nlo_networklist_parm_) - 4); if (!buf) { ret = MACNOBUF; goto fail; } nlo_parm_u32 = &parm->nlo_networklistinfo_content; h2cb_u32 = (u32 *)buf; *h2cb_u32 = cpu_to_le32((parm->nlo_en ? FWCMD_H2C_NLO_NLO_EN : 0) | (parm->nlo_32k_en ? FWCMD_H2C_NLO_NLO_32K_EN : 0) | (parm->ignore_cipher_type ? FWCMD_H2C_NLO_IGNORE_CIPHER_TYPE : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_NLO_MAC_ID)); h2cb_u32++; *h2cb_u32 = cpu_to_le32(*nlo_parm_u32); h2cb_u32++; nlo_parm_u32 = parm->nlo_networklistinfo_more; for (sh = 0; sh < (sizeof(struct mac_ax_nlo_networklist_parm_) / 4 - 1); sh++) *(h2cb_u32 + sh) = cpu_to_le32(*(nlo_parm_u32 + sh)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_NLO, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_wakeup_ctrl(struct mac_ax_adapter *adapter, struct wakeup_ctrl *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_wakeup_ctrl *fwcmd_wakeup_ctr; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_wakeup_ctrl)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_wakeup_ctr = (struct fwcmd_wakeup_ctrl *)buf; fwcmd_wakeup_ctr->dword0 = cpu_to_le32((parm->pattern_match_en ? FWCMD_H2C_WAKEUP_CTRL_PATTERN_MATCH_EN : 0) | (parm->magic_en ? FWCMD_H2C_WAKEUP_CTRL_MAGIC_EN : 0) | (parm->hw_unicast_en ? FWCMD_H2C_WAKEUP_CTRL_HW_UNICAST_EN : 0) | (parm->fw_unicast_en ? FWCMD_H2C_WAKEUP_CTRL_FW_UNICAST_EN : 0) | (parm->deauth_wakeup ? FWCMD_H2C_WAKEUP_CTRL_DEAUTH_WAKEUP : 0) | (parm->rekey_wakeup ? FWCMD_H2C_WAKEUP_CTRL_REKEY_WAKEUP : 0) | (parm->eap_wakeup ? FWCMD_H2C_WAKEUP_CTRL_EAP_WAKEUP : 0) | (parm->all_data_wakeup ? FWCMD_H2C_WAKEUP_CTRL_ALL_DATA_WAKEUP : 0) | SET_WORD(parm->mac_id, FWCMD_H2C_WAKEUP_CTRL_MAC_ID)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_WAKEUP_CTRL, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_negative_pattern(struct mac_ax_adapter *adapter, struct negative_pattern *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_negative_pattern *fwcmd_negative_patter; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_negative_pattern)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_negative_patter = (struct fwcmd_negative_pattern *)buf; fwcmd_negative_patter->dword0 = cpu_to_le32((parm->negative_pattern_en ? FWCMD_H2C_NEGATIVE_PATTERN_NEGATIVE_PATTERN_EN : 0) | SET_WORD(parm->pattern_count, FWCMD_H2C_NEGATIVE_PATTERN_PATTERN_COUNT) | SET_WORD(parm->mac_id, FWCMD_H2C_NEGATIVE_PATTERN_MAC_ID)); fwcmd_negative_patter->dword1 = cpu_to_le32(parm->pattern_content); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_NEGATIVE_PATTERN, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } u32 mac_cfg_dev2hst_gpio(struct mac_ax_adapter *adapter, struct mac_ax_dev2hst_gpio_info *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_dev2hst_gpio *fwcmd_dev2hst_gpi; u32 ret = 0; if (parm->gpio_output_input == MAC_AX_DEV2HST_GPIO_INPUT && parm->toggle_pulse == MAC_AX_DEV2HST_PULSE) { PLTFM_MSG_ERR("pulse mode not supported under input mode"); return MACNOITEM; } if (parm->gpio_num > MAC_AX_GPIO15) { PLTFM_MSG_ERR("gpio num > 15"); return MACNOITEM; } if (parm->toggle_pulse == MAC_AX_DEV2HST_PULSE) { if (parm->gpio_pulse_dura == 0) { PLTFM_MSG_ERR("gpio pulse duration cant be 0"); return MACNOITEM; } if (parm->gpio_pulse_period <= parm->gpio_pulse_dura) { PLTFM_MSG_ERR("gpio pulse period can less than duration"); return MACNOITEM; } if (!parm->gpio_pulse_nonstop && parm->gpio_pulse_count == 0) { PLTFM_MSG_ERR("gpio pulse count cant be 0"); return MACNOITEM; } } h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_dev2hst_gpio)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_dev2hst_gpi = (struct fwcmd_dev2hst_gpio *)buf; fwcmd_dev2hst_gpi->dword0 = cpu_to_le32((parm->dev2hst_gpio_en ? FWCMD_H2C_DEV2HST_GPIO_DEV2HST_GPIO_EN : 0) | (parm->disable_inband ? FWCMD_H2C_DEV2HST_GPIO_DISABLE_INBAND : 0) | (parm->gpio_output_input ? FWCMD_H2C_DEV2HST_GPIO_GPIO_OUTPUT_INPUT : 0) | (parm->gpio_active ? FWCMD_H2C_DEV2HST_GPIO_GPIO_ACTIVE : 0) | (parm->toggle_pulse ? FWCMD_H2C_DEV2HST_GPIO_TOGGLE_PULSE : 0) | (parm->data_pin_wakeup ? FWCMD_H2C_DEV2HST_GPIO_DATA_PIN_WAKEUP : 0) | (parm->data_pin_wakeup ? FWCMD_H2C_DEV2HST_GPIO_DATA_PIN_WAKEUP : 0) | (parm->gpio_pulse_nonstop ? FWCMD_H2C_DEV2HST_GPIO_GPIO_PULSE_NONSTOP : 0) | (parm->gpio_time_unit ? FWCMD_H2C_DEV2HST_GPIO_GPIO_TIME_UNIT : 0) | SET_WORD(parm->gpio_num, FWCMD_H2C_DEV2HST_GPIO_GPIO_NUM) | SET_WORD(parm->gpio_pulse_dura, FWCMD_H2C_DEV2HST_GPIO_GPIO_PULSE_DURATION) | SET_WORD(parm->gpio_pulse_period, FWCMD_H2C_DEV2HST_GPIO_GPIO_PULSE_PERIOD)); fwcmd_dev2hst_gpi->dword1 = cpu_to_le32(SET_WORD(parm->gpio_pulse_count, FWCMD_H2C_DEV2HST_GPIO_GPIO_PULSE_COUNT)); fwcmd_dev2hst_gpi->dword2 = cpu_to_le32(SET_WORD(parm->customer_id, FWCMD_H2C_DEV2HST_GPIO_CUSTOMER_ID)); fwcmd_dev2hst_gpi->dword3 = cpu_to_le32((parm->rsn_a_en ? FWCMD_H2C_DEV2HST_GPIO_RSN_A_EN : 0) | (parm->rsn_a_toggle_pulse ? FWCMD_H2C_DEV2HST_GPIO_RSN_A_TOGGLE_PULSE : 0) | (parm->rsn_a_pulse_nonstop ? FWCMD_H2C_DEV2HST_GPIO_RSN_A_PULSE_NONSTOP : 0) | (parm->rsn_a_time_unit ? FWCMD_H2C_DEV2HST_GPIO_RSN_A_TIME_UNIT : 0)); fwcmd_dev2hst_gpi->dword4 = cpu_to_le32(SET_WORD(parm->rsn_a, FWCMD_H2C_DEV2HST_GPIO_RSN_A) | SET_WORD(parm->rsn_a_pulse_duration, FWCMD_H2C_DEV2HST_GPIO_RSN_A_PULSE_DURATION) | SET_WORD(parm->rsn_a_pulse_period, FWCMD_H2C_DEV2HST_GPIO_RSN_A_PULSE_PERIOD) | SET_WORD(parm->rsn_a_pulse_count, FWCMD_H2C_DEV2HST_GPIO_RSN_A_PULSE_COUNT)); fwcmd_dev2hst_gpi->dword5 = cpu_to_le32((parm->rsn_b_en ? FWCMD_H2C_DEV2HST_GPIO_RSN_B_EN : 0) | (parm->rsn_b_toggle_pulse ? FWCMD_H2C_DEV2HST_GPIO_RSN_B_TOGGLE_PULSE : 0) | (parm->rsn_b_pulse_nonstop ? FWCMD_H2C_DEV2HST_GPIO_RSN_B_PULSE_NONSTOP : 0) | (parm->rsn_b_time_unit ? FWCMD_H2C_DEV2HST_GPIO_RSN_B_TIME_UNIT : 0)); fwcmd_dev2hst_gpi->dword6 = cpu_to_le32(SET_WORD(parm->rsn_b, FWCMD_H2C_DEV2HST_GPIO_RSN_B) | SET_WORD(parm->rsn_b_pulse_duration, FWCMD_H2C_DEV2HST_GPIO_RSN_B_PULSE_DURATION) | SET_WORD(parm->rsn_b_pulse_period, FWCMD_H2C_DEV2HST_GPIO_RSN_B_PULSE_PERIOD) | SET_WORD(parm->rsn_b_pulse_count, FWCMD_H2C_DEV2HST_GPIO_RSN_B_PULSE_COUNT)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_DEV2HST_GPIO, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); PLTFM_MSG_TRACE("ok"); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_uphy_ctrl(struct mac_ax_adapter *adapter, struct uphy_ctrl *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_uphy_ctrl *fwcmd_uphy_ctr; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_uphy_ctrl)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_uphy_ctr = (struct fwcmd_uphy_ctrl *)buf; fwcmd_uphy_ctr->dword0 = cpu_to_le32((parm->disable_uphy ? FWCMD_H2C_UPHY_CTRL_DISABLE_UPHY : 0) | SET_WORD(parm->handshake_mode, FWCMD_H2C_UPHY_CTRL_HANDSHAKE_MODE) | (parm->rise_hst2dev_dis_uphy ? FWCMD_H2C_UPHY_CTRL_RISE_HST2DEV_DIS_UPHY : 0) | (parm->uphy_dis_delay_unit ? FWCMD_H2C_UPHY_CTRL_UPHY_DIS_DELAY_UNIT : 0) | (parm->pdn_as_uphy_dis ? FWCMD_H2C_UPHY_CTRL_PDN_AS_UPHY_DIS : 0) | (parm->pdn_to_enable_uphy ? FWCMD_H2C_UPHY_CTRL_PDN_TO_ENABLE_UPHY : 0) | SET_WORD(parm->hst2dev_gpio_num, FWCMD_H2C_UPHY_CTRL_HST2DEV_GPIO_NUM) | SET_WORD(parm->uphy_dis_delay_count, FWCMD_H2C_UPHY_CTRL_UPHY_DIS_DELAY_COUNT)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_UPHY_CTRL, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } static u32 send_h2c_wowcam_upd(struct mac_ax_adapter *adapter, struct wowcam_upd *parm) { u8 *buf; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_wow_cam_upd *fwcmd_wowcam_upd; u32 ret = 0; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_wow_cam_upd)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_wowcam_upd = (struct fwcmd_wow_cam_upd *)buf; fwcmd_wowcam_upd->dword0 = cpu_to_le32((parm->r_w ? FWCMD_H2C_WOW_CAM_UPD_R_W : 0) | SET_WORD(parm->idx, FWCMD_H2C_WOW_CAM_UPD_IDX)); fwcmd_wowcam_upd->dword1 = cpu_to_le32(parm->wkfm1); fwcmd_wowcam_upd->dword2 = cpu_to_le32(parm->wkfm2); fwcmd_wowcam_upd->dword3 = cpu_to_le32(parm->wkfm3); fwcmd_wowcam_upd->dword4 = cpu_to_le32(parm->wkfm4); fwcmd_wowcam_upd->dword5 = cpu_to_le32(SET_WORD(parm->crc, FWCMD_H2C_WOW_CAM_UPD_CRC) | (parm->negative_pattern_match ? FWCMD_H2C_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH : 0) | (parm->skip_mac_hdr ? FWCMD_H2C_WOW_CAM_UPD_SKIP_MAC_HDR : 0) | (parm->uc ? FWCMD_H2C_WOW_CAM_UPD_UC : 0) | (parm->mc ? FWCMD_H2C_WOW_CAM_UPD_MC : 0) | (parm->bc ? FWCMD_H2C_WOW_CAM_UPD_BC : 0) | (parm->valid ? FWCMD_H2C_WOW_CAM_UPD_VALID : 0)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_WOW_CAM_UPD, 0, 0); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } u32 mac_cfg_wow_wake(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_wow_wake_info *info, struct mac_ax_remotectrl_info_parm_ *content) { u32 ret = 0; struct wow_global parm1; struct wakeup_ctrl parm2; struct mac_role_tbl *role; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; parm2.pattern_match_en = info->pattern_match_en; parm2.magic_en = info->magic_en; parm2.hw_unicast_en = info->hw_unicast_en; parm2.fw_unicast_en = info->fw_unicast_en; parm2.deauth_wakeup = info->deauth_wakeup; parm2.rekey_wakeup = info->rekey_wakeup; parm2.eap_wakeup = info->eap_wakeup; parm2.all_data_wakeup = info->all_data_wakeup; parm2.mac_id = macid; ret = send_h2c_wakeup_ctrl(adapter, &parm2); if (ret) { PLTFM_MSG_ERR("send h2c wakeup ctrl failed\n"); return ret; } parm1.wow_en = info->wow_en; parm1.drop_all_pkt = info->drop_all_pkt; parm1.rx_parse_after_wake = info->rx_parse_after_wake; parm1.mac_id = macid; parm1.pairwise_sec_algo = info->pairwise_sec_algo; parm1.group_sec_algo = info->group_sec_algo; //parm1.remotectrl_info_content = //info->remotectrl_info_content; if (content) PLTFM_MEMCPY(&parm1.remotectrl_info_content, content, sizeof(struct mac_ax_remotectrl_info_parm_)); if (info->wow_en) { role = mac_role_srch(adapter, macid); if (role) { tgt_ind_orig = role->info.tgt_ind; frm_tgt_ind_orig = role->info.frm_tgt_ind; wol_pattern_orig = role->info.wol_pattern; wol_uc_orig = role->info.wol_uc; wol_magic_orig = role->info.wol_magic; wow_bk_status[(macid >> 5)] |= BIT(macid & 0x1F); role->info.wol_pattern = (u8)parm2.pattern_match_en; role->info.wol_uc = info->hw_unicast_en; role->info.wol_magic = info->magic_en; ret = mac_change_role(adapter, &role->info); if (ret) { PLTFM_MSG_ERR("role change failed\n"); return ret; } } else { PLTFM_MSG_ERR("role search failed\n"); return MACNOITEM; } } else { if (wow_bk_status[(macid >> 5)] & BIT(macid & 0x1F)) { //restore address cam role = mac_role_srch(adapter, macid); if (role) { role->info.tgt_ind = (u8)tgt_ind_orig; role->info.frm_tgt_ind = (u8)frm_tgt_ind_orig; role->info.wol_pattern = (u8)wol_pattern_orig; role->info.wol_uc = (u8)wol_uc_orig; role->info.wol_magic = (u8)wol_magic_orig; ret = mac_change_role(adapter, &role->info); if (ret) { PLTFM_MSG_ERR("role change failed\n"); return ret; } } wow_bk_status[(macid >> 5)] &= ~BIT(macid & 0x1F); } else { PLTFM_MSG_ERR("role search failed\n"); return MACNOITEM; } } ret = send_h2c_wow_global(adapter, &parm1); if (ret) PLTFM_MSG_ERR("set wow global failed\n"); return ret; } u32 mac_cfg_disconnect_det(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_disconnect_det_info *info) { u32 ret = 0; struct disconnect_detect parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; parm.disconnect_detect_en = info->disconnect_detect_en; parm.tryok_bcnfail_count_en = info->tryok_bcnfail_count_en; parm.disconnect_en = info->disconnect_en; parm.mac_id = macid; parm.check_period = info->check_period; parm.try_pkt_count = info->try_pkt_count; parm.tryok_bcnfail_count_limit = info->tryok_bcnfail_count_limit; ret = send_h2c_disconnect_detect(adapter, &parm); if (ret) return ret; return MACSUCCESS; } u32 mac_cfg_keep_alive(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_keep_alive_info *info) { u32 ret = 0; struct keep_alive parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; parm.keepalive_en = info->keepalive_en; parm.packet_id = info->packet_id; parm.period = info->period; parm.mac_id = macid; ret = send_h2c_keep_alive(adapter, &parm); if (ret) return ret; return MACSUCCESS; } u32 mac_cfg_gtk_ofld(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_gtk_ofld_info *info, struct mac_ax_gtk_info_parm_ *content) { u32 ret = 0; struct gtk_ofld parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; parm.gtk_en = info->gtk_en; parm.tkip_en = info->tkip_en; parm.ieee80211w_en = info->ieee80211w_en; parm.pairwise_wakeup = info->pairwise_wakeup; parm.mac_id = macid; parm.gtk_rsp_id = info->gtk_rsp_id; parm.pmf_sa_query_id = info->pmf_sa_query_id; parm.bip_sec_algo = info->bip_sec_algo; parm.algo_akm_suit = info->algo_akm_suit; if (content) PLTFM_MEMCPY(&parm.gtk_info_content, content, sizeof(struct mac_ax_gtk_info_parm_)); ret = send_h2c_gtk_ofld(adapter, &parm); if (ret) return ret; return MACSUCCESS; } u32 mac_cfg_arp_ofld(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_arp_ofld_info *info, void *parp_info_content) { u32 ret = 0; struct arp_ofld parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; PLTFM_MEMSET(&parm, 0, sizeof(struct arp_ofld)); parm.arp_en = info->arp_en; parm.arp_action = info->arp_action; parm.mac_id = macid; parm.arp_rsp_id = info->arp_rsp_id; //if (parp_info_content) // PLTFM_MEMCPY(&parm.ndp_info_content, parp_info_content, // sizeof(struct _arp_info_parm_) * 2); ret = send_h2c_arp_ofld(adapter, &parm); if (ret) return ret; return MACSUCCESS; } u32 mac_cfg_ndp_ofld(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_ndp_ofld_info *info, struct mac_ax_ndp_info_parm_ *content) { u32 ret = 0; struct ndp_ofld parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; PLTFM_MEMSET(&parm, 0, sizeof(struct ndp_ofld)); parm.ndp_en = info->ndp_en; parm.na_id = info->na_id; parm.mac_id = macid; if (content) PLTFM_MEMCPY(&parm.ndp_info_content, content, sizeof(struct mac_ax_ndp_info_parm_) * 2); ret = send_h2c_ndp_ofld(adapter, &parm); if (ret) return ret; return MACSUCCESS; } u32 mac_cfg_realwow(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_realwow_info *info, struct mac_ax_realwowv2_info_parm_ *content) { u32 ret = 0; struct realwow parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; PLTFM_MEMSET(&parm, 0, sizeof(struct realwow)); parm.realwow_en = info->realwow_en; parm.auto_wakeup = info->auto_wakeup; parm.mac_id = macid; parm.keepalive_id = info->keepalive_id; parm.wakeup_pattern_id = info->wakeup_pattern_id; parm.ack_pattern_id = info->ack_pattern_id; if (content) PLTFM_MEMCPY(&parm.realwow_info_content, content, sizeof(struct mac_ax_realwowv2_info_parm_)); ret = send_h2c_realwow(adapter, &parm); if (ret) return ret; return MACSUCCESS; } u32 mac_cfg_nlo(struct mac_ax_adapter *adapter, u8 macid, struct mac_ax_nlo_info *info, struct mac_ax_nlo_networklist_parm_ *content) { u32 ret = 0; struct nlo parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; PLTFM_MEMSET(&parm, 0, sizeof(struct nlo)); parm.nlo_en = info->nlo_en; parm.nlo_32k_en = info->nlo_32k_en; parm.ignore_cipher_type = info->ignore_cipher_type; parm.mac_id = macid; if (content) PLTFM_MEMCPY(&parm.nlo_networklistinfo_content, content, sizeof(struct mac_ax_nlo_networklist_parm_)); ret = send_h2c_nlo(adapter, &parm); if (ret) return ret; if (info->nlo_en) nlo_enable_record = 1; return MACSUCCESS; } u32 mac_cfg_uphy_ctrl(struct mac_ax_adapter *adapter, struct mac_ax_uphy_ctrl_info *info) { if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; return MACSUCCESS; } u32 mac_cfg_wowcam_upd(struct mac_ax_adapter *adapter, struct mac_ax_wowcam_upd_info *info) { u32 ret = 0; struct wowcam_upd parm; if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) return MACNOFW; PLTFM_MEMSET(&parm, 0, sizeof(struct wowcam_upd)); parm.r_w = info->r_w; parm.idx = info->idx; parm.wkfm1 = info->wkfm1; parm.wkfm2 = info->wkfm2; parm.wkfm3 = info->wkfm3; parm.wkfm4 = info->wkfm4; parm.crc = info->crc; parm.negative_pattern_match = info->negative_pattern_match; parm.skip_mac_hdr = info->skip_mac_hdr; parm.uc = info->uc; parm.mc = info->mc; parm.bc = info->bc; parm.valid = info->valid; ret = send_h2c_wowcam_upd(adapter, &parm); if (ret) return ret; return MACSUCCESS; } u32 get_wake_reason(struct mac_ax_adapter *adapter, u8 *wowlan_wake_reason) { struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter); if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) || is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB)) *wowlan_wake_reason = MAC_REG_R8(R_AX_C2HREG_DATA3_V1 + 3); else *wowlan_wake_reason = MAC_REG_R8(R_AX_C2HREG_DATA3 + 3); return MACSUCCESS; } u32 mac_get_wow_wake_rsn(struct mac_ax_adapter *adapter, u8 *wake_rsn, u8 *reset) { u32 ret = MACSUCCESS; ret = get_wake_reason(adapter, wake_rsn); if (ret != MACSUCCESS) return ret; switch (*wake_rsn) { case MAC_AX_WOW_DMAC_ERROR_OCCURRED: case MAC_AX_WOW_EXCEPTION_OCCURRED: case MAC_AX_WOW_L0_TO_L1_ERROR_OCCURRED: case MAC_AX_WOW_ASSERT_OCCURRED: case MAC_AX_WOW_L2_ERROR_OCCURRED: case MAC_AX_WOW_WDT_TIMEOUT_WAKE: *reset = 1; break; default: *reset = 0; break; } return MACSUCCESS; } u32 mac_cfg_wow_sleep(struct mac_ax_adapter *adapter, u8 sleep) { u32 ret; u32 val32; u8 dbg_page; struct mac_ax_phy_rpt_cfg cfg; struct mac_ax_ops *mac_ops = adapter_to_mac_ops(adapter); struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter); PLTFM_MEMSET(&cfg, 0, sizeof(struct mac_ax_phy_rpt_cfg)); #if MAC_AX_FW_REG_OFLD if (adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY) { if (sleep) { ret = _patch_redu_rx_qta(adapter); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]patch reduce rx qta %d\n", ret); return ret; } cfg.type = MAC_AX_PPDU_STATUS; cfg.en = 0; ret = mac_ops->cfg_phy_rpt(adapter, &cfg); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]cfg_phy_rpt failed %d\n", ret); return ret; } ret = MAC_REG_W_OFLD(R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP, 1, 0); if (ret) return ret; if (nlo_enable_record == 0) { ret = MAC_REG_W_OFLD(R_AX_RX_FLTR_OPT, B_AX_SNIFFER_MODE, 0, 0); } else { ret = MAC_REG_W_OFLD(R_AX_RX_FLTR_OPT, B_AX_SNIFFER_MODE, 1, 0); PLTFM_MSG_TRACE("Enable sniffer mode since nlo enable"); nlo_enable_record = 0; } if (ret) return ret; ret = MAC_REG_W32_OFLD(R_AX_ACTION_FWD0, 0x00000000, 0); if (ret) return ret; ret = MAC_REG_W32_OFLD(R_AX_ACTION_FWD1, 0x00000000, 0); if (ret) return ret; ret = MAC_REG_W32_OFLD(R_AX_TF_FWD, 0x00000000, 0); if (ret) return ret; ret = MAC_REG_W32_OFLD(R_AX_HW_RPT_FWD, 0x00000000, 1); if (ret) return ret; } else { ret = _patch_restr_rx_qta(adapter); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]patch resume rx qta %d\n", ret); return ret; } ret = MAC_REG_W_OFLD(R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP, 0, 0); if (ret) return ret; ret = MAC_REG_W_OFLD(R_AX_RX_FLTR_OPT, B_AX_SNIFFER_MODE, 1, 0); if (ret) return ret; ret = MAC_REG_W32_OFLD(R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD, 0); if (ret) return ret; ret = MAC_REG_W32_OFLD(R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD, 1); if (ret) return ret; cfg.type = MAC_AX_PPDU_STATUS; cfg.en = 1; ret = mac_ops->cfg_phy_rpt(adapter, &cfg); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]cfg_phy_rpt failed %d\n", ret); return ret; } } return MACSUCCESS; } #endif if (sleep) { ret = _patch_redu_rx_qta(adapter); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]patch reduce rx qta %d\n", ret); return ret; } val32 = MAC_REG_R32(R_AX_RX_FUNCTION_STOP); val32 |= B_AX_HDR_RX_STOP; MAC_REG_W32(R_AX_RX_FUNCTION_STOP, val32); if (nlo_enable_record == 0) { val32 = MAC_REG_R32(R_AX_RX_FLTR_OPT); val32 &= ~B_AX_SNIFFER_MODE; MAC_REG_W32(R_AX_RX_FLTR_OPT, val32); } else { val32 = MAC_REG_R32(R_AX_RX_FLTR_OPT); val32 |= B_AX_SNIFFER_MODE; MAC_REG_W32(R_AX_RX_FLTR_OPT, val32); PLTFM_MSG_TRACE("enable sniffer for nlo\n"); nlo_enable_record = 0; } cfg.type = MAC_AX_PPDU_STATUS; cfg.en = 0; ret = mac_ops->cfg_phy_rpt(adapter, &cfg); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]cfg_phy_rpt failed %d\n", ret); return ret; } MAC_REG_W32(R_AX_ACTION_FWD0, 0x00000000); MAC_REG_W32(R_AX_ACTION_FWD1, 0x00000000); MAC_REG_W32(R_AX_TF_FWD, 0x00000000); MAC_REG_W32(R_AX_HW_RPT_FWD, 0x00000000); } else { ret = _patch_restr_rx_qta(adapter); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]patch resume rx qta %d\n", ret); return ret; } val32 = MAC_REG_R32(R_AX_RX_FUNCTION_STOP); val32 &= ~B_AX_HDR_RX_STOP; MAC_REG_W32(R_AX_RX_FUNCTION_STOP, val32); val32 = MAC_REG_R32(R_AX_RX_FLTR_OPT); MAC_REG_W32(R_AX_RX_FLTR_OPT, val32); cfg.type = MAC_AX_PPDU_STATUS; cfg.en = 1; ret = mac_ops->cfg_phy_rpt(adapter, &cfg); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]cfg_phy_rpt failed %d\n", ret); return ret; } MAC_REG_W32(R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD); MAC_REG_W32(R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD); PLTFM_MSG_ERR("[wow] Start to dump PLE debug pages\n"); for (dbg_page = 0; dbg_page < 4; dbg_page++) mac_ops->dump_ple_dbg_page(adapter, dbg_page); } return MACSUCCESS; } u32 mac_get_wow_fw_status(struct mac_ax_adapter *adapter, u8 *status, u8 func_en) { struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter); if (func_en) func_en = 1; *status = !!((MAC_REG_R8(R_AX_WOW_CTRL) & B_AX_WOW_WOWEN)); if (func_en == *status) *status = 1; else *status = 0; return MACSUCCESS; } u32 _mac_request_aoac_report_rx_rdy(struct mac_ax_adapter *adapter) { u32 ret; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif u8 *buf; struct fwcmd_aoac_report_req *fwcmd_aoac_rpt_req; h2cb = h2cb_alloc(adapter, H2CB_CLASS_DATA); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_aoac_report_req)); if (!buf) { ret = MACNOBUF; goto fail; } fwcmd_aoac_rpt_req = (struct fwcmd_aoac_report_req *)buf; fwcmd_aoac_rpt_req->dword0 = cpu_to_le32(FWCMD_H2C_AOAC_REPORT_REQ_RX_READY); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_WOW, FWCMD_H2C_FUNC_AOAC_REPORT_REQ, 1, 0); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) { PLTFM_MSG_ERR("[ERR]platform tx: %d\n", ret); adapter->sm.aoac_rpt = MAC_AX_AOAC_RPT_ERROR; goto fail; } h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } u32 _mac_request_aoac_report_rx_not_rdy(struct mac_ax_adapter *adapter) { struct mac_ax_wowlan_info *wow_info = &adapter->wowlan_info; struct mac_ax_aoac_report *aoac_rpt = (struct mac_ax_aoac_report *)wow_info->aoac_report; struct mac_ax_h2creg_info h2c_info = {0}; struct mac_ax_c2hreg_poll c2h_poll = {0}; struct fwcmd_c2hreg *c2h_content = &c2h_poll.c2hreg_cont.c2h_content; u32 ret; u8 *p_iv; h2c_info.id = FWCMD_H2CREG_FUNC_AOAC_RPT_1; h2c_info.content_len = sizeof(struct fwcmd_aoac_rpt_1); c2h_poll.polling_id = FWCMD_C2HREG_FUNC_AOAC_RPT_1; c2h_poll.retry_cnt = WOW_GET_AOAC_RPT_C2H_CNT; c2h_poll.retry_wait_us = WOW_GET_AOAC_RPT_C2H_DLY; ret = proc_msg_reg(adapter, &h2c_info, &c2h_poll); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("%s: get aoac rpt(%d) fail: %d\n", __func__, FWCMD_C2HREG_FUNC_AOAC_RPT_1, ret); return ret; } aoac_rpt->key_idx = GET_FIELD(c2h_content->dword0, FWCMD_C2HREG_AOAC_RPT_1_KEY_IDX); aoac_rpt->rekey_ok = GET_FIELD(c2h_content->dword0, FWCMD_C2HREG_AOAC_RPT_1_REKEY_OK); p_iv = (&aoac_rpt->gtk_rx_iv_0[0] + (aoac_rpt->key_idx * IV_LENGTH)); p_iv[0] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_1_IV_0); p_iv[1] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_1_IV_1); p_iv[2] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_1_IV_2); p_iv[3] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_1_IV_3); p_iv[4] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_1_IV_4); p_iv[5] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_1_IV_5); p_iv[6] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_1_IV_6); p_iv[7] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_1_IV_7); aoac_rpt->ptk_rx_iv[0] = GET_FIELD(c2h_content->dword3, FWCMD_C2HREG_AOAC_RPT_1_PKT_IV_0); aoac_rpt->ptk_rx_iv[1] = GET_FIELD(c2h_content->dword3, FWCMD_C2HREG_AOAC_RPT_1_PKT_IV_1); aoac_rpt->ptk_rx_iv[2] = GET_FIELD(c2h_content->dword3, FWCMD_C2HREG_AOAC_RPT_1_PKT_IV_2); aoac_rpt->ptk_rx_iv[3] = GET_FIELD(c2h_content->dword3, FWCMD_C2HREG_AOAC_RPT_1_PKT_IV_3); h2c_info.id = FWCMD_H2CREG_FUNC_AOAC_RPT_2; h2c_info.content_len = sizeof(struct fwcmd_aoac_rpt_2); c2h_poll.polling_id = FWCMD_C2HREG_FUNC_AOAC_RPT_2; c2h_poll.retry_cnt = WOW_GET_AOAC_RPT_C2H_CNT; c2h_poll.retry_wait_us = WOW_GET_AOAC_RPT_C2H_DLY; ret = proc_msg_reg(adapter, &h2c_info, &c2h_poll); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("%s: get aoac rpt(%d) fail: %d\n", __func__, FWCMD_C2HREG_FUNC_AOAC_RPT_2, ret); return ret; } aoac_rpt->ptk_rx_iv[4] = GET_FIELD(c2h_content->dword0, FWCMD_C2HREG_AOAC_RPT_2_PKT_IV_4); aoac_rpt->ptk_rx_iv[5] = GET_FIELD(c2h_content->dword0, FWCMD_C2HREG_AOAC_RPT_2_PKT_IV_5); aoac_rpt->ptk_rx_iv[6] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_2_PKT_IV_6); aoac_rpt->ptk_rx_iv[7] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_2_PKT_IV_7); aoac_rpt->igtk_ipn[0] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_0); aoac_rpt->igtk_ipn[1] = GET_FIELD(c2h_content->dword1, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_1); aoac_rpt->igtk_ipn[2] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_2); aoac_rpt->igtk_ipn[3] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_3); aoac_rpt->igtk_ipn[4] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_4); aoac_rpt->igtk_ipn[5] = GET_FIELD(c2h_content->dword2, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_5); aoac_rpt->igtk_ipn[6] = GET_FIELD(c2h_content->dword3, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_6); aoac_rpt->igtk_ipn[7] = GET_FIELD(c2h_content->dword3, FWCMD_C2HREG_AOAC_RPT_2_IGTK_IPN_7); return MACSUCCESS; } u32 mac_request_aoac_report(struct mac_ax_adapter *adapter, u8 rx_ready) { u32 ret; struct mac_ax_wowlan_info *wow_info = &adapter->wowlan_info; if (adapter->sm.aoac_rpt != MAC_AX_AOAC_RPT_IDLE) return MACPROCERR; if (wow_info->aoac_report) { PLTFM_FREE(wow_info->aoac_report, sizeof(struct mac_ax_aoac_report)); } wow_info->aoac_report = (u8 *)PLTFM_MALLOC(sizeof(struct mac_ax_aoac_report)); if (!wow_info->aoac_report) { PLTFM_MSG_ERR("%s: malloc fail\n", __func__); return MACBUFALLOC; } adapter->sm.aoac_rpt = MAC_AX_AOAC_RPT_H2C_SENDING; if (rx_ready) ret = _mac_request_aoac_report_rx_rdy(adapter); else ret = _mac_request_aoac_report_rx_not_rdy(adapter); return ret; } u32 mac_read_aoac_report(struct mac_ax_adapter *adapter, struct mac_ax_aoac_report *rpt_buf, u8 rx_ready) { struct mac_ax_wowlan_info *wow_info = &adapter->wowlan_info; u32 ret = MACSUCCESS; u8 cnt = 100; while ((rx_ready) && (adapter->sm.aoac_rpt != MAC_AX_AOAC_RPT_H2C_DONE)) { PLTFM_DELAY_MS(1); if (--cnt == 0) { PLTFM_MSG_ERR("[ERR] read aoac report(%d) fail\n", adapter->sm.aoac_rpt); adapter->sm.aoac_rpt = MAC_AX_AOAC_RPT_IDLE; return MACPOLLTO; } } if (wow_info->aoac_report) { PLTFM_MEMCPY(rpt_buf, wow_info->aoac_report, sizeof(struct mac_ax_aoac_report)); PLTFM_FREE(wow_info->aoac_report, sizeof(struct mac_ax_aoac_report)); wow_info->aoac_report = NULL; } else { PLTFM_MSG_ERR("[ERR] aoac report memory allocate fail\n"); ret = MACBUFALLOC; } adapter->sm.aoac_rpt = MAC_AX_AOAC_RPT_IDLE; return ret; } u32 mac_check_aoac_report_done(struct mac_ax_adapter *adapter) { PLTFM_MSG_TRACE("[TRACE]%s: curr state: %d\n", __func__, adapter->sm.aoac_rpt); if (adapter->sm.aoac_rpt == MAC_AX_AOAC_RPT_H2C_DONE) return MACSUCCESS; else return MACPROCBUSY; } u32 mac_wow_stop_trx(struct mac_ax_adapter *adapter) { struct mac_ax_h2creg_info h2c_info; struct mac_ax_c2hreg_poll c2h_poll; u32 ret; if (adapter->sm.wow_stoptrx_stat == MAC_AX_WOW_STOPTRX_BUSY) { PLTFM_MSG_ERR("[ERR]wow stop trx busy\n"); return MACPROCERR; } else if (adapter->sm.wow_stoptrx_stat == MAC_AX_WOW_STOPTRX_FAIL) { PLTFM_MSG_WARN("[WARN]prev wow stop trx fail\n"); } adapter->sm.wow_stoptrx_stat = MAC_AX_WOW_STOPTRX_BUSY; h2c_info.id = FWCMD_H2CREG_FUNC_WOW_TRX_STOP; h2c_info.content_len = 0; h2c_info.h2c_content.dword0 = 0; h2c_info.h2c_content.dword1 = 0; h2c_info.h2c_content.dword2 = 0; h2c_info.h2c_content.dword3 = 0; c2h_poll.polling_id = FWCMD_C2HREG_FUNC_WOW_TRX_STOP; c2h_poll.retry_cnt = WOW_GET_STOP_TRX_C2H_CNT; c2h_poll.retry_wait_us = WOW_GET_STOP_TRX_C2H_DLY; ret = proc_msg_reg(adapter, &h2c_info, &c2h_poll); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]wow stoptrx proc msg reg %d\n", ret); adapter->sm.wow_stoptrx_stat = MAC_AX_WOW_STOPTRX_FAIL; return ret; } adapter->sm.wow_stoptrx_stat = MAC_AX_WOW_STOPTRX_IDLE; return MACSUCCESS; } u32 free_aoac_report(struct mac_ax_adapter *adapter) { struct mac_ax_wowlan_info *wow_info = &adapter->wowlan_info; if (wow_info->aoac_report) { PLTFM_FREE(wow_info->aoac_report, sizeof(struct mac_ax_aoac_report)); wow_info->aoac_report = NULL; } else { PLTFM_MSG_ERR("[ERR] aoac report pointer null\n"); } return MACSUCCESS; }