blob: b0d6d2771aa6a8b9b6530b3a0c6cf819de79d154 [file] [log] [blame]
developer1966afb2023-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/device.h>
9#include <linux/err.h>
10#include <linux/of.h>
11#include <linux/of_platform.h>
12
13#include "pce/internal.h"
14#include "pce/tport_map.h"
15
16int mtk_pce_tport_map_ts_config_read(enum ts_config_entry entry,
17 struct tsc_desc *ts_cfg)
18{
19 struct fe_mem_msg msg;
20 int ret = 0;
21
22 if (!ts_cfg)
23 return -EINVAL;
24
25 if (!(TS_CONFIG_MASK & BIT(entry))) {
26 PCE_ERR("invalid ts config entry: %u\n", entry);
27 return -EPERM;
28 }
29
30 mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_READ, FE_MEM_TYPE_TS_CONFIG, entry);
31 memset(&msg.raw, 0, sizeof(msg.raw));
32
33 ret = mtk_pce_fe_mem_msg_send(&msg);
34 if (ret) {
35 PCE_NOTICE("fe_mem send msg failed: %d\n", ret);
36 return ret;
37 }
38
39 memcpy(ts_cfg, &msg.tdesc, sizeof(*ts_cfg));
40
41 return ret;
42}
43
44int mtk_pce_tport_map_ts_config_write(enum ts_config_entry entry,
45 struct tsc_desc *ts_cfg)
46{
47 struct fe_mem_msg msg;
48 int ret = 0;
49
50 if (!ts_cfg)
51 return -EINVAL;
52
53 if (!(TS_CONFIG_MASK & BIT(entry))) {
54 PCE_NOTICE("invalid ts config entry: %u\n", entry);
55 return -EPERM;
56 }
57
58 mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_WRITE, FE_MEM_TYPE_TS_CONFIG, entry);
59 memset(&msg.raw, 0, sizeof(msg.raw));
60 memcpy(&msg.raw, ts_cfg, sizeof(struct tsc_desc));
61
62 ret = mtk_pce_fe_mem_msg_send(&msg);
63 if (ret) {
64 PCE_NOTICE("fe_mem send msg failed: %d\n", ret);
65 return ret;
66 }
67
68 return ret;
69}
70
71int mtk_pce_tport_map_ppe_read(enum pse_port ppe, u64 *map)
72{
73 if (!map)
74 return -EINVAL;
75
76 if (!(PSE_PORT_PPE_MASK & BIT(ppe))) {
77 PCE_NOTICE("invalid ppe index: %u\n", ppe);
78 return -EPERM;
79 }
80
81 *map = mtk_pce_ppe_read(ppe, PPE_TPORT_TBL_0);
82 *map |= ((u64)mtk_pce_ppe_read(ppe, PPE_TPORT_TBL_1)) << 32;
83
84 return 0;
85}
86
87static int mtk_pce_tport_map_update_ts_config(enum ts_config_entry entry,
88 u32 tport_idx,
89 enum pse_port target)
90{
developerd7577092023-11-23 15:34:36 +080091 u32 shift = (tport_idx % TPORT_IDX_PER_REG) * PSE_PER_PORT_BITS;
92 u32 val = (target & PSE_PER_PORT_MASK) << shift;
93 u32 mask = PSE_PER_PORT_MASK << shift;
developer1966afb2023-08-08 16:02:18 +080094 struct tsc_desc ts_cfg;
95 int ret = 0;
96
97 ret = mtk_pce_tport_map_ts_config_read(entry, &ts_cfg);
98 if (ret)
99 return ret;
100
101 if (tport_idx < TPORT_IDX_MAX / 2) {
developerd7577092023-11-23 15:34:36 +0800102 ts_cfg.tport_map_lower &= ~mask;
103 ts_cfg.tport_map_lower |= val;
developer1966afb2023-08-08 16:02:18 +0800104 } else {
developerd7577092023-11-23 15:34:36 +0800105 ts_cfg.tport_map_upper &= ~mask;
106 ts_cfg.tport_map_upper |= val;
developer1966afb2023-08-08 16:02:18 +0800107 }
108
109 ret = mtk_pce_tport_map_ts_config_write(entry, &ts_cfg);
110 if (ret)
111 return ret;
112
113 return ret;
114}
115
116static int mtk_pce_tport_map_update_ppe(enum pse_port ppe,
117 u32 tport_idx,
118 enum pse_port target)
119{
developerd7577092023-11-23 15:34:36 +0800120 u32 shift = (tport_idx % TPORT_IDX_PER_REG) * PSE_PER_PORT_BITS;
121 u32 val = (target & PSE_PER_PORT_MASK) << shift;
122 u32 mask = PSE_PER_PORT_MASK << shift;
developer1966afb2023-08-08 16:02:18 +0800123
124 if (tport_idx < TPORT_IDX_MAX / 2)
125 mtk_pce_ppe_rmw(ppe, PPE_TPORT_TBL_0, mask, val);
126 else
127 mtk_pce_ppe_rmw(ppe, PPE_TPORT_TBL_1, mask, val);
128
129 return 0;
130}
131
132/*
133 * update tport idx mapping
134 * pse_port: the pse port idx that is going to be modified
135 * tport_idx: the tport idx that is going to be modified
136 * target: the next port for packet when the packet is at pse_port with tport_idx
137 */
138int mtk_pce_tport_map_pse_port_update(enum pse_port pse_port,
139 u32 tport_idx,
140 enum pse_port target)
141{
142 int ret = 0;
143
144 if (pse_port >= __PSE_PORT_MAX || target >= __PSE_PORT_MAX) {
145 PCE_NOTICE("invalid pse_port: %u, target: %u\n", pse_port, target);
146 return -EPERM;
147 }
148
149 if (tport_idx >= TPORT_IDX_MAX) {
150 PCE_NOTICE("invalid tport_idx: %u\n", tport_idx);
151 return -EPERM;
152 }
153
154 if (TS_CONFIG_MASK & BIT(pse_port))
developerd7577092023-11-23 15:34:36 +0800155 ret = mtk_pce_tport_map_update_ts_config((enum ts_config_entry)pse_port,
156 tport_idx, target);
developer1966afb2023-08-08 16:02:18 +0800157 else if (PSE_PORT_PPE_MASK & BIT(pse_port))
158 ret = mtk_pce_tport_map_update_ppe(pse_port, tport_idx, target);
159 else
160 ret = -EINVAL;
161
162 if (ret)
163 PCE_ERR("update tport map failed: %d\n", ret);
164
165 return ret;
166}