1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
2 | /* |
3 | * Driver for Microsemi VSC85xx PHYs - MACsec support |
4 | * |
5 | * Author: Antoine Tenart |
6 | * License: Dual MIT/GPL |
7 | * Copyright (c) 2020 Microsemi Corporation |
8 | */ |
9 | |
10 | #include <linux/phy.h> |
11 | #include <dt-bindings/net/mscc-phy-vsc8531.h> |
12 | |
13 | #include <crypto/aes.h> |
14 | |
15 | #include <net/macsec.h> |
16 | |
17 | #include "mscc.h" |
18 | #include "mscc_mac.h" |
19 | #include "mscc_macsec.h" |
20 | #include "mscc_fc_buffer.h" |
21 | |
22 | static u32 vsc8584_macsec_phy_read(struct phy_device *phydev, |
23 | enum macsec_bank bank, u32 reg) |
24 | { |
25 | u32 val, val_l = 0, val_h = 0; |
26 | unsigned long deadline; |
27 | int rc; |
28 | |
29 | rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC); |
30 | if (rc < 0) |
31 | goto failed; |
32 | |
33 | __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20, |
34 | MSCC_PHY_MACSEC_20_TARGET(bank >> 2)); |
35 | |
36 | if (bank >> 2 == 0x1) |
37 | /* non-MACsec access */ |
38 | bank &= 0x3; |
39 | else |
40 | bank = 0; |
41 | |
42 | __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19, |
43 | MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_READ | |
44 | MSCC_PHY_MACSEC_19_REG_ADDR(reg) | |
45 | MSCC_PHY_MACSEC_19_TARGET(bank)); |
46 | |
47 | deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS); |
48 | do { |
49 | val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19); |
50 | } while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD)); |
51 | |
52 | val_l = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_17); |
53 | val_h = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_18); |
54 | |
55 | failed: |
56 | phy_restore_page(phydev, oldpage: rc, ret: rc); |
57 | |
58 | return (val_h << 16) | val_l; |
59 | } |
60 | |
61 | static void vsc8584_macsec_phy_write(struct phy_device *phydev, |
62 | enum macsec_bank bank, u32 reg, u32 val) |
63 | { |
64 | unsigned long deadline; |
65 | int rc; |
66 | |
67 | rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC); |
68 | if (rc < 0) |
69 | goto failed; |
70 | |
71 | __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20, |
72 | MSCC_PHY_MACSEC_20_TARGET(bank >> 2)); |
73 | |
74 | if ((bank >> 2 == 0x1) || (bank >> 2 == 0x3)) |
75 | bank &= 0x3; |
76 | else |
77 | /* MACsec access */ |
78 | bank = 0; |
79 | |
80 | __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_17, val: (u16)val); |
81 | __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_18, val: (u16)(val >> 16)); |
82 | |
83 | __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19, |
84 | MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_REG_ADDR(reg) | |
85 | MSCC_PHY_MACSEC_19_TARGET(bank)); |
86 | |
87 | deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS); |
88 | do { |
89 | val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19); |
90 | } while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD)); |
91 | |
92 | failed: |
93 | phy_restore_page(phydev, oldpage: rc, ret: rc); |
94 | } |
95 | |
96 | static void vsc8584_macsec_classification(struct phy_device *phydev, |
97 | enum macsec_bank bank) |
98 | { |
99 | /* enable VLAN tag parsing */ |
100 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_CP_TAG, |
101 | MSCC_MS_SAM_CP_TAG_PARSE_STAG | |
102 | MSCC_MS_SAM_CP_TAG_PARSE_QTAG | |
103 | MSCC_MS_SAM_CP_TAG_PARSE_QINQ); |
104 | } |
105 | |
106 | static void vsc8584_macsec_flow_default_action(struct phy_device *phydev, |
107 | enum macsec_bank bank, |
108 | bool block) |
109 | { |
110 | u32 port = (bank == MACSEC_INGR) ? |
111 | MSCC_MS_PORT_UNCONTROLLED : MSCC_MS_PORT_COMMON; |
112 | u32 action = MSCC_MS_FLOW_BYPASS; |
113 | |
114 | if (block) |
115 | action = MSCC_MS_FLOW_DROP; |
116 | |
117 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_NCP, |
118 | /* MACsec untagged */ |
119 | MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) | |
120 | MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
121 | MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DEST_PORT(port) | |
122 | /* MACsec tagged */ |
123 | MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) | |
124 | MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
125 | MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DEST_PORT(port) | |
126 | /* Bad tag */ |
127 | MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) | |
128 | MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
129 | MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DEST_PORT(port) | |
130 | /* Kay tag */ |
131 | MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) | |
132 | MSCC_MS_SAM_NM_FLOW_NCP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
133 | MSCC_MS_SAM_NM_FLOW_NCP_KAY_DEST_PORT(port)); |
134 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_CP, |
135 | /* MACsec untagged */ |
136 | MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) | |
137 | MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
138 | MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DEST_PORT(port) | |
139 | /* MACsec tagged */ |
140 | MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) | |
141 | MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
142 | MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DEST_PORT(port) | |
143 | /* Bad tag */ |
144 | MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) | |
145 | MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
146 | MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DEST_PORT(port) | |
147 | /* Kay tag */ |
148 | MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) | |
149 | MSCC_MS_SAM_NM_FLOW_CP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
150 | MSCC_MS_SAM_NM_FLOW_CP_KAY_DEST_PORT(port)); |
151 | } |
152 | |
153 | static void vsc8584_macsec_integrity_checks(struct phy_device *phydev, |
154 | enum macsec_bank bank) |
155 | { |
156 | u32 val; |
157 | |
158 | if (bank != MACSEC_INGR) |
159 | return; |
160 | |
161 | /* Set default rules to pass unmatched frames */ |
162 | val = vsc8584_macsec_phy_read(phydev, bank, |
163 | MSCC_MS_PARAMS2_IG_CC_CONTROL); |
164 | val |= MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_CTRL_ACT | |
165 | MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_ACT; |
166 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CC_CONTROL, |
167 | val); |
168 | |
169 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CP_TAG, |
170 | MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_STAG | |
171 | MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QTAG | |
172 | MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QINQ); |
173 | } |
174 | |
175 | static void vsc8584_macsec_block_init(struct phy_device *phydev, |
176 | enum macsec_bank bank) |
177 | { |
178 | u32 val; |
179 | int i; |
180 | |
181 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG, |
182 | MSCC_MS_ENA_CFG_SW_RST | |
183 | MSCC_MS_ENA_CFG_MACSEC_BYPASS_ENA); |
184 | |
185 | /* Set the MACsec block out of s/w reset and enable clocks */ |
186 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG, |
187 | MSCC_MS_ENA_CFG_CLK_ENA); |
188 | |
189 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_STATUS_CONTEXT_CTRL, |
190 | val: bank == MACSEC_INGR ? 0xe5880214 : 0xe5880218); |
191 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_MISC_CONTROL, |
192 | MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX(bank == MACSEC_INGR ? 57 : 40) | |
193 | MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE(bank == MACSEC_INGR ? 1 : 2)); |
194 | |
195 | /* Clear the counters */ |
196 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL); |
197 | val |= MSCC_MS_COUNT_CONTROL_AUTO_CNTR_RESET; |
198 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val); |
199 | |
200 | /* Enable octet increment mode */ |
201 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PP_CTRL, |
202 | MSCC_MS_PP_CTRL_MACSEC_OCTET_INCR_MODE); |
203 | |
204 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_BLOCK_CTX_UPDATE, val: 0x3); |
205 | |
206 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL); |
207 | val |= MSCC_MS_COUNT_CONTROL_RESET_ALL; |
208 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val); |
209 | |
210 | /* Set the MTU */ |
211 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_NON_VLAN_MTU_CHECK, |
212 | MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE(32761) | |
213 | MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMP_DROP); |
214 | |
215 | for (i = 0; i < 8; i++) |
216 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_VLAN_MTU_CHECK(i), |
217 | MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE(32761) | |
218 | MSCC_MS_VLAN_MTU_CHECK_MTU_COMP_DROP); |
219 | |
220 | if (bank == MACSEC_EGR) { |
221 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_INTR_CTRL_STATUS); |
222 | val &= ~MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M; |
223 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_INTR_CTRL_STATUS, val); |
224 | |
225 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_FC_CFG, |
226 | MSCC_MS_FC_CFG_FCBUF_ENA | |
227 | MSCC_MS_FC_CFG_LOW_THRESH(0x1) | |
228 | MSCC_MS_FC_CFG_HIGH_THRESH(0x4) | |
229 | MSCC_MS_FC_CFG_LOW_BYTES_VAL(0x4) | |
230 | MSCC_MS_FC_CFG_HIGH_BYTES_VAL(0x6)); |
231 | } |
232 | |
233 | vsc8584_macsec_classification(phydev, bank); |
234 | vsc8584_macsec_flow_default_action(phydev, bank, block: false); |
235 | vsc8584_macsec_integrity_checks(phydev, bank); |
236 | |
237 | /* Enable the MACsec block */ |
238 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG, |
239 | MSCC_MS_ENA_CFG_CLK_ENA | |
240 | MSCC_MS_ENA_CFG_MACSEC_ENA | |
241 | MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE(0x5)); |
242 | } |
243 | |
244 | static void vsc8584_macsec_mac_init(struct phy_device *phydev, |
245 | enum macsec_bank bank) |
246 | { |
247 | u32 val; |
248 | int i; |
249 | |
250 | /* Clear host & line stats */ |
251 | for (i = 0; i < 36; i++) |
252 | vsc8584_macsec_phy_write(phydev, bank, reg: 0x1c + i, val: 0); |
253 | |
254 | val = vsc8584_macsec_phy_read(phydev, bank, |
255 | MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL); |
256 | val &= ~MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE_M; |
257 | val |= MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE(2) | |
258 | MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE(0xffff); |
259 | vsc8584_macsec_phy_write(phydev, bank, |
260 | MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL, val); |
261 | |
262 | val = vsc8584_macsec_phy_read(phydev, bank, |
263 | MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2); |
264 | val |= 0xffff; |
265 | vsc8584_macsec_phy_write(phydev, bank, |
266 | MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2, val); |
267 | |
268 | val = vsc8584_macsec_phy_read(phydev, bank, |
269 | MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL); |
270 | if (bank == HOST_MAC) |
271 | val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_TIMER_ENA | |
272 | MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA; |
273 | else |
274 | val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_REACT_ENA | |
275 | MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA | |
276 | MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_MODE | |
277 | MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_EARLY_PAUSE_DETECT_ENA; |
278 | vsc8584_macsec_phy_write(phydev, bank, |
279 | MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL, val); |
280 | |
281 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_PKTINF_CFG, |
282 | MSCC_MAC_CFG_PKTINF_CFG_STRIP_FCS_ENA | |
283 | MSCC_MAC_CFG_PKTINF_CFG_INSERT_FCS_ENA | |
284 | MSCC_MAC_CFG_PKTINF_CFG_LPI_RELAY_ENA | |
285 | MSCC_MAC_CFG_PKTINF_CFG_STRIP_PREAMBLE_ENA | |
286 | MSCC_MAC_CFG_PKTINF_CFG_INSERT_PREAMBLE_ENA | |
287 | (bank == HOST_MAC ? |
288 | MSCC_MAC_CFG_PKTINF_CFG_ENABLE_TX_PADDING : 0) | |
289 | (IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING) ? |
290 | MSCC_MAC_CFG_PKTINF_CFG_MACSEC_BYPASS_NUM_PTP_STALL_CLKS(0x8) : 0)); |
291 | |
292 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MODE_CFG); |
293 | val &= ~MSCC_MAC_CFG_MODE_CFG_DISABLE_DIC; |
294 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MODE_CFG, val); |
295 | |
296 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG); |
297 | val &= ~MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_M; |
298 | val |= MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN(10240); |
299 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG, val); |
300 | |
301 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ADV_CHK_CFG, |
302 | MSCC_MAC_CFG_ADV_CHK_CFG_SFD_CHK_ENA | |
303 | MSCC_MAC_CFG_ADV_CHK_CFG_PRM_CHK_ENA | |
304 | MSCC_MAC_CFG_ADV_CHK_CFG_OOR_ERR_ENA | |
305 | MSCC_MAC_CFG_ADV_CHK_CFG_INR_ERR_ENA); |
306 | |
307 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_LFS_CFG); |
308 | val &= ~MSCC_MAC_CFG_LFS_CFG_LFS_MODE_ENA; |
309 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_LFS_CFG, val); |
310 | |
311 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ENA_CFG, |
312 | MSCC_MAC_CFG_ENA_CFG_RX_CLK_ENA | |
313 | MSCC_MAC_CFG_ENA_CFG_TX_CLK_ENA | |
314 | MSCC_MAC_CFG_ENA_CFG_RX_ENA | |
315 | MSCC_MAC_CFG_ENA_CFG_TX_ENA); |
316 | } |
317 | |
318 | /* Must be called with mdio_lock taken */ |
319 | static int __vsc8584_macsec_init(struct phy_device *phydev) |
320 | { |
321 | struct vsc8531_private *priv = phydev->priv; |
322 | enum macsec_bank proc_bank; |
323 | u32 val; |
324 | |
325 | vsc8584_macsec_block_init(phydev, bank: MACSEC_INGR); |
326 | vsc8584_macsec_block_init(phydev, bank: MACSEC_EGR); |
327 | vsc8584_macsec_mac_init(phydev, bank: HOST_MAC); |
328 | vsc8584_macsec_mac_init(phydev, bank: LINE_MAC); |
329 | |
330 | vsc8584_macsec_phy_write(phydev, bank: FC_BUFFER, |
331 | MSCC_FCBUF_FC_READ_THRESH_CFG, |
332 | MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH(4) | |
333 | MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH(5)); |
334 | |
335 | val = vsc8584_macsec_phy_read(phydev, bank: FC_BUFFER, MSCC_FCBUF_MODE_CFG); |
336 | val |= MSCC_FCBUF_MODE_CFG_PAUSE_GEN_ENA | |
337 | MSCC_FCBUF_MODE_CFG_RX_PPM_RATE_ADAPT_ENA | |
338 | MSCC_FCBUF_MODE_CFG_TX_PPM_RATE_ADAPT_ENA; |
339 | vsc8584_macsec_phy_write(phydev, bank: FC_BUFFER, MSCC_FCBUF_MODE_CFG, val); |
340 | |
341 | vsc8584_macsec_phy_write(phydev, bank: FC_BUFFER, MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG, |
342 | MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH(8) | |
343 | MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET(9)); |
344 | |
345 | val = vsc8584_macsec_phy_read(phydev, bank: FC_BUFFER, |
346 | MSCC_FCBUF_TX_DATA_QUEUE_CFG); |
347 | val &= ~(MSCC_FCBUF_TX_DATA_QUEUE_CFG_START_M | |
348 | MSCC_FCBUF_TX_DATA_QUEUE_CFG_END_M); |
349 | val |= MSCC_FCBUF_TX_DATA_QUEUE_CFG_START(0) | |
350 | MSCC_FCBUF_TX_DATA_QUEUE_CFG_END(5119); |
351 | vsc8584_macsec_phy_write(phydev, bank: FC_BUFFER, |
352 | MSCC_FCBUF_TX_DATA_QUEUE_CFG, val); |
353 | |
354 | val = vsc8584_macsec_phy_read(phydev, bank: FC_BUFFER, MSCC_FCBUF_ENA_CFG); |
355 | val |= MSCC_FCBUF_ENA_CFG_TX_ENA | MSCC_FCBUF_ENA_CFG_RX_ENA; |
356 | vsc8584_macsec_phy_write(phydev, bank: FC_BUFFER, MSCC_FCBUF_ENA_CFG, val); |
357 | |
358 | proc_bank = (priv->addr < 2) ? PROC_0 : PROC_2; |
359 | |
360 | val = vsc8584_macsec_phy_read(phydev, bank: proc_bank, |
361 | MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL); |
362 | val &= ~MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE_M; |
363 | val |= MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE(4); |
364 | vsc8584_macsec_phy_write(phydev, bank: proc_bank, |
365 | MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL, val); |
366 | |
367 | return 0; |
368 | } |
369 | |
370 | static void vsc8584_macsec_flow(struct phy_device *phydev, |
371 | struct macsec_flow *flow) |
372 | { |
373 | struct vsc8531_private *priv = phydev->priv; |
374 | enum macsec_bank bank = flow->bank; |
375 | u32 val, match = 0, mask = 0, action = 0, idx = flow->index; |
376 | |
377 | if (flow->match.tagged) |
378 | match |= MSCC_MS_SAM_MISC_MATCH_TAGGED; |
379 | if (flow->match.untagged) |
380 | match |= MSCC_MS_SAM_MISC_MATCH_UNTAGGED; |
381 | |
382 | if (bank == MACSEC_INGR && flow->assoc_num >= 0) { |
383 | match |= MSCC_MS_SAM_MISC_MATCH_AN(flow->assoc_num); |
384 | mask |= MSCC_MS_SAM_MASK_AN_MASK(0x3); |
385 | } |
386 | |
387 | if (bank == MACSEC_INGR && flow->match.sci && flow->rx_sa->sc->sci) { |
388 | u64 sci = (__force u64)flow->rx_sa->sc->sci; |
389 | |
390 | match |= MSCC_MS_SAM_MISC_MATCH_TCI(BIT(3)); |
391 | mask |= MSCC_MS_SAM_MASK_TCI_MASK(BIT(3)) | |
392 | MSCC_MS_SAM_MASK_SCI_MASK; |
393 | |
394 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_LO(idx), |
395 | lower_32_bits(sci)); |
396 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_HI(idx), |
397 | upper_32_bits(sci)); |
398 | } |
399 | |
400 | if (flow->match.etype) { |
401 | mask |= MSCC_MS_SAM_MASK_MAC_ETYPE_MASK; |
402 | |
403 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MAC_SA_MATCH_HI(idx), |
404 | MSCC_MS_SAM_MAC_SA_MATCH_HI_ETYPE((__force u32)htons(flow->etype))); |
405 | } |
406 | |
407 | match |= MSCC_MS_SAM_MISC_MATCH_PRIORITY(flow->priority); |
408 | |
409 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MISC_MATCH(idx), val: match); |
410 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MASK(idx), val: mask); |
411 | |
412 | /* Action for matching packets */ |
413 | if (flow->action.drop) |
414 | action = MSCC_MS_FLOW_DROP; |
415 | else if (flow->action.bypass || flow->port == MSCC_MS_PORT_UNCONTROLLED) |
416 | action = MSCC_MS_FLOW_BYPASS; |
417 | else |
418 | action = (bank == MACSEC_INGR) ? |
419 | MSCC_MS_FLOW_INGRESS : MSCC_MS_FLOW_EGRESS; |
420 | |
421 | val = MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE(action) | |
422 | MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION(MSCC_MS_ACTION_DROP) | |
423 | MSCC_MS_SAM_FLOW_CTRL_DEST_PORT(flow->port); |
424 | |
425 | if (action == MSCC_MS_FLOW_BYPASS) |
426 | goto write_ctrl; |
427 | |
428 | if (bank == MACSEC_INGR) { |
429 | if (priv->secy->replay_protect) |
430 | val |= MSCC_MS_SAM_FLOW_CTRL_REPLAY_PROTECT; |
431 | if (priv->secy->validate_frames == MACSEC_VALIDATE_STRICT) |
432 | val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_STRICT); |
433 | else if (priv->secy->validate_frames == MACSEC_VALIDATE_CHECK) |
434 | val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_CHECK); |
435 | } else if (bank == MACSEC_EGR) { |
436 | if (priv->secy->protect_frames) |
437 | val |= MSCC_MS_SAM_FLOW_CTRL_PROTECT_FRAME; |
438 | if (priv->secy->tx_sc.encrypt) |
439 | val |= MSCC_MS_SAM_FLOW_CTRL_CONF_PROTECT; |
440 | if (priv->secy->tx_sc.send_sci) |
441 | val |= MSCC_MS_SAM_FLOW_CTRL_INCLUDE_SCI; |
442 | } |
443 | |
444 | write_ctrl: |
445 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val); |
446 | } |
447 | |
448 | static struct macsec_flow *vsc8584_macsec_find_flow(struct macsec_context *ctx, |
449 | enum macsec_bank bank) |
450 | { |
451 | struct vsc8531_private *priv = ctx->phydev->priv; |
452 | struct macsec_flow *pos, *tmp; |
453 | |
454 | list_for_each_entry_safe(pos, tmp, &priv->macsec_flows, list) |
455 | if (pos->assoc_num == ctx->sa.assoc_num && pos->bank == bank) |
456 | return pos; |
457 | |
458 | return ERR_PTR(error: -ENOENT); |
459 | } |
460 | |
461 | static void vsc8584_macsec_flow_enable(struct phy_device *phydev, |
462 | struct macsec_flow *flow) |
463 | { |
464 | enum macsec_bank bank = flow->bank; |
465 | u32 val, idx = flow->index; |
466 | |
467 | if ((flow->bank == MACSEC_INGR && flow->rx_sa && !flow->rx_sa->active) || |
468 | (flow->bank == MACSEC_EGR && flow->tx_sa && !flow->tx_sa->active)) |
469 | return; |
470 | |
471 | /* Enable */ |
472 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_SET1, BIT(idx)); |
473 | |
474 | /* Set in-use */ |
475 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx)); |
476 | val |= MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE; |
477 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val); |
478 | } |
479 | |
480 | static void vsc8584_macsec_flow_disable(struct phy_device *phydev, |
481 | struct macsec_flow *flow) |
482 | { |
483 | enum macsec_bank bank = flow->bank; |
484 | u32 val, idx = flow->index; |
485 | |
486 | /* Disable */ |
487 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_CLEAR1, BIT(idx)); |
488 | |
489 | /* Clear in-use */ |
490 | val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx)); |
491 | val &= ~MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE; |
492 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val); |
493 | } |
494 | |
495 | static u32 vsc8584_macsec_flow_context_id(struct macsec_flow *flow) |
496 | { |
497 | if (flow->bank == MACSEC_INGR) |
498 | return flow->index + MSCC_MS_MAX_FLOWS; |
499 | |
500 | return flow->index; |
501 | } |
502 | |
503 | /* Derive the AES key to get a key for the hash autentication */ |
504 | static int vsc8584_macsec_derive_key(const u8 *key, u16 key_len, u8 hkey[16]) |
505 | { |
506 | const u8 input[AES_BLOCK_SIZE] = {0}; |
507 | struct crypto_aes_ctx ctx; |
508 | int ret; |
509 | |
510 | ret = aes_expandkey(ctx: &ctx, in_key: key, key_len); |
511 | if (ret) |
512 | return ret; |
513 | |
514 | aes_encrypt(ctx: &ctx, out: hkey, in: input); |
515 | memzero_explicit(s: &ctx, count: sizeof(ctx)); |
516 | return 0; |
517 | } |
518 | |
519 | static int vsc8584_macsec_transformation(struct phy_device *phydev, |
520 | struct macsec_flow *flow, |
521 | const u8 *key) |
522 | { |
523 | struct vsc8531_private *priv = phydev->priv; |
524 | enum macsec_bank bank = flow->bank; |
525 | int i, ret, index = flow->index; |
526 | u32 rec = 0, control = 0; |
527 | u8 hkey[16]; |
528 | u64 sci; |
529 | |
530 | ret = vsc8584_macsec_derive_key(key, key_len: priv->secy->key_len, hkey); |
531 | if (ret) |
532 | return ret; |
533 | |
534 | switch (priv->secy->key_len) { |
535 | case 16: |
536 | control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_128); |
537 | break; |
538 | case 32: |
539 | control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_256); |
540 | break; |
541 | default: |
542 | return -EINVAL; |
543 | } |
544 | |
545 | control |= (bank == MACSEC_EGR) ? |
546 | (CONTROL_TYPE_EGRESS | CONTROL_AN(priv->secy->tx_sc.encoding_sa)) : |
547 | (CONTROL_TYPE_INGRESS | CONTROL_SEQ_MASK); |
548 | |
549 | control |= CONTROL_UPDATE_SEQ | CONTROL_ENCRYPT_AUTH | CONTROL_KEY_IN_CTX | |
550 | CONTROL_IV0 | CONTROL_IV1 | CONTROL_IV_IN_SEQ | |
551 | CONTROL_DIGEST_TYPE(0x2) | CONTROL_SEQ_TYPE(0x1) | |
552 | CONTROL_AUTH_ALG(AUTH_ALG_AES_GHAS) | CONTROL_CONTEXT_ID; |
553 | |
554 | /* Set the control word */ |
555 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), |
556 | val: control); |
557 | |
558 | /* Set the context ID. Must be unique. */ |
559 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), |
560 | val: vsc8584_macsec_flow_context_id(flow)); |
561 | |
562 | /* Set the encryption/decryption key */ |
563 | for (i = 0; i < priv->secy->key_len / sizeof(u32); i++) |
564 | vsc8584_macsec_phy_write(phydev, bank, |
565 | MSCC_MS_XFORM_REC(index, rec++), |
566 | val: ((u32 *)key)[i]); |
567 | |
568 | /* Set the authentication key */ |
569 | for (i = 0; i < 4; i++) |
570 | vsc8584_macsec_phy_write(phydev, bank, |
571 | MSCC_MS_XFORM_REC(index, rec++), |
572 | val: ((u32 *)hkey)[i]); |
573 | |
574 | /* Initial sequence number */ |
575 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), |
576 | val: bank == MACSEC_INGR ? |
577 | flow->rx_sa->next_pn : flow->tx_sa->next_pn); |
578 | |
579 | if (bank == MACSEC_INGR) |
580 | /* Set the mask (replay window size) */ |
581 | vsc8584_macsec_phy_write(phydev, bank, |
582 | MSCC_MS_XFORM_REC(index, rec++), |
583 | val: priv->secy->replay_window); |
584 | |
585 | /* Set the input vectors */ |
586 | sci = (__force u64)(bank == MACSEC_INGR ? flow->rx_sa->sc->sci : priv->secy->sci); |
587 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), |
588 | lower_32_bits(sci)); |
589 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), |
590 | upper_32_bits(sci)); |
591 | |
592 | while (rec < 20) |
593 | vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), |
594 | val: 0); |
595 | |
596 | flow->has_transformation = true; |
597 | return 0; |
598 | } |
599 | |
600 | static struct macsec_flow *vsc8584_macsec_alloc_flow(struct vsc8531_private *priv, |
601 | enum macsec_bank bank) |
602 | { |
603 | unsigned long *bitmap = bank == MACSEC_INGR ? |
604 | &priv->ingr_flows : &priv->egr_flows; |
605 | struct macsec_flow *flow; |
606 | int index; |
607 | |
608 | index = find_first_zero_bit(addr: bitmap, MSCC_MS_MAX_FLOWS); |
609 | |
610 | if (index == MSCC_MS_MAX_FLOWS) |
611 | return ERR_PTR(error: -ENOMEM); |
612 | |
613 | flow = kzalloc(size: sizeof(*flow), GFP_KERNEL); |
614 | if (!flow) |
615 | return ERR_PTR(error: -ENOMEM); |
616 | |
617 | set_bit(nr: index, addr: bitmap); |
618 | flow->index = index; |
619 | flow->bank = bank; |
620 | flow->priority = 8; |
621 | flow->assoc_num = -1; |
622 | |
623 | list_add_tail(new: &flow->list, head: &priv->macsec_flows); |
624 | return flow; |
625 | } |
626 | |
627 | static void vsc8584_macsec_free_flow(struct vsc8531_private *priv, |
628 | struct macsec_flow *flow) |
629 | { |
630 | unsigned long *bitmap = flow->bank == MACSEC_INGR ? |
631 | &priv->ingr_flows : &priv->egr_flows; |
632 | |
633 | list_del(entry: &flow->list); |
634 | clear_bit(nr: flow->index, addr: bitmap); |
635 | kfree(objp: flow); |
636 | } |
637 | |
638 | static void vsc8584_macsec_add_flow(struct phy_device *phydev, |
639 | struct macsec_flow *flow) |
640 | { |
641 | flow->port = MSCC_MS_PORT_CONTROLLED; |
642 | vsc8584_macsec_flow(phydev, flow); |
643 | } |
644 | |
645 | static int vsc8584_macsec_default_flows(struct phy_device *phydev) |
646 | { |
647 | struct macsec_flow *flow; |
648 | |
649 | /* Add a rule to let the MKA traffic go through, ingress */ |
650 | flow = vsc8584_macsec_alloc_flow(priv: phydev->priv, bank: MACSEC_INGR); |
651 | if (IS_ERR(ptr: flow)) |
652 | return PTR_ERR(ptr: flow); |
653 | |
654 | flow->priority = 15; |
655 | flow->port = MSCC_MS_PORT_UNCONTROLLED; |
656 | flow->match.tagged = 1; |
657 | flow->match.untagged = 1; |
658 | flow->match.etype = 1; |
659 | flow->etype = ETH_P_PAE; |
660 | flow->action.bypass = 1; |
661 | |
662 | vsc8584_macsec_flow(phydev, flow); |
663 | vsc8584_macsec_flow_enable(phydev, flow); |
664 | |
665 | /* Add a rule to let the MKA traffic go through, egress */ |
666 | flow = vsc8584_macsec_alloc_flow(priv: phydev->priv, bank: MACSEC_EGR); |
667 | if (IS_ERR(ptr: flow)) |
668 | return PTR_ERR(ptr: flow); |
669 | |
670 | flow->priority = 15; |
671 | flow->port = MSCC_MS_PORT_COMMON; |
672 | flow->match.untagged = 1; |
673 | flow->match.etype = 1; |
674 | flow->etype = ETH_P_PAE; |
675 | flow->action.bypass = 1; |
676 | |
677 | vsc8584_macsec_flow(phydev, flow); |
678 | vsc8584_macsec_flow_enable(phydev, flow); |
679 | |
680 | return 0; |
681 | } |
682 | |
683 | static void vsc8584_macsec_del_flow(struct phy_device *phydev, |
684 | struct macsec_flow *flow) |
685 | { |
686 | vsc8584_macsec_flow_disable(phydev, flow); |
687 | vsc8584_macsec_free_flow(priv: phydev->priv, flow); |
688 | } |
689 | |
690 | static int __vsc8584_macsec_add_rxsa(struct macsec_context *ctx, |
691 | struct macsec_flow *flow, bool update) |
692 | { |
693 | struct phy_device *phydev = ctx->phydev; |
694 | struct vsc8531_private *priv = phydev->priv; |
695 | int ret; |
696 | |
697 | flow->assoc_num = ctx->sa.assoc_num; |
698 | flow->rx_sa = ctx->sa.rx_sa; |
699 | |
700 | /* Always match tagged packets on ingress */ |
701 | flow->match.tagged = 1; |
702 | flow->match.sci = 1; |
703 | |
704 | if (priv->secy->validate_frames != MACSEC_VALIDATE_DISABLED) |
705 | flow->match.untagged = 1; |
706 | |
707 | vsc8584_macsec_add_flow(phydev, flow); |
708 | |
709 | if (update) |
710 | return 0; |
711 | |
712 | ret = vsc8584_macsec_transformation(phydev, flow, key: ctx->sa.key); |
713 | if (ret) |
714 | vsc8584_macsec_free_flow(priv: phydev->priv, flow); |
715 | |
716 | return ret; |
717 | } |
718 | |
719 | static int __vsc8584_macsec_add_txsa(struct macsec_context *ctx, |
720 | struct macsec_flow *flow, bool update) |
721 | { |
722 | int ret; |
723 | |
724 | flow->assoc_num = ctx->sa.assoc_num; |
725 | flow->tx_sa = ctx->sa.tx_sa; |
726 | |
727 | /* Always match untagged packets on egress */ |
728 | flow->match.untagged = 1; |
729 | |
730 | vsc8584_macsec_add_flow(phydev: ctx->phydev, flow); |
731 | |
732 | if (update) |
733 | return 0; |
734 | |
735 | ret = vsc8584_macsec_transformation(phydev: ctx->phydev, flow, key: ctx->sa.key); |
736 | if (ret) |
737 | vsc8584_macsec_free_flow(priv: ctx->phydev->priv, flow); |
738 | |
739 | return ret; |
740 | } |
741 | |
742 | static int vsc8584_macsec_dev_open(struct macsec_context *ctx) |
743 | { |
744 | struct vsc8531_private *priv = ctx->phydev->priv; |
745 | struct macsec_flow *flow, *tmp; |
746 | |
747 | list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) |
748 | vsc8584_macsec_flow_enable(phydev: ctx->phydev, flow); |
749 | |
750 | return 0; |
751 | } |
752 | |
753 | static int vsc8584_macsec_dev_stop(struct macsec_context *ctx) |
754 | { |
755 | struct vsc8531_private *priv = ctx->phydev->priv; |
756 | struct macsec_flow *flow, *tmp; |
757 | |
758 | list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) |
759 | vsc8584_macsec_flow_disable(phydev: ctx->phydev, flow); |
760 | |
761 | return 0; |
762 | } |
763 | |
764 | static int vsc8584_macsec_add_secy(struct macsec_context *ctx) |
765 | { |
766 | struct vsc8531_private *priv = ctx->phydev->priv; |
767 | struct macsec_secy *secy = ctx->secy; |
768 | |
769 | if (priv->secy) |
770 | return -EEXIST; |
771 | |
772 | priv->secy = secy; |
773 | |
774 | vsc8584_macsec_flow_default_action(phydev: ctx->phydev, bank: MACSEC_EGR, |
775 | block: secy->validate_frames != MACSEC_VALIDATE_DISABLED); |
776 | vsc8584_macsec_flow_default_action(phydev: ctx->phydev, bank: MACSEC_INGR, |
777 | block: secy->validate_frames != MACSEC_VALIDATE_DISABLED); |
778 | |
779 | return vsc8584_macsec_default_flows(phydev: ctx->phydev); |
780 | } |
781 | |
782 | static int vsc8584_macsec_del_secy(struct macsec_context *ctx) |
783 | { |
784 | struct vsc8531_private *priv = ctx->phydev->priv; |
785 | struct macsec_flow *flow, *tmp; |
786 | |
787 | list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) |
788 | vsc8584_macsec_del_flow(phydev: ctx->phydev, flow); |
789 | |
790 | vsc8584_macsec_flow_default_action(phydev: ctx->phydev, bank: MACSEC_EGR, block: false); |
791 | vsc8584_macsec_flow_default_action(phydev: ctx->phydev, bank: MACSEC_INGR, block: false); |
792 | |
793 | priv->secy = NULL; |
794 | return 0; |
795 | } |
796 | |
797 | static int vsc8584_macsec_upd_secy(struct macsec_context *ctx) |
798 | { |
799 | vsc8584_macsec_del_secy(ctx); |
800 | return vsc8584_macsec_add_secy(ctx); |
801 | } |
802 | |
803 | static int vsc8584_macsec_add_rxsc(struct macsec_context *ctx) |
804 | { |
805 | /* Nothing to do */ |
806 | return 0; |
807 | } |
808 | |
809 | static int vsc8584_macsec_upd_rxsc(struct macsec_context *ctx) |
810 | { |
811 | return -EOPNOTSUPP; |
812 | } |
813 | |
814 | static int vsc8584_macsec_del_rxsc(struct macsec_context *ctx) |
815 | { |
816 | struct vsc8531_private *priv = ctx->phydev->priv; |
817 | struct macsec_flow *flow, *tmp; |
818 | |
819 | list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) { |
820 | if (flow->bank == MACSEC_INGR && flow->rx_sa && |
821 | flow->rx_sa->sc->sci == ctx->rx_sc->sci) |
822 | vsc8584_macsec_del_flow(phydev: ctx->phydev, flow); |
823 | } |
824 | |
825 | return 0; |
826 | } |
827 | |
828 | static int vsc8584_macsec_add_rxsa(struct macsec_context *ctx) |
829 | { |
830 | struct phy_device *phydev = ctx->phydev; |
831 | struct vsc8531_private *priv = phydev->priv; |
832 | struct macsec_flow *flow; |
833 | int ret; |
834 | |
835 | flow = vsc8584_macsec_alloc_flow(priv, bank: MACSEC_INGR); |
836 | if (IS_ERR(ptr: flow)) |
837 | return PTR_ERR(ptr: flow); |
838 | |
839 | ret = __vsc8584_macsec_add_rxsa(ctx, flow, update: false); |
840 | if (ret) |
841 | return ret; |
842 | |
843 | vsc8584_macsec_flow_enable(phydev, flow); |
844 | return 0; |
845 | } |
846 | |
847 | static int vsc8584_macsec_upd_rxsa(struct macsec_context *ctx) |
848 | { |
849 | struct macsec_flow *flow; |
850 | int ret; |
851 | |
852 | if (ctx->sa.update_pn) |
853 | return -EINVAL; |
854 | |
855 | flow = vsc8584_macsec_find_flow(ctx, bank: MACSEC_INGR); |
856 | if (IS_ERR(ptr: flow)) |
857 | return PTR_ERR(ptr: flow); |
858 | |
859 | /* Make sure the flow is disabled before updating it */ |
860 | vsc8584_macsec_flow_disable(phydev: ctx->phydev, flow); |
861 | |
862 | ret = __vsc8584_macsec_add_rxsa(ctx, flow, update: true); |
863 | if (ret) |
864 | return ret; |
865 | |
866 | vsc8584_macsec_flow_enable(phydev: ctx->phydev, flow); |
867 | return 0; |
868 | } |
869 | |
870 | static int vsc8584_macsec_del_rxsa(struct macsec_context *ctx) |
871 | { |
872 | struct macsec_flow *flow; |
873 | |
874 | flow = vsc8584_macsec_find_flow(ctx, bank: MACSEC_INGR); |
875 | if (IS_ERR(ptr: flow)) |
876 | return PTR_ERR(ptr: flow); |
877 | |
878 | vsc8584_macsec_del_flow(phydev: ctx->phydev, flow); |
879 | return 0; |
880 | } |
881 | |
882 | static int vsc8584_macsec_add_txsa(struct macsec_context *ctx) |
883 | { |
884 | struct phy_device *phydev = ctx->phydev; |
885 | struct vsc8531_private *priv = phydev->priv; |
886 | struct macsec_flow *flow; |
887 | int ret; |
888 | |
889 | flow = vsc8584_macsec_alloc_flow(priv, bank: MACSEC_EGR); |
890 | if (IS_ERR(ptr: flow)) |
891 | return PTR_ERR(ptr: flow); |
892 | |
893 | ret = __vsc8584_macsec_add_txsa(ctx, flow, update: false); |
894 | if (ret) |
895 | return ret; |
896 | |
897 | vsc8584_macsec_flow_enable(phydev, flow); |
898 | return 0; |
899 | } |
900 | |
901 | static int vsc8584_macsec_upd_txsa(struct macsec_context *ctx) |
902 | { |
903 | struct macsec_flow *flow; |
904 | int ret; |
905 | |
906 | if (ctx->sa.update_pn) |
907 | return -EINVAL; |
908 | |
909 | flow = vsc8584_macsec_find_flow(ctx, bank: MACSEC_EGR); |
910 | if (IS_ERR(ptr: flow)) |
911 | return PTR_ERR(ptr: flow); |
912 | |
913 | /* Make sure the flow is disabled before updating it */ |
914 | vsc8584_macsec_flow_disable(phydev: ctx->phydev, flow); |
915 | |
916 | ret = __vsc8584_macsec_add_txsa(ctx, flow, update: true); |
917 | if (ret) |
918 | return ret; |
919 | |
920 | vsc8584_macsec_flow_enable(phydev: ctx->phydev, flow); |
921 | return 0; |
922 | } |
923 | |
924 | static int vsc8584_macsec_del_txsa(struct macsec_context *ctx) |
925 | { |
926 | struct macsec_flow *flow; |
927 | |
928 | flow = vsc8584_macsec_find_flow(ctx, bank: MACSEC_EGR); |
929 | if (IS_ERR(ptr: flow)) |
930 | return PTR_ERR(ptr: flow); |
931 | |
932 | vsc8584_macsec_del_flow(phydev: ctx->phydev, flow); |
933 | return 0; |
934 | } |
935 | |
936 | static const struct macsec_ops vsc8584_macsec_ops = { |
937 | .mdo_dev_open = vsc8584_macsec_dev_open, |
938 | .mdo_dev_stop = vsc8584_macsec_dev_stop, |
939 | .mdo_add_secy = vsc8584_macsec_add_secy, |
940 | .mdo_upd_secy = vsc8584_macsec_upd_secy, |
941 | .mdo_del_secy = vsc8584_macsec_del_secy, |
942 | .mdo_add_rxsc = vsc8584_macsec_add_rxsc, |
943 | .mdo_upd_rxsc = vsc8584_macsec_upd_rxsc, |
944 | .mdo_del_rxsc = vsc8584_macsec_del_rxsc, |
945 | .mdo_add_rxsa = vsc8584_macsec_add_rxsa, |
946 | .mdo_upd_rxsa = vsc8584_macsec_upd_rxsa, |
947 | .mdo_del_rxsa = vsc8584_macsec_del_rxsa, |
948 | .mdo_add_txsa = vsc8584_macsec_add_txsa, |
949 | .mdo_upd_txsa = vsc8584_macsec_upd_txsa, |
950 | .mdo_del_txsa = vsc8584_macsec_del_txsa, |
951 | }; |
952 | |
953 | int vsc8584_macsec_init(struct phy_device *phydev) |
954 | { |
955 | struct vsc8531_private *vsc8531 = phydev->priv; |
956 | |
957 | switch (phydev->phy_id & phydev->drv->phy_id_mask) { |
958 | case PHY_ID_VSC856X: |
959 | case PHY_ID_VSC8582: |
960 | case PHY_ID_VSC8584: |
961 | INIT_LIST_HEAD(list: &vsc8531->macsec_flows); |
962 | vsc8531->secy = NULL; |
963 | |
964 | phydev->macsec_ops = &vsc8584_macsec_ops; |
965 | |
966 | return __vsc8584_macsec_init(phydev); |
967 | } |
968 | |
969 | return 0; |
970 | } |
971 | |
972 | void vsc8584_handle_macsec_interrupt(struct phy_device *phydev) |
973 | { |
974 | struct vsc8531_private *priv = phydev->priv; |
975 | struct macsec_flow *flow, *tmp; |
976 | u32 cause, rec; |
977 | |
978 | /* Check MACsec PN rollover */ |
979 | cause = vsc8584_macsec_phy_read(phydev, bank: MACSEC_EGR, |
980 | MSCC_MS_INTR_CTRL_STATUS); |
981 | cause &= MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M; |
982 | if (!(cause & MACSEC_INTR_CTRL_STATUS_ROLLOVER)) |
983 | return; |
984 | |
985 | rec = 6 + priv->secy->key_len / sizeof(u32); |
986 | list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) { |
987 | u32 val; |
988 | |
989 | if (flow->bank != MACSEC_EGR || !flow->has_transformation) |
990 | continue; |
991 | |
992 | val = vsc8584_macsec_phy_read(phydev, bank: MACSEC_EGR, |
993 | MSCC_MS_XFORM_REC(flow->index, rec)); |
994 | if (val == 0xffffffff) { |
995 | vsc8584_macsec_flow_disable(phydev, flow); |
996 | macsec_pn_wrapped(secy: priv->secy, tx_sa: flow->tx_sa); |
997 | return; |
998 | } |
999 | } |
1000 | } |
1001 | |
1002 | void vsc8584_config_macsec_intr(struct phy_device *phydev) |
1003 | { |
1004 | phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2); |
1005 | phy_write(phydev, MSCC_PHY_EXTENDED_INT, MSCC_PHY_EXTENDED_INT_MS_EGR); |
1006 | phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); |
1007 | |
1008 | vsc8584_macsec_phy_write(phydev, bank: MACSEC_EGR, MSCC_MS_AIC_CTRL, val: 0xf); |
1009 | vsc8584_macsec_phy_write(phydev, bank: MACSEC_EGR, MSCC_MS_INTR_CTRL_STATUS, |
1010 | MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(MACSEC_INTR_CTRL_STATUS_ROLLOVER)); |
1011 | } |
1012 | |