xref: /linux/drivers/net/wwan/t7xx/t7xx_state_monitor.c (revision 7255fcc80d4b525cc10cfaaf7f485830d4ed2000)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2021, MediaTek Inc.
4  * Copyright (c) 2021-2022, Intel Corporation.
5  *
6  * Authors:
7  *  Haijun Liu <haijun.liu@mediatek.com>
8  *  Eliot Lee <eliot.lee@intel.com>
9  *  Moises Veleta <moises.veleta@intel.com>
10  *  Ricardo Martinez <ricardo.martinez@linux.intel.com>
11  *
12  * Contributors:
13  *  Amir Hanania <amir.hanania@intel.com>
14  *  Sreehari Kancharla <sreehari.kancharla@intel.com>
15  */
16 
17 #include <linux/bits.h>
18 #include <linux/bitfield.h>
19 #include <linux/completion.h>
20 #include <linux/device.h>
21 #include <linux/delay.h>
22 #include <linux/err.h>
23 #include <linux/gfp.h>
24 #include <linux/iopoll.h>
25 #include <linux/jiffies.h>
26 #include <linux/kernel.h>
27 #include <linux/kthread.h>
28 #include <linux/list.h>
29 #include <linux/slab.h>
30 #include <linux/spinlock.h>
31 #include <linux/string.h>
32 #include <linux/types.h>
33 #include <linux/wait.h>
34 
35 #include "t7xx_hif_cldma.h"
36 #include "t7xx_mhccif.h"
37 #include "t7xx_modem_ops.h"
38 #include "t7xx_pci.h"
39 #include "t7xx_pcie_mac.h"
40 #include "t7xx_port_proxy.h"
41 #include "t7xx_reg.h"
42 #include "t7xx_state_monitor.h"
43 
44 #define FSM_DRM_DISABLE_DELAY_MS		200
45 #define FSM_EVENT_POLL_INTERVAL_MS		20
46 #define FSM_MD_EX_REC_OK_TIMEOUT_MS		10000
47 #define FSM_MD_EX_PASS_TIMEOUT_MS		45000
48 #define FSM_CMD_TIMEOUT_MS			2000
49 
50 #define wait_for_expected_dev_stage(status)	\
51 	read_poll_timeout(ioread32, status,	\
52 			  ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LINUX) ||	\
53 			  ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LK), 100000,	\
54 			  20000000, false, IREG_BASE(md->t7xx_dev) +	\
55 			  T7XX_PCIE_MISC_DEV_STATUS)
56 
57 void t7xx_fsm_notifier_register(struct t7xx_modem *md, struct t7xx_fsm_notifier *notifier)
58 {
59 	struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
60 	unsigned long flags;
61 
62 	spin_lock_irqsave(&ctl->notifier_lock, flags);
63 	list_add_tail(&notifier->entry, &ctl->notifier_list);
64 	spin_unlock_irqrestore(&ctl->notifier_lock, flags);
65 }
66 
67 void t7xx_fsm_notifier_unregister(struct t7xx_modem *md, struct t7xx_fsm_notifier *notifier)
68 {
69 	struct t7xx_fsm_notifier *notifier_cur, *notifier_next;
70 	struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
71 	unsigned long flags;
72 
73 	spin_lock_irqsave(&ctl->notifier_lock, flags);
74 	list_for_each_entry_safe(notifier_cur, notifier_next, &ctl->notifier_list, entry) {
75 		if (notifier_cur == notifier)
76 			list_del(&notifier->entry);
77 	}
78 	spin_unlock_irqrestore(&ctl->notifier_lock, flags);
79 }
80 
81 static void fsm_state_notify(struct t7xx_modem *md, enum md_state state)
82 {
83 	struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
84 	struct t7xx_fsm_notifier *notifier;
85 	unsigned long flags;
86 
87 	spin_lock_irqsave(&ctl->notifier_lock, flags);
88 	list_for_each_entry(notifier, &ctl->notifier_list, entry) {
89 		spin_unlock_irqrestore(&ctl->notifier_lock, flags);
90 		if (notifier->notifier_fn)
91 			notifier->notifier_fn(state, notifier->data);
92 
93 		spin_lock_irqsave(&ctl->notifier_lock, flags);
94 	}
95 	spin_unlock_irqrestore(&ctl->notifier_lock, flags);
96 }
97 
98 void t7xx_fsm_broadcast_state(struct t7xx_fsm_ctl *ctl, enum md_state state)
99 {
100 	ctl->md_state = state;
101 
102 	/* Update to port first, otherwise sending message on HS2 may fail */
103 	t7xx_port_proxy_md_status_notify(ctl->md->port_prox, state);
104 	fsm_state_notify(ctl->md, state);
105 }
106 
107 static void fsm_finish_command(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd, int result)
108 {
109 	if (cmd->flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
110 		*cmd->ret = result;
111 		complete_all(cmd->done);
112 	}
113 
114 	kfree(cmd);
115 }
116 
117 static void fsm_del_kf_event(struct t7xx_fsm_event *event)
118 {
119 	list_del(&event->entry);
120 	kfree(event);
121 }
122 
123 static void fsm_flush_event_cmd_qs(struct t7xx_fsm_ctl *ctl)
124 {
125 	struct device *dev = &ctl->md->t7xx_dev->pdev->dev;
126 	struct t7xx_fsm_event *event, *evt_next;
127 	struct t7xx_fsm_command *cmd, *cmd_next;
128 	unsigned long flags;
129 
130 	spin_lock_irqsave(&ctl->command_lock, flags);
131 	list_for_each_entry_safe(cmd, cmd_next, &ctl->command_queue, entry) {
132 		dev_warn(dev, "Unhandled command %d\n", cmd->cmd_id);
133 		list_del(&cmd->entry);
134 		fsm_finish_command(ctl, cmd, -EINVAL);
135 	}
136 	spin_unlock_irqrestore(&ctl->command_lock, flags);
137 
138 	spin_lock_irqsave(&ctl->event_lock, flags);
139 	list_for_each_entry_safe(event, evt_next, &ctl->event_queue, entry) {
140 		dev_warn(dev, "Unhandled event %d\n", event->event_id);
141 		fsm_del_kf_event(event);
142 	}
143 	spin_unlock_irqrestore(&ctl->event_lock, flags);
144 }
145 
146 static void fsm_wait_for_event(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_event_state event_expected,
147 			       enum t7xx_fsm_event_state event_ignore, int retries)
148 {
149 	struct t7xx_fsm_event *event;
150 	bool event_received = false;
151 	unsigned long flags;
152 	int cnt = 0;
153 
154 	while (cnt++ < retries && !event_received) {
155 		bool sleep_required = true;
156 
157 		if (kthread_should_stop())
158 			return;
159 
160 		spin_lock_irqsave(&ctl->event_lock, flags);
161 		event = list_first_entry_or_null(&ctl->event_queue, struct t7xx_fsm_event, entry);
162 		if (event) {
163 			event_received = event->event_id == event_expected;
164 			if (event_received || event->event_id == event_ignore) {
165 				fsm_del_kf_event(event);
166 				sleep_required = false;
167 			}
168 		}
169 		spin_unlock_irqrestore(&ctl->event_lock, flags);
170 
171 		if (sleep_required)
172 			msleep(FSM_EVENT_POLL_INTERVAL_MS);
173 	}
174 }
175 
176 static void fsm_routine_exception(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd,
177 				  enum t7xx_ex_reason reason)
178 {
179 	struct device *dev = &ctl->md->t7xx_dev->pdev->dev;
180 
181 	if (ctl->curr_state != FSM_STATE_READY && ctl->curr_state != FSM_STATE_STARTING) {
182 		if (cmd)
183 			fsm_finish_command(ctl, cmd, -EINVAL);
184 
185 		return;
186 	}
187 
188 	ctl->curr_state = FSM_STATE_EXCEPTION;
189 
190 	switch (reason) {
191 	case EXCEPTION_HS_TIMEOUT:
192 		dev_err(dev, "Boot Handshake failure\n");
193 		break;
194 
195 	case EXCEPTION_EVENT:
196 		dev_err(dev, "Exception event\n");
197 		t7xx_fsm_broadcast_state(ctl, MD_STATE_EXCEPTION);
198 		t7xx_pci_pm_exp_detected(ctl->md->t7xx_dev);
199 		t7xx_md_exception_handshake(ctl->md);
200 
201 		fsm_wait_for_event(ctl, FSM_EVENT_MD_EX_REC_OK, FSM_EVENT_MD_EX,
202 				   FSM_MD_EX_REC_OK_TIMEOUT_MS / FSM_EVENT_POLL_INTERVAL_MS);
203 		fsm_wait_for_event(ctl, FSM_EVENT_MD_EX_PASS, FSM_EVENT_INVALID,
204 				   FSM_MD_EX_PASS_TIMEOUT_MS / FSM_EVENT_POLL_INTERVAL_MS);
205 		break;
206 
207 	default:
208 		dev_err(dev, "Exception %d\n", reason);
209 		break;
210 	}
211 
212 	if (cmd)
213 		fsm_finish_command(ctl, cmd, 0);
214 }
215 
216 static void t7xx_host_event_notify(struct t7xx_modem *md, unsigned int event_id)
217 {
218 	u32 value;
219 
220 	value = ioread32(IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS);
221 	value &= ~HOST_EVENT_MASK;
222 	value |= FIELD_PREP(HOST_EVENT_MASK, event_id);
223 	iowrite32(value, IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS);
224 }
225 
226 static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int status)
227 {
228 	struct t7xx_modem *md = ctl->md;
229 	struct cldma_ctrl *md_ctrl;
230 	enum lk_event_id lk_event;
231 	struct device *dev;
232 	struct t7xx_port *port;
233 
234 	dev = &md->t7xx_dev->pdev->dev;
235 	lk_event = FIELD_GET(MISC_LK_EVENT_MASK, status);
236 	switch (lk_event) {
237 	case LK_EVENT_NORMAL:
238 	case LK_EVENT_RESET:
239 		break;
240 
241 	case LK_EVENT_CREATE_PD_PORT:
242 	case LK_EVENT_CREATE_POST_DL_PORT:
243 		md_ctrl = md->md_ctrl[CLDMA_ID_AP];
244 		t7xx_cldma_hif_hw_init(md_ctrl);
245 		t7xx_cldma_stop(md_ctrl);
246 		t7xx_cldma_switch_cfg(md_ctrl, CLDMA_DEDICATED_Q_CFG);
247 
248 		port = &ctl->md->port_prox->ports[0];
249 		port->port_conf->ops->enable_chl(port);
250 
251 		t7xx_cldma_start(md_ctrl);
252 
253 		if (lk_event == LK_EVENT_CREATE_POST_DL_PORT)
254 			t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DOWNLOAD);
255 		else
256 			t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DUMP);
257 		break;
258 
259 	default:
260 		dev_err(dev, "Invalid LK event %d\n", lk_event);
261 		break;
262 	}
263 }
264 
265 static int fsm_stopped_handler(struct t7xx_fsm_ctl *ctl)
266 {
267 	ctl->curr_state = FSM_STATE_STOPPED;
268 
269 	t7xx_fsm_broadcast_state(ctl, MD_STATE_STOPPED);
270 	return t7xx_md_reset(ctl->md->t7xx_dev);
271 }
272 
273 static void fsm_routine_stopped(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd)
274 {
275 	if (ctl->curr_state == FSM_STATE_STOPPED) {
276 		fsm_finish_command(ctl, cmd, -EINVAL);
277 		return;
278 	}
279 
280 	fsm_finish_command(ctl, cmd, fsm_stopped_handler(ctl));
281 }
282 
283 static void fsm_routine_stopping(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd)
284 {
285 	struct cldma_ctrl *md_ctrl = ctl->md->md_ctrl[CLDMA_ID_MD];
286 	struct t7xx_pci_dev *t7xx_dev = ctl->md->t7xx_dev;
287 	enum t7xx_mode mode = READ_ONCE(t7xx_dev->mode);
288 	int err;
289 
290 	if (ctl->curr_state == FSM_STATE_STOPPED || ctl->curr_state == FSM_STATE_STOPPING) {
291 		fsm_finish_command(ctl, cmd, -EINVAL);
292 		return;
293 	}
294 
295 	ctl->curr_state = FSM_STATE_STOPPING;
296 	t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_TO_STOP);
297 	t7xx_cldma_stop(md_ctrl);
298 
299 	if (mode == T7XX_FASTBOOT_SWITCHING)
300 		t7xx_host_event_notify(ctl->md, FASTBOOT_DL_NOTIFY);
301 
302 	t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DRM_DISABLE_AP);
303 	/* Wait for the DRM disable to take effect */
304 	msleep(FSM_DRM_DISABLE_DELAY_MS);
305 
306 	if (mode == T7XX_FASTBOOT_SWITCHING) {
307 		t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET);
308 	} else {
309 		err = t7xx_acpi_fldr_func(t7xx_dev);
310 		if (err)
311 			t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET);
312 	}
313 
314 	fsm_finish_command(ctl, cmd, fsm_stopped_handler(ctl));
315 }
316 
317 static void t7xx_fsm_broadcast_ready_state(struct t7xx_fsm_ctl *ctl)
318 {
319 	if (ctl->md_state != MD_STATE_WAITING_FOR_HS2)
320 		return;
321 
322 	ctl->md_state = MD_STATE_READY;
323 
324 	fsm_state_notify(ctl->md, MD_STATE_READY);
325 	t7xx_port_proxy_md_status_notify(ctl->md->port_prox, MD_STATE_READY);
326 }
327 
328 static void fsm_routine_ready(struct t7xx_fsm_ctl *ctl)
329 {
330 	struct t7xx_modem *md = ctl->md;
331 
332 	ctl->curr_state = FSM_STATE_READY;
333 	t7xx_fsm_broadcast_ready_state(ctl);
334 	t7xx_mode_update(md->t7xx_dev, T7XX_READY);
335 	t7xx_md_event_notify(md, FSM_READY);
336 }
337 
338 static int fsm_routine_starting(struct t7xx_fsm_ctl *ctl)
339 {
340 	struct t7xx_modem *md = ctl->md;
341 	struct device *dev;
342 
343 	ctl->curr_state = FSM_STATE_STARTING;
344 
345 	t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_FOR_HS1);
346 	t7xx_md_event_notify(md, FSM_START);
347 
348 	wait_event_interruptible_timeout(ctl->async_hk_wq,
349 					 (md->core_md.ready && md->core_ap.ready) ||
350 					  ctl->exp_flg, HZ * 60);
351 	dev = &md->t7xx_dev->pdev->dev;
352 
353 	if (ctl->exp_flg)
354 		dev_err(dev, "MD exception is captured during handshake\n");
355 
356 	if (!md->core_md.ready) {
357 		dev_err(dev, "MD handshake timeout\n");
358 		if (md->core_md.handshake_ongoing)
359 			t7xx_fsm_append_event(ctl, FSM_EVENT_MD_HS2_EXIT, NULL, 0);
360 
361 		fsm_routine_exception(ctl, NULL, EXCEPTION_HS_TIMEOUT);
362 		return -ETIMEDOUT;
363 	} else if (!md->core_ap.ready) {
364 		dev_err(dev, "AP handshake timeout\n");
365 		if (md->core_ap.handshake_ongoing)
366 			t7xx_fsm_append_event(ctl, FSM_EVENT_AP_HS2_EXIT, NULL, 0);
367 
368 		fsm_routine_exception(ctl, NULL, EXCEPTION_HS_TIMEOUT);
369 		return -ETIMEDOUT;
370 	}
371 
372 	t7xx_pci_pm_init_late(md->t7xx_dev);
373 	fsm_routine_ready(ctl);
374 	return 0;
375 }
376 
377 static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd)
378 {
379 	struct t7xx_modem *md = ctl->md;
380 	struct device *dev;
381 	u32 status;
382 	int ret;
383 
384 	if (!md)
385 		return;
386 
387 	if (ctl->curr_state != FSM_STATE_INIT && ctl->curr_state != FSM_STATE_PRE_START &&
388 	    ctl->curr_state != FSM_STATE_STOPPED) {
389 		fsm_finish_command(ctl, cmd, -EINVAL);
390 		return;
391 	}
392 
393 	dev = &md->t7xx_dev->pdev->dev;
394 	ctl->curr_state = FSM_STATE_PRE_START;
395 	t7xx_md_event_notify(md, FSM_PRE_START);
396 
397 	ret = wait_for_expected_dev_stage(status);
398 
399 	if (ret) {
400 		dev_err(dev, "read poll timeout %d\n", ret);
401 		goto finish_command;
402 	}
403 
404 	if (status != ctl->status || cmd->flag != 0) {
405 		u32 stage = FIELD_GET(MISC_STAGE_MASK, status);
406 
407 		switch (stage) {
408 		case T7XX_DEV_STAGE_INIT:
409 		case T7XX_DEV_STAGE_BROM_PRE:
410 		case T7XX_DEV_STAGE_BROM_POST:
411 			dev_dbg(dev, "BROM_STAGE Entered\n");
412 			ret = t7xx_fsm_append_cmd(ctl, FSM_CMD_START, 0);
413 			break;
414 
415 		case T7XX_DEV_STAGE_LK:
416 			dev_dbg(dev, "LK_STAGE Entered\n");
417 			t7xx_lk_stage_event_handling(ctl, status);
418 			break;
419 
420 		case T7XX_DEV_STAGE_LINUX:
421 			dev_dbg(dev, "LINUX_STAGE Entered\n");
422 			t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM |
423 					     D2H_INT_ASYNC_MD_HK | D2H_INT_ASYNC_AP_HK);
424 			if (cmd->flag == 0)
425 				break;
426 			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]);
427 			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]);
428 			t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_NORMAL);
429 			ret = fsm_routine_starting(ctl);
430 			break;
431 
432 		default:
433 			break;
434 		}
435 		ctl->status = status;
436 	}
437 
438 finish_command:
439 	fsm_finish_command(ctl, cmd, ret);
440 }
441 
442 static int fsm_main_thread(void *data)
443 {
444 	struct t7xx_fsm_ctl *ctl = data;
445 	struct t7xx_fsm_command *cmd;
446 	unsigned long flags;
447 
448 	while (!kthread_should_stop()) {
449 		if (wait_event_interruptible(ctl->command_wq, !list_empty(&ctl->command_queue) ||
450 					     kthread_should_stop()))
451 			continue;
452 
453 		if (kthread_should_stop())
454 			break;
455 
456 		spin_lock_irqsave(&ctl->command_lock, flags);
457 		cmd = list_first_entry(&ctl->command_queue, struct t7xx_fsm_command, entry);
458 		list_del(&cmd->entry);
459 		spin_unlock_irqrestore(&ctl->command_lock, flags);
460 
461 		switch (cmd->cmd_id) {
462 		case FSM_CMD_START:
463 			fsm_routine_start(ctl, cmd);
464 			break;
465 
466 		case FSM_CMD_EXCEPTION:
467 			fsm_routine_exception(ctl, cmd, FIELD_GET(FSM_CMD_EX_REASON, cmd->flag));
468 			break;
469 
470 		case FSM_CMD_PRE_STOP:
471 			fsm_routine_stopping(ctl, cmd);
472 			break;
473 
474 		case FSM_CMD_STOP:
475 			fsm_routine_stopped(ctl, cmd);
476 			break;
477 
478 		default:
479 			fsm_finish_command(ctl, cmd, -EINVAL);
480 			fsm_flush_event_cmd_qs(ctl);
481 			break;
482 		}
483 	}
484 
485 	return 0;
486 }
487 
488 int t7xx_fsm_append_cmd(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_cmd_state cmd_id, unsigned int flag)
489 {
490 	DECLARE_COMPLETION_ONSTACK(done);
491 	struct t7xx_fsm_command *cmd;
492 	unsigned long flags;
493 	int ret;
494 
495 	cmd = kzalloc(sizeof(*cmd), flag & FSM_CMD_FLAG_IN_INTERRUPT ? GFP_ATOMIC : GFP_KERNEL);
496 	if (!cmd)
497 		return -ENOMEM;
498 
499 	INIT_LIST_HEAD(&cmd->entry);
500 	cmd->cmd_id = cmd_id;
501 	cmd->flag = flag;
502 	if (flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
503 		cmd->done = &done;
504 		cmd->ret = &ret;
505 	}
506 
507 	spin_lock_irqsave(&ctl->command_lock, flags);
508 	list_add_tail(&cmd->entry, &ctl->command_queue);
509 	spin_unlock_irqrestore(&ctl->command_lock, flags);
510 
511 	wake_up(&ctl->command_wq);
512 
513 	if (flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
514 		unsigned long wait_ret;
515 
516 		wait_ret = wait_for_completion_timeout(&done,
517 						       msecs_to_jiffies(FSM_CMD_TIMEOUT_MS));
518 		if (!wait_ret)
519 			return -ETIMEDOUT;
520 
521 		return ret;
522 	}
523 
524 	return 0;
525 }
526 
527 int t7xx_fsm_append_event(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_event_state event_id,
528 			  unsigned char *data, unsigned int length)
529 {
530 	struct device *dev = &ctl->md->t7xx_dev->pdev->dev;
531 	struct t7xx_fsm_event *event;
532 	unsigned long flags;
533 
534 	if (event_id <= FSM_EVENT_INVALID || event_id >= FSM_EVENT_MAX) {
535 		dev_err(dev, "Invalid event %d\n", event_id);
536 		return -EINVAL;
537 	}
538 
539 	event = kmalloc(struct_size(event, data, length),
540 			in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
541 	if (!event)
542 		return -ENOMEM;
543 
544 	INIT_LIST_HEAD(&event->entry);
545 	event->event_id = event_id;
546 	event->length = length;
547 
548 	if (data && length)
549 		memcpy(event->data, data, length);
550 
551 	spin_lock_irqsave(&ctl->event_lock, flags);
552 	list_add_tail(&event->entry, &ctl->event_queue);
553 	spin_unlock_irqrestore(&ctl->event_lock, flags);
554 
555 	wake_up_all(&ctl->event_wq);
556 	return 0;
557 }
558 
559 void t7xx_fsm_clr_event(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_event_state event_id)
560 {
561 	struct t7xx_fsm_event *event, *evt_next;
562 	unsigned long flags;
563 
564 	spin_lock_irqsave(&ctl->event_lock, flags);
565 	list_for_each_entry_safe(event, evt_next, &ctl->event_queue, entry) {
566 		if (event->event_id == event_id)
567 			fsm_del_kf_event(event);
568 	}
569 	spin_unlock_irqrestore(&ctl->event_lock, flags);
570 }
571 
572 enum md_state t7xx_fsm_get_md_state(struct t7xx_fsm_ctl *ctl)
573 {
574 	if (ctl)
575 		return ctl->md_state;
576 
577 	return MD_STATE_INVALID;
578 }
579 
580 unsigned int t7xx_fsm_get_ctl_state(struct t7xx_fsm_ctl *ctl)
581 {
582 	if (ctl)
583 		return ctl->curr_state;
584 
585 	return FSM_STATE_STOPPED;
586 }
587 
588 int t7xx_fsm_recv_md_intr(struct t7xx_fsm_ctl *ctl, enum t7xx_md_irq_type type)
589 {
590 	unsigned int cmd_flags = FSM_CMD_FLAG_IN_INTERRUPT;
591 
592 	if (type == MD_IRQ_PORT_ENUM) {
593 		return t7xx_fsm_append_cmd(ctl, FSM_CMD_START, cmd_flags);
594 	} else if (type == MD_IRQ_CCIF_EX) {
595 		ctl->exp_flg = true;
596 		wake_up(&ctl->async_hk_wq);
597 		cmd_flags |= FIELD_PREP(FSM_CMD_EX_REASON, EXCEPTION_EVENT);
598 		return t7xx_fsm_append_cmd(ctl, FSM_CMD_EXCEPTION, cmd_flags);
599 	}
600 
601 	return -EINVAL;
602 }
603 
604 void t7xx_fsm_reset(struct t7xx_modem *md)
605 {
606 	struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
607 
608 	fsm_flush_event_cmd_qs(ctl);
609 	ctl->curr_state = FSM_STATE_STOPPED;
610 	ctl->exp_flg = false;
611 	ctl->status = T7XX_DEV_STAGE_INIT;
612 }
613 
614 int t7xx_fsm_init(struct t7xx_modem *md)
615 {
616 	struct device *dev = &md->t7xx_dev->pdev->dev;
617 	struct t7xx_fsm_ctl *ctl;
618 
619 	ctl = devm_kzalloc(dev, sizeof(*ctl), GFP_KERNEL);
620 	if (!ctl)
621 		return -ENOMEM;
622 
623 	md->fsm_ctl = ctl;
624 	ctl->md = md;
625 	ctl->curr_state = FSM_STATE_INIT;
626 	INIT_LIST_HEAD(&ctl->command_queue);
627 	INIT_LIST_HEAD(&ctl->event_queue);
628 	init_waitqueue_head(&ctl->async_hk_wq);
629 	init_waitqueue_head(&ctl->event_wq);
630 	INIT_LIST_HEAD(&ctl->notifier_list);
631 	init_waitqueue_head(&ctl->command_wq);
632 	spin_lock_init(&ctl->event_lock);
633 	spin_lock_init(&ctl->command_lock);
634 	ctl->exp_flg = false;
635 	spin_lock_init(&ctl->notifier_lock);
636 
637 	ctl->fsm_thread = kthread_run(fsm_main_thread, ctl, "t7xx_fsm");
638 	return PTR_ERR_OR_ZERO(ctl->fsm_thread);
639 }
640 
641 void t7xx_fsm_uninit(struct t7xx_modem *md)
642 {
643 	struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
644 
645 	if (!ctl)
646 		return;
647 
648 	if (ctl->fsm_thread)
649 		kthread_stop(ctl->fsm_thread);
650 
651 	fsm_flush_event_cmd_qs(ctl);
652 }
653