diff options
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/ser.c')
| -rw-r--r-- | drivers/net/wireless/realtek/rtw89/ser.c | 165 |
1 files changed, 135 insertions, 30 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index c1a4bc1c64d1..f99e179f7ff9 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -20,12 +20,14 @@ enum ser_evt { SER_EV_NONE, SER_EV_STATE_IN, SER_EV_STATE_OUT, + SER_EV_L1_RESET_PREPARE, /* pre-M0 */ SER_EV_L1_RESET, /* M1 */ SER_EV_DO_RECOVERY, /* M3 */ SER_EV_MAC_RESET_DONE, /* M5 */ SER_EV_L2_RESET, SER_EV_L2_RECFG_DONE, SER_EV_L2_RECFG_TIMEOUT, + SER_EV_M1_TIMEOUT, SER_EV_M3_TIMEOUT, SER_EV_FW_M5_TIMEOUT, SER_EV_L0_RESET, @@ -34,6 +36,7 @@ enum ser_evt { enum ser_state { SER_IDLE_ST, + SER_L1_RESET_PRE_ST, SER_RESET_TRX_ST, SER_DO_HCI_ST, SER_L2_RESET_ST, @@ -153,9 +156,9 @@ static void ser_state_run(struct rtw89_ser *ser, u8 evt) rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s receive %s\n", ser_st_name(ser), ser_ev_name(ser, evt)); - mutex_lock(&rtwdev->mutex); + wiphy_lock(rtwdev->hw->wiphy); rtw89_leave_lps(rtwdev); - mutex_unlock(&rtwdev->mutex); + wiphy_unlock(rtwdev->hw->wiphy); ser->st_tbl[ser->state].st_func(ser, evt); } @@ -202,7 +205,6 @@ static void rtw89_ser_hdl_work(struct work_struct *work) static int ser_send_msg(struct rtw89_ser *ser, u8 event) { - struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); struct ser_msg *msg = NULL; if (test_bit(RTW89_SER_DRV_STOP_RUN, ser->flags)) @@ -218,7 +220,7 @@ static int ser_send_msg(struct rtw89_ser *ser, u8 event) list_add(&msg->list, &ser->msg_q); spin_unlock_irq(&ser->msg_q_lock); - ieee80211_queue_work(rtwdev->hw, &ser->ser_hdl_work); + schedule_work(&ser->ser_hdl_work); return 0; } @@ -297,32 +299,57 @@ static void drv_resume_rx(struct rtw89_ser *ser) static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); - rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; - rtwvif->trigger = false; + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + + rtwvif->tdls_peer = 0; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif_link->port); + rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK; + rtwvif_link->trigger = false; + rtwvif_link->rand_tsf_done = false; + + rtw89_p2p_noa_once_deinit(rtwvif_link); + } } static void ser_sta_deinit_cam_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)data; + struct rtw89_vif *target_rtwvif = (struct rtw89_vif *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_dev *rtwdev = rtwvif->rtwdev; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) - rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam); - if (sta->tdls) - rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam); + if (rtwvif != target_rtwvif) + return; - INIT_LIST_HEAD(&rtwsta->ba_cam_list); + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) + rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta_link->addr_cam); + if (sta->tdls) + rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta_link->bssid_cam); + + INIT_LIST_HEAD(&rtwsta_link->ba_cam_list); + } } static void ser_deinit_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + ieee80211_iterate_stations_atomic(rtwdev->hw, ser_sta_deinit_cam_iter, rtwvif); - rtw89_cam_deinit(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_cam_deinit(rtwdev, rtwvif_link); bitmap_zero(rtwdev->cam_info.ba_cam_map, RTW89_MAX_BA_CAM_NUM); } @@ -338,6 +365,9 @@ static void ser_reset_mac_binding(struct rtw89_dev *rtwdev) rtw89_core_release_all_bits_map(rtwdev->mac_id_map, RTW89_MAX_MAC_ID_NUM); rtw89_for_each_rtwvif(rtwdev, rtwvif) ser_reset_vif(rtwdev, rtwvif); + + rtwdev->total_sta_assoc = 0; + refcount_set(&rtwdev->refcount_ap_info, 0); } /* hal function */ @@ -355,6 +385,9 @@ static int hal_enable_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2); if (!ret) clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to start dma: %d\n", ret); return ret; } @@ -370,10 +403,20 @@ static int hal_stop_dma(struct rtw89_ser *ser) ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1); if (!ret) set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); + else + rtw89_debug(rtwdev, RTW89_DBG_SER, + "lv1 rcvy fail to stop dma: %d\n", ret); return ret; } +static void hal_send_post_m0_event(struct rtw89_ser *ser) +{ + struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); + + rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RESET_START_DMAC); +} + static void hal_send_m2_event(struct rtw89_ser *ser) { struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); @@ -396,8 +439,12 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) switch (evt) { case SER_EV_STATE_IN: rtw89_hci_recovery_complete(rtwdev); + clear_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags); clear_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags); break; + case SER_EV_L1_RESET_PREPARE: + ser_state_goto(ser, SER_L1_RESET_PRE_ST); + break; case SER_EV_L1_RESET: ser_state_goto(ser, SER_RESET_TRX_ST); break; @@ -405,6 +452,7 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) ser_state_goto(ser, SER_L2_RESET_ST); break; case SER_EV_STATE_OUT: + set_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags); rtw89_hci_recovery_start(rtwdev); break; default: @@ -412,10 +460,39 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) } } +static void ser_l1_reset_pre_st_hdl(struct rtw89_ser *ser, u8 evt) +{ + switch (evt) { + case SER_EV_STATE_IN: + ser->prehandle_l1 = true; + hal_send_post_m0_event(ser); + ser_set_alarm(ser, 1000, SER_EV_M1_TIMEOUT); + break; + case SER_EV_L1_RESET: + ser_state_goto(ser, SER_RESET_TRX_ST); + break; + case SER_EV_M1_TIMEOUT: + ser_state_goto(ser, SER_L2_RESET_ST); + break; + case SER_EV_STATE_OUT: + ser_del_alarm(ser); + break; + default: + break; + } +} + static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) { + struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); + struct wiphy *wiphy = rtwdev->hw->wiphy; + switch (evt) { case SER_EV_STATE_IN: + wiphy_lock(wiphy); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); + wiphy_unlock(wiphy); drv_stop_tx(ser); if (hal_stop_dma(ser)) { @@ -424,7 +501,9 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) } drv_stop_rx(ser); + wiphy_lock(wiphy); drv_trx_reset(ser); + wiphy_unlock(wiphy); /* wait m3 */ hal_send_m2_event(ser); @@ -446,6 +525,10 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) hal_enable_dma(ser); drv_resume_rx(ser); drv_resume_tx(ser); + wiphy_delayed_work_queue(wiphy, &rtwdev->track_work, + RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); break; default: @@ -484,21 +567,25 @@ static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt) static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf, u8 sel, u32 start_addr, u32 len) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + u32 filter_model_addr = mac->filter_model_addr; + u32 indir_access_addr = mac->indir_access_addr; + u32 mem_page_size = mac->mem_page_size; u32 *ptr = (u32 *)buf; u32 base_addr, start_page, residue; u32 cnt = 0; u32 i; - start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE; - residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE; - base_addr = rtw89_mac_mem_base_addrs[sel]; - base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE; + start_page = start_addr / mem_page_size; + residue = start_addr % mem_page_size; + base_addr = mac->mem_base_addrs[sel]; + base_addr += start_page * mem_page_size; while (cnt < len) { - rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, base_addr); + rtw89_write32(rtwdev, filter_model_addr, base_addr); - for (i = R_AX_INDIR_ACCESS_ENTRY + residue; - i < R_AX_INDIR_ACCESS_ENTRY + MAC_MEM_DUMP_PAGE_SIZE; + for (i = indir_access_addr + residue; + i < indir_access_addr + mem_page_size; i += 4, ptr++) { *ptr = rtw89_read32(rtwdev, i); cnt += 4; @@ -507,7 +594,7 @@ static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf, } residue = 0; - base_addr += MAC_MEM_DUMP_PAGE_SIZE; + base_addr += mem_page_size; } } @@ -536,11 +623,22 @@ struct __fw_backtrace_info { static_assert(RTW89_FW_BACKTRACE_INFO_SIZE == sizeof(struct __fw_backtrace_info)); +static u32 convert_addr_from_wcpu(u32 wcpu_addr) +{ + if (wcpu_addr < 0x30000000) + return wcpu_addr; + + return wcpu_addr & GENMASK(28, 0); +} + static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf, const struct __fw_backtrace_entry *ent) { struct __fw_backtrace_info *ptr = (struct __fw_backtrace_info *)buf; - u32 fwbt_addr = ent->wcpu_addr & RTW89_WCPU_BASE_MASK; + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + u32 filter_model_addr = mac->filter_model_addr; + u32 indir_access_addr = mac->indir_access_addr; + u32 fwbt_addr = convert_addr_from_wcpu(ent->wcpu_addr); u32 fwbt_size = ent->size; u32 fwbt_key = ent->key; u32 i; @@ -565,10 +663,10 @@ static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf, } rtw89_debug(rtwdev, RTW89_DBG_SER, "dump fw backtrace start\n"); - rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, fwbt_addr); + rtw89_write32(rtwdev, filter_model_addr, fwbt_addr); - for (i = R_AX_INDIR_ACCESS_ENTRY; - i < R_AX_INDIR_ACCESS_ENTRY + fwbt_size; + for (i = indir_access_addr; + i < indir_access_addr + fwbt_size; i += RTW89_FW_BACKTRACE_INFO_SIZE, ptr++) { *ptr = (struct __fw_backtrace_info){ .ra = rtw89_read32(rtwdev, i), @@ -611,6 +709,7 @@ bottom: ser_reset_mac_binding(rtwdev); rtw89_core_stop(rtwdev); rtw89_entity_init(rtwdev); + rtw89_fw_release_general_pkt_list(rtwdev, false); INIT_LIST_HEAD(&rtwdev->rtwvifs_list); } @@ -620,9 +719,9 @@ static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt) switch (evt) { case SER_EV_STATE_IN: - mutex_lock(&rtwdev->mutex); + wiphy_lock(rtwdev->hw->wiphy); ser_l2_reset_st_pre_hdl(ser); - mutex_unlock(&rtwdev->mutex); + wiphy_unlock(rtwdev->hw->wiphy); ieee80211_restart_hw(rtwdev->hw); ser_set_alarm(ser, SER_RECFG_TIMEOUT, SER_EV_L2_RECFG_TIMEOUT); @@ -648,12 +747,14 @@ static const struct event_ent ser_ev_tbl[] = { {SER_EV_NONE, "SER_EV_NONE"}, {SER_EV_STATE_IN, "SER_EV_STATE_IN"}, {SER_EV_STATE_OUT, "SER_EV_STATE_OUT"}, - {SER_EV_L1_RESET, "SER_EV_L1_RESET"}, + {SER_EV_L1_RESET_PREPARE, "SER_EV_L1_RESET_PREPARE pre-m0"}, + {SER_EV_L1_RESET, "SER_EV_L1_RESET m1"}, {SER_EV_DO_RECOVERY, "SER_EV_DO_RECOVERY m3"}, {SER_EV_MAC_RESET_DONE, "SER_EV_MAC_RESET_DONE m5"}, {SER_EV_L2_RESET, "SER_EV_L2_RESET"}, {SER_EV_L2_RECFG_DONE, "SER_EV_L2_RECFG_DONE"}, {SER_EV_L2_RECFG_TIMEOUT, "SER_EV_L2_RECFG_TIMEOUT"}, + {SER_EV_M1_TIMEOUT, "SER_EV_M1_TIMEOUT"}, {SER_EV_M3_TIMEOUT, "SER_EV_M3_TIMEOUT"}, {SER_EV_FW_M5_TIMEOUT, "SER_EV_FW_M5_TIMEOUT"}, {SER_EV_L0_RESET, "SER_EV_L0_RESET"}, @@ -662,6 +763,7 @@ static const struct event_ent ser_ev_tbl[] = { static const struct state_ent ser_st_tbl[] = { {SER_IDLE_ST, "SER_IDLE_ST", ser_idle_st_hdl}, + {SER_L1_RESET_PRE_ST, "SER_L1_RESET_PRE_ST", ser_l1_reset_pre_st_hdl}, {SER_RESET_TRX_ST, "SER_RESET_TRX_ST", ser_reset_trx_st_hdl}, {SER_DO_HCI_ST, "SER_DO_HCI_ST", ser_do_hci_st_hdl}, {SER_L2_RESET_ST, "SER_L2_RESET_ST", ser_l2_reset_st_hdl} @@ -707,6 +809,9 @@ int rtw89_ser_notify(struct rtw89_dev *rtwdev, u32 err) rtw89_info(rtwdev, "SER catches error: 0x%x\n", err); switch (err) { + case MAC_AX_ERR_L1_PREERR_DMAC: /* pre-M0 */ + event = SER_EV_L1_RESET_PREPARE; + break; case MAC_AX_ERR_L1_ERR_DMAC: case MAC_AX_ERR_L0_PROMOTE_TO_L1: event = SER_EV_L1_RESET; /* M1 */ |
