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