blob: a126185bb82f8ff01ed384bae96e26579938111c [file] [log] [blame]
developere5e687d2023-08-08 16:05:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Alvin Kuo <alvin.kuog@mediatek.com>
6 */
7
8#include <linux/err.h>
9#include <linux/workqueue.h>
10#include <linux/netdevice.h>
11#include <linux/rtnetlink.h>
12
13#include "internal.h"
14#include "net-event.h"
15#include "ser.h"
16#include "trm.h"
17
18struct tops_ser {
19 struct work_struct work;
20 struct tops_ser_params ser_params;
21 spinlock_t params_lock;
22};
23
24struct tops_ser tops_ser;
25
26static inline void __mtk_tops_ser_cmd_clear(void)
27{
28 memset(&tops_ser.ser_params, 0, sizeof(struct tops_ser_params));
29 tops_ser.ser_params.type = __TOPS_SER_TYPE_MAX;
30}
31
32static inline void mtk_tops_ser_cmd_clear(void)
33{
34 unsigned long flag;
35
36 spin_lock_irqsave(&tops_ser.params_lock, flag);
37
38 __mtk_tops_ser_cmd_clear();
39
40 spin_unlock_irqrestore(&tops_ser.params_lock, flag);
41}
42
43static void mtk_tops_ser_setup_mcmd(struct tops_ser_params *ser_params,
44 struct mcu_ctrl_cmd *mcmd)
45{
46 memset(mcmd, 0, sizeof(struct mcu_ctrl_cmd));
47
48 switch (ser_params->type) {
49 case TOPS_SER_NETSYS_FE_RST:
50 mcmd->e = MCU_EVENT_TYPE_FE_RESET;
51 break;
52 case TOPS_SER_WDT_TO:
53 mcmd->e = MCU_EVENT_TYPE_WDT_TIMEOUT;
54 break;
55 default:
56 TOPS_ERR("unsupport TOPS SER type: %u\n", ser_params->type);
57 return;
58 }
59
60 if (ser_params->ser_mcmd_setup)
61 ser_params->ser_mcmd_setup(ser_params, mcmd);
62}
63
64static void mtk_tops_ser_reset_callback(void *params)
65{
66 struct tops_ser_params *ser_params = params;
67
68 if (ser_params->ser_callback)
69 ser_params->ser_callback(ser_params);
70}
71
72static void mtk_tops_ser_work(struct work_struct *work)
73{
74 struct tops_ser_params ser_params;
75 struct mcu_ctrl_cmd mcmd;
76 unsigned long flag = 0;
77
78 spin_lock_irqsave(&tops_ser.params_lock, flag);
79
80 while (tops_ser.ser_params.type != __TOPS_SER_TYPE_MAX) {
81 memcpy(&ser_params,
82 &tops_ser.ser_params,
83 sizeof(struct tops_ser_params));
84
85 spin_unlock_irqrestore(&tops_ser.params_lock, flag);
86
87 mtk_tops_ser_setup_mcmd(&ser_params, &mcmd);
88
89 if (mtk_tops_mcu_reset(&mcmd,
90 mtk_tops_ser_reset_callback,
91 &ser_params)) {
92 TOPS_INFO("SER type: %u failed to recover\n",
93 ser_params.type);
94 /*
95 * TODO: check is OK to directly return
96 * since mcu state machine should handle
97 * state transition failed?
98 */
99 mtk_tops_ser_cmd_clear();
100 return;
101 }
102
103 TOPS_INFO("SER type: %u successfully recovered\n", ser_params.type);
104
105 spin_lock_irqsave(&tops_ser.params_lock, flag);
106 /*
107 * If there isn't queued any other SER cmd that has higher priority
108 * than current SER command, clear SER command and exit.
109 * Otherwise let the work perform reset again for high priority SER.
110 */
111 if (tops_ser.ser_params.type > ser_params.type
112 || !memcmp(&tops_ser.ser_params, &ser_params,
113 sizeof(struct tops_ser_params)))
114 __mtk_tops_ser_cmd_clear();
115 }
116
117 spin_unlock_irqrestore(&tops_ser.params_lock, flag);
118}
119
120int mtk_tops_ser(struct tops_ser_params *ser_params)
121{
122 unsigned long flag;
123
124 if (!ser_params)
125 return -EINVAL;
126
127 spin_lock_irqsave(&tops_ser.params_lock, flag);
128
129 /* higher SER type should not override lower SER type */
130 if (tops_ser.ser_params.type != __TOPS_SER_TYPE_MAX
131 && tops_ser.ser_params.type < ser_params->type)
132 goto unlock;
133
134 memcpy(&tops_ser.ser_params, ser_params, sizeof(*ser_params));
135
136 schedule_work(&tops_ser.work);
137
138unlock:
139 spin_unlock_irqrestore(&tops_ser.params_lock, flag);
140
141 return 0;
142}
143
144int mtk_tops_ser_init(struct platform_device *pdev)
145{
146 INIT_WORK(&tops_ser.work, mtk_tops_ser_work);
147
148 spin_lock_init(&tops_ser.params_lock);
149
150 tops_ser.ser_params.type = __TOPS_SER_TYPE_MAX;
151
152 return 0;
153}
154
155int mtk_tops_ser_deinit(struct platform_device *pdev)
156{
157 return 0;
158}