blob: c10e7ed227bfd4162b223fd09df2d7374539fb1f [file] [log] [blame]
developerfd40db22021-04-29 10:08:25 +08001/* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License as published by
3 * the Free Software Foundation; version 2 of the License
4 *
5 * This program is distributed in the hope that it will be useful,
6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 * GNU General Public License for more details.
9 *
10 * Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
11 * Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
12 */
13
14#include <linux/dma-mapping.h>
15#include <linux/delay.h>
16#include <linux/if.h>
17#include <linux/io.h>
18#include <linux/module.h>
19#include <linux/of_device.h>
20#include <linux/platform_device.h>
21#include <linux/reset.h>
developer731b98f2021-09-17 17:44:37 +080022#include <linux/rtnetlink.h>
23#include <net/netlink.h>
developerfd40db22021-04-29 10:08:25 +080024
25#include "nf_hnat_mtk.h"
26#include "hnat.h"
27
28struct mtk_hnat *hnat_priv;
developer731b98f2021-09-17 17:44:37 +080029static struct socket *_hnat_roam_sock;
30static struct work_struct _hnat_roam_work;
developerfd40db22021-04-29 10:08:25 +080031
32int (*ra_sw_nat_hook_rx)(struct sk_buff *skb) = NULL;
33EXPORT_SYMBOL(ra_sw_nat_hook_rx);
34int (*ra_sw_nat_hook_tx)(struct sk_buff *skb, int gmac_no) = NULL;
35EXPORT_SYMBOL(ra_sw_nat_hook_tx);
36
37void (*ppe_dev_register_hook)(struct net_device *dev) = NULL;
38EXPORT_SYMBOL(ppe_dev_register_hook);
39void (*ppe_dev_unregister_hook)(struct net_device *dev) = NULL;
40EXPORT_SYMBOL(ppe_dev_unregister_hook);
41
42static void hnat_sma_build_entry(struct timer_list *t)
43{
developer471f6562021-05-10 20:48:34 +080044 int i;
45
46 for (i = 0; i < CFG_PPE_NUM; i++)
47 cr_set_field(hnat_priv->ppe_base[i] + PPE_TB_CFG,
48 SMA, SMA_FWD_CPU_BUILD_ENTRY);
developerfd40db22021-04-29 10:08:25 +080049}
50
51void hnat_cache_ebl(int enable)
52{
developer471f6562021-05-10 20:48:34 +080053 int i;
54
55 for (i = 0; i < CFG_PPE_NUM; i++) {
56 cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_X_MODE, 1);
57 cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_X_MODE, 0);
58 cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_EN, enable);
59 }
developerfd40db22021-04-29 10:08:25 +080060}
61
62static void hnat_reset_timestamp(struct timer_list *t)
63{
64 struct foe_entry *entry;
65 int hash_index;
66
67 hnat_cache_ebl(0);
developer471f6562021-05-10 20:48:34 +080068 cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, TCP_AGE, 0);
69 cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, UDP_AGE, 0);
developerfd40db22021-04-29 10:08:25 +080070 writel(0, hnat_priv->fe_base + 0x0010);
71
72 for (hash_index = 0; hash_index < hnat_priv->foe_etry_num; hash_index++) {
developer471f6562021-05-10 20:48:34 +080073 entry = hnat_priv->foe_table_cpu[0] + hash_index;
developerfd40db22021-04-29 10:08:25 +080074 if (entry->bfib1.state == BIND)
75 entry->bfib1.time_stamp =
76 readl(hnat_priv->fe_base + 0x0010) & (0xFFFF);
77 }
78
developer471f6562021-05-10 20:48:34 +080079 cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, TCP_AGE, 1);
80 cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, UDP_AGE, 1);
developerfd40db22021-04-29 10:08:25 +080081 hnat_cache_ebl(1);
82
83 mod_timer(&hnat_priv->hnat_reset_timestamp_timer, jiffies + 14400 * HZ);
84}
85
86static void cr_set_bits(void __iomem *reg, u32 bs)
87{
88 u32 val = readl(reg);
89
90 val |= bs;
91 writel(val, reg);
92}
93
94static void cr_clr_bits(void __iomem *reg, u32 bs)
95{
96 u32 val = readl(reg);
97
98 val &= ~bs;
99 writel(val, reg);
100}
101
102void cr_set_field(void __iomem *reg, u32 field, u32 val)
103{
104 unsigned int tv = readl(reg);
105
106 tv &= ~field;
107 tv |= ((val) << (ffs((unsigned int)field) - 1));
108 writel(tv, reg);
109}
110
111/*boundary entry can't be used to accelerate data flow*/
112static void exclude_boundary_entry(struct foe_entry *foe_table_cpu)
113{
114 int entry_base = 0;
115 int bad_entry, i, j;
116 struct foe_entry *foe_entry;
117 /*these entries are boundary every 128 entries*/
118 int boundary_entry_offset[8] = { 12, 25, 38, 51, 76, 89, 102, 115};
119
120 if (!foe_table_cpu)
121 return;
122
123 for (i = 0; entry_base < hnat_priv->foe_etry_num; i++) {
124 /* set boundary entries as static*/
125 for (j = 0; j < 8; j++) {
126 bad_entry = entry_base + boundary_entry_offset[j];
127 foe_entry = &foe_table_cpu[bad_entry];
128 foe_entry->udib1.sta = 1;
129 }
130 entry_base = (i + 1) * 128;
131 }
132}
133
134void set_gmac_ppe_fwd(int id, int enable)
135{
136 void __iomem *reg;
137 u32 val;
138
139 reg = hnat_priv->fe_base + (id ? GDMA2_FWD_CFG : GDMA1_FWD_CFG);
140
141 if (enable) {
142 cr_set_bits(reg, BITS_GDM_ALL_FRC_P_PPE);
143
144 return;
145 }
146
147 /*disabled */
148 val = readl(reg);
149 if ((val & GDM_ALL_FRC_MASK) == BITS_GDM_ALL_FRC_P_PPE)
150 cr_set_field(reg, GDM_ALL_FRC_MASK,
151 BITS_GDM_ALL_FRC_P_CPU_PDMA);
152}
153
developer731b98f2021-09-17 17:44:37 +0800154static int entry_mac_cmp(struct foe_entry *entry, u8 *mac)
155{
developer08c720e2021-11-12 14:18:53 +0800156 int ret = 0;
developer731b98f2021-09-17 17:44:37 +0800157
158 if(IS_IPV4_GRP(entry)) {
159 if(((swab32(entry->ipv4_hnapt.dmac_hi) == *(u32 *)mac) &&
160 (swab16(entry->ipv4_hnapt.dmac_lo) == *(u16 *)&mac[4])) ||
161 ((swab32(entry->ipv4_hnapt.smac_hi) == *(u32 *)mac) &&
162 (swab16(entry->ipv4_hnapt.smac_lo) == *(u16 *)&mac[4])))
163 ret = 1;
164 } else {
165 if(((swab32(entry->ipv6_5t_route.dmac_hi) == *(u32 *)mac) &&
166 (swab16(entry->ipv6_5t_route.dmac_lo) == *(u16 *)&mac[4])) ||
167 ((swab32(entry->ipv6_5t_route.smac_hi) == *(u32 *)mac) &&
168 (swab16(entry->ipv6_5t_route.smac_lo) == *(u16 *)&mac[4])))
169 ret = 1;
170 }
171
developer08c720e2021-11-12 14:18:53 +0800172 if (ret && debug_level >= 2)
173 pr_info("mac=%pM\n", mac);
developer731b98f2021-09-17 17:44:37 +0800174
175 return ret;
176}
177
178int entry_delete_by_mac(u8 *mac)
179{
180 struct foe_entry *entry = NULL;
181 int index, i, ret = 0;
182
183 for (i = 0; i < CFG_PPE_NUM; i++) {
184 entry = hnat_priv->foe_table_cpu[i];
185 for (index = 0; index < DEF_ETRY_NUM; entry++, index++) {
186 if(entry->bfib1.state == BIND && entry_mac_cmp(entry, mac)) {
187 memset(entry, 0, sizeof(*entry));
188 hnat_cache_ebl(1);
developer08c720e2021-11-12 14:18:53 +0800189 if (debug_level >= 2)
190 pr_info("delete entry idx = %d\n", index);
developer731b98f2021-09-17 17:44:37 +0800191 ret++;
192 }
193 }
194 }
195
196 if(!ret && debug_level >= 2)
197 pr_info("entry not found\n");
198
199 return ret;
200}
201EXPORT_SYMBOL(entry_delete_by_mac);
202
203static void hnat_roam_handler(struct work_struct *work)
204{
205 struct kvec iov;
206 struct msghdr msg;
207 struct nlmsghdr *nlh;
208 struct ndmsg *ndm;
209 struct nlattr *nla;
210 u8 rcv_buf[512];
211 int len;
212
213 if (!_hnat_roam_sock)
214 return;
215
216 iov.iov_base = rcv_buf;
217 iov.iov_len = sizeof(rcv_buf);
218 memset(&msg, 0, sizeof(msg));
219 msg.msg_namelen = sizeof(struct sockaddr_nl);
220
221 len = kernel_recvmsg(_hnat_roam_sock, &msg, &iov, 1, iov.iov_len, 0);
222 if (len <= 0)
223 goto out;
224
225 nlh = (struct nlmsghdr*)rcv_buf;
226 if (!NLMSG_OK(nlh, len) || nlh->nlmsg_type != RTM_NEWNEIGH)
227 goto out;
228
229 len = nlh->nlmsg_len - NLMSG_HDRLEN;
230 ndm = (struct ndmsg *)NLMSG_DATA(nlh);
231 if (ndm->ndm_family != PF_BRIDGE)
232 goto out;
233
234 nla = (struct nlattr *)((u8 *)ndm + sizeof(struct ndmsg));
235 len -= NLMSG_LENGTH(sizeof(struct ndmsg));
236 while (nla_ok(nla, len)) {
237 if (nla_type(nla) == NDA_LLADDR) {
238 entry_delete_by_mac(nla_data(nla));
239 }
240 nla = nla_next(nla, &len);
241 }
242
243out:
244 schedule_work(&_hnat_roam_work);
245}
246
247static int hnat_roaming_enable(void)
248{
249 struct socket *sock = NULL;
250 struct sockaddr_nl addr;
251 int ret;
252
253 INIT_WORK(&_hnat_roam_work, hnat_roam_handler);
254
255 ret = sock_create_kern(&init_net, AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &sock);
256 if (ret < 0)
257 goto out;
258
259 _hnat_roam_sock = sock;
260
261 addr.nl_family = AF_NETLINK;
262 addr.nl_pad = 0;
263 addr.nl_pid = 65534;
264 addr.nl_groups = 1 << (RTNLGRP_NEIGH - 1);
265 ret = kernel_bind(sock, (struct sockaddr *)&addr, sizeof(addr));
266 if (ret < 0)
267 goto out;
268
269 schedule_work(&_hnat_roam_work);
270 pr_info("hnat roaming work enable\n");
271
272 return 0;
273out:
274 if (sock)
275 sock_release(sock);
276
277 return ret;
278}
279
280static void hnat_roaming_disable(void)
281{
282 if (_hnat_roam_sock)
283 sock_release(_hnat_roam_sock);
284 _hnat_roam_sock = NULL;
285 pr_info("hnat roaming work disable\n");
286}
287
developer4c32b7a2021-11-13 16:46:43 +0800288static int hnat_start(u32 ppe_id)
developerfd40db22021-04-29 10:08:25 +0800289{
290 u32 foe_table_sz;
291 u32 foe_mib_tb_sz;
292 int etry_num_cfg;
293
developer4c32b7a2021-11-13 16:46:43 +0800294 if (ppe_id >= CFG_PPE_NUM)
295 return -EINVAL;
296
developerfd40db22021-04-29 10:08:25 +0800297 /* mapp the FOE table */
298 for (etry_num_cfg = DEF_ETRY_NUM_CFG ; etry_num_cfg >= 0 ; etry_num_cfg--, hnat_priv->foe_etry_num /= 2) {
299 foe_table_sz = hnat_priv->foe_etry_num * sizeof(struct foe_entry);
developer471f6562021-05-10 20:48:34 +0800300 hnat_priv->foe_table_cpu[ppe_id] = dma_alloc_coherent(
301 hnat_priv->dev, foe_table_sz,
302 &hnat_priv->foe_table_dev[ppe_id], GFP_KERNEL);
developerfd40db22021-04-29 10:08:25 +0800303
developer471f6562021-05-10 20:48:34 +0800304 if (hnat_priv->foe_table_cpu[ppe_id])
developerfd40db22021-04-29 10:08:25 +0800305 break;
306 }
307
developer471f6562021-05-10 20:48:34 +0800308 if (!hnat_priv->foe_table_cpu[ppe_id])
developerfd40db22021-04-29 10:08:25 +0800309 return -1;
developer471f6562021-05-10 20:48:34 +0800310 dev_info(hnat_priv->dev, "PPE%d entry number = %d\n",
311 ppe_id, hnat_priv->foe_etry_num);
developerfd40db22021-04-29 10:08:25 +0800312
developer471f6562021-05-10 20:48:34 +0800313 writel(hnat_priv->foe_table_dev[ppe_id], hnat_priv->ppe_base[ppe_id] + PPE_TB_BASE);
314 memset(hnat_priv->foe_table_cpu[ppe_id], 0, foe_table_sz);
developerfd40db22021-04-29 10:08:25 +0800315
316 if (hnat_priv->data->version == MTK_HNAT_V1)
developer471f6562021-05-10 20:48:34 +0800317 exclude_boundary_entry(hnat_priv->foe_table_cpu[ppe_id]);
developerfd40db22021-04-29 10:08:25 +0800318
319 if (hnat_priv->data->per_flow_accounting) {
320 foe_mib_tb_sz = hnat_priv->foe_etry_num * sizeof(struct mib_entry);
developer471f6562021-05-10 20:48:34 +0800321 hnat_priv->foe_mib_cpu[ppe_id] =
322 dma_alloc_coherent(hnat_priv->dev, foe_mib_tb_sz,
323 &hnat_priv->foe_mib_dev[ppe_id], GFP_KERNEL);
324 if (!hnat_priv->foe_mib_cpu[ppe_id])
developerfd40db22021-04-29 10:08:25 +0800325 return -1;
developer471f6562021-05-10 20:48:34 +0800326 writel(hnat_priv->foe_mib_dev[ppe_id],
327 hnat_priv->ppe_base[ppe_id] + PPE_MIB_TB_BASE);
328 memset(hnat_priv->foe_mib_cpu[ppe_id], 0, foe_mib_tb_sz);
developerfd40db22021-04-29 10:08:25 +0800329
developer471f6562021-05-10 20:48:34 +0800330 hnat_priv->acct[ppe_id] =
developerfd40db22021-04-29 10:08:25 +0800331 kzalloc(hnat_priv->foe_etry_num * sizeof(struct hnat_accounting),
332 GFP_KERNEL);
developer471f6562021-05-10 20:48:34 +0800333 if (!hnat_priv->acct[ppe_id])
developerfd40db22021-04-29 10:08:25 +0800334 return -1;
335 }
336 /* setup hashing */
developer471f6562021-05-10 20:48:34 +0800337 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TB_ETRY_NUM, etry_num_cfg);
338 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, HASH_MODE, HASH_MODE_1);
339 writel(HASH_SEED_KEY, hnat_priv->ppe_base[ppe_id] + PPE_HASH_SEED);
340 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, XMODE, 0);
341 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TB_ENTRY_SIZE, ENTRY_80B);
342 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, SMA, SMA_FWD_CPU_BUILD_ENTRY);
developerfd40db22021-04-29 10:08:25 +0800343
344 /* set ip proto */
developer471f6562021-05-10 20:48:34 +0800345 writel(0xFFFFFFFF, hnat_priv->ppe_base[ppe_id] + PPE_IP_PROT_CHK);
developerfd40db22021-04-29 10:08:25 +0800346
347 /* setup caching */
348 hnat_cache_ebl(1);
349
350 /* enable FOE */
developer471f6562021-05-10 20:48:34 +0800351 cr_set_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
developerfd40db22021-04-29 10:08:25 +0800352 BIT_UDP_IP4F_NAT_EN | BIT_IPV4_NAT_EN | BIT_IPV4_NAPT_EN |
353 BIT_IPV4_NAT_FRAG_EN | BIT_IPV4_HASH_GREK |
354 BIT_IPV4_DSL_EN | BIT_IPV6_6RD_EN |
355 BIT_IPV6_3T_ROUTE_EN | BIT_IPV6_5T_ROUTE_EN);
356
357 if (hnat_priv->data->version == MTK_HNAT_V4)
developer471f6562021-05-10 20:48:34 +0800358 cr_set_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
developerfd40db22021-04-29 10:08:25 +0800359 BIT_IPV4_MAPE_EN | BIT_IPV4_MAPT_EN);
360
361 /* setup FOE aging */
developer471f6562021-05-10 20:48:34 +0800362 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, NTU_AGE, 1);
363 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UNBD_AGE, 1);
364 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_UNB_AGE, UNB_MNP, 1000);
365 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_UNB_AGE, UNB_DLTA, 3);
366 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TCP_AGE, 1);
367 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UDP_AGE, 1);
368 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, FIN_AGE, 1);
369 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_0, UDP_DLTA, 12);
370 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_0, NTU_DLTA, 1);
371 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_1, FIN_DLTA, 1);
372 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_1, TCP_DLTA, 7);
developerfd40db22021-04-29 10:08:25 +0800373
374 /* setup FOE ka */
developer471f6562021-05-10 20:48:34 +0800375 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, SCAN_MODE, 2);
376 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, KA_CFG, 3);
377 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_KA, KA_T, 1);
378 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_KA, TCP_KA, 1);
379 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_KA, UDP_KA, 1);
380 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_1, NTU_KA, 1);
developerfd40db22021-04-29 10:08:25 +0800381
382 /* setup FOE rate limit */
developer471f6562021-05-10 20:48:34 +0800383 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_0, QURT_LMT, 16383);
384 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_0, HALF_LMT, 16383);
385 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_1, FULL_LMT, 16383);
developerfd40db22021-04-29 10:08:25 +0800386 /* setup binding threshold as 30 packets per second */
developer471f6562021-05-10 20:48:34 +0800387 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BNDR, BIND_RATE, 0x1E);
developerfd40db22021-04-29 10:08:25 +0800388
389 /* setup FOE cf gen */
developer471f6562021-05-10 20:48:34 +0800390 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, PPE_EN, 1);
391 writel(0, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT); /* pdma */
392 /* writel(0x55555555, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT); */ /* qdma */
393 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, TTL0_DRP, 0);
developerfd40db22021-04-29 10:08:25 +0800394
395 if (hnat_priv->data->version == MTK_HNAT_V4) {
developer471f6562021-05-10 20:48:34 +0800396 writel(0xcb777, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT1);
397 writel(0x7f, hnat_priv->ppe_base[ppe_id] + PPE_SBW_CTRL);
developerfd40db22021-04-29 10:08:25 +0800398 }
399
400 /*enable ppe mib counter*/
401 if (hnat_priv->data->per_flow_accounting) {
developer471f6562021-05-10 20:48:34 +0800402 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MIB_CFG, MIB_EN, 1);
403 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MIB_CFG, MIB_READ_CLEAR, 1);
404 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MIB_CAH_CTRL, MIB_CAH_EN, 1);
developerfd40db22021-04-29 10:08:25 +0800405 }
406
407 hnat_priv->g_ppdev = dev_get_by_name(&init_net, hnat_priv->ppd);
developer8c9c0d02021-06-18 16:15:37 +0800408 hnat_priv->g_wandev = dev_get_by_name(&init_net, hnat_priv->wan);
developerfd40db22021-04-29 10:08:25 +0800409
developer471f6562021-05-10 20:48:34 +0800410 dev_info(hnat_priv->dev, "PPE%d hwnat start\n", ppe_id);
developerfd40db22021-04-29 10:08:25 +0800411
412 return 0;
413}
414
developer4c32b7a2021-11-13 16:46:43 +0800415static int ppe_busy_wait(u32 ppe_id)
developerfd40db22021-04-29 10:08:25 +0800416{
417 unsigned long t_start = jiffies;
418 u32 r = 0;
419
developer4c32b7a2021-11-13 16:46:43 +0800420 if (ppe_id >= CFG_PPE_NUM)
421 return -EINVAL;
422
developerfd40db22021-04-29 10:08:25 +0800423 while (1) {
developer471f6562021-05-10 20:48:34 +0800424 r = readl((hnat_priv->ppe_base[ppe_id] + 0x0));
developerfd40db22021-04-29 10:08:25 +0800425 if (!(r & BIT(31)))
426 return 0;
427 if (time_after(jiffies, t_start + HZ))
428 break;
429 usleep_range(10, 20);
430 }
431
432 dev_notice(hnat_priv->dev, "ppe:%s timeout\n", __func__);
433
434 return -1;
435}
436
developer4c32b7a2021-11-13 16:46:43 +0800437static void hnat_stop(u32 ppe_id)
developerfd40db22021-04-29 10:08:25 +0800438{
439 u32 foe_table_sz;
440 u32 foe_mib_tb_sz;
441 struct foe_entry *entry, *end;
442 u32 r1 = 0, r2 = 0;
443
developer4c32b7a2021-11-13 16:46:43 +0800444 if (ppe_id >= CFG_PPE_NUM)
445 return;
446
developerfd40db22021-04-29 10:08:25 +0800447 /* send all traffic back to the DMA engine */
448 set_gmac_ppe_fwd(0, 0);
449 set_gmac_ppe_fwd(1, 0);
450
451 dev_info(hnat_priv->dev, "hwnat stop\n");
452
developer471f6562021-05-10 20:48:34 +0800453 if (hnat_priv->foe_table_cpu[ppe_id]) {
454 entry = hnat_priv->foe_table_cpu[ppe_id];
455 end = hnat_priv->foe_table_cpu[ppe_id] + hnat_priv->foe_etry_num;
developerfd40db22021-04-29 10:08:25 +0800456 while (entry < end) {
457 entry->bfib1.state = INVALID;
458 entry++;
459 }
460 }
461 /* disable caching */
462 hnat_cache_ebl(0);
463
464 /* flush cache has to be ahead of hnat disable --*/
developer471f6562021-05-10 20:48:34 +0800465 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, PPE_EN, 0);
developerfd40db22021-04-29 10:08:25 +0800466
467 /* disable scan mode and keep-alive */
developer471f6562021-05-10 20:48:34 +0800468 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, SCAN_MODE, 0);
469 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, KA_CFG, 0);
developerfd40db22021-04-29 10:08:25 +0800470
developer471f6562021-05-10 20:48:34 +0800471 ppe_busy_wait(ppe_id);
developerfd40db22021-04-29 10:08:25 +0800472
473 /* disable FOE */
developer471f6562021-05-10 20:48:34 +0800474 cr_clr_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
developerfd40db22021-04-29 10:08:25 +0800475 BIT_IPV4_NAPT_EN | BIT_IPV4_NAT_EN | BIT_IPV4_NAT_FRAG_EN |
476 BIT_IPV6_HASH_GREK | BIT_IPV4_DSL_EN |
477 BIT_IPV6_6RD_EN | BIT_IPV6_3T_ROUTE_EN |
478 BIT_IPV6_5T_ROUTE_EN | BIT_FUC_FOE | BIT_FMC_FOE);
479
480 if (hnat_priv->data->version == MTK_HNAT_V4)
developer471f6562021-05-10 20:48:34 +0800481 cr_clr_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
developerfd40db22021-04-29 10:08:25 +0800482 BIT_IPV4_MAPE_EN | BIT_IPV4_MAPT_EN);
483
484 /* disable FOE aging */
developer471f6562021-05-10 20:48:34 +0800485 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, NTU_AGE, 0);
486 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UNBD_AGE, 0);
487 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TCP_AGE, 0);
488 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UDP_AGE, 0);
489 cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, FIN_AGE, 0);
developerfd40db22021-04-29 10:08:25 +0800490
491 r1 = readl(hnat_priv->fe_base + 0x100);
492 r2 = readl(hnat_priv->fe_base + 0x10c);
493
494 dev_info(hnat_priv->dev, "0x100 = 0x%x, 0x10c = 0x%x\n", r1, r2);
495
496 if (((r1 & 0xff00) >> 0x8) >= (r1 & 0xff) ||
497 ((r1 & 0xff00) >> 0x8) >= (r2 & 0xff)) {
498 dev_info(hnat_priv->dev, "reset pse\n");
499 writel(0x1, hnat_priv->fe_base + 0x4);
500 }
501
502 /* free the FOE table */
503 foe_table_sz = hnat_priv->foe_etry_num * sizeof(struct foe_entry);
developer471f6562021-05-10 20:48:34 +0800504 if (hnat_priv->foe_table_cpu[ppe_id])
505 dma_free_coherent(hnat_priv->dev, foe_table_sz,
506 hnat_priv->foe_table_cpu[ppe_id],
507 hnat_priv->foe_table_dev[ppe_id]);
508 writel(0, hnat_priv->ppe_base[ppe_id] + PPE_TB_BASE);
developerfd40db22021-04-29 10:08:25 +0800509
510 if (hnat_priv->data->per_flow_accounting) {
511 foe_mib_tb_sz = hnat_priv->foe_etry_num * sizeof(struct mib_entry);
developer471f6562021-05-10 20:48:34 +0800512 if (hnat_priv->foe_mib_cpu[ppe_id])
developerfd40db22021-04-29 10:08:25 +0800513 dma_free_coherent(hnat_priv->dev, foe_mib_tb_sz,
developer471f6562021-05-10 20:48:34 +0800514 hnat_priv->foe_mib_cpu[ppe_id],
515 hnat_priv->foe_mib_dev[ppe_id]);
516 writel(0, hnat_priv->ppe_base[ppe_id] + PPE_MIB_TB_BASE);
517 kfree(hnat_priv->acct[ppe_id]);
developerfd40db22021-04-29 10:08:25 +0800518 }
519}
520
521static void hnat_release_netdev(void)
522{
523 int i;
524 struct extdev_entry *ext_entry;
525
526 for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
527 ext_entry = hnat_priv->ext_if[i];
528 if (ext_entry->dev)
529 dev_put(ext_entry->dev);
530 ext_if_del(ext_entry);
531 kfree(ext_entry);
532 }
533
534 if (hnat_priv->g_ppdev)
535 dev_put(hnat_priv->g_ppdev);
developer8c9c0d02021-06-18 16:15:37 +0800536
537 if (hnat_priv->g_wandev)
538 dev_put(hnat_priv->g_wandev);
developerfd40db22021-04-29 10:08:25 +0800539}
540
541static struct notifier_block nf_hnat_netdevice_nb __read_mostly = {
542 .notifier_call = nf_hnat_netdevice_event,
543};
544
545static struct notifier_block nf_hnat_netevent_nb __read_mostly = {
546 .notifier_call = nf_hnat_netevent_handler,
547};
548
549int hnat_enable_hook(void)
550{
551 /* register hook functions used by WHNAT module.
552 */
553 if (hnat_priv->data->whnat) {
554 ra_sw_nat_hook_rx =
555 (hnat_priv->data->version == MTK_HNAT_V4) ?
556 mtk_sw_nat_hook_rx : NULL;
557 ra_sw_nat_hook_tx = mtk_sw_nat_hook_tx;
558 ppe_dev_register_hook = mtk_ppe_dev_register_hook;
559 ppe_dev_unregister_hook = mtk_ppe_dev_unregister_hook;
560 }
561
562 if (hnat_register_nf_hooks())
563 return -1;
564
565 hook_toggle = 1;
566
567 return 0;
568}
569
570int hnat_disable_hook(void)
571{
developer471f6562021-05-10 20:48:34 +0800572 int i, hash_index;
developerfd40db22021-04-29 10:08:25 +0800573 struct foe_entry *entry;
574
575 ra_sw_nat_hook_tx = NULL;
576 ra_sw_nat_hook_rx = NULL;
577 hnat_unregister_nf_hooks();
578
developer471f6562021-05-10 20:48:34 +0800579 for (i = 0; i < CFG_PPE_NUM; i++) {
580 cr_set_field(hnat_priv->ppe_base[i] + PPE_TB_CFG,
581 SMA, SMA_ONLY_FWD_CPU);
582
583 for (hash_index = 0; hash_index < hnat_priv->foe_etry_num; hash_index++) {
584 entry = hnat_priv->foe_table_cpu[i] + hash_index;
585 if (entry->bfib1.state == BIND) {
586 entry->ipv4_hnapt.udib1.state = INVALID;
587 entry->ipv4_hnapt.udib1.time_stamp =
588 readl((hnat_priv->fe_base + 0x0010)) & 0xFF;
589 }
developerfd40db22021-04-29 10:08:25 +0800590 }
591 }
592
593 /* clear HWNAT cache */
594 hnat_cache_ebl(1);
595
596 mod_timer(&hnat_priv->hnat_sma_build_entry_timer, jiffies + 3 * HZ);
597 hook_toggle = 0;
598
599 return 0;
600}
601
602#if defined(CONFIG_NET_MEDIATEK_HW_QOS)
603static struct packet_type mtk_pack_type __read_mostly = {
604 .type = HQOS_MAGIC_TAG,
605 .func = mtk_hqos_ptype_cb,
606};
607#endif
608
609static int hnat_probe(struct platform_device *pdev)
610{
611 int i;
612 int err = 0;
613 int index = 0;
614 struct resource *res;
615 const char *name;
616 struct device_node *np;
617 unsigned int val;
618 struct property *prop;
619 struct extdev_entry *ext_entry;
620 const struct of_device_id *match;
621
622 hnat_priv = devm_kzalloc(&pdev->dev, sizeof(struct mtk_hnat), GFP_KERNEL);
623 if (!hnat_priv)
624 return -ENOMEM;
625
626 hnat_priv->foe_etry_num = DEF_ETRY_NUM;
627
628 match = of_match_device(of_hnat_match, &pdev->dev);
developer4c32b7a2021-11-13 16:46:43 +0800629 if (unlikely(!match))
630 return -EINVAL;
631
developerfd40db22021-04-29 10:08:25 +0800632 hnat_priv->data = (struct mtk_hnat_data *)match->data;
633
634 hnat_priv->dev = &pdev->dev;
635 np = hnat_priv->dev->of_node;
636
637 err = of_property_read_string(np, "mtketh-wan", &name);
638 if (err < 0)
639 return -EINVAL;
640
developer4c32b7a2021-11-13 16:46:43 +0800641 strncpy(hnat_priv->wan, (char *)name, IFNAMSIZ - 1);
developerfd40db22021-04-29 10:08:25 +0800642 dev_info(&pdev->dev, "wan = %s\n", hnat_priv->wan);
643
644 err = of_property_read_string(np, "mtketh-lan", &name);
645 if (err < 0)
646 strncpy(hnat_priv->lan, "eth0", IFNAMSIZ);
647 else
developer4c32b7a2021-11-13 16:46:43 +0800648 strncpy(hnat_priv->lan, (char *)name, IFNAMSIZ - 1);
developerfd40db22021-04-29 10:08:25 +0800649 dev_info(&pdev->dev, "lan = %s\n", hnat_priv->lan);
650
651 err = of_property_read_string(np, "mtketh-ppd", &name);
652 if (err < 0)
653 strncpy(hnat_priv->ppd, "eth0", IFNAMSIZ);
654 else
developer4c32b7a2021-11-13 16:46:43 +0800655 strncpy(hnat_priv->ppd, (char *)name, IFNAMSIZ - 1);
developerfd40db22021-04-29 10:08:25 +0800656 dev_info(&pdev->dev, "ppd = %s\n", hnat_priv->ppd);
657
658 /*get total gmac num in hnat*/
659 err = of_property_read_u32_index(np, "mtketh-max-gmac", 0, &val);
660
661 if (err < 0)
662 return -EINVAL;
663
664 hnat_priv->gmac_num = val;
665
666 dev_info(&pdev->dev, "gmac num = %d\n", hnat_priv->gmac_num);
667
668 err = of_property_read_u32_index(np, "mtkdsa-wan-port", 0, &val);
669
670 if (err < 0) {
671 hnat_priv->wan_dsa_port = NONE_DSA_PORT;
672 } else {
673 hnat_priv->wan_dsa_port = val;
674 dev_info(&pdev->dev, "wan dsa port = %d\n", hnat_priv->wan_dsa_port);
675 }
676
developer471f6562021-05-10 20:48:34 +0800677 err = of_property_read_u32_index(np, "mtketh-ppe-num", 0, &val);
678
679 if (err < 0)
680 hnat_priv->ppe_num = 1;
681 else
682 hnat_priv->ppe_num = val;
683
684 dev_info(&pdev->dev, "ppe num = %d\n", hnat_priv->ppe_num);
685
developerfd40db22021-04-29 10:08:25 +0800686 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
687 if (!res)
688 return -ENOENT;
689
690 hnat_priv->fe_base = devm_ioremap_nocache(&pdev->dev, res->start,
691 res->end - res->start + 1);
692 if (!hnat_priv->fe_base)
693 return -EADDRNOTAVAIL;
694
developer471f6562021-05-10 20:48:34 +0800695#if defined(CONFIG_MEDIATEK_NETSYS_V2)
696 hnat_priv->ppe_base[0] = hnat_priv->fe_base + 0x2200;
697
698 if (CFG_PPE_NUM > 1)
699 hnat_priv->ppe_base[1] = hnat_priv->fe_base + 0x2600;
700#else
701 hnat_priv->ppe_base[0] = hnat_priv->fe_base + 0xe00;
702#endif
developerfd40db22021-04-29 10:08:25 +0800703
704 err = hnat_init_debugfs(hnat_priv);
705 if (err)
706 return err;
707
708 prop = of_find_property(np, "ext-devices", NULL);
709 for (name = of_prop_next_string(prop, NULL); name;
710 name = of_prop_next_string(prop, name), index++) {
711 ext_entry = kzalloc(sizeof(*ext_entry), GFP_KERNEL);
712 if (!ext_entry) {
713 err = -ENOMEM;
714 goto err_out1;
715 }
developer4c32b7a2021-11-13 16:46:43 +0800716 strncpy(ext_entry->name, (char *)name, IFNAMSIZ - 1);
developerfd40db22021-04-29 10:08:25 +0800717 ext_if_add(ext_entry);
718 }
719
720 for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
721 ext_entry = hnat_priv->ext_if[i];
722 dev_info(&pdev->dev, "ext devices = %s\n", ext_entry->name);
723 }
724
725 hnat_priv->lvid = 1;
726 hnat_priv->wvid = 2;
727
developer471f6562021-05-10 20:48:34 +0800728 for (i = 0; i < CFG_PPE_NUM; i++) {
729 err = hnat_start(i);
730 if (err)
731 goto err_out;
732 }
developerfd40db22021-04-29 10:08:25 +0800733
734 if (hnat_priv->data->whnat) {
735 err = whnat_adjust_nf_hooks();
736 if (err)
737 goto err_out;
738 }
739
740 err = hnat_enable_hook();
741 if (err)
742 goto err_out;
743
744 register_netdevice_notifier(&nf_hnat_netdevice_nb);
745 register_netevent_notifier(&nf_hnat_netevent_nb);
developer471f6562021-05-10 20:48:34 +0800746
747 if (hnat_priv->data->mcast) {
748 for (i = 0; i < CFG_PPE_NUM; i++)
749 hnat_mcast_enable(i);
750 }
751
developerfd40db22021-04-29 10:08:25 +0800752 timer_setup(&hnat_priv->hnat_sma_build_entry_timer, hnat_sma_build_entry, 0);
753 if (hnat_priv->data->version == MTK_HNAT_V3) {
754 timer_setup(&hnat_priv->hnat_reset_timestamp_timer, hnat_reset_timestamp, 0);
755 hnat_priv->hnat_reset_timestamp_timer.expires = jiffies;
756 add_timer(&hnat_priv->hnat_reset_timestamp_timer);
757 }
758
759#if defined(CONFIG_NET_MEDIATEK_HW_QOS)
developeraf07fad2021-11-19 17:53:42 +0800760 if (qos_toggle && IS_GMAC1_MODE)
developerfd40db22021-04-29 10:08:25 +0800761 dev_add_pack(&mtk_pack_type);
762#endif
developer731b98f2021-09-17 17:44:37 +0800763 err = hnat_roaming_enable();
764 if (err)
765 pr_info("hnat roaming work fail\n");
developerfd40db22021-04-29 10:08:25 +0800766
767 return 0;
768
769err_out:
developer471f6562021-05-10 20:48:34 +0800770 for (i = 0; i < CFG_PPE_NUM; i++)
771 hnat_stop(i);
developerfd40db22021-04-29 10:08:25 +0800772err_out1:
773 hnat_deinit_debugfs(hnat_priv);
774 for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
775 ext_entry = hnat_priv->ext_if[i];
776 ext_if_del(ext_entry);
777 kfree(ext_entry);
778 }
779 return err;
780}
781
782static int hnat_remove(struct platform_device *pdev)
783{
developer471f6562021-05-10 20:48:34 +0800784 int i;
785
developer731b98f2021-09-17 17:44:37 +0800786 hnat_roaming_disable();
developerfd40db22021-04-29 10:08:25 +0800787 unregister_netdevice_notifier(&nf_hnat_netdevice_nb);
788 unregister_netevent_notifier(&nf_hnat_netevent_nb);
789 hnat_disable_hook();
790
791 if (hnat_priv->data->mcast)
792 hnat_mcast_disable();
793
developer471f6562021-05-10 20:48:34 +0800794 for (i = 0; i < CFG_PPE_NUM; i++)
795 hnat_stop(i);
796
developerfd40db22021-04-29 10:08:25 +0800797 hnat_deinit_debugfs(hnat_priv);
798 hnat_release_netdev();
799 del_timer_sync(&hnat_priv->hnat_sma_build_entry_timer);
800 if (hnat_priv->data->version == MTK_HNAT_V3)
801 del_timer_sync(&hnat_priv->hnat_reset_timestamp_timer);
802
803#if defined(CONFIG_NET_MEDIATEK_HW_QOS)
developeraf07fad2021-11-19 17:53:42 +0800804 if (qos_toggle && IS_GMAC1_MODE)
developerfd40db22021-04-29 10:08:25 +0800805 dev_remove_pack(&mtk_pack_type);
806#endif
807
808 return 0;
809}
810
811static const struct mtk_hnat_data hnat_data_v1 = {
812 .num_of_sch = 2,
813 .whnat = false,
814 .per_flow_accounting = false,
815 .mcast = false,
816 .version = MTK_HNAT_V1,
817};
818
819static const struct mtk_hnat_data hnat_data_v2 = {
820 .num_of_sch = 2,
821 .whnat = true,
822 .per_flow_accounting = true,
823 .mcast = false,
824 .version = MTK_HNAT_V2,
825};
826
827static const struct mtk_hnat_data hnat_data_v3 = {
828 .num_of_sch = 4,
829 .whnat = false,
830 .per_flow_accounting = false,
831 .mcast = false,
832 .version = MTK_HNAT_V3,
833};
834
835static const struct mtk_hnat_data hnat_data_v4 = {
836 .num_of_sch = 4,
837 .whnat = true,
838 .per_flow_accounting = true,
839 .mcast = false,
840 .version = MTK_HNAT_V4,
841};
842
843const struct of_device_id of_hnat_match[] = {
844 { .compatible = "mediatek,mtk-hnat", .data = &hnat_data_v3 },
845 { .compatible = "mediatek,mtk-hnat_v1", .data = &hnat_data_v1 },
846 { .compatible = "mediatek,mtk-hnat_v2", .data = &hnat_data_v2 },
847 { .compatible = "mediatek,mtk-hnat_v3", .data = &hnat_data_v3 },
848 { .compatible = "mediatek,mtk-hnat_v4", .data = &hnat_data_v4 },
849 {},
850};
851MODULE_DEVICE_TABLE(of, of_hnat_match);
852
853static struct platform_driver hnat_driver = {
854 .probe = hnat_probe,
855 .remove = hnat_remove,
856 .driver = {
857 .name = "mediatek_soc_hnat",
858 .of_match_table = of_hnat_match,
859 },
860};
861
862module_platform_driver(hnat_driver);
863
864MODULE_LICENSE("GPL v2");
865MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
866MODULE_AUTHOR("John Crispin <john@phrozen.org>");
867MODULE_DESCRIPTION("Mediatek Hardware NAT");