blob: 847dff80d304e38f50877c97ba5c7141849476cc [file] [log] [blame]
developerf2f1b882023-08-08 16:02:18 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 Mediatek Inc. All Rights Reserved.
4 *
5 * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
6 */
7
8#include <linux/err.h>
9#include <linux/lockdep.h>
10#include <linux/spinlock.h>
11
12#include "pce/cls.h"
13#include "pce/internal.h"
14#include "pce/netsys.h"
15
16struct cls_hw {
17 struct cls_entry *cls_tbl[FE_MEM_CLS_MAX_INDEX];
18 spinlock_t lock;
19};
20
21struct cls_hw cls_hw;
22
23int mtk_pce_cls_enable(void)
24{
25 mtk_pce_netsys_setbits(GLO_MEM_CFG, GDM_CLS_EN);
26
27 return 0;
28}
29
30void mtk_pce_cls_disable(void)
31{
32 mtk_pce_netsys_clrbits(GLO_MEM_CFG, GDM_CLS_EN);
33}
34
35static void mtk_pce_cls_clean_up(void)
36{
37 struct fe_mem_msg msg = {
38 .cmd = FE_MEM_CMD_WRITE,
39 .type = FE_MEM_TYPE_CLS,
40 };
41 unsigned long flag;
42 int ret = 0;
43 u32 i = 0;
44
45 memset(&msg.raw, 0, sizeof(msg.raw));
46
47 spin_lock_irqsave(&cls_hw.lock, flag);
48
49 /* clean up cls table */
50 for (i = 0; i < FE_MEM_CLS_MAX_INDEX; i++) {
51 msg.index = i;
52 ret = mtk_pce_fe_mem_msg_send(&msg);
53 if (ret)
54 goto unlock;
55 }
56
57unlock:
58 spin_unlock_irqrestore(&cls_hw.lock, flag);
59}
60
61int mtk_pce_cls_init(struct platform_device *pdev)
62{
63 spin_lock_init(&cls_hw.lock);
64
65 mtk_pce_cls_clean_up();
66
67 return 0;
68}
69
70void mtk_pce_cls_deinit(struct platform_device *pdev)
71{
72 mtk_pce_cls_clean_up();
73}
74
75/*
76 * Read a cls_desc without checking it is in used or not
77 * cls_hw.lock should be held before calling this function
78 */
79static int __mtk_pce_cls_desc_read(struct cls_desc *cdesc, enum cls_entry_type entry)
80{
81 struct fe_mem_msg msg;
82 int ret;
83
84 lockdep_assert_held(&cls_hw.lock);
85
86 mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_READ, FE_MEM_TYPE_CLS, entry);
87
88 memset(&msg.raw, 0, sizeof(msg.raw));
89
90 ret = mtk_pce_fe_mem_msg_send(&msg);
91 if (ret)
92 return ret;
93
94 memcpy(cdesc, &msg.cdesc, sizeof(struct cls_desc));
95
96 return ret;
97}
98
99/*
100 * Read a cls_desc without checking it is in used or not
101 * This function is only used for debugging purpose
102 */
103int mtk_pce_cls_desc_read(struct cls_desc *cdesc, enum cls_entry_type entry)
104{
105 unsigned long flag;
106 int ret;
107
108 if (unlikely(entry == CLS_ENTRY_NONE || entry >= __CLS_ENTRY_MAX)) {
109 PCE_ERR("invalid cls entry: %u\n", entry);
110 return -EINVAL;
111 }
112
113 spin_lock_irqsave(&cls_hw.lock, flag);
114 ret = __mtk_pce_cls_desc_read(cdesc, entry);
115 spin_unlock_irqrestore(&cls_hw.lock, flag);
116
117 return ret;
118}
119
120/*
121 * Write a cls_desc to an entry without checking the entry is occupied
122 * cls_hw.lock should be held before calling this function
123 */
124static int __mtk_pce_cls_desc_write(struct cls_desc *cdesc,
125 enum cls_entry_type entry)
126{
127 struct fe_mem_msg msg;
128
129 lockdep_assert_held(&cls_hw.lock);
130
131 mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_WRITE, FE_MEM_TYPE_CLS, entry);
132
133 memset(&msg.raw, 0, sizeof(msg.raw));
134 memcpy(&msg.cdesc, cdesc, sizeof(struct cls_desc));
135
136 return mtk_pce_fe_mem_msg_send(&msg);
137}
138
139/*
140 * Write a cls_desc to an entry without checking the entry is used by others.
141 * The user should check the entry is occupied by themselves or use the standard API
142 * mtk_pce_cls_entry_register().
143 *
144 * This function is only used for debugging purpose
145 */
146int mtk_pce_cls_desc_write(struct cls_desc *cdesc, enum cls_entry_type entry)
147{
148 unsigned long flag;
149 int ret;
150
151 if (unlikely(!cdesc))
152 return -EINVAL;
153
154 spin_lock_irqsave(&cls_hw.lock, flag);
155 ret = __mtk_pce_cls_desc_write(cdesc, entry);
156 spin_unlock_irqrestore(&cls_hw.lock, flag);
157
158 return ret;
159}
160
161int mtk_pce_cls_entry_register(struct cls_entry *cls)
162{
163 unsigned long flag;
164 int ret = 0;
165
166 if (unlikely(!cls))
167 return -EINVAL;
168
169 if (unlikely(cls->entry == CLS_ENTRY_NONE || cls->entry >= __CLS_ENTRY_MAX)) {
170 PCE_ERR("invalid cls entry: %u\n", cls->entry);
171 return -EINVAL;
172 }
173
174 spin_lock_irqsave(&cls_hw.lock, flag);
175
176 if (cls_hw.cls_tbl[cls->entry]) {
177 PCE_ERR("cls rules already registered ofr entry: %u\n", cls->entry);
178 ret = -EBUSY;
179 goto unlock;
180 }
181
182 ret = __mtk_pce_cls_desc_write(&cls->cdesc, cls->entry);
183 if (ret) {
184 PCE_NOTICE("send cls message failed: %d\n", ret);
185 goto unlock;
186 }
187
188 cls_hw.cls_tbl[cls->entry] = cls;
189
190unlock:
191 spin_unlock_irqrestore(&cls_hw.lock, flag);
192
193 return ret;
194}
195EXPORT_SYMBOL(mtk_pce_cls_entry_register);
196
197void mtk_pce_cls_entry_unregister(struct cls_entry *cls)
198{
199 struct cls_desc cdesc;
200 unsigned long flag;
201 int ret = 0;
202
203 if (unlikely(!cls))
204 return;
205
206 if (unlikely(cls->entry == CLS_ENTRY_NONE || cls->entry >= __CLS_ENTRY_MAX)) {
207 PCE_ERR("invalid cls entry: %u\n", cls->entry);
208 return;
209 }
210
211 spin_lock_irqsave(&cls_hw.lock, flag);
212
213 if (cls_hw.cls_tbl[cls->entry] != cls) {
214 PCE_ERR("cls rules is registered by others\n");
215 goto unlock;
216 }
217
218 memset(&cdesc, 0, sizeof(struct cls_desc));
219
220 ret = __mtk_pce_cls_desc_write(&cdesc, cls->entry);
221 if (ret) {
222 PCE_NOTICE("fe send cls message failed: %d\n", ret);
223 goto unlock;
224 }
225
226 cls_hw.cls_tbl[cls->entry] = NULL;
227
228unlock:
229 spin_unlock_irqrestore(&cls_hw.lock, flag);
230}
231EXPORT_SYMBOL(mtk_pce_cls_entry_unregister);