1// SPDX-License-Identifier: GPL-2.0
2/* Marvell MCS driver
3 *
4 * Copyright (C) 2022 Marvell.
5 */
6
7#include "mcs.h"
8#include "mcs_reg.h"
9
10static struct mcs_ops cnf10kb_mcs_ops   = {
11	.mcs_set_hw_capabilities	= cnf10kb_mcs_set_hw_capabilities,
12	.mcs_parser_cfg			= cnf10kb_mcs_parser_cfg,
13	.mcs_tx_sa_mem_map_write	= cnf10kb_mcs_tx_sa_mem_map_write,
14	.mcs_rx_sa_mem_map_write	= cnf10kb_mcs_rx_sa_mem_map_write,
15	.mcs_flowid_secy_map		= cnf10kb_mcs_flowid_secy_map,
16	.mcs_bbe_intr_handler		= cnf10kb_mcs_bbe_intr_handler,
17	.mcs_pab_intr_handler		= cnf10kb_mcs_pab_intr_handler,
18};
19
20struct mcs_ops *cnf10kb_get_mac_ops(void)
21{
22	return &cnf10kb_mcs_ops;
23}
24
25void cnf10kb_mcs_set_hw_capabilities(struct mcs *mcs)
26{
27	struct hwinfo *hw = mcs->hw;
28
29	hw->tcam_entries = 64;		/* TCAM entries */
30	hw->secy_entries  = 64;		/* SecY entries */
31	hw->sc_entries = 64;		/* SC CAM entries */
32	hw->sa_entries = 128;		/* SA entries */
33	hw->lmac_cnt = 4;		/* lmacs/ports per mcs block */
34	hw->mcs_x2p_intf = 1;		/* x2p clabration intf */
35	hw->mcs_blks = 7;		/* MCS blocks */
36	hw->ip_vec = MCS_CNF10KB_INT_VEC_IP; /* IP vector */
37}
38
39void cnf10kb_mcs_parser_cfg(struct mcs *mcs)
40{
41	u64 reg, val;
42
43	/* VLAN Ctag */
44	val = (0x8100ull & 0xFFFF) | BIT_ULL(20) | BIT_ULL(22);
45
46	reg = MCSX_PEX_RX_SLAVE_CUSTOM_TAGX(0);
47	mcs_reg_write(mcs, reg, val);
48
49	reg = MCSX_PEX_TX_SLAVE_CUSTOM_TAGX(0);
50	mcs_reg_write(mcs, reg, val);
51
52	/* VLAN STag */
53	val = (0x88a8ull & 0xFFFF) | BIT_ULL(20) | BIT_ULL(23);
54
55	/* RX */
56	reg = MCSX_PEX_RX_SLAVE_CUSTOM_TAGX(1);
57	mcs_reg_write(mcs, reg, val);
58
59	/* TX */
60	reg = MCSX_PEX_TX_SLAVE_CUSTOM_TAGX(1);
61	mcs_reg_write(mcs, reg, val);
62
63	/* Enable custom tage 0 and 1 and sectag */
64	val = BIT_ULL(0) | BIT_ULL(1) | BIT_ULL(12);
65
66	reg = MCSX_PEX_RX_SLAVE_ETYPE_ENABLE;
67	mcs_reg_write(mcs, reg, val);
68
69	reg = MCSX_PEX_TX_SLAVE_ETYPE_ENABLE;
70	mcs_reg_write(mcs, reg, val);
71}
72
73void cnf10kb_mcs_flowid_secy_map(struct mcs *mcs, struct secy_mem_map *map, int dir)
74{
75	u64 reg, val;
76
77	val = (map->secy & 0x3F) | (map->ctrl_pkt & 0x1) << 6;
78	if (dir == MCS_RX) {
79		reg = MCSX_CPM_RX_SLAVE_SECY_MAP_MEMX(map->flow_id);
80	} else {
81		reg = MCSX_CPM_TX_SLAVE_SECY_MAP_MEM_0X(map->flow_id);
82		mcs_reg_write(mcs, reg, map->sci);
83		val |= (map->sc & 0x3F) << 7;
84		reg = MCSX_CPM_TX_SLAVE_SECY_MAP_MEM_1X(map->flow_id);
85	}
86
87	mcs_reg_write(mcs, reg, val);
88}
89
90void cnf10kb_mcs_tx_sa_mem_map_write(struct mcs *mcs, struct mcs_tx_sc_sa_map *map)
91{
92	u64 reg, val;
93
94	val = (map->sa_index0 & 0x7F) | (map->sa_index1 & 0x7F) << 7;
95
96	reg = MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(map->sc_id);
97	mcs_reg_write(mcs, reg, val);
98
99	reg = MCSX_CPM_TX_SLAVE_AUTO_REKEY_ENABLE_0;
100	val = mcs_reg_read(mcs, reg);
101
102	if (map->rekey_ena)
103		val |= BIT_ULL(map->sc_id);
104	else
105		val &= ~BIT_ULL(map->sc_id);
106
107	mcs_reg_write(mcs, reg, val);
108
109	mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_SA_INDEX0_VLDX(map->sc_id), map->sa_index0_vld);
110	mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_SA_INDEX1_VLDX(map->sc_id), map->sa_index1_vld);
111
112	mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_TX_SA_ACTIVEX(map->sc_id), map->tx_sa_active);
113}
114
115void cnf10kb_mcs_rx_sa_mem_map_write(struct mcs *mcs, struct mcs_rx_sc_sa_map *map)
116{
117	u64 val, reg;
118
119	val = (map->sa_index & 0x7F) | (map->sa_in_use << 7);
120
121	reg = MCSX_CPM_RX_SLAVE_SA_MAP_MEMX((4 * map->sc_id) + map->an);
122	mcs_reg_write(mcs, reg, val);
123}
124
125int mcs_set_force_clk_en(struct mcs *mcs, bool set)
126{
127	unsigned long timeout = jiffies + usecs_to_jiffies(2000);
128	u64 val;
129
130	val = mcs_reg_read(mcs, MCSX_MIL_GLOBAL);
131
132	if (set) {
133		val |= BIT_ULL(4);
134		mcs_reg_write(mcs, MCSX_MIL_GLOBAL, val);
135
136		/* Poll till mcsx_mil_ip_gbl_status.mcs_ip_stats_ready value is 1 */
137		while (!(mcs_reg_read(mcs, MCSX_MIL_IP_GBL_STATUS) & BIT_ULL(0))) {
138			if (time_after(jiffies, timeout)) {
139				dev_err(mcs->dev, "MCS set force clk enable failed\n");
140				break;
141			}
142		}
143	} else {
144		val &= ~BIT_ULL(4);
145		mcs_reg_write(mcs, MCSX_MIL_GLOBAL, val);
146	}
147
148	return 0;
149}
150
151/* TX SA interrupt is raised only if autorekey is enabled.
152 * MCS_CPM_TX_SLAVE_SA_MAP_MEM_0X[sc].tx_sa_active bit gets toggled if
153 * one of two SAs mapped to SC gets expired. If tx_sa_active=0 implies
154 * SA in SA_index1 got expired else SA in SA_index0 got expired.
155 */
156void cnf10kb_mcs_tx_pn_thresh_reached_handler(struct mcs *mcs)
157{
158	struct mcs_intr_event event;
159	struct rsrc_bmap *sc_bmap;
160	unsigned long rekey_ena;
161	u64 val, sa_status;
162	int sc;
163
164	sc_bmap = &mcs->tx.sc;
165
166	event.mcs_id = mcs->mcs_id;
167	event.intr_mask = MCS_CPM_TX_PN_THRESH_REACHED_INT;
168
169	rekey_ena = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_AUTO_REKEY_ENABLE_0);
170
171	for_each_set_bit(sc, sc_bmap->bmap, mcs->hw->sc_entries) {
172		/* Auto rekey is enable */
173		if (!test_bit(sc, &rekey_ena))
174			continue;
175		sa_status = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_TX_SA_ACTIVEX(sc));
176		/* Check if tx_sa_active status had changed */
177		if (sa_status == mcs->tx_sa_active[sc])
178			continue;
179
180		/* SA_index0 is expired */
181		val = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(sc));
182		if (sa_status)
183			event.sa_id = val & 0x7F;
184		else
185			event.sa_id = (val >> 7) & 0x7F;
186
187		event.pcifunc = mcs->tx.sa2pf_map[event.sa_id];
188		mcs_add_intr_wq_entry(mcs, &event);
189	}
190}
191
192void cnf10kb_mcs_tx_pn_wrapped_handler(struct mcs *mcs)
193{
194	struct mcs_intr_event event = { 0 };
195	struct rsrc_bmap *sc_bmap;
196	u64 val;
197	int sc;
198
199	sc_bmap = &mcs->tx.sc;
200
201	event.mcs_id = mcs->mcs_id;
202	event.intr_mask = MCS_CPM_TX_PACKET_XPN_EQ0_INT;
203
204	for_each_set_bit(sc, sc_bmap->bmap, mcs->hw->sc_entries) {
205		val = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(sc));
206
207		if (mcs->tx_sa_active[sc])
208			/* SA_index1 was used and got expired */
209			event.sa_id = (val >> 7) & 0x7F;
210		else
211			/* SA_index0 was used and got expired */
212			event.sa_id = val & 0x7F;
213
214		event.pcifunc = mcs->tx.sa2pf_map[event.sa_id];
215		mcs_add_intr_wq_entry(mcs, &event);
216	}
217}
218
219void cnf10kb_mcs_bbe_intr_handler(struct mcs *mcs, u64 intr,
220				  enum mcs_direction dir)
221{
222	struct mcs_intr_event event = { 0 };
223	int i;
224
225	if (!(intr & MCS_BBE_INT_MASK))
226		return;
227
228	event.mcs_id = mcs->mcs_id;
229	event.pcifunc = mcs->pf_map[0];
230
231	for (i = 0; i < MCS_MAX_BBE_INT; i++) {
232		if (!(intr & BIT_ULL(i)))
233			continue;
234
235		/* Lower nibble denotes data fifo overflow interrupts and
236		 * upper nibble indicates policy fifo overflow interrupts.
237		 */
238		if (intr & 0xFULL)
239			event.intr_mask = (dir == MCS_RX) ?
240					  MCS_BBE_RX_DFIFO_OVERFLOW_INT :
241					  MCS_BBE_TX_DFIFO_OVERFLOW_INT;
242		else
243			event.intr_mask = (dir == MCS_RX) ?
244					  MCS_BBE_RX_PLFIFO_OVERFLOW_INT :
245					  MCS_BBE_TX_PLFIFO_OVERFLOW_INT;
246
247		/* Notify the lmac_id info which ran into BBE fatal error */
248		event.lmac_id = i & 0x3ULL;
249		mcs_add_intr_wq_entry(mcs, &event);
250	}
251}
252
253void cnf10kb_mcs_pab_intr_handler(struct mcs *mcs, u64 intr,
254				  enum mcs_direction dir)
255{
256	struct mcs_intr_event event = { 0 };
257	int i;
258
259	if (!(intr & MCS_PAB_INT_MASK))
260		return;
261
262	event.mcs_id = mcs->mcs_id;
263	event.pcifunc = mcs->pf_map[0];
264
265	for (i = 0; i < MCS_MAX_PAB_INT; i++) {
266		if (!(intr & BIT_ULL(i)))
267			continue;
268
269		event.intr_mask = (dir == MCS_RX) ?
270				  MCS_PAB_RX_CHAN_OVERFLOW_INT :
271				  MCS_PAB_TX_CHAN_OVERFLOW_INT;
272
273		/* Notify the lmac_id info which ran into PAB fatal error */
274		event.lmac_id = i;
275		mcs_add_intr_wq_entry(mcs, &event);
276	}
277}
278