162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2019-2020 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/devcoredump.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "cam.h" 862306a36Sopenharmony_ci#include "chan.h" 962306a36Sopenharmony_ci#include "debug.h" 1062306a36Sopenharmony_ci#include "fw.h" 1162306a36Sopenharmony_ci#include "mac.h" 1262306a36Sopenharmony_ci#include "ps.h" 1362306a36Sopenharmony_ci#include "reg.h" 1462306a36Sopenharmony_ci#include "ser.h" 1562306a36Sopenharmony_ci#include "util.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define SER_RECFG_TIMEOUT 1000 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cienum ser_evt { 2062306a36Sopenharmony_ci SER_EV_NONE, 2162306a36Sopenharmony_ci SER_EV_STATE_IN, 2262306a36Sopenharmony_ci SER_EV_STATE_OUT, 2362306a36Sopenharmony_ci SER_EV_L1_RESET_PREPARE, /* pre-M0 */ 2462306a36Sopenharmony_ci SER_EV_L1_RESET, /* M1 */ 2562306a36Sopenharmony_ci SER_EV_DO_RECOVERY, /* M3 */ 2662306a36Sopenharmony_ci SER_EV_MAC_RESET_DONE, /* M5 */ 2762306a36Sopenharmony_ci SER_EV_L2_RESET, 2862306a36Sopenharmony_ci SER_EV_L2_RECFG_DONE, 2962306a36Sopenharmony_ci SER_EV_L2_RECFG_TIMEOUT, 3062306a36Sopenharmony_ci SER_EV_M1_TIMEOUT, 3162306a36Sopenharmony_ci SER_EV_M3_TIMEOUT, 3262306a36Sopenharmony_ci SER_EV_FW_M5_TIMEOUT, 3362306a36Sopenharmony_ci SER_EV_L0_RESET, 3462306a36Sopenharmony_ci SER_EV_MAXX 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cienum ser_state { 3862306a36Sopenharmony_ci SER_IDLE_ST, 3962306a36Sopenharmony_ci SER_L1_RESET_PRE_ST, 4062306a36Sopenharmony_ci SER_RESET_TRX_ST, 4162306a36Sopenharmony_ci SER_DO_HCI_ST, 4262306a36Sopenharmony_ci SER_L2_RESET_ST, 4362306a36Sopenharmony_ci SER_ST_MAX_ST 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct ser_msg { 4762306a36Sopenharmony_ci struct list_head list; 4862306a36Sopenharmony_ci u8 event; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct state_ent { 5262306a36Sopenharmony_ci u8 state; 5362306a36Sopenharmony_ci char *name; 5462306a36Sopenharmony_ci void (*st_func)(struct rtw89_ser *ser, u8 event); 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct event_ent { 5862306a36Sopenharmony_ci u8 event; 5962306a36Sopenharmony_ci char *name; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic char *ser_ev_name(struct rtw89_ser *ser, u8 event) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci if (event < SER_EV_MAXX) 6562306a36Sopenharmony_ci return ser->ev_tbl[event].name; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return "err_ev_name"; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic char *ser_st_name(struct rtw89_ser *ser) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci if (ser->state < SER_ST_MAX_ST) 7362306a36Sopenharmony_ci return ser->st_tbl[ser->state].name; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return "err_st_name"; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define RTW89_DEF_SER_CD_TYPE(_name, _type, _size) \ 7962306a36Sopenharmony_cistruct ser_cd_ ## _name { \ 8062306a36Sopenharmony_ci u32 type; \ 8162306a36Sopenharmony_ci u32 type_size; \ 8262306a36Sopenharmony_ci u64 padding; \ 8362306a36Sopenharmony_ci u8 data[_size]; \ 8462306a36Sopenharmony_ci} __packed; \ 8562306a36Sopenharmony_cistatic void ser_cd_ ## _name ## _init(struct ser_cd_ ## _name *p) \ 8662306a36Sopenharmony_ci{ \ 8762306a36Sopenharmony_ci p->type = _type; \ 8862306a36Sopenharmony_ci p->type_size = sizeof(p->data); \ 8962306a36Sopenharmony_ci p->padding = 0x0123456789abcdef; \ 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cienum rtw89_ser_cd_type { 9362306a36Sopenharmony_ci RTW89_SER_CD_FW_RSVD_PLE = 0, 9462306a36Sopenharmony_ci RTW89_SER_CD_FW_BACKTRACE = 1, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciRTW89_DEF_SER_CD_TYPE(fw_rsvd_ple, 9862306a36Sopenharmony_ci RTW89_SER_CD_FW_RSVD_PLE, 9962306a36Sopenharmony_ci RTW89_FW_RSVD_PLE_SIZE); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciRTW89_DEF_SER_CD_TYPE(fw_backtrace, 10262306a36Sopenharmony_ci RTW89_SER_CD_FW_BACKTRACE, 10362306a36Sopenharmony_ci RTW89_FW_BACKTRACE_MAX_SIZE); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistruct rtw89_ser_cd_buffer { 10662306a36Sopenharmony_ci struct ser_cd_fw_rsvd_ple fwple; 10762306a36Sopenharmony_ci struct ser_cd_fw_backtrace fwbt; 10862306a36Sopenharmony_ci} __packed; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct rtw89_ser_cd_buffer *rtw89_ser_cd_prep(struct rtw89_dev *rtwdev) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct rtw89_ser_cd_buffer *buf; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci buf = vzalloc(sizeof(*buf)); 11562306a36Sopenharmony_ci if (!buf) 11662306a36Sopenharmony_ci return NULL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ser_cd_fw_rsvd_ple_init(&buf->fwple); 11962306a36Sopenharmony_ci ser_cd_fw_backtrace_init(&buf->fwbt); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return buf; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void rtw89_ser_cd_send(struct rtw89_dev *rtwdev, 12562306a36Sopenharmony_ci struct rtw89_ser_cd_buffer *buf) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, "SER sends core dump\n"); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* After calling dev_coredump, buf's lifetime is supposed to be 13062306a36Sopenharmony_ci * handled by the device coredump framework. Note that a new dump 13162306a36Sopenharmony_ci * will be discarded if a previous one hasn't been released by 13262306a36Sopenharmony_ci * framework yet. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci dev_coredumpv(rtwdev->dev, buf, sizeof(*buf), GFP_KERNEL); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void rtw89_ser_cd_free(struct rtw89_dev *rtwdev, 13862306a36Sopenharmony_ci struct rtw89_ser_cd_buffer *buf, bool free_self) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci if (!free_self) 14162306a36Sopenharmony_ci return; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, "SER frees core dump by self\n"); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* When some problems happen during filling data of core dump, 14662306a36Sopenharmony_ci * we won't send it to device coredump framework. Instead, we 14762306a36Sopenharmony_ci * free buf by ourselves. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci vfree(buf); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void ser_state_run(struct rtw89_ser *ser, u8 evt) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s receive %s\n", 15762306a36Sopenharmony_ci ser_st_name(ser), ser_ev_name(ser, evt)); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 16062306a36Sopenharmony_ci rtw89_leave_lps(rtwdev); 16162306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci ser->st_tbl[ser->state].st_func(ser, evt); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic void ser_state_goto(struct rtw89_ser *ser, u8 new_state) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (ser->state == new_state || new_state >= SER_ST_MAX_ST) 17162306a36Sopenharmony_ci return; 17262306a36Sopenharmony_ci ser_state_run(ser, SER_EV_STATE_OUT); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s goto -> %s\n", 17562306a36Sopenharmony_ci ser_st_name(ser), ser->st_tbl[new_state].name); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ser->state = new_state; 17862306a36Sopenharmony_ci ser_state_run(ser, SER_EV_STATE_IN); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct ser_msg *__rtw89_ser_dequeue_msg(struct rtw89_ser *ser) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct ser_msg *msg; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci spin_lock_irq(&ser->msg_q_lock); 18662306a36Sopenharmony_ci msg = list_first_entry_or_null(&ser->msg_q, struct ser_msg, list); 18762306a36Sopenharmony_ci if (msg) 18862306a36Sopenharmony_ci list_del(&msg->list); 18962306a36Sopenharmony_ci spin_unlock_irq(&ser->msg_q_lock); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return msg; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void rtw89_ser_hdl_work(struct work_struct *work) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct ser_msg *msg; 19762306a36Sopenharmony_ci struct rtw89_ser *ser = container_of(work, struct rtw89_ser, 19862306a36Sopenharmony_ci ser_hdl_work); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci while ((msg = __rtw89_ser_dequeue_msg(ser))) { 20162306a36Sopenharmony_ci ser_state_run(ser, msg->event); 20262306a36Sopenharmony_ci kfree(msg); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int ser_send_msg(struct rtw89_ser *ser, u8 event) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 20962306a36Sopenharmony_ci struct ser_msg *msg = NULL; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (test_bit(RTW89_SER_DRV_STOP_RUN, ser->flags)) 21262306a36Sopenharmony_ci return -EIO; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci msg = kmalloc(sizeof(*msg), GFP_ATOMIC); 21562306a36Sopenharmony_ci if (!msg) 21662306a36Sopenharmony_ci return -ENOMEM; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci msg->event = event; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci spin_lock_irq(&ser->msg_q_lock); 22162306a36Sopenharmony_ci list_add(&msg->list, &ser->msg_q); 22262306a36Sopenharmony_ci spin_unlock_irq(&ser->msg_q_lock); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ieee80211_queue_work(rtwdev->hw, &ser->ser_hdl_work); 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void rtw89_ser_alarm_work(struct work_struct *work) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct rtw89_ser *ser = container_of(work, struct rtw89_ser, 23162306a36Sopenharmony_ci ser_alarm_work.work); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci ser_send_msg(ser, ser->alarm_event); 23462306a36Sopenharmony_ci ser->alarm_event = SER_EV_NONE; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void ser_set_alarm(struct rtw89_ser *ser, u32 ms, u8 event) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (test_bit(RTW89_SER_DRV_STOP_RUN, ser->flags)) 24262306a36Sopenharmony_ci return; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci ser->alarm_event = event; 24562306a36Sopenharmony_ci ieee80211_queue_delayed_work(rtwdev->hw, &ser->ser_alarm_work, 24662306a36Sopenharmony_ci msecs_to_jiffies(ms)); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic void ser_del_alarm(struct rtw89_ser *ser) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci cancel_delayed_work(&ser->ser_alarm_work); 25262306a36Sopenharmony_ci ser->alarm_event = SER_EV_NONE; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* driver function */ 25662306a36Sopenharmony_cistatic void drv_stop_tx(struct rtw89_ser *ser) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci ieee80211_stop_queues(rtwdev->hw); 26162306a36Sopenharmony_ci set_bit(RTW89_SER_DRV_STOP_TX, ser->flags); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic void drv_stop_rx(struct rtw89_ser *ser) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci clear_bit(RTW89_FLAG_RUNNING, rtwdev->flags); 26962306a36Sopenharmony_ci set_bit(RTW89_SER_DRV_STOP_RX, ser->flags); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void drv_trx_reset(struct rtw89_ser *ser) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci rtw89_hci_reset(rtwdev); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void drv_resume_tx(struct rtw89_ser *ser) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (!test_bit(RTW89_SER_DRV_STOP_TX, ser->flags)) 28462306a36Sopenharmony_ci return; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ieee80211_wake_queues(rtwdev->hw); 28762306a36Sopenharmony_ci clear_bit(RTW89_SER_DRV_STOP_TX, ser->flags); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void drv_resume_rx(struct rtw89_ser *ser) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (!test_bit(RTW89_SER_DRV_STOP_RX, ser->flags)) 29562306a36Sopenharmony_ci return; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci set_bit(RTW89_FLAG_RUNNING, rtwdev->flags); 29862306a36Sopenharmony_ci clear_bit(RTW89_SER_DRV_STOP_RX, ser->flags); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); 30462306a36Sopenharmony_ci rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; 30562306a36Sopenharmony_ci rtwvif->trigger = false; 30662306a36Sopenharmony_ci rtwvif->tdls_peer = 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic void ser_sta_deinit_cam_iter(void *data, struct ieee80211_sta *sta) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)data; 31262306a36Sopenharmony_ci struct rtw89_dev *rtwdev = rtwvif->rtwdev; 31362306a36Sopenharmony_ci struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) 31662306a36Sopenharmony_ci rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam); 31762306a36Sopenharmony_ci if (sta->tdls) 31862306a36Sopenharmony_ci rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci INIT_LIST_HEAD(&rtwsta->ba_cam_list); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void ser_deinit_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(rtwdev->hw, 32662306a36Sopenharmony_ci ser_sta_deinit_cam_iter, 32762306a36Sopenharmony_ci rtwvif); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci rtw89_cam_deinit(rtwdev, rtwvif); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci bitmap_zero(rtwdev->cam_info.ba_cam_map, RTW89_MAX_BA_CAM_NUM); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void ser_reset_mac_binding(struct rtw89_dev *rtwdev) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct rtw89_vif *rtwvif; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci rtw89_cam_reset_keys(rtwdev); 33962306a36Sopenharmony_ci rtw89_for_each_rtwvif(rtwdev, rtwvif) 34062306a36Sopenharmony_ci ser_deinit_cam(rtwdev, rtwvif); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci rtw89_core_release_all_bits_map(rtwdev->mac_id_map, RTW89_MAX_MAC_ID_NUM); 34362306a36Sopenharmony_ci rtw89_for_each_rtwvif(rtwdev, rtwvif) 34462306a36Sopenharmony_ci ser_reset_vif(rtwdev, rtwvif); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci rtwdev->total_sta_assoc = 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* hal function */ 35062306a36Sopenharmony_cistatic int hal_enable_dma(struct rtw89_ser *ser) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 35362306a36Sopenharmony_ci int ret; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (!test_bit(RTW89_SER_HAL_STOP_DMA, ser->flags)) 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (!rtwdev->hci.ops->mac_lv1_rcvy) 35962306a36Sopenharmony_ci return -EIO; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2); 36262306a36Sopenharmony_ci if (!ret) 36362306a36Sopenharmony_ci clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int hal_stop_dma(struct rtw89_ser *ser) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 37162306a36Sopenharmony_ci int ret; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (!rtwdev->hci.ops->mac_lv1_rcvy) 37462306a36Sopenharmony_ci return -EIO; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1); 37762306a36Sopenharmony_ci if (!ret) 37862306a36Sopenharmony_ci set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return ret; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic void hal_send_post_m0_event(struct rtw89_ser *ser) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RESET_START_DMAC); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic void hal_send_m2_event(struct rtw89_ser *ser) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_DISABLE_EN); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic void hal_send_m4_event(struct rtw89_ser *ser) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RCVY_EN); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci/* state handler */ 40562306a36Sopenharmony_cistatic void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci switch (evt) { 41062306a36Sopenharmony_ci case SER_EV_STATE_IN: 41162306a36Sopenharmony_ci rtw89_hci_recovery_complete(rtwdev); 41262306a36Sopenharmony_ci clear_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags); 41362306a36Sopenharmony_ci clear_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags); 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case SER_EV_L1_RESET_PREPARE: 41662306a36Sopenharmony_ci ser_state_goto(ser, SER_L1_RESET_PRE_ST); 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci case SER_EV_L1_RESET: 41962306a36Sopenharmony_ci ser_state_goto(ser, SER_RESET_TRX_ST); 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case SER_EV_L2_RESET: 42262306a36Sopenharmony_ci ser_state_goto(ser, SER_L2_RESET_ST); 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci case SER_EV_STATE_OUT: 42562306a36Sopenharmony_ci set_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags); 42662306a36Sopenharmony_ci rtw89_hci_recovery_start(rtwdev); 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void ser_l1_reset_pre_st_hdl(struct rtw89_ser *ser, u8 evt) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci switch (evt) { 43662306a36Sopenharmony_ci case SER_EV_STATE_IN: 43762306a36Sopenharmony_ci ser->prehandle_l1 = true; 43862306a36Sopenharmony_ci hal_send_post_m0_event(ser); 43962306a36Sopenharmony_ci ser_set_alarm(ser, 1000, SER_EV_M1_TIMEOUT); 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci case SER_EV_L1_RESET: 44262306a36Sopenharmony_ci ser_state_goto(ser, SER_RESET_TRX_ST); 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci case SER_EV_M1_TIMEOUT: 44562306a36Sopenharmony_ci ser_state_goto(ser, SER_L2_RESET_ST); 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case SER_EV_STATE_OUT: 44862306a36Sopenharmony_ci ser_del_alarm(ser); 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci default: 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci switch (evt) { 46062306a36Sopenharmony_ci case SER_EV_STATE_IN: 46162306a36Sopenharmony_ci cancel_delayed_work_sync(&rtwdev->track_work); 46262306a36Sopenharmony_ci drv_stop_tx(ser); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (hal_stop_dma(ser)) { 46562306a36Sopenharmony_ci ser_state_goto(ser, SER_L2_RESET_ST); 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci drv_stop_rx(ser); 47062306a36Sopenharmony_ci drv_trx_reset(ser); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* wait m3 */ 47362306a36Sopenharmony_ci hal_send_m2_event(ser); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* set alarm to prevent FW response timeout */ 47662306a36Sopenharmony_ci ser_set_alarm(ser, 1000, SER_EV_M3_TIMEOUT); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci case SER_EV_DO_RECOVERY: 48062306a36Sopenharmony_ci ser_state_goto(ser, SER_DO_HCI_ST); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci case SER_EV_M3_TIMEOUT: 48462306a36Sopenharmony_ci ser_state_goto(ser, SER_L2_RESET_ST); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci case SER_EV_STATE_OUT: 48862306a36Sopenharmony_ci ser_del_alarm(ser); 48962306a36Sopenharmony_ci hal_enable_dma(ser); 49062306a36Sopenharmony_ci drv_resume_rx(ser); 49162306a36Sopenharmony_ci drv_resume_tx(ser); 49262306a36Sopenharmony_ci ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, 49362306a36Sopenharmony_ci RTW89_TRACK_WORK_PERIOD); 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci default: 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci switch (evt) { 50462306a36Sopenharmony_ci case SER_EV_STATE_IN: 50562306a36Sopenharmony_ci /* wait m5 */ 50662306a36Sopenharmony_ci hal_send_m4_event(ser); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* prevent FW response timeout */ 50962306a36Sopenharmony_ci ser_set_alarm(ser, 1000, SER_EV_FW_M5_TIMEOUT); 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci case SER_EV_FW_M5_TIMEOUT: 51362306a36Sopenharmony_ci ser_state_goto(ser, SER_L2_RESET_ST); 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci case SER_EV_MAC_RESET_DONE: 51762306a36Sopenharmony_ci ser_state_goto(ser, SER_IDLE_ST); 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci case SER_EV_STATE_OUT: 52162306a36Sopenharmony_ci ser_del_alarm(ser); 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci default: 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf, 53062306a36Sopenharmony_ci u8 sel, u32 start_addr, u32 len) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; 53362306a36Sopenharmony_ci u32 filter_model_addr = mac->filter_model_addr; 53462306a36Sopenharmony_ci u32 indir_access_addr = mac->indir_access_addr; 53562306a36Sopenharmony_ci u32 *ptr = (u32 *)buf; 53662306a36Sopenharmony_ci u32 base_addr, start_page, residue; 53762306a36Sopenharmony_ci u32 cnt = 0; 53862306a36Sopenharmony_ci u32 i; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE; 54162306a36Sopenharmony_ci residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE; 54262306a36Sopenharmony_ci base_addr = mac->mem_base_addrs[sel]; 54362306a36Sopenharmony_ci base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci while (cnt < len) { 54662306a36Sopenharmony_ci rtw89_write32(rtwdev, filter_model_addr, base_addr); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci for (i = indir_access_addr + residue; 54962306a36Sopenharmony_ci i < indir_access_addr + MAC_MEM_DUMP_PAGE_SIZE; 55062306a36Sopenharmony_ci i += 4, ptr++) { 55162306a36Sopenharmony_ci *ptr = rtw89_read32(rtwdev, i); 55262306a36Sopenharmony_ci cnt += 4; 55362306a36Sopenharmony_ci if (cnt >= len) 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci residue = 0; 55862306a36Sopenharmony_ci base_addr += MAC_MEM_DUMP_PAGE_SIZE; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void rtw89_ser_fw_rsvd_ple_dump(struct rtw89_dev *rtwdev, u8 *buf) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci u32 start_addr = rtwdev->chip->rsvd_ple_ofst; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, 56762306a36Sopenharmony_ci "dump mem for fw rsvd payload engine (start addr: 0x%x)\n", 56862306a36Sopenharmony_ci start_addr); 56962306a36Sopenharmony_ci ser_mac_mem_dump(rtwdev, buf, RTW89_MAC_MEM_SHARED_BUF, start_addr, 57062306a36Sopenharmony_ci RTW89_FW_RSVD_PLE_SIZE); 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistruct __fw_backtrace_entry { 57462306a36Sopenharmony_ci u32 wcpu_addr; 57562306a36Sopenharmony_ci u32 size; 57662306a36Sopenharmony_ci u32 key; 57762306a36Sopenharmony_ci} __packed; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistruct __fw_backtrace_info { 58062306a36Sopenharmony_ci u32 ra; 58162306a36Sopenharmony_ci u32 sp; 58262306a36Sopenharmony_ci} __packed; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic_assert(RTW89_FW_BACKTRACE_INFO_SIZE == 58562306a36Sopenharmony_ci sizeof(struct __fw_backtrace_info)); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf, 58862306a36Sopenharmony_ci const struct __fw_backtrace_entry *ent) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct __fw_backtrace_info *ptr = (struct __fw_backtrace_info *)buf; 59162306a36Sopenharmony_ci const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; 59262306a36Sopenharmony_ci u32 filter_model_addr = mac->filter_model_addr; 59362306a36Sopenharmony_ci u32 indir_access_addr = mac->indir_access_addr; 59462306a36Sopenharmony_ci u32 fwbt_addr = ent->wcpu_addr & RTW89_WCPU_BASE_MASK; 59562306a36Sopenharmony_ci u32 fwbt_size = ent->size; 59662306a36Sopenharmony_ci u32 fwbt_key = ent->key; 59762306a36Sopenharmony_ci u32 i; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (fwbt_addr == 0) { 60062306a36Sopenharmony_ci rtw89_warn(rtwdev, "FW backtrace invalid address: 0x%x\n", 60162306a36Sopenharmony_ci fwbt_addr); 60262306a36Sopenharmony_ci return -EINVAL; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (fwbt_key != RTW89_FW_BACKTRACE_KEY) { 60662306a36Sopenharmony_ci rtw89_warn(rtwdev, "FW backtrace invalid key: 0x%x\n", 60762306a36Sopenharmony_ci fwbt_key); 60862306a36Sopenharmony_ci return -EINVAL; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (fwbt_size == 0 || !RTW89_VALID_FW_BACKTRACE_SIZE(fwbt_size) || 61262306a36Sopenharmony_ci fwbt_size > RTW89_FW_BACKTRACE_MAX_SIZE) { 61362306a36Sopenharmony_ci rtw89_warn(rtwdev, "FW backtrace invalid size: 0x%x\n", 61462306a36Sopenharmony_ci fwbt_size); 61562306a36Sopenharmony_ci return -EINVAL; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, "dump fw backtrace start\n"); 61962306a36Sopenharmony_ci rtw89_write32(rtwdev, filter_model_addr, fwbt_addr); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci for (i = indir_access_addr; 62262306a36Sopenharmony_ci i < indir_access_addr + fwbt_size; 62362306a36Sopenharmony_ci i += RTW89_FW_BACKTRACE_INFO_SIZE, ptr++) { 62462306a36Sopenharmony_ci *ptr = (struct __fw_backtrace_info){ 62562306a36Sopenharmony_ci .ra = rtw89_read32(rtwdev, i), 62662306a36Sopenharmony_ci .sp = rtw89_read32(rtwdev, i + 4), 62762306a36Sopenharmony_ci }; 62862306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, 62962306a36Sopenharmony_ci "next sp: 0x%x, next ra: 0x%x\n", 63062306a36Sopenharmony_ci ptr->sp, ptr->ra); 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_SER, "dump fw backtrace end\n"); 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic void ser_l2_reset_st_pre_hdl(struct rtw89_ser *ser) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 64062306a36Sopenharmony_ci struct rtw89_ser_cd_buffer *buf; 64162306a36Sopenharmony_ci struct __fw_backtrace_entry fwbt_ent; 64262306a36Sopenharmony_ci int ret = 0; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci buf = rtw89_ser_cd_prep(rtwdev); 64562306a36Sopenharmony_ci if (!buf) { 64662306a36Sopenharmony_ci ret = -ENOMEM; 64762306a36Sopenharmony_ci goto bottom; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci rtw89_ser_fw_rsvd_ple_dump(rtwdev, buf->fwple.data); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci fwbt_ent = *(struct __fw_backtrace_entry *)buf->fwple.data; 65362306a36Sopenharmony_ci ret = rtw89_ser_fw_backtrace_dump(rtwdev, buf->fwbt.data, &fwbt_ent); 65462306a36Sopenharmony_ci if (ret) 65562306a36Sopenharmony_ci goto bottom; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci rtw89_ser_cd_send(rtwdev, buf); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cibottom: 66062306a36Sopenharmony_ci rtw89_ser_cd_free(rtwdev, buf, !!ret); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci ser_reset_mac_binding(rtwdev); 66362306a36Sopenharmony_ci rtw89_core_stop(rtwdev); 66462306a36Sopenharmony_ci rtw89_entity_init(rtwdev); 66562306a36Sopenharmony_ci rtw89_fw_release_general_pkt_list(rtwdev, false); 66662306a36Sopenharmony_ci INIT_LIST_HEAD(&rtwdev->rtwvifs_list); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci switch (evt) { 67462306a36Sopenharmony_ci case SER_EV_STATE_IN: 67562306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 67662306a36Sopenharmony_ci ser_l2_reset_st_pre_hdl(ser); 67762306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ieee80211_restart_hw(rtwdev->hw); 68062306a36Sopenharmony_ci ser_set_alarm(ser, SER_RECFG_TIMEOUT, SER_EV_L2_RECFG_TIMEOUT); 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci case SER_EV_L2_RECFG_TIMEOUT: 68462306a36Sopenharmony_ci rtw89_info(rtwdev, "Err: ser L2 re-config timeout\n"); 68562306a36Sopenharmony_ci fallthrough; 68662306a36Sopenharmony_ci case SER_EV_L2_RECFG_DONE: 68762306a36Sopenharmony_ci ser_state_goto(ser, SER_IDLE_ST); 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci case SER_EV_STATE_OUT: 69162306a36Sopenharmony_ci ser_del_alarm(ser); 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci default: 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic const struct event_ent ser_ev_tbl[] = { 70062306a36Sopenharmony_ci {SER_EV_NONE, "SER_EV_NONE"}, 70162306a36Sopenharmony_ci {SER_EV_STATE_IN, "SER_EV_STATE_IN"}, 70262306a36Sopenharmony_ci {SER_EV_STATE_OUT, "SER_EV_STATE_OUT"}, 70362306a36Sopenharmony_ci {SER_EV_L1_RESET_PREPARE, "SER_EV_L1_RESET_PREPARE pre-m0"}, 70462306a36Sopenharmony_ci {SER_EV_L1_RESET, "SER_EV_L1_RESET m1"}, 70562306a36Sopenharmony_ci {SER_EV_DO_RECOVERY, "SER_EV_DO_RECOVERY m3"}, 70662306a36Sopenharmony_ci {SER_EV_MAC_RESET_DONE, "SER_EV_MAC_RESET_DONE m5"}, 70762306a36Sopenharmony_ci {SER_EV_L2_RESET, "SER_EV_L2_RESET"}, 70862306a36Sopenharmony_ci {SER_EV_L2_RECFG_DONE, "SER_EV_L2_RECFG_DONE"}, 70962306a36Sopenharmony_ci {SER_EV_L2_RECFG_TIMEOUT, "SER_EV_L2_RECFG_TIMEOUT"}, 71062306a36Sopenharmony_ci {SER_EV_M1_TIMEOUT, "SER_EV_M1_TIMEOUT"}, 71162306a36Sopenharmony_ci {SER_EV_M3_TIMEOUT, "SER_EV_M3_TIMEOUT"}, 71262306a36Sopenharmony_ci {SER_EV_FW_M5_TIMEOUT, "SER_EV_FW_M5_TIMEOUT"}, 71362306a36Sopenharmony_ci {SER_EV_L0_RESET, "SER_EV_L0_RESET"}, 71462306a36Sopenharmony_ci {SER_EV_MAXX, "SER_EV_MAX"} 71562306a36Sopenharmony_ci}; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic const struct state_ent ser_st_tbl[] = { 71862306a36Sopenharmony_ci {SER_IDLE_ST, "SER_IDLE_ST", ser_idle_st_hdl}, 71962306a36Sopenharmony_ci {SER_L1_RESET_PRE_ST, "SER_L1_RESET_PRE_ST", ser_l1_reset_pre_st_hdl}, 72062306a36Sopenharmony_ci {SER_RESET_TRX_ST, "SER_RESET_TRX_ST", ser_reset_trx_st_hdl}, 72162306a36Sopenharmony_ci {SER_DO_HCI_ST, "SER_DO_HCI_ST", ser_do_hci_st_hdl}, 72262306a36Sopenharmony_ci {SER_L2_RESET_ST, "SER_L2_RESET_ST", ser_l2_reset_st_hdl} 72362306a36Sopenharmony_ci}; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ciint rtw89_ser_init(struct rtw89_dev *rtwdev) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct rtw89_ser *ser = &rtwdev->ser; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci memset(ser, 0, sizeof(*ser)); 73062306a36Sopenharmony_ci INIT_LIST_HEAD(&ser->msg_q); 73162306a36Sopenharmony_ci ser->state = SER_IDLE_ST; 73262306a36Sopenharmony_ci ser->st_tbl = ser_st_tbl; 73362306a36Sopenharmony_ci ser->ev_tbl = ser_ev_tbl; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci bitmap_zero(ser->flags, RTW89_NUM_OF_SER_FLAGS); 73662306a36Sopenharmony_ci spin_lock_init(&ser->msg_q_lock); 73762306a36Sopenharmony_ci INIT_WORK(&ser->ser_hdl_work, rtw89_ser_hdl_work); 73862306a36Sopenharmony_ci INIT_DELAYED_WORK(&ser->ser_alarm_work, rtw89_ser_alarm_work); 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ciint rtw89_ser_deinit(struct rtw89_dev *rtwdev) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct rtw89_ser *ser = (struct rtw89_ser *)&rtwdev->ser; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci set_bit(RTW89_SER_DRV_STOP_RUN, ser->flags); 74762306a36Sopenharmony_ci cancel_delayed_work_sync(&ser->ser_alarm_work); 74862306a36Sopenharmony_ci cancel_work_sync(&ser->ser_hdl_work); 74962306a36Sopenharmony_ci clear_bit(RTW89_SER_DRV_STOP_RUN, ser->flags); 75062306a36Sopenharmony_ci return 0; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_civoid rtw89_ser_recfg_done(struct rtw89_dev *rtwdev) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci ser_send_msg(&rtwdev->ser, SER_EV_L2_RECFG_DONE); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ciint rtw89_ser_notify(struct rtw89_dev *rtwdev, u32 err) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci u8 event = SER_EV_NONE; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci rtw89_info(rtwdev, "SER catches error: 0x%x\n", err); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci switch (err) { 76562306a36Sopenharmony_ci case MAC_AX_ERR_L1_PREERR_DMAC: /* pre-M0 */ 76662306a36Sopenharmony_ci event = SER_EV_L1_RESET_PREPARE; 76762306a36Sopenharmony_ci break; 76862306a36Sopenharmony_ci case MAC_AX_ERR_L1_ERR_DMAC: 76962306a36Sopenharmony_ci case MAC_AX_ERR_L0_PROMOTE_TO_L1: 77062306a36Sopenharmony_ci event = SER_EV_L1_RESET; /* M1 */ 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci case MAC_AX_ERR_L1_RESET_DISABLE_DMAC_DONE: 77362306a36Sopenharmony_ci event = SER_EV_DO_RECOVERY; /* M3 */ 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci case MAC_AX_ERR_L1_RESET_RECOVERY_DONE: 77662306a36Sopenharmony_ci event = SER_EV_MAC_RESET_DONE; /* M5 */ 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci case MAC_AX_ERR_L0_ERR_CMAC0: 77962306a36Sopenharmony_ci case MAC_AX_ERR_L0_ERR_CMAC1: 78062306a36Sopenharmony_ci case MAC_AX_ERR_L0_RESET_DONE: 78162306a36Sopenharmony_ci event = SER_EV_L0_RESET; 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci default: 78462306a36Sopenharmony_ci if (err == MAC_AX_ERR_L1_PROMOTE_TO_L2 || 78562306a36Sopenharmony_ci (err >= MAC_AX_ERR_L2_ERR_AH_DMA && 78662306a36Sopenharmony_ci err <= MAC_AX_GET_ERR_MAX)) 78762306a36Sopenharmony_ci event = SER_EV_L2_RESET; 78862306a36Sopenharmony_ci break; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (event == SER_EV_NONE) { 79262306a36Sopenharmony_ci rtw89_warn(rtwdev, "SER cannot recognize error: 0x%x\n", err); 79362306a36Sopenharmony_ci return -EINVAL; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ser_send_msg(&rtwdev->ser, event); 79762306a36Sopenharmony_ci return 0; 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_ser_notify); 800