1*e3ec7017SPing-Ke Shih // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2*e3ec7017SPing-Ke Shih /* Copyright(c) 2019-2020 Realtek Corporation 3*e3ec7017SPing-Ke Shih */ 4*e3ec7017SPing-Ke Shih 5*e3ec7017SPing-Ke Shih #include "cam.h" 6*e3ec7017SPing-Ke Shih #include "debug.h" 7*e3ec7017SPing-Ke Shih #include "mac.h" 8*e3ec7017SPing-Ke Shih #include "ps.h" 9*e3ec7017SPing-Ke Shih #include "ser.h" 10*e3ec7017SPing-Ke Shih #include "util.h" 11*e3ec7017SPing-Ke Shih 12*e3ec7017SPing-Ke Shih #define SER_RECFG_TIMEOUT 1000 13*e3ec7017SPing-Ke Shih 14*e3ec7017SPing-Ke Shih enum ser_evt { 15*e3ec7017SPing-Ke Shih SER_EV_NONE, 16*e3ec7017SPing-Ke Shih SER_EV_STATE_IN, 17*e3ec7017SPing-Ke Shih SER_EV_STATE_OUT, 18*e3ec7017SPing-Ke Shih SER_EV_L1_RESET, /* M1 */ 19*e3ec7017SPing-Ke Shih SER_EV_DO_RECOVERY, /* M3 */ 20*e3ec7017SPing-Ke Shih SER_EV_MAC_RESET_DONE, /* M5 */ 21*e3ec7017SPing-Ke Shih SER_EV_L2_RESET, 22*e3ec7017SPing-Ke Shih SER_EV_L2_RECFG_DONE, 23*e3ec7017SPing-Ke Shih SER_EV_L2_RECFG_TIMEOUT, 24*e3ec7017SPing-Ke Shih SER_EV_M3_TIMEOUT, 25*e3ec7017SPing-Ke Shih SER_EV_FW_M5_TIMEOUT, 26*e3ec7017SPing-Ke Shih SER_EV_L0_RESET, 27*e3ec7017SPing-Ke Shih SER_EV_MAXX 28*e3ec7017SPing-Ke Shih }; 29*e3ec7017SPing-Ke Shih 30*e3ec7017SPing-Ke Shih enum ser_state { 31*e3ec7017SPing-Ke Shih SER_IDLE_ST, 32*e3ec7017SPing-Ke Shih SER_RESET_TRX_ST, 33*e3ec7017SPing-Ke Shih SER_DO_HCI_ST, 34*e3ec7017SPing-Ke Shih SER_L2_RESET_ST, 35*e3ec7017SPing-Ke Shih SER_ST_MAX_ST 36*e3ec7017SPing-Ke Shih }; 37*e3ec7017SPing-Ke Shih 38*e3ec7017SPing-Ke Shih struct ser_msg { 39*e3ec7017SPing-Ke Shih struct list_head list; 40*e3ec7017SPing-Ke Shih u8 event; 41*e3ec7017SPing-Ke Shih }; 42*e3ec7017SPing-Ke Shih 43*e3ec7017SPing-Ke Shih struct state_ent { 44*e3ec7017SPing-Ke Shih u8 state; 45*e3ec7017SPing-Ke Shih char *name; 46*e3ec7017SPing-Ke Shih void (*st_func)(struct rtw89_ser *ser, u8 event); 47*e3ec7017SPing-Ke Shih }; 48*e3ec7017SPing-Ke Shih 49*e3ec7017SPing-Ke Shih struct event_ent { 50*e3ec7017SPing-Ke Shih u8 event; 51*e3ec7017SPing-Ke Shih char *name; 52*e3ec7017SPing-Ke Shih }; 53*e3ec7017SPing-Ke Shih 54*e3ec7017SPing-Ke Shih static char *ser_ev_name(struct rtw89_ser *ser, u8 event) 55*e3ec7017SPing-Ke Shih { 56*e3ec7017SPing-Ke Shih if (event < SER_EV_MAXX) 57*e3ec7017SPing-Ke Shih return ser->ev_tbl[event].name; 58*e3ec7017SPing-Ke Shih 59*e3ec7017SPing-Ke Shih return "err_ev_name"; 60*e3ec7017SPing-Ke Shih } 61*e3ec7017SPing-Ke Shih 62*e3ec7017SPing-Ke Shih static char *ser_st_name(struct rtw89_ser *ser) 63*e3ec7017SPing-Ke Shih { 64*e3ec7017SPing-Ke Shih if (ser->state < SER_ST_MAX_ST) 65*e3ec7017SPing-Ke Shih return ser->st_tbl[ser->state].name; 66*e3ec7017SPing-Ke Shih 67*e3ec7017SPing-Ke Shih return "err_st_name"; 68*e3ec7017SPing-Ke Shih } 69*e3ec7017SPing-Ke Shih 70*e3ec7017SPing-Ke Shih static void ser_state_run(struct rtw89_ser *ser, u8 evt) 71*e3ec7017SPing-Ke Shih { 72*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 73*e3ec7017SPing-Ke Shih 74*e3ec7017SPing-Ke Shih rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s receive %s\n", 75*e3ec7017SPing-Ke Shih ser_st_name(ser), ser_ev_name(ser, evt)); 76*e3ec7017SPing-Ke Shih 77*e3ec7017SPing-Ke Shih rtw89_leave_lps(rtwdev); 78*e3ec7017SPing-Ke Shih ser->st_tbl[ser->state].st_func(ser, evt); 79*e3ec7017SPing-Ke Shih } 80*e3ec7017SPing-Ke Shih 81*e3ec7017SPing-Ke Shih static void ser_state_goto(struct rtw89_ser *ser, u8 new_state) 82*e3ec7017SPing-Ke Shih { 83*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 84*e3ec7017SPing-Ke Shih 85*e3ec7017SPing-Ke Shih if (ser->state == new_state || new_state >= SER_ST_MAX_ST) 86*e3ec7017SPing-Ke Shih return; 87*e3ec7017SPing-Ke Shih ser_state_run(ser, SER_EV_STATE_OUT); 88*e3ec7017SPing-Ke Shih 89*e3ec7017SPing-Ke Shih rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s goto -> %s\n", 90*e3ec7017SPing-Ke Shih ser_st_name(ser), ser->st_tbl[new_state].name); 91*e3ec7017SPing-Ke Shih 92*e3ec7017SPing-Ke Shih ser->state = new_state; 93*e3ec7017SPing-Ke Shih ser_state_run(ser, SER_EV_STATE_IN); 94*e3ec7017SPing-Ke Shih } 95*e3ec7017SPing-Ke Shih 96*e3ec7017SPing-Ke Shih static struct ser_msg *__rtw89_ser_dequeue_msg(struct rtw89_ser *ser) 97*e3ec7017SPing-Ke Shih { 98*e3ec7017SPing-Ke Shih struct ser_msg *msg; 99*e3ec7017SPing-Ke Shih 100*e3ec7017SPing-Ke Shih spin_lock_irq(&ser->msg_q_lock); 101*e3ec7017SPing-Ke Shih msg = list_first_entry_or_null(&ser->msg_q, struct ser_msg, list); 102*e3ec7017SPing-Ke Shih if (msg) 103*e3ec7017SPing-Ke Shih list_del(&msg->list); 104*e3ec7017SPing-Ke Shih spin_unlock_irq(&ser->msg_q_lock); 105*e3ec7017SPing-Ke Shih 106*e3ec7017SPing-Ke Shih return msg; 107*e3ec7017SPing-Ke Shih } 108*e3ec7017SPing-Ke Shih 109*e3ec7017SPing-Ke Shih static void rtw89_ser_hdl_work(struct work_struct *work) 110*e3ec7017SPing-Ke Shih { 111*e3ec7017SPing-Ke Shih struct ser_msg *msg; 112*e3ec7017SPing-Ke Shih struct rtw89_ser *ser = container_of(work, struct rtw89_ser, 113*e3ec7017SPing-Ke Shih ser_hdl_work); 114*e3ec7017SPing-Ke Shih 115*e3ec7017SPing-Ke Shih while ((msg = __rtw89_ser_dequeue_msg(ser))) { 116*e3ec7017SPing-Ke Shih ser_state_run(ser, msg->event); 117*e3ec7017SPing-Ke Shih kfree(msg); 118*e3ec7017SPing-Ke Shih } 119*e3ec7017SPing-Ke Shih } 120*e3ec7017SPing-Ke Shih 121*e3ec7017SPing-Ke Shih static int ser_send_msg(struct rtw89_ser *ser, u8 event) 122*e3ec7017SPing-Ke Shih { 123*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 124*e3ec7017SPing-Ke Shih struct ser_msg *msg = NULL; 125*e3ec7017SPing-Ke Shih 126*e3ec7017SPing-Ke Shih if (test_bit(RTW89_SER_DRV_STOP_RUN, ser->flags)) 127*e3ec7017SPing-Ke Shih return -EIO; 128*e3ec7017SPing-Ke Shih 129*e3ec7017SPing-Ke Shih msg = kmalloc(sizeof(*msg), GFP_ATOMIC); 130*e3ec7017SPing-Ke Shih if (!msg) 131*e3ec7017SPing-Ke Shih return -ENOMEM; 132*e3ec7017SPing-Ke Shih 133*e3ec7017SPing-Ke Shih msg->event = event; 134*e3ec7017SPing-Ke Shih 135*e3ec7017SPing-Ke Shih spin_lock_irq(&ser->msg_q_lock); 136*e3ec7017SPing-Ke Shih list_add(&msg->list, &ser->msg_q); 137*e3ec7017SPing-Ke Shih spin_unlock_irq(&ser->msg_q_lock); 138*e3ec7017SPing-Ke Shih 139*e3ec7017SPing-Ke Shih ieee80211_queue_work(rtwdev->hw, &ser->ser_hdl_work); 140*e3ec7017SPing-Ke Shih return 0; 141*e3ec7017SPing-Ke Shih } 142*e3ec7017SPing-Ke Shih 143*e3ec7017SPing-Ke Shih static void rtw89_ser_alarm_work(struct work_struct *work) 144*e3ec7017SPing-Ke Shih { 145*e3ec7017SPing-Ke Shih struct rtw89_ser *ser = container_of(work, struct rtw89_ser, 146*e3ec7017SPing-Ke Shih ser_alarm_work.work); 147*e3ec7017SPing-Ke Shih 148*e3ec7017SPing-Ke Shih ser_send_msg(ser, ser->alarm_event); 149*e3ec7017SPing-Ke Shih ser->alarm_event = SER_EV_NONE; 150*e3ec7017SPing-Ke Shih } 151*e3ec7017SPing-Ke Shih 152*e3ec7017SPing-Ke Shih static void ser_set_alarm(struct rtw89_ser *ser, u32 ms, u8 event) 153*e3ec7017SPing-Ke Shih { 154*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 155*e3ec7017SPing-Ke Shih 156*e3ec7017SPing-Ke Shih if (test_bit(RTW89_SER_DRV_STOP_RUN, ser->flags)) 157*e3ec7017SPing-Ke Shih return; 158*e3ec7017SPing-Ke Shih 159*e3ec7017SPing-Ke Shih ser->alarm_event = event; 160*e3ec7017SPing-Ke Shih ieee80211_queue_delayed_work(rtwdev->hw, &ser->ser_alarm_work, 161*e3ec7017SPing-Ke Shih msecs_to_jiffies(ms)); 162*e3ec7017SPing-Ke Shih } 163*e3ec7017SPing-Ke Shih 164*e3ec7017SPing-Ke Shih static void ser_del_alarm(struct rtw89_ser *ser) 165*e3ec7017SPing-Ke Shih { 166*e3ec7017SPing-Ke Shih cancel_delayed_work(&ser->ser_alarm_work); 167*e3ec7017SPing-Ke Shih ser->alarm_event = SER_EV_NONE; 168*e3ec7017SPing-Ke Shih } 169*e3ec7017SPing-Ke Shih 170*e3ec7017SPing-Ke Shih /* driver function */ 171*e3ec7017SPing-Ke Shih static void drv_stop_tx(struct rtw89_ser *ser) 172*e3ec7017SPing-Ke Shih { 173*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 174*e3ec7017SPing-Ke Shih 175*e3ec7017SPing-Ke Shih ieee80211_stop_queues(rtwdev->hw); 176*e3ec7017SPing-Ke Shih set_bit(RTW89_SER_DRV_STOP_TX, ser->flags); 177*e3ec7017SPing-Ke Shih } 178*e3ec7017SPing-Ke Shih 179*e3ec7017SPing-Ke Shih static void drv_stop_rx(struct rtw89_ser *ser) 180*e3ec7017SPing-Ke Shih { 181*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 182*e3ec7017SPing-Ke Shih 183*e3ec7017SPing-Ke Shih clear_bit(RTW89_FLAG_RUNNING, rtwdev->flags); 184*e3ec7017SPing-Ke Shih set_bit(RTW89_SER_DRV_STOP_RX, ser->flags); 185*e3ec7017SPing-Ke Shih } 186*e3ec7017SPing-Ke Shih 187*e3ec7017SPing-Ke Shih static void drv_trx_reset(struct rtw89_ser *ser) 188*e3ec7017SPing-Ke Shih { 189*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 190*e3ec7017SPing-Ke Shih 191*e3ec7017SPing-Ke Shih rtw89_hci_reset(rtwdev); 192*e3ec7017SPing-Ke Shih } 193*e3ec7017SPing-Ke Shih 194*e3ec7017SPing-Ke Shih static void drv_resume_tx(struct rtw89_ser *ser) 195*e3ec7017SPing-Ke Shih { 196*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 197*e3ec7017SPing-Ke Shih 198*e3ec7017SPing-Ke Shih if (!test_bit(RTW89_SER_DRV_STOP_TX, ser->flags)) 199*e3ec7017SPing-Ke Shih return; 200*e3ec7017SPing-Ke Shih 201*e3ec7017SPing-Ke Shih ieee80211_wake_queues(rtwdev->hw); 202*e3ec7017SPing-Ke Shih clear_bit(RTW89_SER_DRV_STOP_TX, ser->flags); 203*e3ec7017SPing-Ke Shih } 204*e3ec7017SPing-Ke Shih 205*e3ec7017SPing-Ke Shih static void drv_resume_rx(struct rtw89_ser *ser) 206*e3ec7017SPing-Ke Shih { 207*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 208*e3ec7017SPing-Ke Shih 209*e3ec7017SPing-Ke Shih if (!test_bit(RTW89_SER_DRV_STOP_RX, ser->flags)) 210*e3ec7017SPing-Ke Shih return; 211*e3ec7017SPing-Ke Shih 212*e3ec7017SPing-Ke Shih set_bit(RTW89_FLAG_RUNNING, rtwdev->flags); 213*e3ec7017SPing-Ke Shih clear_bit(RTW89_SER_DRV_STOP_RX, ser->flags); 214*e3ec7017SPing-Ke Shih } 215*e3ec7017SPing-Ke Shih 216*e3ec7017SPing-Ke Shih static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 217*e3ec7017SPing-Ke Shih { 218*e3ec7017SPing-Ke Shih rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); 219*e3ec7017SPing-Ke Shih rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; 220*e3ec7017SPing-Ke Shih rtwvif->trigger = false; 221*e3ec7017SPing-Ke Shih } 222*e3ec7017SPing-Ke Shih 223*e3ec7017SPing-Ke Shih static void ser_reset_mac_binding(struct rtw89_dev *rtwdev) 224*e3ec7017SPing-Ke Shih { 225*e3ec7017SPing-Ke Shih struct rtw89_vif *rtwvif; 226*e3ec7017SPing-Ke Shih 227*e3ec7017SPing-Ke Shih rtw89_cam_reset_keys(rtwdev); 228*e3ec7017SPing-Ke Shih rtw89_core_release_all_bits_map(rtwdev->mac_id_map, RTW89_MAX_MAC_ID_NUM); 229*e3ec7017SPing-Ke Shih rtw89_for_each_rtwvif(rtwdev, rtwvif) 230*e3ec7017SPing-Ke Shih ser_reset_vif(rtwdev, rtwvif); 231*e3ec7017SPing-Ke Shih } 232*e3ec7017SPing-Ke Shih 233*e3ec7017SPing-Ke Shih /* hal function */ 234*e3ec7017SPing-Ke Shih static int hal_enable_dma(struct rtw89_ser *ser) 235*e3ec7017SPing-Ke Shih { 236*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 237*e3ec7017SPing-Ke Shih int ret; 238*e3ec7017SPing-Ke Shih 239*e3ec7017SPing-Ke Shih if (!test_bit(RTW89_SER_HAL_STOP_DMA, ser->flags)) 240*e3ec7017SPing-Ke Shih return 0; 241*e3ec7017SPing-Ke Shih 242*e3ec7017SPing-Ke Shih if (!rtwdev->hci.ops->mac_lv1_rcvy) 243*e3ec7017SPing-Ke Shih return -EIO; 244*e3ec7017SPing-Ke Shih 245*e3ec7017SPing-Ke Shih ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2); 246*e3ec7017SPing-Ke Shih if (!ret) 247*e3ec7017SPing-Ke Shih clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); 248*e3ec7017SPing-Ke Shih 249*e3ec7017SPing-Ke Shih return ret; 250*e3ec7017SPing-Ke Shih } 251*e3ec7017SPing-Ke Shih 252*e3ec7017SPing-Ke Shih static int hal_stop_dma(struct rtw89_ser *ser) 253*e3ec7017SPing-Ke Shih { 254*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 255*e3ec7017SPing-Ke Shih int ret; 256*e3ec7017SPing-Ke Shih 257*e3ec7017SPing-Ke Shih if (!rtwdev->hci.ops->mac_lv1_rcvy) 258*e3ec7017SPing-Ke Shih return -EIO; 259*e3ec7017SPing-Ke Shih 260*e3ec7017SPing-Ke Shih ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1); 261*e3ec7017SPing-Ke Shih if (!ret) 262*e3ec7017SPing-Ke Shih set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); 263*e3ec7017SPing-Ke Shih 264*e3ec7017SPing-Ke Shih return ret; 265*e3ec7017SPing-Ke Shih } 266*e3ec7017SPing-Ke Shih 267*e3ec7017SPing-Ke Shih static void hal_send_m2_event(struct rtw89_ser *ser) 268*e3ec7017SPing-Ke Shih { 269*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 270*e3ec7017SPing-Ke Shih 271*e3ec7017SPing-Ke Shih rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_DISABLE_EN); 272*e3ec7017SPing-Ke Shih } 273*e3ec7017SPing-Ke Shih 274*e3ec7017SPing-Ke Shih static void hal_send_m4_event(struct rtw89_ser *ser) 275*e3ec7017SPing-Ke Shih { 276*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 277*e3ec7017SPing-Ke Shih 278*e3ec7017SPing-Ke Shih rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RCVY_EN); 279*e3ec7017SPing-Ke Shih } 280*e3ec7017SPing-Ke Shih 281*e3ec7017SPing-Ke Shih /* state handler */ 282*e3ec7017SPing-Ke Shih static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) 283*e3ec7017SPing-Ke Shih { 284*e3ec7017SPing-Ke Shih switch (evt) { 285*e3ec7017SPing-Ke Shih case SER_EV_STATE_IN: 286*e3ec7017SPing-Ke Shih break; 287*e3ec7017SPing-Ke Shih case SER_EV_L1_RESET: 288*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_RESET_TRX_ST); 289*e3ec7017SPing-Ke Shih break; 290*e3ec7017SPing-Ke Shih case SER_EV_L2_RESET: 291*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_L2_RESET_ST); 292*e3ec7017SPing-Ke Shih break; 293*e3ec7017SPing-Ke Shih case SER_EV_STATE_OUT: 294*e3ec7017SPing-Ke Shih default: 295*e3ec7017SPing-Ke Shih break; 296*e3ec7017SPing-Ke Shih } 297*e3ec7017SPing-Ke Shih } 298*e3ec7017SPing-Ke Shih 299*e3ec7017SPing-Ke Shih static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) 300*e3ec7017SPing-Ke Shih { 301*e3ec7017SPing-Ke Shih switch (evt) { 302*e3ec7017SPing-Ke Shih case SER_EV_STATE_IN: 303*e3ec7017SPing-Ke Shih drv_stop_tx(ser); 304*e3ec7017SPing-Ke Shih 305*e3ec7017SPing-Ke Shih if (hal_stop_dma(ser)) { 306*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_L2_RESET_ST); 307*e3ec7017SPing-Ke Shih break; 308*e3ec7017SPing-Ke Shih } 309*e3ec7017SPing-Ke Shih 310*e3ec7017SPing-Ke Shih drv_stop_rx(ser); 311*e3ec7017SPing-Ke Shih drv_trx_reset(ser); 312*e3ec7017SPing-Ke Shih 313*e3ec7017SPing-Ke Shih /* wait m3 */ 314*e3ec7017SPing-Ke Shih hal_send_m2_event(ser); 315*e3ec7017SPing-Ke Shih 316*e3ec7017SPing-Ke Shih /* set alarm to prevent FW response timeout */ 317*e3ec7017SPing-Ke Shih ser_set_alarm(ser, 1000, SER_EV_M3_TIMEOUT); 318*e3ec7017SPing-Ke Shih break; 319*e3ec7017SPing-Ke Shih 320*e3ec7017SPing-Ke Shih case SER_EV_DO_RECOVERY: 321*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_DO_HCI_ST); 322*e3ec7017SPing-Ke Shih break; 323*e3ec7017SPing-Ke Shih 324*e3ec7017SPing-Ke Shih case SER_EV_M3_TIMEOUT: 325*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_L2_RESET_ST); 326*e3ec7017SPing-Ke Shih break; 327*e3ec7017SPing-Ke Shih 328*e3ec7017SPing-Ke Shih case SER_EV_STATE_OUT: 329*e3ec7017SPing-Ke Shih ser_del_alarm(ser); 330*e3ec7017SPing-Ke Shih hal_enable_dma(ser); 331*e3ec7017SPing-Ke Shih drv_resume_rx(ser); 332*e3ec7017SPing-Ke Shih drv_resume_tx(ser); 333*e3ec7017SPing-Ke Shih break; 334*e3ec7017SPing-Ke Shih 335*e3ec7017SPing-Ke Shih default: 336*e3ec7017SPing-Ke Shih break; 337*e3ec7017SPing-Ke Shih } 338*e3ec7017SPing-Ke Shih } 339*e3ec7017SPing-Ke Shih 340*e3ec7017SPing-Ke Shih static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt) 341*e3ec7017SPing-Ke Shih { 342*e3ec7017SPing-Ke Shih switch (evt) { 343*e3ec7017SPing-Ke Shih case SER_EV_STATE_IN: 344*e3ec7017SPing-Ke Shih /* wait m5 */ 345*e3ec7017SPing-Ke Shih hal_send_m4_event(ser); 346*e3ec7017SPing-Ke Shih 347*e3ec7017SPing-Ke Shih /* prevent FW response timeout */ 348*e3ec7017SPing-Ke Shih ser_set_alarm(ser, 1000, SER_EV_FW_M5_TIMEOUT); 349*e3ec7017SPing-Ke Shih break; 350*e3ec7017SPing-Ke Shih 351*e3ec7017SPing-Ke Shih case SER_EV_FW_M5_TIMEOUT: 352*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_L2_RESET_ST); 353*e3ec7017SPing-Ke Shih break; 354*e3ec7017SPing-Ke Shih 355*e3ec7017SPing-Ke Shih case SER_EV_MAC_RESET_DONE: 356*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_IDLE_ST); 357*e3ec7017SPing-Ke Shih break; 358*e3ec7017SPing-Ke Shih 359*e3ec7017SPing-Ke Shih case SER_EV_STATE_OUT: 360*e3ec7017SPing-Ke Shih ser_del_alarm(ser); 361*e3ec7017SPing-Ke Shih break; 362*e3ec7017SPing-Ke Shih 363*e3ec7017SPing-Ke Shih default: 364*e3ec7017SPing-Ke Shih break; 365*e3ec7017SPing-Ke Shih } 366*e3ec7017SPing-Ke Shih } 367*e3ec7017SPing-Ke Shih 368*e3ec7017SPing-Ke Shih static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt) 369*e3ec7017SPing-Ke Shih { 370*e3ec7017SPing-Ke Shih struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); 371*e3ec7017SPing-Ke Shih 372*e3ec7017SPing-Ke Shih switch (evt) { 373*e3ec7017SPing-Ke Shih case SER_EV_STATE_IN: 374*e3ec7017SPing-Ke Shih mutex_lock(&rtwdev->mutex); 375*e3ec7017SPing-Ke Shih ser_reset_mac_binding(rtwdev); 376*e3ec7017SPing-Ke Shih rtw89_core_stop(rtwdev); 377*e3ec7017SPing-Ke Shih mutex_unlock(&rtwdev->mutex); 378*e3ec7017SPing-Ke Shih 379*e3ec7017SPing-Ke Shih ieee80211_restart_hw(rtwdev->hw); 380*e3ec7017SPing-Ke Shih ser_set_alarm(ser, SER_RECFG_TIMEOUT, SER_EV_L2_RECFG_TIMEOUT); 381*e3ec7017SPing-Ke Shih break; 382*e3ec7017SPing-Ke Shih 383*e3ec7017SPing-Ke Shih case SER_EV_L2_RECFG_TIMEOUT: 384*e3ec7017SPing-Ke Shih rtw89_info(rtwdev, "Err: ser L2 re-config timeout\n"); 385*e3ec7017SPing-Ke Shih fallthrough; 386*e3ec7017SPing-Ke Shih case SER_EV_L2_RECFG_DONE: 387*e3ec7017SPing-Ke Shih ser_state_goto(ser, SER_IDLE_ST); 388*e3ec7017SPing-Ke Shih break; 389*e3ec7017SPing-Ke Shih 390*e3ec7017SPing-Ke Shih case SER_EV_STATE_OUT: 391*e3ec7017SPing-Ke Shih ser_del_alarm(ser); 392*e3ec7017SPing-Ke Shih break; 393*e3ec7017SPing-Ke Shih 394*e3ec7017SPing-Ke Shih default: 395*e3ec7017SPing-Ke Shih break; 396*e3ec7017SPing-Ke Shih } 397*e3ec7017SPing-Ke Shih } 398*e3ec7017SPing-Ke Shih 399*e3ec7017SPing-Ke Shih static struct event_ent ser_ev_tbl[] = { 400*e3ec7017SPing-Ke Shih {SER_EV_NONE, "SER_EV_NONE"}, 401*e3ec7017SPing-Ke Shih {SER_EV_STATE_IN, "SER_EV_STATE_IN"}, 402*e3ec7017SPing-Ke Shih {SER_EV_STATE_OUT, "SER_EV_STATE_OUT"}, 403*e3ec7017SPing-Ke Shih {SER_EV_L1_RESET, "SER_EV_L1_RESET"}, 404*e3ec7017SPing-Ke Shih {SER_EV_DO_RECOVERY, "SER_EV_DO_RECOVERY m3"}, 405*e3ec7017SPing-Ke Shih {SER_EV_MAC_RESET_DONE, "SER_EV_MAC_RESET_DONE m5"}, 406*e3ec7017SPing-Ke Shih {SER_EV_L2_RESET, "SER_EV_L2_RESET"}, 407*e3ec7017SPing-Ke Shih {SER_EV_L2_RECFG_DONE, "SER_EV_L2_RECFG_DONE"}, 408*e3ec7017SPing-Ke Shih {SER_EV_L2_RECFG_TIMEOUT, "SER_EV_L2_RECFG_TIMEOUT"}, 409*e3ec7017SPing-Ke Shih {SER_EV_M3_TIMEOUT, "SER_EV_M3_TIMEOUT"}, 410*e3ec7017SPing-Ke Shih {SER_EV_FW_M5_TIMEOUT, "SER_EV_FW_M5_TIMEOUT"}, 411*e3ec7017SPing-Ke Shih {SER_EV_L0_RESET, "SER_EV_L0_RESET"}, 412*e3ec7017SPing-Ke Shih {SER_EV_MAXX, "SER_EV_MAX"} 413*e3ec7017SPing-Ke Shih }; 414*e3ec7017SPing-Ke Shih 415*e3ec7017SPing-Ke Shih static struct state_ent ser_st_tbl[] = { 416*e3ec7017SPing-Ke Shih {SER_IDLE_ST, "SER_IDLE_ST", ser_idle_st_hdl}, 417*e3ec7017SPing-Ke Shih {SER_RESET_TRX_ST, "SER_RESET_TRX_ST", ser_reset_trx_st_hdl}, 418*e3ec7017SPing-Ke Shih {SER_DO_HCI_ST, "SER_DO_HCI_ST", ser_do_hci_st_hdl}, 419*e3ec7017SPing-Ke Shih {SER_L2_RESET_ST, "SER_L2_RESET_ST", ser_l2_reset_st_hdl} 420*e3ec7017SPing-Ke Shih }; 421*e3ec7017SPing-Ke Shih 422*e3ec7017SPing-Ke Shih int rtw89_ser_init(struct rtw89_dev *rtwdev) 423*e3ec7017SPing-Ke Shih { 424*e3ec7017SPing-Ke Shih struct rtw89_ser *ser = &rtwdev->ser; 425*e3ec7017SPing-Ke Shih 426*e3ec7017SPing-Ke Shih memset(ser, 0, sizeof(*ser)); 427*e3ec7017SPing-Ke Shih INIT_LIST_HEAD(&ser->msg_q); 428*e3ec7017SPing-Ke Shih ser->state = SER_IDLE_ST; 429*e3ec7017SPing-Ke Shih ser->st_tbl = ser_st_tbl; 430*e3ec7017SPing-Ke Shih ser->ev_tbl = ser_ev_tbl; 431*e3ec7017SPing-Ke Shih 432*e3ec7017SPing-Ke Shih bitmap_zero(ser->flags, RTW89_NUM_OF_SER_FLAGS); 433*e3ec7017SPing-Ke Shih spin_lock_init(&ser->msg_q_lock); 434*e3ec7017SPing-Ke Shih INIT_WORK(&ser->ser_hdl_work, rtw89_ser_hdl_work); 435*e3ec7017SPing-Ke Shih INIT_DELAYED_WORK(&ser->ser_alarm_work, rtw89_ser_alarm_work); 436*e3ec7017SPing-Ke Shih return 0; 437*e3ec7017SPing-Ke Shih } 438*e3ec7017SPing-Ke Shih 439*e3ec7017SPing-Ke Shih int rtw89_ser_deinit(struct rtw89_dev *rtwdev) 440*e3ec7017SPing-Ke Shih { 441*e3ec7017SPing-Ke Shih struct rtw89_ser *ser = (struct rtw89_ser *)&rtwdev->ser; 442*e3ec7017SPing-Ke Shih 443*e3ec7017SPing-Ke Shih set_bit(RTW89_SER_DRV_STOP_RUN, ser->flags); 444*e3ec7017SPing-Ke Shih cancel_delayed_work_sync(&ser->ser_alarm_work); 445*e3ec7017SPing-Ke Shih cancel_work_sync(&ser->ser_hdl_work); 446*e3ec7017SPing-Ke Shih clear_bit(RTW89_SER_DRV_STOP_RUN, ser->flags); 447*e3ec7017SPing-Ke Shih return 0; 448*e3ec7017SPing-Ke Shih } 449*e3ec7017SPing-Ke Shih 450*e3ec7017SPing-Ke Shih void rtw89_ser_recfg_done(struct rtw89_dev *rtwdev) 451*e3ec7017SPing-Ke Shih { 452*e3ec7017SPing-Ke Shih ser_send_msg(&rtwdev->ser, SER_EV_L2_RECFG_DONE); 453*e3ec7017SPing-Ke Shih } 454*e3ec7017SPing-Ke Shih 455*e3ec7017SPing-Ke Shih int rtw89_ser_notify(struct rtw89_dev *rtwdev, u32 err) 456*e3ec7017SPing-Ke Shih { 457*e3ec7017SPing-Ke Shih u8 event = SER_EV_NONE; 458*e3ec7017SPing-Ke Shih 459*e3ec7017SPing-Ke Shih rtw89_info(rtwdev, "ser event = 0x%04x\n", err); 460*e3ec7017SPing-Ke Shih 461*e3ec7017SPing-Ke Shih switch (err) { 462*e3ec7017SPing-Ke Shih case MAC_AX_ERR_L1_ERR_DMAC: 463*e3ec7017SPing-Ke Shih case MAC_AX_ERR_L0_PROMOTE_TO_L1: 464*e3ec7017SPing-Ke Shih event = SER_EV_L1_RESET; /* M1 */ 465*e3ec7017SPing-Ke Shih break; 466*e3ec7017SPing-Ke Shih case MAC_AX_ERR_L1_RESET_DISABLE_DMAC_DONE: 467*e3ec7017SPing-Ke Shih event = SER_EV_DO_RECOVERY; /* M3 */ 468*e3ec7017SPing-Ke Shih break; 469*e3ec7017SPing-Ke Shih case MAC_AX_ERR_L1_RESET_RECOVERY_DONE: 470*e3ec7017SPing-Ke Shih event = SER_EV_MAC_RESET_DONE; /* M5 */ 471*e3ec7017SPing-Ke Shih break; 472*e3ec7017SPing-Ke Shih case MAC_AX_ERR_L0_ERR_CMAC0: 473*e3ec7017SPing-Ke Shih case MAC_AX_ERR_L0_ERR_CMAC1: 474*e3ec7017SPing-Ke Shih case MAC_AX_ERR_L0_RESET_DONE: 475*e3ec7017SPing-Ke Shih event = SER_EV_L0_RESET; 476*e3ec7017SPing-Ke Shih break; 477*e3ec7017SPing-Ke Shih default: 478*e3ec7017SPing-Ke Shih if (err == MAC_AX_ERR_L1_PROMOTE_TO_L2 || 479*e3ec7017SPing-Ke Shih (err >= MAC_AX_ERR_L2_ERR_AH_DMA && 480*e3ec7017SPing-Ke Shih err <= MAC_AX_GET_ERR_MAX)) 481*e3ec7017SPing-Ke Shih event = SER_EV_L2_RESET; 482*e3ec7017SPing-Ke Shih break; 483*e3ec7017SPing-Ke Shih } 484*e3ec7017SPing-Ke Shih 485*e3ec7017SPing-Ke Shih if (event == SER_EV_NONE) 486*e3ec7017SPing-Ke Shih return -EINVAL; 487*e3ec7017SPing-Ke Shih 488*e3ec7017SPing-Ke Shih ser_send_msg(&rtwdev->ser, event); 489*e3ec7017SPing-Ke Shih return 0; 490*e3ec7017SPing-Ke Shih } 491*e3ec7017SPing-Ke Shih EXPORT_SYMBOL(rtw89_ser_notify); 492