OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From bdb1d42c9398eb14e997e026bd46602543a7ed03 Mon Sep 17 00:00:00 2001 |
2 | From: Biwen Li <biwen.li@nxp.com> |
||
3 | Date: Tue, 30 Oct 2018 18:26:16 +0800 |
||
4 | Subject: [PATCH 09/40] dpaa2-l2switch: support layerscape |
||
5 | This is an integrated patch of dpaa2-l2switch for |
||
6 | layerscape |
||
7 | |||
8 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
||
9 | Signed-off-by: Guanhua Gao <guanhua.gao@nxp.com> |
||
10 | Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com> |
||
11 | Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com> |
||
12 | Signed-off-by: Biwen Li <biwen.li@nxp.com> |
||
13 | --- |
||
14 | drivers/staging/fsl-dpaa2/ethsw/Makefile | 10 + |
||
15 | drivers/staging/fsl-dpaa2/ethsw/README | 106 ++ |
||
16 | drivers/staging/fsl-dpaa2/ethsw/TODO | 14 + |
||
17 | drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 359 ++++ |
||
18 | drivers/staging/fsl-dpaa2/ethsw/dpsw.c | 1165 +++++++++++++ |
||
19 | drivers/staging/fsl-dpaa2/ethsw/dpsw.h | 592 +++++++ |
||
20 | .../staging/fsl-dpaa2/ethsw/ethsw-ethtool.c | 206 +++ |
||
21 | drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 1438 +++++++++++++++++ |
||
22 | drivers/staging/fsl-dpaa2/ethsw/ethsw.h | 90 ++ |
||
23 | 9 files changed, 3980 insertions(+) |
||
24 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/Makefile |
||
25 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/README |
||
26 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/TODO |
||
27 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h |
||
28 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/dpsw.c |
||
29 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/dpsw.h |
||
30 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c |
||
31 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/ethsw.c |
||
32 | create mode 100644 drivers/staging/fsl-dpaa2/ethsw/ethsw.h |
||
33 | |||
34 | --- /dev/null |
||
35 | +++ b/drivers/staging/fsl-dpaa2/ethsw/Makefile |
||
36 | @@ -0,0 +1,10 @@ |
||
37 | +# SPDX-License-Identifier: GPL-2.0 |
||
38 | +# |
||
39 | +# Makefile for the Freescale DPAA2 Ethernet Switch |
||
40 | +# |
||
41 | +# Copyright 2014-2017 Freescale Semiconductor, Inc. |
||
42 | +# Copyright 2017-2018 NXP |
||
43 | + |
||
44 | +obj-$(CONFIG_FSL_DPAA2_ETHSW) += dpaa2-ethsw.o |
||
45 | + |
||
46 | +dpaa2-ethsw-objs := ethsw.o ethsw-ethtool.o dpsw.o |
||
47 | --- /dev/null |
||
48 | +++ b/drivers/staging/fsl-dpaa2/ethsw/README |
||
49 | @@ -0,0 +1,106 @@ |
||
50 | +DPAA2 Ethernet Switch driver |
||
51 | +============================ |
||
52 | + |
||
53 | +This file provides documentation for the DPAA2 Ethernet Switch driver |
||
54 | + |
||
55 | + |
||
56 | +Contents |
||
57 | +======== |
||
58 | + Supported Platforms |
||
59 | + Architecture Overview |
||
60 | + Creating an Ethernet Switch |
||
61 | + Features |
||
62 | + |
||
63 | + |
||
64 | + Supported Platforms |
||
65 | +=================== |
||
66 | +This driver provides networking support for Freescale LS2085A, LS2088A |
||
67 | +DPAA2 SoCs. |
||
68 | + |
||
69 | + |
||
70 | +Architecture Overview |
||
71 | +===================== |
||
72 | +The Ethernet Switch in the DPAA2 architecture consists of several hardware |
||
73 | +resources that provide the functionality. These are allocated and |
||
74 | +configured via the Management Complex (MC) portals. MC abstracts most of |
||
75 | +these resources as DPAA2 objects and exposes ABIs through which they can |
||
76 | +be configured and controlled. |
||
77 | + |
||
78 | +For a more detailed description of the DPAA2 architecture and its object |
||
79 | +abstractions see: |
||
80 | + drivers/staging/fsl-mc/README.txt |
||
81 | + |
||
82 | +The Ethernet Switch is built on top of a Datapath Switch (DPSW) object. |
||
83 | + |
||
84 | +Configuration interface: |
||
85 | + |
||
86 | + --------------------- |
||
87 | + | DPAA2 Switch driver | |
||
88 | + --------------------- |
||
89 | + . |
||
90 | + . |
||
91 | + ---------- |
||
92 | + | DPSW API | |
||
93 | + ---------- |
||
94 | + . software |
||
95 | + ================= . ============== |
||
96 | + . hardware |
||
97 | + --------------------- |
||
98 | + | MC hardware portals | |
||
99 | + --------------------- |
||
100 | + . |
||
101 | + . |
||
102 | + ------ |
||
103 | + | DPSW | |
||
104 | + ------ |
||
105 | + |
||
106 | +Driver uses the switch device driver model and exposes each switch port as |
||
107 | +a network interface, which can be included in a bridge. Traffic switched |
||
108 | +between ports is offloaded into the hardware. Exposed network interfaces |
||
109 | +are not used for I/O, they are used just for configuration. This |
||
110 | +limitation is going to be addressed in the future. |
||
111 | + |
||
112 | +The DPSW can have ports connected to DPNIs or to PHYs via DPMACs. |
||
113 | + |
||
114 | + |
||
115 | + [ethA] [ethB] [ethC] [ethD] [ethE] [ethF] |
||
116 | + : : : : : : |
||
117 | + : : : : : : |
||
118 | +[eth drv] [eth drv] [ ethsw drv ] |
||
119 | + : : : : : : kernel |
||
120 | +======================================================================== |
||
121 | + : : : : : : hardware |
||
122 | + [DPNI] [DPNI] [============= DPSW =================] |
||
123 | + | | | | | | |
||
124 | + | ---------- | [DPMAC] [DPMAC] |
||
125 | + ------------------------------- | | |
||
126 | + | | |
||
127 | + [PHY] [PHY] |
||
128 | + |
||
129 | +For a more detailed description of the Ethernet switch device driver model |
||
130 | +see: |
||
131 | + Documentation/networking/switchdev.txt |
||
132 | + |
||
133 | +Creating an Ethernet Switch |
||
134 | +=========================== |
||
135 | +A device is created for the switch objects probed on the MC bus. Each DPSW |
||
136 | +has a number of properties which determine the configuration options and |
||
137 | +associated hardware resources. |
||
138 | + |
||
139 | +A DPSW object (and the other DPAA2 objects needed for a DPAA2 switch) can |
||
140 | +be added to a container on the MC bus in one of two ways: statically, |
||
141 | +through a Datapath Layout Binary file (DPL) that is parsed by MC at boot |
||
142 | +time; or created dynamically at runtime, via the DPAA2 objects APIs. |
||
143 | + |
||
144 | +Features |
||
145 | +======== |
||
146 | +Driver configures DPSW to perform hardware switching offload of |
||
147 | +unicast/multicast/broadcast (VLAN tagged or untagged) traffic between its |
||
148 | +ports. |
||
149 | + |
||
150 | +It allows configuration of hardware learning, flooding, multicast groups, |
||
151 | +port VLAN configuration and STP state. |
||
152 | + |
||
153 | +Static entries can be added/removed from the FDB. |
||
154 | + |
||
155 | +Hardware statistics for each port are provided through ethtool -S option. |
||
156 | --- /dev/null |
||
157 | +++ b/drivers/staging/fsl-dpaa2/ethsw/TODO |
||
158 | @@ -0,0 +1,14 @@ |
||
159 | +* Add I/O capabilities on switch port netdevices. This will allow control |
||
160 | +traffic to reach the CPU. |
||
161 | +* Add ACL to redirect control traffic to CPU. |
||
162 | +* Add support for displaying learned FDB entries |
||
163 | +* MC firmware uprev; the DPAA2 objects used by the Ethernet Switch driver |
||
164 | +need to be kept in sync with binary interface changes in MC |
||
165 | +* refine README file |
||
166 | +* cleanup |
||
167 | + |
||
168 | +NOTE: At least first three of the above are required before getting the |
||
169 | +DPAA2 Ethernet Switch driver out of staging. Another requirement is that |
||
170 | +the fsl-mc bus driver is moved to drivers/bus and dpio driver is moved to |
||
171 | +drivers/soc (this is required for I/O). |
||
172 | + |
||
173 | --- /dev/null |
||
174 | +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h |
||
175 | @@ -0,0 +1,359 @@ |
||
176 | +// SPDX-License-Identifier: GPL-2.0 |
||
177 | +/* |
||
178 | + * Copyright 2013-2016 Freescale Semiconductor, Inc. |
||
179 | + * Copyright 2017-2018 NXP |
||
180 | + * |
||
181 | + */ |
||
182 | + |
||
183 | +#ifndef __FSL_DPSW_CMD_H |
||
184 | +#define __FSL_DPSW_CMD_H |
||
185 | + |
||
186 | +/* DPSW Version */ |
||
187 | +#define DPSW_VER_MAJOR 8 |
||
188 | +#define DPSW_VER_MINOR 0 |
||
189 | + |
||
190 | +#define DPSW_CMD_BASE_VERSION 1 |
||
191 | +#define DPSW_CMD_ID_OFFSET 4 |
||
192 | + |
||
193 | +#define DPSW_CMD_ID(id) (((id) << DPSW_CMD_ID_OFFSET) | DPSW_CMD_BASE_VERSION) |
||
194 | + |
||
195 | +/* Command IDs */ |
||
196 | +#define DPSW_CMDID_CLOSE DPSW_CMD_ID(0x800) |
||
197 | +#define DPSW_CMDID_OPEN DPSW_CMD_ID(0x802) |
||
198 | + |
||
199 | +#define DPSW_CMDID_GET_API_VERSION DPSW_CMD_ID(0xa02) |
||
200 | + |
||
201 | +#define DPSW_CMDID_ENABLE DPSW_CMD_ID(0x002) |
||
202 | +#define DPSW_CMDID_DISABLE DPSW_CMD_ID(0x003) |
||
203 | +#define DPSW_CMDID_GET_ATTR DPSW_CMD_ID(0x004) |
||
204 | +#define DPSW_CMDID_RESET DPSW_CMD_ID(0x005) |
||
205 | + |
||
206 | +#define DPSW_CMDID_SET_IRQ_ENABLE DPSW_CMD_ID(0x012) |
||
207 | + |
||
208 | +#define DPSW_CMDID_SET_IRQ_MASK DPSW_CMD_ID(0x014) |
||
209 | + |
||
210 | +#define DPSW_CMDID_GET_IRQ_STATUS DPSW_CMD_ID(0x016) |
||
211 | +#define DPSW_CMDID_CLEAR_IRQ_STATUS DPSW_CMD_ID(0x017) |
||
212 | + |
||
213 | +#define DPSW_CMDID_IF_SET_TCI DPSW_CMD_ID(0x030) |
||
214 | +#define DPSW_CMDID_IF_SET_STP DPSW_CMD_ID(0x031) |
||
215 | + |
||
216 | +#define DPSW_CMDID_IF_GET_COUNTER DPSW_CMD_ID(0x034) |
||
217 | + |
||
218 | +#define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D) |
||
219 | +#define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E) |
||
220 | + |
||
221 | +#define DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH DPSW_CMD_ID(0x044) |
||
222 | + |
||
223 | +#define DPSW_CMDID_IF_GET_LINK_STATE DPSW_CMD_ID(0x046) |
||
224 | +#define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047) |
||
225 | +#define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048) |
||
226 | + |
||
227 | +#define DPSW_CMDID_IF_GET_TCI DPSW_CMD_ID(0x04A) |
||
228 | + |
||
229 | +#define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C) |
||
230 | + |
||
231 | +#define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060) |
||
232 | +#define DPSW_CMDID_VLAN_ADD_IF DPSW_CMD_ID(0x061) |
||
233 | +#define DPSW_CMDID_VLAN_ADD_IF_UNTAGGED DPSW_CMD_ID(0x062) |
||
234 | + |
||
235 | +#define DPSW_CMDID_VLAN_REMOVE_IF DPSW_CMD_ID(0x064) |
||
236 | +#define DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED DPSW_CMD_ID(0x065) |
||
237 | +#define DPSW_CMDID_VLAN_REMOVE_IF_FLOODING DPSW_CMD_ID(0x066) |
||
238 | +#define DPSW_CMDID_VLAN_REMOVE DPSW_CMD_ID(0x067) |
||
239 | + |
||
240 | +#define DPSW_CMDID_FDB_ADD_UNICAST DPSW_CMD_ID(0x084) |
||
241 | +#define DPSW_CMDID_FDB_REMOVE_UNICAST DPSW_CMD_ID(0x085) |
||
242 | +#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086) |
||
243 | +#define DPSW_CMDID_FDB_REMOVE_MULTICAST DPSW_CMD_ID(0x087) |
||
244 | +#define DPSW_CMDID_FDB_SET_LEARNING_MODE DPSW_CMD_ID(0x088) |
||
245 | + |
||
246 | +/* Macros for accessing command fields smaller than 1byte */ |
||
247 | +#define DPSW_MASK(field) \ |
||
248 | + GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \ |
||
249 | + DPSW_##field##_SHIFT) |
||
250 | +#define dpsw_set_field(var, field, val) \ |
||
251 | + ((var) |= (((val) << DPSW_##field##_SHIFT) & DPSW_MASK(field))) |
||
252 | +#define dpsw_get_field(var, field) \ |
||
253 | + (((var) & DPSW_MASK(field)) >> DPSW_##field##_SHIFT) |
||
254 | +#define dpsw_get_bit(var, bit) \ |
||
255 | + (((var) >> (bit)) & GENMASK(0, 0)) |
||
256 | + |
||
257 | +struct dpsw_cmd_open { |
||
258 | + __le32 dpsw_id; |
||
259 | +}; |
||
260 | + |
||
261 | +#define DPSW_COMPONENT_TYPE_SHIFT 0 |
||
262 | +#define DPSW_COMPONENT_TYPE_SIZE 4 |
||
263 | + |
||
264 | +struct dpsw_cmd_create { |
||
265 | + /* cmd word 0 */ |
||
266 | + __le16 num_ifs; |
||
267 | + u8 max_fdbs; |
||
268 | + u8 max_meters_per_if; |
||
269 | + /* from LSB: only the first 4 bits */ |
||
270 | + u8 component_type; |
||
271 | + u8 pad[3]; |
||
272 | + /* cmd word 1 */ |
||
273 | + __le16 max_vlans; |
||
274 | + __le16 max_fdb_entries; |
||
275 | + __le16 fdb_aging_time; |
||
276 | + __le16 max_fdb_mc_groups; |
||
277 | + /* cmd word 2 */ |
||
278 | + __le64 options; |
||
279 | +}; |
||
280 | + |
||
281 | +struct dpsw_cmd_destroy { |
||
282 | + __le32 dpsw_id; |
||
283 | +}; |
||
284 | + |
||
285 | +#define DPSW_ENABLE_SHIFT 0 |
||
286 | +#define DPSW_ENABLE_SIZE 1 |
||
287 | + |
||
288 | +struct dpsw_rsp_is_enabled { |
||
289 | + /* from LSB: enable:1 */ |
||
290 | + u8 enabled; |
||
291 | +}; |
||
292 | + |
||
293 | +struct dpsw_cmd_set_irq_enable { |
||
294 | + u8 enable_state; |
||
295 | + u8 pad[3]; |
||
296 | + u8 irq_index; |
||
297 | +}; |
||
298 | + |
||
299 | +struct dpsw_cmd_get_irq_enable { |
||
300 | + __le32 pad; |
||
301 | + u8 irq_index; |
||
302 | +}; |
||
303 | + |
||
304 | +struct dpsw_rsp_get_irq_enable { |
||
305 | + u8 enable_state; |
||
306 | +}; |
||
307 | + |
||
308 | +struct dpsw_cmd_set_irq_mask { |
||
309 | + __le32 mask; |
||
310 | + u8 irq_index; |
||
311 | +}; |
||
312 | + |
||
313 | +struct dpsw_cmd_get_irq_mask { |
||
314 | + __le32 pad; |
||
315 | + u8 irq_index; |
||
316 | +}; |
||
317 | + |
||
318 | +struct dpsw_rsp_get_irq_mask { |
||
319 | + __le32 mask; |
||
320 | +}; |
||
321 | + |
||
322 | +struct dpsw_cmd_get_irq_status { |
||
323 | + __le32 status; |
||
324 | + u8 irq_index; |
||
325 | +}; |
||
326 | + |
||
327 | +struct dpsw_rsp_get_irq_status { |
||
328 | + __le32 status; |
||
329 | +}; |
||
330 | + |
||
331 | +struct dpsw_cmd_clear_irq_status { |
||
332 | + __le32 status; |
||
333 | + u8 irq_index; |
||
334 | +}; |
||
335 | + |
||
336 | +#define DPSW_COMPONENT_TYPE_SHIFT 0 |
||
337 | +#define DPSW_COMPONENT_TYPE_SIZE 4 |
||
338 | + |
||
339 | +struct dpsw_rsp_get_attr { |
||
340 | + /* cmd word 0 */ |
||
341 | + __le16 num_ifs; |
||
342 | + u8 max_fdbs; |
||
343 | + u8 num_fdbs; |
||
344 | + __le16 max_vlans; |
||
345 | + __le16 num_vlans; |
||
346 | + /* cmd word 1 */ |
||
347 | + __le16 max_fdb_entries; |
||
348 | + __le16 fdb_aging_time; |
||
349 | + __le32 dpsw_id; |
||
350 | + /* cmd word 2 */ |
||
351 | + __le16 mem_size; |
||
352 | + __le16 max_fdb_mc_groups; |
||
353 | + u8 max_meters_per_if; |
||
354 | + /* from LSB only the first 4 bits */ |
||
355 | + u8 component_type; |
||
356 | + __le16 pad; |
||
357 | + /* cmd word 3 */ |
||
358 | + __le64 options; |
||
359 | +}; |
||
360 | + |
||
361 | +struct dpsw_cmd_if_set_flooding { |
||
362 | + __le16 if_id; |
||
363 | + /* from LSB: enable:1 */ |
||
364 | + u8 enable; |
||
365 | +}; |
||
366 | + |
||
367 | +struct dpsw_cmd_if_set_broadcast { |
||
368 | + __le16 if_id; |
||
369 | + /* from LSB: enable:1 */ |
||
370 | + u8 enable; |
||
371 | +}; |
||
372 | + |
||
373 | +#define DPSW_VLAN_ID_SHIFT 0 |
||
374 | +#define DPSW_VLAN_ID_SIZE 12 |
||
375 | +#define DPSW_DEI_SHIFT 12 |
||
376 | +#define DPSW_DEI_SIZE 1 |
||
377 | +#define DPSW_PCP_SHIFT 13 |
||
378 | +#define DPSW_PCP_SIZE 3 |
||
379 | + |
||
380 | +struct dpsw_cmd_if_set_tci { |
||
381 | + __le16 if_id; |
||
382 | + /* from LSB: VLAN_ID:12 DEI:1 PCP:3 */ |
||
383 | + __le16 conf; |
||
384 | +}; |
||
385 | + |
||
386 | +struct dpsw_cmd_if_get_tci { |
||
387 | + __le16 if_id; |
||
388 | +}; |
||
389 | + |
||
390 | +struct dpsw_rsp_if_get_tci { |
||
391 | + __le16 pad; |
||
392 | + __le16 vlan_id; |
||
393 | + u8 dei; |
||
394 | + u8 pcp; |
||
395 | +}; |
||
396 | + |
||
397 | +#define DPSW_STATE_SHIFT 0 |
||
398 | +#define DPSW_STATE_SIZE 4 |
||
399 | + |
||
400 | +struct dpsw_cmd_if_set_stp { |
||
401 | + __le16 if_id; |
||
402 | + __le16 vlan_id; |
||
403 | + /* only the first LSB 4 bits */ |
||
404 | + u8 state; |
||
405 | +}; |
||
406 | + |
||
407 | +#define DPSW_COUNTER_TYPE_SHIFT 0 |
||
408 | +#define DPSW_COUNTER_TYPE_SIZE 5 |
||
409 | + |
||
410 | +struct dpsw_cmd_if_get_counter { |
||
411 | + __le16 if_id; |
||
412 | + /* from LSB: type:5 */ |
||
413 | + u8 type; |
||
414 | +}; |
||
415 | + |
||
416 | +struct dpsw_rsp_if_get_counter { |
||
417 | + __le64 pad; |
||
418 | + __le64 counter; |
||
419 | +}; |
||
420 | + |
||
421 | +struct dpsw_cmd_if { |
||
422 | + __le16 if_id; |
||
423 | +}; |
||
424 | + |
||
425 | +struct dpsw_cmd_if_set_max_frame_length { |
||
426 | + __le16 if_id; |
||
427 | + __le16 frame_length; |
||
428 | +}; |
||
429 | + |
||
430 | +struct dpsw_cmd_if_set_link_cfg { |
||
431 | + /* cmd word 0 */ |
||
432 | + __le16 if_id; |
||
433 | + u8 pad[6]; |
||
434 | + /* cmd word 1 */ |
||
435 | + __le32 rate; |
||
436 | + __le32 pad1; |
||
437 | + /* cmd word 2 */ |
||
438 | + __le64 options; |
||
439 | +}; |
||
440 | + |
||
441 | +struct dpsw_cmd_if_get_link_state { |
||
442 | + __le16 if_id; |
||
443 | +}; |
||
444 | + |
||
445 | +#define DPSW_UP_SHIFT 0 |
||
446 | +#define DPSW_UP_SIZE 1 |
||
447 | + |
||
448 | +struct dpsw_rsp_if_get_link_state { |
||
449 | + /* cmd word 0 */ |
||
450 | + __le32 pad0; |
||
451 | + u8 up; |
||
452 | + u8 pad1[3]; |
||
453 | + /* cmd word 1 */ |
||
454 | + __le32 rate; |
||
455 | + __le32 pad2; |
||
456 | + /* cmd word 2 */ |
||
457 | + __le64 options; |
||
458 | +}; |
||
459 | + |
||
460 | +struct dpsw_vlan_add { |
||
461 | + __le16 fdb_id; |
||
462 | + __le16 vlan_id; |
||
463 | +}; |
||
464 | + |
||
465 | +struct dpsw_cmd_vlan_manage_if { |
||
466 | + /* cmd word 0 */ |
||
467 | + __le16 pad0; |
||
468 | + __le16 vlan_id; |
||
469 | + __le32 pad1; |
||
470 | + /* cmd word 1-4 */ |
||
471 | + __le64 if_id[4]; |
||
472 | +}; |
||
473 | + |
||
474 | +struct dpsw_cmd_vlan_remove { |
||
475 | + __le16 pad; |
||
476 | + __le16 vlan_id; |
||
477 | +}; |
||
478 | + |
||
479 | +struct dpsw_cmd_fdb_add { |
||
480 | + __le32 pad; |
||
481 | + __le16 fdb_aging_time; |
||
482 | + __le16 num_fdb_entries; |
||
483 | +}; |
||
484 | + |
||
485 | +struct dpsw_rsp_fdb_add { |
||
486 | + __le16 fdb_id; |
||
487 | +}; |
||
488 | + |
||
489 | +struct dpsw_cmd_fdb_remove { |
||
490 | + __le16 fdb_id; |
||
491 | +}; |
||
492 | + |
||
493 | +#define DPSW_ENTRY_TYPE_SHIFT 0 |
||
494 | +#define DPSW_ENTRY_TYPE_SIZE 4 |
||
495 | + |
||
496 | +struct dpsw_cmd_fdb_unicast_op { |
||
497 | + /* cmd word 0 */ |
||
498 | + __le16 fdb_id; |
||
499 | + u8 mac_addr[6]; |
||
500 | + /* cmd word 1 */ |
||
501 | + __le16 if_egress; |
||
502 | + /* only the first 4 bits from LSB */ |
||
503 | + u8 type; |
||
504 | +}; |
||
505 | + |
||
506 | +struct dpsw_cmd_fdb_multicast_op { |
||
507 | + /* cmd word 0 */ |
||
508 | + __le16 fdb_id; |
||
509 | + __le16 num_ifs; |
||
510 | + /* only the first 4 bits from LSB */ |
||
511 | + u8 type; |
||
512 | + u8 pad[3]; |
||
513 | + /* cmd word 1 */ |
||
514 | + u8 mac_addr[6]; |
||
515 | + __le16 pad2; |
||
516 | + /* cmd word 2-5 */ |
||
517 | + __le64 if_id[4]; |
||
518 | +}; |
||
519 | + |
||
520 | +#define DPSW_LEARNING_MODE_SHIFT 0 |
||
521 | +#define DPSW_LEARNING_MODE_SIZE 4 |
||
522 | + |
||
523 | +struct dpsw_cmd_fdb_set_learning_mode { |
||
524 | + __le16 fdb_id; |
||
525 | + /* only the first 4 bits from LSB */ |
||
526 | + u8 mode; |
||
527 | +}; |
||
528 | + |
||
529 | +struct dpsw_rsp_get_api_version { |
||
530 | + __le16 version_major; |
||
531 | + __le16 version_minor; |
||
532 | +}; |
||
533 | + |
||
534 | +#endif /* __FSL_DPSW_CMD_H */ |
||
535 | --- /dev/null |
||
536 | +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c |
||
537 | @@ -0,0 +1,1165 @@ |
||
538 | +// SPDX-License-Identifier: GPL-2.0 |
||
539 | +/* |
||
540 | + * Copyright 2013-2016 Freescale Semiconductor, Inc. |
||
541 | + * Copyright 2017-2018 NXP |
||
542 | + * |
||
543 | + */ |
||
544 | + |
||
545 | +#include <linux/fsl/mc.h> |
||
546 | +#include "dpsw.h" |
||
547 | +#include "dpsw-cmd.h" |
||
548 | + |
||
549 | +static void build_if_id_bitmap(__le64 *bmap, |
||
550 | + const u16 *id, |
||
551 | + const u16 num_ifs) |
||
552 | +{ |
||
553 | + int i; |
||
554 | + |
||
555 | + for (i = 0; (i < num_ifs) && (i < DPSW_MAX_IF); i++) { |
||
556 | + if (id[i] < DPSW_MAX_IF) |
||
557 | + bmap[id[i] / 64] |= cpu_to_le64(BIT_MASK(id[i] % 64)); |
||
558 | + } |
||
559 | +} |
||
560 | + |
||
561 | +/** |
||
562 | + * dpsw_open() - Open a control session for the specified object |
||
563 | + * @mc_io: Pointer to MC portal's I/O object |
||
564 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
565 | + * @dpsw_id: DPSW unique ID |
||
566 | + * @token: Returned token; use in subsequent API calls |
||
567 | + * |
||
568 | + * This function can be used to open a control session for an |
||
569 | + * already created object; an object may have been declared in |
||
570 | + * the DPL or by calling the dpsw_create() function. |
||
571 | + * This function returns a unique authentication token, |
||
572 | + * associated with the specific object ID and the specific MC |
||
573 | + * portal; this token must be used in all subsequent commands for |
||
574 | + * this specific object |
||
575 | + * |
||
576 | + * Return: '0' on Success; Error code otherwise. |
||
577 | + */ |
||
578 | +int dpsw_open(struct fsl_mc_io *mc_io, |
||
579 | + u32 cmd_flags, |
||
580 | + int dpsw_id, |
||
581 | + u16 *token) |
||
582 | +{ |
||
583 | + struct fsl_mc_command cmd = { 0 }; |
||
584 | + struct dpsw_cmd_open *cmd_params; |
||
585 | + int err; |
||
586 | + |
||
587 | + /* prepare command */ |
||
588 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_OPEN, |
||
589 | + cmd_flags, |
||
590 | + 0); |
||
591 | + cmd_params = (struct dpsw_cmd_open *)cmd.params; |
||
592 | + cmd_params->dpsw_id = cpu_to_le32(dpsw_id); |
||
593 | + |
||
594 | + /* send command to mc*/ |
||
595 | + err = mc_send_command(mc_io, &cmd); |
||
596 | + if (err) |
||
597 | + return err; |
||
598 | + |
||
599 | + /* retrieve response parameters */ |
||
600 | + *token = mc_cmd_hdr_read_token(&cmd); |
||
601 | + |
||
602 | + return 0; |
||
603 | +} |
||
604 | + |
||
605 | +/** |
||
606 | + * dpsw_close() - Close the control session of the object |
||
607 | + * @mc_io: Pointer to MC portal's I/O object |
||
608 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
609 | + * @token: Token of DPSW object |
||
610 | + * |
||
611 | + * After this function is called, no further operations are |
||
612 | + * allowed on the object without opening a new control session. |
||
613 | + * |
||
614 | + * Return: '0' on Success; Error code otherwise. |
||
615 | + */ |
||
616 | +int dpsw_close(struct fsl_mc_io *mc_io, |
||
617 | + u32 cmd_flags, |
||
618 | + u16 token) |
||
619 | +{ |
||
620 | + struct fsl_mc_command cmd = { 0 }; |
||
621 | + |
||
622 | + /* prepare command */ |
||
623 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLOSE, |
||
624 | + cmd_flags, |
||
625 | + token); |
||
626 | + |
||
627 | + /* send command to mc*/ |
||
628 | + return mc_send_command(mc_io, &cmd); |
||
629 | +} |
||
630 | + |
||
631 | +/** |
||
632 | + * dpsw_enable() - Enable DPSW functionality |
||
633 | + * @mc_io: Pointer to MC portal's I/O object |
||
634 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
635 | + * @token: Token of DPSW object |
||
636 | + * |
||
637 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
638 | + */ |
||
639 | +int dpsw_enable(struct fsl_mc_io *mc_io, |
||
640 | + u32 cmd_flags, |
||
641 | + u16 token) |
||
642 | +{ |
||
643 | + struct fsl_mc_command cmd = { 0 }; |
||
644 | + |
||
645 | + /* prepare command */ |
||
646 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_ENABLE, |
||
647 | + cmd_flags, |
||
648 | + token); |
||
649 | + |
||
650 | + /* send command to mc*/ |
||
651 | + return mc_send_command(mc_io, &cmd); |
||
652 | +} |
||
653 | + |
||
654 | +/** |
||
655 | + * dpsw_disable() - Disable DPSW functionality |
||
656 | + * @mc_io: Pointer to MC portal's I/O object |
||
657 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
658 | + * @token: Token of DPSW object |
||
659 | + * |
||
660 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
661 | + */ |
||
662 | +int dpsw_disable(struct fsl_mc_io *mc_io, |
||
663 | + u32 cmd_flags, |
||
664 | + u16 token) |
||
665 | +{ |
||
666 | + struct fsl_mc_command cmd = { 0 }; |
||
667 | + |
||
668 | + /* prepare command */ |
||
669 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_DISABLE, |
||
670 | + cmd_flags, |
||
671 | + token); |
||
672 | + |
||
673 | + /* send command to mc*/ |
||
674 | + return mc_send_command(mc_io, &cmd); |
||
675 | +} |
||
676 | + |
||
677 | +/** |
||
678 | + * dpsw_reset() - Reset the DPSW, returns the object to initial state. |
||
679 | + * @mc_io: Pointer to MC portal's I/O object |
||
680 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
681 | + * @token: Token of DPSW object |
||
682 | + * |
||
683 | + * Return: '0' on Success; Error code otherwise. |
||
684 | + */ |
||
685 | +int dpsw_reset(struct fsl_mc_io *mc_io, |
||
686 | + u32 cmd_flags, |
||
687 | + u16 token) |
||
688 | +{ |
||
689 | + struct fsl_mc_command cmd = { 0 }; |
||
690 | + |
||
691 | + /* prepare command */ |
||
692 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_RESET, |
||
693 | + cmd_flags, |
||
694 | + token); |
||
695 | + |
||
696 | + /* send command to mc*/ |
||
697 | + return mc_send_command(mc_io, &cmd); |
||
698 | +} |
||
699 | + |
||
700 | +/** |
||
701 | + * dpsw_set_irq_enable() - Set overall interrupt state. |
||
702 | + * @mc_io: Pointer to MC portal's I/O object |
||
703 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
704 | + * @token: Token of DPCI object |
||
705 | + * @irq_index: The interrupt index to configure |
||
706 | + * @en: Interrupt state - enable = 1, disable = 0 |
||
707 | + * |
||
708 | + * Allows GPP software to control when interrupts are generated. |
||
709 | + * Each interrupt can have up to 32 causes. The enable/disable control's the |
||
710 | + * overall interrupt state. if the interrupt is disabled no causes will cause |
||
711 | + * an interrupt |
||
712 | + * |
||
713 | + * Return: '0' on Success; Error code otherwise. |
||
714 | + */ |
||
715 | +int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, |
||
716 | + u32 cmd_flags, |
||
717 | + u16 token, |
||
718 | + u8 irq_index, |
||
719 | + u8 en) |
||
720 | +{ |
||
721 | + struct fsl_mc_command cmd = { 0 }; |
||
722 | + struct dpsw_cmd_set_irq_enable *cmd_params; |
||
723 | + |
||
724 | + /* prepare command */ |
||
725 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_ENABLE, |
||
726 | + cmd_flags, |
||
727 | + token); |
||
728 | + cmd_params = (struct dpsw_cmd_set_irq_enable *)cmd.params; |
||
729 | + dpsw_set_field(cmd_params->enable_state, ENABLE, en); |
||
730 | + cmd_params->irq_index = irq_index; |
||
731 | + |
||
732 | + /* send command to mc*/ |
||
733 | + return mc_send_command(mc_io, &cmd); |
||
734 | +} |
||
735 | + |
||
736 | +/** |
||
737 | + * dpsw_set_irq_mask() - Set interrupt mask. |
||
738 | + * @mc_io: Pointer to MC portal's I/O object |
||
739 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
740 | + * @token: Token of DPCI object |
||
741 | + * @irq_index: The interrupt index to configure |
||
742 | + * @mask: Event mask to trigger interrupt; |
||
743 | + * each bit: |
||
744 | + * 0 = ignore event |
||
745 | + * 1 = consider event for asserting IRQ |
||
746 | + * |
||
747 | + * Every interrupt can have up to 32 causes and the interrupt model supports |
||
748 | + * masking/unmasking each cause independently |
||
749 | + * |
||
750 | + * Return: '0' on Success; Error code otherwise. |
||
751 | + */ |
||
752 | +int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, |
||
753 | + u32 cmd_flags, |
||
754 | + u16 token, |
||
755 | + u8 irq_index, |
||
756 | + u32 mask) |
||
757 | +{ |
||
758 | + struct fsl_mc_command cmd = { 0 }; |
||
759 | + struct dpsw_cmd_set_irq_mask *cmd_params; |
||
760 | + |
||
761 | + /* prepare command */ |
||
762 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_MASK, |
||
763 | + cmd_flags, |
||
764 | + token); |
||
765 | + cmd_params = (struct dpsw_cmd_set_irq_mask *)cmd.params; |
||
766 | + cmd_params->mask = cpu_to_le32(mask); |
||
767 | + cmd_params->irq_index = irq_index; |
||
768 | + |
||
769 | + /* send command to mc*/ |
||
770 | + return mc_send_command(mc_io, &cmd); |
||
771 | +} |
||
772 | + |
||
773 | +/** |
||
774 | + * dpsw_get_irq_status() - Get the current status of any pending interrupts |
||
775 | + * @mc_io: Pointer to MC portal's I/O object |
||
776 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
777 | + * @token: Token of DPSW object |
||
778 | + * @irq_index: The interrupt index to configure |
||
779 | + * @status: Returned interrupts status - one bit per cause: |
||
780 | + * 0 = no interrupt pending |
||
781 | + * 1 = interrupt pending |
||
782 | + * |
||
783 | + * Return: '0' on Success; Error code otherwise. |
||
784 | + */ |
||
785 | +int dpsw_get_irq_status(struct fsl_mc_io *mc_io, |
||
786 | + u32 cmd_flags, |
||
787 | + u16 token, |
||
788 | + u8 irq_index, |
||
789 | + u32 *status) |
||
790 | +{ |
||
791 | + struct fsl_mc_command cmd = { 0 }; |
||
792 | + struct dpsw_cmd_get_irq_status *cmd_params; |
||
793 | + struct dpsw_rsp_get_irq_status *rsp_params; |
||
794 | + int err; |
||
795 | + |
||
796 | + /* prepare command */ |
||
797 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_IRQ_STATUS, |
||
798 | + cmd_flags, |
||
799 | + token); |
||
800 | + cmd_params = (struct dpsw_cmd_get_irq_status *)cmd.params; |
||
801 | + cmd_params->status = cpu_to_le32(*status); |
||
802 | + cmd_params->irq_index = irq_index; |
||
803 | + |
||
804 | + /* send command to mc*/ |
||
805 | + err = mc_send_command(mc_io, &cmd); |
||
806 | + if (err) |
||
807 | + return err; |
||
808 | + |
||
809 | + /* retrieve response parameters */ |
||
810 | + rsp_params = (struct dpsw_rsp_get_irq_status *)cmd.params; |
||
811 | + *status = le32_to_cpu(rsp_params->status); |
||
812 | + |
||
813 | + return 0; |
||
814 | +} |
||
815 | + |
||
816 | +/** |
||
817 | + * dpsw_clear_irq_status() - Clear a pending interrupt's status |
||
818 | + * @mc_io: Pointer to MC portal's I/O object |
||
819 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
820 | + * @token: Token of DPCI object |
||
821 | + * @irq_index: The interrupt index to configure |
||
822 | + * @status: bits to clear (W1C) - one bit per cause: |
||
823 | + * 0 = don't change |
||
824 | + * 1 = clear status bit |
||
825 | + * |
||
826 | + * Return: '0' on Success; Error code otherwise. |
||
827 | + */ |
||
828 | +int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, |
||
829 | + u32 cmd_flags, |
||
830 | + u16 token, |
||
831 | + u8 irq_index, |
||
832 | + u32 status) |
||
833 | +{ |
||
834 | + struct fsl_mc_command cmd = { 0 }; |
||
835 | + struct dpsw_cmd_clear_irq_status *cmd_params; |
||
836 | + |
||
837 | + /* prepare command */ |
||
838 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLEAR_IRQ_STATUS, |
||
839 | + cmd_flags, |
||
840 | + token); |
||
841 | + cmd_params = (struct dpsw_cmd_clear_irq_status *)cmd.params; |
||
842 | + cmd_params->status = cpu_to_le32(status); |
||
843 | + cmd_params->irq_index = irq_index; |
||
844 | + |
||
845 | + /* send command to mc*/ |
||
846 | + return mc_send_command(mc_io, &cmd); |
||
847 | +} |
||
848 | + |
||
849 | +/** |
||
850 | + * dpsw_get_attributes() - Retrieve DPSW attributes |
||
851 | + * @mc_io: Pointer to MC portal's I/O object |
||
852 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
853 | + * @token: Token of DPSW object |
||
854 | + * @attr: Returned DPSW attributes |
||
855 | + * |
||
856 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
857 | + */ |
||
858 | +int dpsw_get_attributes(struct fsl_mc_io *mc_io, |
||
859 | + u32 cmd_flags, |
||
860 | + u16 token, |
||
861 | + struct dpsw_attr *attr) |
||
862 | +{ |
||
863 | + struct fsl_mc_command cmd = { 0 }; |
||
864 | + struct dpsw_rsp_get_attr *rsp_params; |
||
865 | + int err; |
||
866 | + |
||
867 | + /* prepare command */ |
||
868 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_ATTR, |
||
869 | + cmd_flags, |
||
870 | + token); |
||
871 | + |
||
872 | + /* send command to mc*/ |
||
873 | + err = mc_send_command(mc_io, &cmd); |
||
874 | + if (err) |
||
875 | + return err; |
||
876 | + |
||
877 | + /* retrieve response parameters */ |
||
878 | + rsp_params = (struct dpsw_rsp_get_attr *)cmd.params; |
||
879 | + attr->num_ifs = le16_to_cpu(rsp_params->num_ifs); |
||
880 | + attr->max_fdbs = rsp_params->max_fdbs; |
||
881 | + attr->num_fdbs = rsp_params->num_fdbs; |
||
882 | + attr->max_vlans = le16_to_cpu(rsp_params->max_vlans); |
||
883 | + attr->num_vlans = le16_to_cpu(rsp_params->num_vlans); |
||
884 | + attr->max_fdb_entries = le16_to_cpu(rsp_params->max_fdb_entries); |
||
885 | + attr->fdb_aging_time = le16_to_cpu(rsp_params->fdb_aging_time); |
||
886 | + attr->id = le32_to_cpu(rsp_params->dpsw_id); |
||
887 | + attr->mem_size = le16_to_cpu(rsp_params->mem_size); |
||
888 | + attr->max_fdb_mc_groups = le16_to_cpu(rsp_params->max_fdb_mc_groups); |
||
889 | + attr->max_meters_per_if = rsp_params->max_meters_per_if; |
||
890 | + attr->options = le64_to_cpu(rsp_params->options); |
||
891 | + attr->component_type = dpsw_get_field(rsp_params->component_type, |
||
892 | + COMPONENT_TYPE); |
||
893 | + |
||
894 | + return 0; |
||
895 | +} |
||
896 | + |
||
897 | +/** |
||
898 | + * dpsw_if_set_link_cfg() - Set the link configuration. |
||
899 | + * @mc_io: Pointer to MC portal's I/O object |
||
900 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
901 | + * @token: Token of DPSW object |
||
902 | + * @if_id: Interface id |
||
903 | + * @cfg: Link configuration |
||
904 | + * |
||
905 | + * Return: '0' on Success; Error code otherwise. |
||
906 | + */ |
||
907 | +int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, |
||
908 | + u32 cmd_flags, |
||
909 | + u16 token, |
||
910 | + u16 if_id, |
||
911 | + struct dpsw_link_cfg *cfg) |
||
912 | +{ |
||
913 | + struct fsl_mc_command cmd = { 0 }; |
||
914 | + struct dpsw_cmd_if_set_link_cfg *cmd_params; |
||
915 | + |
||
916 | + /* prepare command */ |
||
917 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LINK_CFG, |
||
918 | + cmd_flags, |
||
919 | + token); |
||
920 | + cmd_params = (struct dpsw_cmd_if_set_link_cfg *)cmd.params; |
||
921 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
922 | + cmd_params->rate = cpu_to_le32(cfg->rate); |
||
923 | + cmd_params->options = cpu_to_le64(cfg->options); |
||
924 | + |
||
925 | + /* send command to mc*/ |
||
926 | + return mc_send_command(mc_io, &cmd); |
||
927 | +} |
||
928 | + |
||
929 | +/** |
||
930 | + * dpsw_if_get_link_state - Return the link state |
||
931 | + * @mc_io: Pointer to MC portal's I/O object |
||
932 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
933 | + * @token: Token of DPSW object |
||
934 | + * @if_id: Interface id |
||
935 | + * @state: Link state 1 - linkup, 0 - link down or disconnected |
||
936 | + * |
||
937 | + * @Return '0' on Success; Error code otherwise. |
||
938 | + */ |
||
939 | +int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, |
||
940 | + u32 cmd_flags, |
||
941 | + u16 token, |
||
942 | + u16 if_id, |
||
943 | + struct dpsw_link_state *state) |
||
944 | +{ |
||
945 | + struct fsl_mc_command cmd = { 0 }; |
||
946 | + struct dpsw_cmd_if_get_link_state *cmd_params; |
||
947 | + struct dpsw_rsp_if_get_link_state *rsp_params; |
||
948 | + int err; |
||
949 | + |
||
950 | + /* prepare command */ |
||
951 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_LINK_STATE, |
||
952 | + cmd_flags, |
||
953 | + token); |
||
954 | + cmd_params = (struct dpsw_cmd_if_get_link_state *)cmd.params; |
||
955 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
956 | + |
||
957 | + /* send command to mc*/ |
||
958 | + err = mc_send_command(mc_io, &cmd); |
||
959 | + if (err) |
||
960 | + return err; |
||
961 | + |
||
962 | + /* retrieve response parameters */ |
||
963 | + rsp_params = (struct dpsw_rsp_if_get_link_state *)cmd.params; |
||
964 | + state->rate = le32_to_cpu(rsp_params->rate); |
||
965 | + state->options = le64_to_cpu(rsp_params->options); |
||
966 | + state->up = dpsw_get_field(rsp_params->up, UP); |
||
967 | + |
||
968 | + return 0; |
||
969 | +} |
||
970 | + |
||
971 | +/** |
||
972 | + * dpsw_if_set_flooding() - Enable Disable flooding for particular interface |
||
973 | + * @mc_io: Pointer to MC portal's I/O object |
||
974 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
975 | + * @token: Token of DPSW object |
||
976 | + * @if_id: Interface Identifier |
||
977 | + * @en: 1 - enable, 0 - disable |
||
978 | + * |
||
979 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
980 | + */ |
||
981 | +int dpsw_if_set_flooding(struct fsl_mc_io *mc_io, |
||
982 | + u32 cmd_flags, |
||
983 | + u16 token, |
||
984 | + u16 if_id, |
||
985 | + u8 en) |
||
986 | +{ |
||
987 | + struct fsl_mc_command cmd = { 0 }; |
||
988 | + struct dpsw_cmd_if_set_flooding *cmd_params; |
||
989 | + |
||
990 | + /* prepare command */ |
||
991 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_FLOODING, |
||
992 | + cmd_flags, |
||
993 | + token); |
||
994 | + cmd_params = (struct dpsw_cmd_if_set_flooding *)cmd.params; |
||
995 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
996 | + dpsw_set_field(cmd_params->enable, ENABLE, en); |
||
997 | + |
||
998 | + /* send command to mc*/ |
||
999 | + return mc_send_command(mc_io, &cmd); |
||
1000 | +} |
||
1001 | + |
||
1002 | +/** |
||
1003 | + * dpsw_if_set_broadcast() - Enable/disable broadcast for particular interface |
||
1004 | + * @mc_io: Pointer to MC portal's I/O object |
||
1005 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1006 | + * @token: Token of DPSW object |
||
1007 | + * @if_id: Interface Identifier |
||
1008 | + * @en: 1 - enable, 0 - disable |
||
1009 | + * |
||
1010 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1011 | + */ |
||
1012 | +int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io, |
||
1013 | + u32 cmd_flags, |
||
1014 | + u16 token, |
||
1015 | + u16 if_id, |
||
1016 | + u8 en) |
||
1017 | +{ |
||
1018 | + struct fsl_mc_command cmd = { 0 }; |
||
1019 | + struct dpsw_cmd_if_set_broadcast *cmd_params; |
||
1020 | + |
||
1021 | + /* prepare command */ |
||
1022 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_BROADCAST, |
||
1023 | + cmd_flags, |
||
1024 | + token); |
||
1025 | + cmd_params = (struct dpsw_cmd_if_set_broadcast *)cmd.params; |
||
1026 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1027 | + dpsw_set_field(cmd_params->enable, ENABLE, en); |
||
1028 | + |
||
1029 | + /* send command to mc*/ |
||
1030 | + return mc_send_command(mc_io, &cmd); |
||
1031 | +} |
||
1032 | + |
||
1033 | +/** |
||
1034 | + * dpsw_if_set_tci() - Set default VLAN Tag Control Information (TCI) |
||
1035 | + * @mc_io: Pointer to MC portal's I/O object |
||
1036 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1037 | + * @token: Token of DPSW object |
||
1038 | + * @if_id: Interface Identifier |
||
1039 | + * @cfg: Tag Control Information Configuration |
||
1040 | + * |
||
1041 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1042 | + */ |
||
1043 | +int dpsw_if_set_tci(struct fsl_mc_io *mc_io, |
||
1044 | + u32 cmd_flags, |
||
1045 | + u16 token, |
||
1046 | + u16 if_id, |
||
1047 | + const struct dpsw_tci_cfg *cfg) |
||
1048 | +{ |
||
1049 | + struct fsl_mc_command cmd = { 0 }; |
||
1050 | + struct dpsw_cmd_if_set_tci *cmd_params; |
||
1051 | + u16 tmp_conf = 0; |
||
1052 | + |
||
1053 | + /* prepare command */ |
||
1054 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_TCI, |
||
1055 | + cmd_flags, |
||
1056 | + token); |
||
1057 | + cmd_params = (struct dpsw_cmd_if_set_tci *)cmd.params; |
||
1058 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1059 | + dpsw_set_field(tmp_conf, VLAN_ID, cfg->vlan_id); |
||
1060 | + dpsw_set_field(tmp_conf, DEI, cfg->dei); |
||
1061 | + dpsw_set_field(tmp_conf, PCP, cfg->pcp); |
||
1062 | + cmd_params->conf = cpu_to_le16(tmp_conf); |
||
1063 | + |
||
1064 | + /* send command to mc*/ |
||
1065 | + return mc_send_command(mc_io, &cmd); |
||
1066 | +} |
||
1067 | + |
||
1068 | +/** |
||
1069 | + * dpsw_if_get_tci() - Get default VLAN Tag Control Information (TCI) |
||
1070 | + * @mc_io: Pointer to MC portal's I/O object |
||
1071 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1072 | + * @token: Token of DPSW object |
||
1073 | + * @if_id: Interface Identifier |
||
1074 | + * @cfg: Tag Control Information Configuration |
||
1075 | + * |
||
1076 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1077 | + */ |
||
1078 | +int dpsw_if_get_tci(struct fsl_mc_io *mc_io, |
||
1079 | + u32 cmd_flags, |
||
1080 | + u16 token, |
||
1081 | + u16 if_id, |
||
1082 | + struct dpsw_tci_cfg *cfg) |
||
1083 | +{ |
||
1084 | + struct fsl_mc_command cmd = { 0 }; |
||
1085 | + struct dpsw_cmd_if_get_tci *cmd_params; |
||
1086 | + struct dpsw_rsp_if_get_tci *rsp_params; |
||
1087 | + int err; |
||
1088 | + |
||
1089 | + /* prepare command */ |
||
1090 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_TCI, |
||
1091 | + cmd_flags, |
||
1092 | + token); |
||
1093 | + cmd_params = (struct dpsw_cmd_if_get_tci *)cmd.params; |
||
1094 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1095 | + |
||
1096 | + /* send command to mc*/ |
||
1097 | + err = mc_send_command(mc_io, &cmd); |
||
1098 | + if (err) |
||
1099 | + return err; |
||
1100 | + |
||
1101 | + /* retrieve response parameters */ |
||
1102 | + rsp_params = (struct dpsw_rsp_if_get_tci *)cmd.params; |
||
1103 | + cfg->pcp = rsp_params->pcp; |
||
1104 | + cfg->dei = rsp_params->dei; |
||
1105 | + cfg->vlan_id = le16_to_cpu(rsp_params->vlan_id); |
||
1106 | + |
||
1107 | + return 0; |
||
1108 | +} |
||
1109 | + |
||
1110 | +/** |
||
1111 | + * dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state. |
||
1112 | + * @mc_io: Pointer to MC portal's I/O object |
||
1113 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1114 | + * @token: Token of DPSW object |
||
1115 | + * @if_id: Interface Identifier |
||
1116 | + * @cfg: STP State configuration parameters |
||
1117 | + * |
||
1118 | + * The following STP states are supported - |
||
1119 | + * blocking, listening, learning, forwarding and disabled. |
||
1120 | + * |
||
1121 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1122 | + */ |
||
1123 | +int dpsw_if_set_stp(struct fsl_mc_io *mc_io, |
||
1124 | + u32 cmd_flags, |
||
1125 | + u16 token, |
||
1126 | + u16 if_id, |
||
1127 | + const struct dpsw_stp_cfg *cfg) |
||
1128 | +{ |
||
1129 | + struct fsl_mc_command cmd = { 0 }; |
||
1130 | + struct dpsw_cmd_if_set_stp *cmd_params; |
||
1131 | + |
||
1132 | + /* prepare command */ |
||
1133 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_STP, |
||
1134 | + cmd_flags, |
||
1135 | + token); |
||
1136 | + cmd_params = (struct dpsw_cmd_if_set_stp *)cmd.params; |
||
1137 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1138 | + cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id); |
||
1139 | + dpsw_set_field(cmd_params->state, STATE, cfg->state); |
||
1140 | + |
||
1141 | + /* send command to mc*/ |
||
1142 | + return mc_send_command(mc_io, &cmd); |
||
1143 | +} |
||
1144 | + |
||
1145 | +/** |
||
1146 | + * dpsw_if_get_counter() - Get specific counter of particular interface |
||
1147 | + * @mc_io: Pointer to MC portal's I/O object |
||
1148 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1149 | + * @token: Token of DPSW object |
||
1150 | + * @if_id: Interface Identifier |
||
1151 | + * @type: Counter type |
||
1152 | + * @counter: return value |
||
1153 | + * |
||
1154 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1155 | + */ |
||
1156 | +int dpsw_if_get_counter(struct fsl_mc_io *mc_io, |
||
1157 | + u32 cmd_flags, |
||
1158 | + u16 token, |
||
1159 | + u16 if_id, |
||
1160 | + enum dpsw_counter type, |
||
1161 | + u64 *counter) |
||
1162 | +{ |
||
1163 | + struct fsl_mc_command cmd = { 0 }; |
||
1164 | + struct dpsw_cmd_if_get_counter *cmd_params; |
||
1165 | + struct dpsw_rsp_if_get_counter *rsp_params; |
||
1166 | + int err; |
||
1167 | + |
||
1168 | + /* prepare command */ |
||
1169 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_COUNTER, |
||
1170 | + cmd_flags, |
||
1171 | + token); |
||
1172 | + cmd_params = (struct dpsw_cmd_if_get_counter *)cmd.params; |
||
1173 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1174 | + dpsw_set_field(cmd_params->type, COUNTER_TYPE, type); |
||
1175 | + |
||
1176 | + /* send command to mc*/ |
||
1177 | + err = mc_send_command(mc_io, &cmd); |
||
1178 | + if (err) |
||
1179 | + return err; |
||
1180 | + |
||
1181 | + /* retrieve response parameters */ |
||
1182 | + rsp_params = (struct dpsw_rsp_if_get_counter *)cmd.params; |
||
1183 | + *counter = le64_to_cpu(rsp_params->counter); |
||
1184 | + |
||
1185 | + return 0; |
||
1186 | +} |
||
1187 | + |
||
1188 | +/** |
||
1189 | + * dpsw_if_enable() - Enable Interface |
||
1190 | + * @mc_io: Pointer to MC portal's I/O object |
||
1191 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1192 | + * @token: Token of DPSW object |
||
1193 | + * @if_id: Interface Identifier |
||
1194 | + * |
||
1195 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1196 | + */ |
||
1197 | +int dpsw_if_enable(struct fsl_mc_io *mc_io, |
||
1198 | + u32 cmd_flags, |
||
1199 | + u16 token, |
||
1200 | + u16 if_id) |
||
1201 | +{ |
||
1202 | + struct fsl_mc_command cmd = { 0 }; |
||
1203 | + struct dpsw_cmd_if *cmd_params; |
||
1204 | + |
||
1205 | + /* prepare command */ |
||
1206 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_ENABLE, |
||
1207 | + cmd_flags, |
||
1208 | + token); |
||
1209 | + cmd_params = (struct dpsw_cmd_if *)cmd.params; |
||
1210 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1211 | + |
||
1212 | + /* send command to mc*/ |
||
1213 | + return mc_send_command(mc_io, &cmd); |
||
1214 | +} |
||
1215 | + |
||
1216 | +/** |
||
1217 | + * dpsw_if_disable() - Disable Interface |
||
1218 | + * @mc_io: Pointer to MC portal's I/O object |
||
1219 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1220 | + * @token: Token of DPSW object |
||
1221 | + * @if_id: Interface Identifier |
||
1222 | + * |
||
1223 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1224 | + */ |
||
1225 | +int dpsw_if_disable(struct fsl_mc_io *mc_io, |
||
1226 | + u32 cmd_flags, |
||
1227 | + u16 token, |
||
1228 | + u16 if_id) |
||
1229 | +{ |
||
1230 | + struct fsl_mc_command cmd = { 0 }; |
||
1231 | + struct dpsw_cmd_if *cmd_params; |
||
1232 | + |
||
1233 | + /* prepare command */ |
||
1234 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_DISABLE, |
||
1235 | + cmd_flags, |
||
1236 | + token); |
||
1237 | + cmd_params = (struct dpsw_cmd_if *)cmd.params; |
||
1238 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1239 | + |
||
1240 | + /* send command to mc*/ |
||
1241 | + return mc_send_command(mc_io, &cmd); |
||
1242 | +} |
||
1243 | + |
||
1244 | +/** |
||
1245 | + * dpsw_if_set_max_frame_length() - Set Maximum Receive frame length. |
||
1246 | + * @mc_io: Pointer to MC portal's I/O object |
||
1247 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1248 | + * @token: Token of DPSW object |
||
1249 | + * @if_id: Interface Identifier |
||
1250 | + * @frame_length: Maximum Frame Length |
||
1251 | + * |
||
1252 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1253 | + */ |
||
1254 | +int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, |
||
1255 | + u32 cmd_flags, |
||
1256 | + u16 token, |
||
1257 | + u16 if_id, |
||
1258 | + u16 frame_length) |
||
1259 | +{ |
||
1260 | + struct fsl_mc_command cmd = { 0 }; |
||
1261 | + struct dpsw_cmd_if_set_max_frame_length *cmd_params; |
||
1262 | + |
||
1263 | + /* prepare command */ |
||
1264 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH, |
||
1265 | + cmd_flags, |
||
1266 | + token); |
||
1267 | + cmd_params = (struct dpsw_cmd_if_set_max_frame_length *)cmd.params; |
||
1268 | + cmd_params->if_id = cpu_to_le16(if_id); |
||
1269 | + cmd_params->frame_length = cpu_to_le16(frame_length); |
||
1270 | + |
||
1271 | + /* send command to mc*/ |
||
1272 | + return mc_send_command(mc_io, &cmd); |
||
1273 | +} |
||
1274 | + |
||
1275 | +/** |
||
1276 | + * dpsw_vlan_add() - Adding new VLAN to DPSW. |
||
1277 | + * @mc_io: Pointer to MC portal's I/O object |
||
1278 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1279 | + * @token: Token of DPSW object |
||
1280 | + * @vlan_id: VLAN Identifier |
||
1281 | + * @cfg: VLAN configuration |
||
1282 | + * |
||
1283 | + * Only VLAN ID and FDB ID are required parameters here. |
||
1284 | + * 12 bit VLAN ID is defined in IEEE802.1Q. |
||
1285 | + * Adding a duplicate VLAN ID is not allowed. |
||
1286 | + * FDB ID can be shared across multiple VLANs. Shared learning |
||
1287 | + * is obtained by calling dpsw_vlan_add for multiple VLAN IDs |
||
1288 | + * with same fdb_id |
||
1289 | + * |
||
1290 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1291 | + */ |
||
1292 | +int dpsw_vlan_add(struct fsl_mc_io *mc_io, |
||
1293 | + u32 cmd_flags, |
||
1294 | + u16 token, |
||
1295 | + u16 vlan_id, |
||
1296 | + const struct dpsw_vlan_cfg *cfg) |
||
1297 | +{ |
||
1298 | + struct fsl_mc_command cmd = { 0 }; |
||
1299 | + struct dpsw_vlan_add *cmd_params; |
||
1300 | + |
||
1301 | + /* prepare command */ |
||
1302 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD, |
||
1303 | + cmd_flags, |
||
1304 | + token); |
||
1305 | + cmd_params = (struct dpsw_vlan_add *)cmd.params; |
||
1306 | + cmd_params->fdb_id = cpu_to_le16(cfg->fdb_id); |
||
1307 | + cmd_params->vlan_id = cpu_to_le16(vlan_id); |
||
1308 | + |
||
1309 | + /* send command to mc*/ |
||
1310 | + return mc_send_command(mc_io, &cmd); |
||
1311 | +} |
||
1312 | + |
||
1313 | +/** |
||
1314 | + * dpsw_vlan_add_if() - Adding a set of interfaces to an existing VLAN. |
||
1315 | + * @mc_io: Pointer to MC portal's I/O object |
||
1316 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1317 | + * @token: Token of DPSW object |
||
1318 | + * @vlan_id: VLAN Identifier |
||
1319 | + * @cfg: Set of interfaces to add |
||
1320 | + * |
||
1321 | + * It adds only interfaces not belonging to this VLAN yet, |
||
1322 | + * otherwise an error is generated and an entire command is |
||
1323 | + * ignored. This function can be called numerous times always |
||
1324 | + * providing required interfaces delta. |
||
1325 | + * |
||
1326 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1327 | + */ |
||
1328 | +int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, |
||
1329 | + u32 cmd_flags, |
||
1330 | + u16 token, |
||
1331 | + u16 vlan_id, |
||
1332 | + const struct dpsw_vlan_if_cfg *cfg) |
||
1333 | +{ |
||
1334 | + struct fsl_mc_command cmd = { 0 }; |
||
1335 | + struct dpsw_cmd_vlan_manage_if *cmd_params; |
||
1336 | + |
||
1337 | + /* prepare command */ |
||
1338 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF, |
||
1339 | + cmd_flags, |
||
1340 | + token); |
||
1341 | + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; |
||
1342 | + cmd_params->vlan_id = cpu_to_le16(vlan_id); |
||
1343 | + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); |
||
1344 | + |
||
1345 | + /* send command to mc*/ |
||
1346 | + return mc_send_command(mc_io, &cmd); |
||
1347 | +} |
||
1348 | + |
||
1349 | +/** |
||
1350 | + * dpsw_vlan_add_if_untagged() - Defining a set of interfaces that should be |
||
1351 | + * transmitted as untagged. |
||
1352 | + * @mc_io: Pointer to MC portal's I/O object |
||
1353 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1354 | + * @token: Token of DPSW object |
||
1355 | + * @vlan_id: VLAN Identifier |
||
1356 | + * @cfg: Set of interfaces that should be transmitted as untagged |
||
1357 | + * |
||
1358 | + * These interfaces should already belong to this VLAN. |
||
1359 | + * By default all interfaces are transmitted as tagged. |
||
1360 | + * Providing un-existing interface or untagged interface that is |
||
1361 | + * configured untagged already generates an error and the entire |
||
1362 | + * command is ignored. |
||
1363 | + * |
||
1364 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1365 | + */ |
||
1366 | +int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, |
||
1367 | + u32 cmd_flags, |
||
1368 | + u16 token, |
||
1369 | + u16 vlan_id, |
||
1370 | + const struct dpsw_vlan_if_cfg *cfg) |
||
1371 | +{ |
||
1372 | + struct fsl_mc_command cmd = { 0 }; |
||
1373 | + struct dpsw_cmd_vlan_manage_if *cmd_params; |
||
1374 | + |
||
1375 | + /* prepare command */ |
||
1376 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF_UNTAGGED, |
||
1377 | + cmd_flags, |
||
1378 | + token); |
||
1379 | + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; |
||
1380 | + cmd_params->vlan_id = cpu_to_le16(vlan_id); |
||
1381 | + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); |
||
1382 | + |
||
1383 | + /* send command to mc*/ |
||
1384 | + return mc_send_command(mc_io, &cmd); |
||
1385 | +} |
||
1386 | + |
||
1387 | +/** |
||
1388 | + * dpsw_vlan_remove_if() - Remove interfaces from an existing VLAN. |
||
1389 | + * @mc_io: Pointer to MC portal's I/O object |
||
1390 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1391 | + * @token: Token of DPSW object |
||
1392 | + * @vlan_id: VLAN Identifier |
||
1393 | + * @cfg: Set of interfaces that should be removed |
||
1394 | + * |
||
1395 | + * Interfaces must belong to this VLAN, otherwise an error |
||
1396 | + * is returned and an the command is ignored |
||
1397 | + * |
||
1398 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1399 | + */ |
||
1400 | +int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, |
||
1401 | + u32 cmd_flags, |
||
1402 | + u16 token, |
||
1403 | + u16 vlan_id, |
||
1404 | + const struct dpsw_vlan_if_cfg *cfg) |
||
1405 | +{ |
||
1406 | + struct fsl_mc_command cmd = { 0 }; |
||
1407 | + struct dpsw_cmd_vlan_manage_if *cmd_params; |
||
1408 | + |
||
1409 | + /* prepare command */ |
||
1410 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF, |
||
1411 | + cmd_flags, |
||
1412 | + token); |
||
1413 | + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; |
||
1414 | + cmd_params->vlan_id = cpu_to_le16(vlan_id); |
||
1415 | + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); |
||
1416 | + |
||
1417 | + /* send command to mc*/ |
||
1418 | + return mc_send_command(mc_io, &cmd); |
||
1419 | +} |
||
1420 | + |
||
1421 | +/** |
||
1422 | + * dpsw_vlan_remove_if_untagged() - Define a set of interfaces that should be |
||
1423 | + * converted from transmitted as untagged to transmit as tagged. |
||
1424 | + * @mc_io: Pointer to MC portal's I/O object |
||
1425 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1426 | + * @token: Token of DPSW object |
||
1427 | + * @vlan_id: VLAN Identifier |
||
1428 | + * @cfg: Set of interfaces that should be removed |
||
1429 | + * |
||
1430 | + * Interfaces provided by API have to belong to this VLAN and |
||
1431 | + * configured untagged, otherwise an error is returned and the |
||
1432 | + * command is ignored |
||
1433 | + * |
||
1434 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1435 | + */ |
||
1436 | +int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, |
||
1437 | + u32 cmd_flags, |
||
1438 | + u16 token, |
||
1439 | + u16 vlan_id, |
||
1440 | + const struct dpsw_vlan_if_cfg *cfg) |
||
1441 | +{ |
||
1442 | + struct fsl_mc_command cmd = { 0 }; |
||
1443 | + struct dpsw_cmd_vlan_manage_if *cmd_params; |
||
1444 | + |
||
1445 | + /* prepare command */ |
||
1446 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED, |
||
1447 | + cmd_flags, |
||
1448 | + token); |
||
1449 | + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; |
||
1450 | + cmd_params->vlan_id = cpu_to_le16(vlan_id); |
||
1451 | + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); |
||
1452 | + |
||
1453 | + /* send command to mc*/ |
||
1454 | + return mc_send_command(mc_io, &cmd); |
||
1455 | +} |
||
1456 | + |
||
1457 | +/** |
||
1458 | + * dpsw_vlan_remove() - Remove an entire VLAN |
||
1459 | + * @mc_io: Pointer to MC portal's I/O object |
||
1460 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1461 | + * @token: Token of DPSW object |
||
1462 | + * @vlan_id: VLAN Identifier |
||
1463 | + * |
||
1464 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1465 | + */ |
||
1466 | +int dpsw_vlan_remove(struct fsl_mc_io *mc_io, |
||
1467 | + u32 cmd_flags, |
||
1468 | + u16 token, |
||
1469 | + u16 vlan_id) |
||
1470 | +{ |
||
1471 | + struct fsl_mc_command cmd = { 0 }; |
||
1472 | + struct dpsw_cmd_vlan_remove *cmd_params; |
||
1473 | + |
||
1474 | + /* prepare command */ |
||
1475 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE, |
||
1476 | + cmd_flags, |
||
1477 | + token); |
||
1478 | + cmd_params = (struct dpsw_cmd_vlan_remove *)cmd.params; |
||
1479 | + cmd_params->vlan_id = cpu_to_le16(vlan_id); |
||
1480 | + |
||
1481 | + /* send command to mc*/ |
||
1482 | + return mc_send_command(mc_io, &cmd); |
||
1483 | +} |
||
1484 | + |
||
1485 | +/** |
||
1486 | + * dpsw_fdb_add_unicast() - Function adds an unicast entry into MAC lookup table |
||
1487 | + * @mc_io: Pointer to MC portal's I/O object |
||
1488 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1489 | + * @token: Token of DPSW object |
||
1490 | + * @fdb_id: Forwarding Database Identifier |
||
1491 | + * @cfg: Unicast entry configuration |
||
1492 | + * |
||
1493 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1494 | + */ |
||
1495 | +int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, |
||
1496 | + u32 cmd_flags, |
||
1497 | + u16 token, |
||
1498 | + u16 fdb_id, |
||
1499 | + const struct dpsw_fdb_unicast_cfg *cfg) |
||
1500 | +{ |
||
1501 | + struct fsl_mc_command cmd = { 0 }; |
||
1502 | + struct dpsw_cmd_fdb_unicast_op *cmd_params; |
||
1503 | + int i; |
||
1504 | + |
||
1505 | + /* prepare command */ |
||
1506 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_UNICAST, |
||
1507 | + cmd_flags, |
||
1508 | + token); |
||
1509 | + cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params; |
||
1510 | + cmd_params->fdb_id = cpu_to_le16(fdb_id); |
||
1511 | + cmd_params->if_egress = cpu_to_le16(cfg->if_egress); |
||
1512 | + for (i = 0; i < 6; i++) |
||
1513 | + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; |
||
1514 | + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); |
||
1515 | + |
||
1516 | + /* send command to mc*/ |
||
1517 | + return mc_send_command(mc_io, &cmd); |
||
1518 | +} |
||
1519 | + |
||
1520 | +/** |
||
1521 | + * dpsw_fdb_remove_unicast() - removes an entry from MAC lookup table |
||
1522 | + * @mc_io: Pointer to MC portal's I/O object |
||
1523 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1524 | + * @token: Token of DPSW object |
||
1525 | + * @fdb_id: Forwarding Database Identifier |
||
1526 | + * @cfg: Unicast entry configuration |
||
1527 | + * |
||
1528 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1529 | + */ |
||
1530 | +int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, |
||
1531 | + u32 cmd_flags, |
||
1532 | + u16 token, |
||
1533 | + u16 fdb_id, |
||
1534 | + const struct dpsw_fdb_unicast_cfg *cfg) |
||
1535 | +{ |
||
1536 | + struct fsl_mc_command cmd = { 0 }; |
||
1537 | + struct dpsw_cmd_fdb_unicast_op *cmd_params; |
||
1538 | + int i; |
||
1539 | + |
||
1540 | + /* prepare command */ |
||
1541 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_UNICAST, |
||
1542 | + cmd_flags, |
||
1543 | + token); |
||
1544 | + cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params; |
||
1545 | + cmd_params->fdb_id = cpu_to_le16(fdb_id); |
||
1546 | + for (i = 0; i < 6; i++) |
||
1547 | + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; |
||
1548 | + cmd_params->if_egress = cpu_to_le16(cfg->if_egress); |
||
1549 | + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); |
||
1550 | + |
||
1551 | + /* send command to mc*/ |
||
1552 | + return mc_send_command(mc_io, &cmd); |
||
1553 | +} |
||
1554 | + |
||
1555 | +/** |
||
1556 | + * dpsw_fdb_add_multicast() - Add a set of egress interfaces to multi-cast group |
||
1557 | + * @mc_io: Pointer to MC portal's I/O object |
||
1558 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1559 | + * @token: Token of DPSW object |
||
1560 | + * @fdb_id: Forwarding Database Identifier |
||
1561 | + * @cfg: Multicast entry configuration |
||
1562 | + * |
||
1563 | + * If group doesn't exist, it will be created. |
||
1564 | + * It adds only interfaces not belonging to this multicast group |
||
1565 | + * yet, otherwise error will be generated and the command is |
||
1566 | + * ignored. |
||
1567 | + * This function may be called numerous times always providing |
||
1568 | + * required interfaces delta. |
||
1569 | + * |
||
1570 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1571 | + */ |
||
1572 | +int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, |
||
1573 | + u32 cmd_flags, |
||
1574 | + u16 token, |
||
1575 | + u16 fdb_id, |
||
1576 | + const struct dpsw_fdb_multicast_cfg *cfg) |
||
1577 | +{ |
||
1578 | + struct fsl_mc_command cmd = { 0 }; |
||
1579 | + struct dpsw_cmd_fdb_multicast_op *cmd_params; |
||
1580 | + int i; |
||
1581 | + |
||
1582 | + /* prepare command */ |
||
1583 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_MULTICAST, |
||
1584 | + cmd_flags, |
||
1585 | + token); |
||
1586 | + cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params; |
||
1587 | + cmd_params->fdb_id = cpu_to_le16(fdb_id); |
||
1588 | + cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); |
||
1589 | + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); |
||
1590 | + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); |
||
1591 | + for (i = 0; i < 6; i++) |
||
1592 | + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; |
||
1593 | + |
||
1594 | + /* send command to mc*/ |
||
1595 | + return mc_send_command(mc_io, &cmd); |
||
1596 | +} |
||
1597 | + |
||
1598 | +/** |
||
1599 | + * dpsw_fdb_remove_multicast() - Removing interfaces from an existing multicast |
||
1600 | + * group. |
||
1601 | + * @mc_io: Pointer to MC portal's I/O object |
||
1602 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1603 | + * @token: Token of DPSW object |
||
1604 | + * @fdb_id: Forwarding Database Identifier |
||
1605 | + * @cfg: Multicast entry configuration |
||
1606 | + * |
||
1607 | + * Interfaces provided by this API have to exist in the group, |
||
1608 | + * otherwise an error will be returned and an entire command |
||
1609 | + * ignored. If there is no interface left in the group, |
||
1610 | + * an entire group is deleted |
||
1611 | + * |
||
1612 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1613 | + */ |
||
1614 | +int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, |
||
1615 | + u32 cmd_flags, |
||
1616 | + u16 token, |
||
1617 | + u16 fdb_id, |
||
1618 | + const struct dpsw_fdb_multicast_cfg *cfg) |
||
1619 | +{ |
||
1620 | + struct fsl_mc_command cmd = { 0 }; |
||
1621 | + struct dpsw_cmd_fdb_multicast_op *cmd_params; |
||
1622 | + int i; |
||
1623 | + |
||
1624 | + /* prepare command */ |
||
1625 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_MULTICAST, |
||
1626 | + cmd_flags, |
||
1627 | + token); |
||
1628 | + cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params; |
||
1629 | + cmd_params->fdb_id = cpu_to_le16(fdb_id); |
||
1630 | + cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); |
||
1631 | + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); |
||
1632 | + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); |
||
1633 | + for (i = 0; i < 6; i++) |
||
1634 | + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; |
||
1635 | + |
||
1636 | + /* send command to mc*/ |
||
1637 | + return mc_send_command(mc_io, &cmd); |
||
1638 | +} |
||
1639 | + |
||
1640 | +/** |
||
1641 | + * dpsw_fdb_set_learning_mode() - Define FDB learning mode |
||
1642 | + * @mc_io: Pointer to MC portal's I/O object |
||
1643 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1644 | + * @token: Token of DPSW object |
||
1645 | + * @fdb_id: Forwarding Database Identifier |
||
1646 | + * @mode: Learning mode |
||
1647 | + * |
||
1648 | + * Return: Completion status. '0' on Success; Error code otherwise. |
||
1649 | + */ |
||
1650 | +int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io, |
||
1651 | + u32 cmd_flags, |
||
1652 | + u16 token, |
||
1653 | + u16 fdb_id, |
||
1654 | + enum dpsw_fdb_learning_mode mode) |
||
1655 | +{ |
||
1656 | + struct fsl_mc_command cmd = { 0 }; |
||
1657 | + struct dpsw_cmd_fdb_set_learning_mode *cmd_params; |
||
1658 | + |
||
1659 | + /* prepare command */ |
||
1660 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_SET_LEARNING_MODE, |
||
1661 | + cmd_flags, |
||
1662 | + token); |
||
1663 | + cmd_params = (struct dpsw_cmd_fdb_set_learning_mode *)cmd.params; |
||
1664 | + cmd_params->fdb_id = cpu_to_le16(fdb_id); |
||
1665 | + dpsw_set_field(cmd_params->mode, LEARNING_MODE, mode); |
||
1666 | + |
||
1667 | + /* send command to mc*/ |
||
1668 | + return mc_send_command(mc_io, &cmd); |
||
1669 | +} |
||
1670 | + |
||
1671 | +/** |
||
1672 | + * dpsw_get_api_version() - Get Data Path Switch API version |
||
1673 | + * @mc_io: Pointer to MC portal's I/O object |
||
1674 | + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' |
||
1675 | + * @major_ver: Major version of data path switch API |
||
1676 | + * @minor_ver: Minor version of data path switch API |
||
1677 | + * |
||
1678 | + * Return: '0' on Success; Error code otherwise. |
||
1679 | + */ |
||
1680 | +int dpsw_get_api_version(struct fsl_mc_io *mc_io, |
||
1681 | + u32 cmd_flags, |
||
1682 | + u16 *major_ver, |
||
1683 | + u16 *minor_ver) |
||
1684 | +{ |
||
1685 | + struct fsl_mc_command cmd = { 0 }; |
||
1686 | + struct dpsw_rsp_get_api_version *rsp_params; |
||
1687 | + int err; |
||
1688 | + |
||
1689 | + cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_API_VERSION, |
||
1690 | + cmd_flags, |
||
1691 | + 0); |
||
1692 | + |
||
1693 | + err = mc_send_command(mc_io, &cmd); |
||
1694 | + if (err) |
||
1695 | + return err; |
||
1696 | + |
||
1697 | + rsp_params = (struct dpsw_rsp_get_api_version *)cmd.params; |
||
1698 | + *major_ver = le16_to_cpu(rsp_params->version_major); |
||
1699 | + *minor_ver = le16_to_cpu(rsp_params->version_minor); |
||
1700 | + |
||
1701 | + return 0; |
||
1702 | +} |
||
1703 | --- /dev/null |
||
1704 | +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h |
||
1705 | @@ -0,0 +1,592 @@ |
||
1706 | +// SPDX-License-Identifier: GPL-2.0 |
||
1707 | +/* |
||
1708 | + * Copyright 2013-2016 Freescale Semiconductor, Inc. |
||
1709 | + * Copyright 2017-2018 NXP |
||
1710 | + * |
||
1711 | + */ |
||
1712 | + |
||
1713 | +#ifndef __FSL_DPSW_H |
||
1714 | +#define __FSL_DPSW_H |
||
1715 | + |
||
1716 | +/* Data Path L2-Switch API |
||
1717 | + * Contains API for handling DPSW topology and functionality |
||
1718 | + */ |
||
1719 | + |
||
1720 | +struct fsl_mc_io; |
||
1721 | + |
||
1722 | +/** |
||
1723 | + * DPSW general definitions |
||
1724 | + */ |
||
1725 | + |
||
1726 | +/** |
||
1727 | + * Maximum number of traffic class priorities |
||
1728 | + */ |
||
1729 | +#define DPSW_MAX_PRIORITIES 8 |
||
1730 | +/** |
||
1731 | + * Maximum number of interfaces |
||
1732 | + */ |
||
1733 | +#define DPSW_MAX_IF 64 |
||
1734 | + |
||
1735 | +int dpsw_open(struct fsl_mc_io *mc_io, |
||
1736 | + u32 cmd_flags, |
||
1737 | + int dpsw_id, |
||
1738 | + u16 *token); |
||
1739 | + |
||
1740 | +int dpsw_close(struct fsl_mc_io *mc_io, |
||
1741 | + u32 cmd_flags, |
||
1742 | + u16 token); |
||
1743 | + |
||
1744 | +/** |
||
1745 | + * DPSW options |
||
1746 | + */ |
||
1747 | + |
||
1748 | +/** |
||
1749 | + * Disable flooding |
||
1750 | + */ |
||
1751 | +#define DPSW_OPT_FLOODING_DIS 0x0000000000000001ULL |
||
1752 | +/** |
||
1753 | + * Disable Multicast |
||
1754 | + */ |
||
1755 | +#define DPSW_OPT_MULTICAST_DIS 0x0000000000000004ULL |
||
1756 | +/** |
||
1757 | + * Support control interface |
||
1758 | + */ |
||
1759 | +#define DPSW_OPT_CTRL_IF_DIS 0x0000000000000010ULL |
||
1760 | +/** |
||
1761 | + * Disable flooding metering |
||
1762 | + */ |
||
1763 | +#define DPSW_OPT_FLOODING_METERING_DIS 0x0000000000000020ULL |
||
1764 | +/** |
||
1765 | + * Enable metering |
||
1766 | + */ |
||
1767 | +#define DPSW_OPT_METERING_EN 0x0000000000000040ULL |
||
1768 | + |
||
1769 | +/** |
||
1770 | + * enum dpsw_component_type - component type of a bridge |
||
1771 | + * @DPSW_COMPONENT_TYPE_C_VLAN: A C-VLAN component of an |
||
1772 | + * enterprise VLAN bridge or of a Provider Bridge used |
||
1773 | + * to process C-tagged frames |
||
1774 | + * @DPSW_COMPONENT_TYPE_S_VLAN: An S-VLAN component of a |
||
1775 | + * Provider Bridge |
||
1776 | + * |
||
1777 | + */ |
||
1778 | +enum dpsw_component_type { |
||
1779 | + DPSW_COMPONENT_TYPE_C_VLAN = 0, |
||
1780 | + DPSW_COMPONENT_TYPE_S_VLAN |
||
1781 | +}; |
||
1782 | + |
||
1783 | +/** |
||
1784 | + * struct dpsw_cfg - DPSW configuration |
||
1785 | + * @num_ifs: Number of external and internal interfaces |
||
1786 | + * @adv: Advanced parameters; default is all zeros; |
||
1787 | + * use this structure to change default settings |
||
1788 | + */ |
||
1789 | +struct dpsw_cfg { |
||
1790 | + u16 num_ifs; |
||
1791 | + /** |
||
1792 | + * struct adv - Advanced parameters |
||
1793 | + * @options: Enable/Disable DPSW features (bitmap) |
||
1794 | + * @max_vlans: Maximum Number of VLAN's; 0 - indicates default 16 |
||
1795 | + * @max_meters_per_if: Number of meters per interface |
||
1796 | + * @max_fdbs: Maximum Number of FDB's; 0 - indicates default 16 |
||
1797 | + * @max_fdb_entries: Number of FDB entries for default FDB table; |
||
1798 | + * 0 - indicates default 1024 entries. |
||
1799 | + * @fdb_aging_time: Default FDB aging time for default FDB table; |
||
1800 | + * 0 - indicates default 300 seconds |
||
1801 | + * @max_fdb_mc_groups: Number of multicast groups in each FDB table; |
||
1802 | + * 0 - indicates default 32 |
||
1803 | + * @component_type: Indicates the component type of this bridge |
||
1804 | + */ |
||
1805 | + struct { |
||
1806 | + u64 options; |
||
1807 | + u16 max_vlans; |
||
1808 | + u8 max_meters_per_if; |
||
1809 | + u8 max_fdbs; |
||
1810 | + u16 max_fdb_entries; |
||
1811 | + u16 fdb_aging_time; |
||
1812 | + u16 max_fdb_mc_groups; |
||
1813 | + enum dpsw_component_type component_type; |
||
1814 | + } adv; |
||
1815 | +}; |
||
1816 | + |
||
1817 | +int dpsw_enable(struct fsl_mc_io *mc_io, |
||
1818 | + u32 cmd_flags, |
||
1819 | + u16 token); |
||
1820 | + |
||
1821 | +int dpsw_disable(struct fsl_mc_io *mc_io, |
||
1822 | + u32 cmd_flags, |
||
1823 | + u16 token); |
||
1824 | + |
||
1825 | +int dpsw_reset(struct fsl_mc_io *mc_io, |
||
1826 | + u32 cmd_flags, |
||
1827 | + u16 token); |
||
1828 | + |
||
1829 | +/** |
||
1830 | + * DPSW IRQ Index and Events |
||
1831 | + */ |
||
1832 | + |
||
1833 | +#define DPSW_IRQ_INDEX_IF 0x0000 |
||
1834 | +#define DPSW_IRQ_INDEX_L2SW 0x0001 |
||
1835 | + |
||
1836 | +/** |
||
1837 | + * IRQ event - Indicates that the link state changed |
||
1838 | + */ |
||
1839 | +#define DPSW_IRQ_EVENT_LINK_CHANGED 0x0001 |
||
1840 | + |
||
1841 | +/** |
||
1842 | + * struct dpsw_irq_cfg - IRQ configuration |
||
1843 | + * @addr: Address that must be written to signal a message-based interrupt |
||
1844 | + * @val: Value to write into irq_addr address |
||
1845 | + * @irq_num: A user defined number associated with this IRQ |
||
1846 | + */ |
||
1847 | +struct dpsw_irq_cfg { |
||
1848 | + u64 addr; |
||
1849 | + u32 val; |
||
1850 | + int irq_num; |
||
1851 | +}; |
||
1852 | + |
||
1853 | +int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, |
||
1854 | + u32 cmd_flags, |
||
1855 | + u16 token, |
||
1856 | + u8 irq_index, |
||
1857 | + u8 en); |
||
1858 | + |
||
1859 | +int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, |
||
1860 | + u32 cmd_flags, |
||
1861 | + u16 token, |
||
1862 | + u8 irq_index, |
||
1863 | + u32 mask); |
||
1864 | + |
||
1865 | +int dpsw_get_irq_status(struct fsl_mc_io *mc_io, |
||
1866 | + u32 cmd_flags, |
||
1867 | + u16 token, |
||
1868 | + u8 irq_index, |
||
1869 | + u32 *status); |
||
1870 | + |
||
1871 | +int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, |
||
1872 | + u32 cmd_flags, |
||
1873 | + u16 token, |
||
1874 | + u8 irq_index, |
||
1875 | + u32 status); |
||
1876 | + |
||
1877 | +/** |
||
1878 | + * struct dpsw_attr - Structure representing DPSW attributes |
||
1879 | + * @id: DPSW object ID |
||
1880 | + * @options: Enable/Disable DPSW features |
||
1881 | + * @max_vlans: Maximum Number of VLANs |
||
1882 | + * @max_meters_per_if: Number of meters per interface |
||
1883 | + * @max_fdbs: Maximum Number of FDBs |
||
1884 | + * @max_fdb_entries: Number of FDB entries for default FDB table; |
||
1885 | + * 0 - indicates default 1024 entries. |
||
1886 | + * @fdb_aging_time: Default FDB aging time for default FDB table; |
||
1887 | + * 0 - indicates default 300 seconds |
||
1888 | + * @max_fdb_mc_groups: Number of multicast groups in each FDB table; |
||
1889 | + * 0 - indicates default 32 |
||
1890 | + * @mem_size: DPSW frame storage memory size |
||
1891 | + * @num_ifs: Number of interfaces |
||
1892 | + * @num_vlans: Current number of VLANs |
||
1893 | + * @num_fdbs: Current number of FDBs |
||
1894 | + * @component_type: Component type of this bridge |
||
1895 | + */ |
||
1896 | +struct dpsw_attr { |
||
1897 | + int id; |
||
1898 | + u64 options; |
||
1899 | + u16 max_vlans; |
||
1900 | + u8 max_meters_per_if; |
||
1901 | + u8 max_fdbs; |
||
1902 | + u16 max_fdb_entries; |
||
1903 | + u16 fdb_aging_time; |
||
1904 | + u16 max_fdb_mc_groups; |
||
1905 | + u16 num_ifs; |
||
1906 | + u16 mem_size; |
||
1907 | + u16 num_vlans; |
||
1908 | + u8 num_fdbs; |
||
1909 | + enum dpsw_component_type component_type; |
||
1910 | +}; |
||
1911 | + |
||
1912 | +int dpsw_get_attributes(struct fsl_mc_io *mc_io, |
||
1913 | + u32 cmd_flags, |
||
1914 | + u16 token, |
||
1915 | + struct dpsw_attr *attr); |
||
1916 | + |
||
1917 | +/** |
||
1918 | + * enum dpsw_action - Action selection for special/control frames |
||
1919 | + * @DPSW_ACTION_DROP: Drop frame |
||
1920 | + * @DPSW_ACTION_REDIRECT: Redirect frame to control port |
||
1921 | + */ |
||
1922 | +enum dpsw_action { |
||
1923 | + DPSW_ACTION_DROP = 0, |
||
1924 | + DPSW_ACTION_REDIRECT = 1 |
||
1925 | +}; |
||
1926 | + |
||
1927 | +/** |
||
1928 | + * Enable auto-negotiation |
||
1929 | + */ |
||
1930 | +#define DPSW_LINK_OPT_AUTONEG 0x0000000000000001ULL |
||
1931 | +/** |
||
1932 | + * Enable half-duplex mode |
||
1933 | + */ |
||
1934 | +#define DPSW_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL |
||
1935 | +/** |
||
1936 | + * Enable pause frames |
||
1937 | + */ |
||
1938 | +#define DPSW_LINK_OPT_PAUSE 0x0000000000000004ULL |
||
1939 | +/** |
||
1940 | + * Enable a-symmetric pause frames |
||
1941 | + */ |
||
1942 | +#define DPSW_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL |
||
1943 | + |
||
1944 | +/** |
||
1945 | + * struct dpsw_link_cfg - Structure representing DPSW link configuration |
||
1946 | + * @rate: Rate |
||
1947 | + * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values |
||
1948 | + */ |
||
1949 | +struct dpsw_link_cfg { |
||
1950 | + u32 rate; |
||
1951 | + u64 options; |
||
1952 | +}; |
||
1953 | + |
||
1954 | +int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, |
||
1955 | + u32 cmd_flags, |
||
1956 | + u16 token, |
||
1957 | + u16 if_id, |
||
1958 | + struct dpsw_link_cfg *cfg); |
||
1959 | +/** |
||
1960 | + * struct dpsw_link_state - Structure representing DPSW link state |
||
1961 | + * @rate: Rate |
||
1962 | + * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values |
||
1963 | + * @up: 0 - covers two cases: down and disconnected, 1 - up |
||
1964 | + */ |
||
1965 | +struct dpsw_link_state { |
||
1966 | + u32 rate; |
||
1967 | + u64 options; |
||
1968 | + u8 up; |
||
1969 | +}; |
||
1970 | + |
||
1971 | +int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, |
||
1972 | + u32 cmd_flags, |
||
1973 | + u16 token, |
||
1974 | + u16 if_id, |
||
1975 | + struct dpsw_link_state *state); |
||
1976 | + |
||
1977 | +int dpsw_if_set_flooding(struct fsl_mc_io *mc_io, |
||
1978 | + u32 cmd_flags, |
||
1979 | + u16 token, |
||
1980 | + u16 if_id, |
||
1981 | + u8 en); |
||
1982 | + |
||
1983 | +int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io, |
||
1984 | + u32 cmd_flags, |
||
1985 | + u16 token, |
||
1986 | + u16 if_id, |
||
1987 | + u8 en); |
||
1988 | + |
||
1989 | +/** |
||
1990 | + * struct dpsw_tci_cfg - Tag Control Information (TCI) configuration |
||
1991 | + * @pcp: Priority Code Point (PCP): a 3-bit field which refers |
||
1992 | + * to the IEEE 802.1p priority |
||
1993 | + * @dei: Drop Eligible Indicator (DEI): a 1-bit field. May be used |
||
1994 | + * separately or in conjunction with PCP to indicate frames |
||
1995 | + * eligible to be dropped in the presence of congestion |
||
1996 | + * @vlan_id: VLAN Identifier (VID): a 12-bit field specifying the VLAN |
||
1997 | + * to which the frame belongs. The hexadecimal values |
||
1998 | + * of 0x000 and 0xFFF are reserved; |
||
1999 | + * all other values may be used as VLAN identifiers, |
||
2000 | + * allowing up to 4,094 VLANs |
||
2001 | + */ |
||
2002 | +struct dpsw_tci_cfg { |
||
2003 | + u8 pcp; |
||
2004 | + u8 dei; |
||
2005 | + u16 vlan_id; |
||
2006 | +}; |
||
2007 | + |
||
2008 | +int dpsw_if_set_tci(struct fsl_mc_io *mc_io, |
||
2009 | + u32 cmd_flags, |
||
2010 | + u16 token, |
||
2011 | + u16 if_id, |
||
2012 | + const struct dpsw_tci_cfg *cfg); |
||
2013 | + |
||
2014 | +int dpsw_if_get_tci(struct fsl_mc_io *mc_io, |
||
2015 | + u32 cmd_flags, |
||
2016 | + u16 token, |
||
2017 | + u16 if_id, |
||
2018 | + struct dpsw_tci_cfg *cfg); |
||
2019 | + |
||
2020 | +/** |
||
2021 | + * enum dpsw_stp_state - Spanning Tree Protocol (STP) states |
||
2022 | + * @DPSW_STP_STATE_BLOCKING: Blocking state |
||
2023 | + * @DPSW_STP_STATE_LISTENING: Listening state |
||
2024 | + * @DPSW_STP_STATE_LEARNING: Learning state |
||
2025 | + * @DPSW_STP_STATE_FORWARDING: Forwarding state |
||
2026 | + * |
||
2027 | + */ |
||
2028 | +enum dpsw_stp_state { |
||
2029 | + DPSW_STP_STATE_DISABLED = 0, |
||
2030 | + DPSW_STP_STATE_LISTENING = 1, |
||
2031 | + DPSW_STP_STATE_LEARNING = 2, |
||
2032 | + DPSW_STP_STATE_FORWARDING = 3, |
||
2033 | + DPSW_STP_STATE_BLOCKING = 0 |
||
2034 | +}; |
||
2035 | + |
||
2036 | +/** |
||
2037 | + * struct dpsw_stp_cfg - Spanning Tree Protocol (STP) Configuration |
||
2038 | + * @vlan_id: VLAN ID STP state |
||
2039 | + * @state: STP state |
||
2040 | + */ |
||
2041 | +struct dpsw_stp_cfg { |
||
2042 | + u16 vlan_id; |
||
2043 | + enum dpsw_stp_state state; |
||
2044 | +}; |
||
2045 | + |
||
2046 | +int dpsw_if_set_stp(struct fsl_mc_io *mc_io, |
||
2047 | + u32 cmd_flags, |
||
2048 | + u16 token, |
||
2049 | + u16 if_id, |
||
2050 | + const struct dpsw_stp_cfg *cfg); |
||
2051 | + |
||
2052 | +/** |
||
2053 | + * enum dpsw_accepted_frames - Types of frames to accept |
||
2054 | + * @DPSW_ADMIT_ALL: The device accepts VLAN tagged, untagged and |
||
2055 | + * priority tagged frames |
||
2056 | + * @DPSW_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or |
||
2057 | + * Priority-Tagged frames received on this interface. |
||
2058 | + * |
||
2059 | + */ |
||
2060 | +enum dpsw_accepted_frames { |
||
2061 | + DPSW_ADMIT_ALL = 1, |
||
2062 | + DPSW_ADMIT_ONLY_VLAN_TAGGED = 3 |
||
2063 | +}; |
||
2064 | + |
||
2065 | +/** |
||
2066 | + * enum dpsw_counter - Counters types |
||
2067 | + * @DPSW_CNT_ING_FRAME: Counts ingress frames |
||
2068 | + * @DPSW_CNT_ING_BYTE: Counts ingress bytes |
||
2069 | + * @DPSW_CNT_ING_FLTR_FRAME: Counts filtered ingress frames |
||
2070 | + * @DPSW_CNT_ING_FRAME_DISCARD: Counts discarded ingress frame |
||
2071 | + * @DPSW_CNT_ING_MCAST_FRAME: Counts ingress multicast frames |
||
2072 | + * @DPSW_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes |
||
2073 | + * @DPSW_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames |
||
2074 | + * @DPSW_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes |
||
2075 | + * @DPSW_CNT_EGR_FRAME: Counts egress frames |
||
2076 | + * @DPSW_CNT_EGR_BYTE: Counts eEgress bytes |
||
2077 | + * @DPSW_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames |
||
2078 | + * @DPSW_CNT_EGR_STP_FRAME_DISCARD: Counts egress STP discarded frames |
||
2079 | + */ |
||
2080 | +enum dpsw_counter { |
||
2081 | + DPSW_CNT_ING_FRAME = 0x0, |
||
2082 | + DPSW_CNT_ING_BYTE = 0x1, |
||
2083 | + DPSW_CNT_ING_FLTR_FRAME = 0x2, |
||
2084 | + DPSW_CNT_ING_FRAME_DISCARD = 0x3, |
||
2085 | + DPSW_CNT_ING_MCAST_FRAME = 0x4, |
||
2086 | + DPSW_CNT_ING_MCAST_BYTE = 0x5, |
||
2087 | + DPSW_CNT_ING_BCAST_FRAME = 0x6, |
||
2088 | + DPSW_CNT_ING_BCAST_BYTES = 0x7, |
||
2089 | + DPSW_CNT_EGR_FRAME = 0x8, |
||
2090 | + DPSW_CNT_EGR_BYTE = 0x9, |
||
2091 | + DPSW_CNT_EGR_FRAME_DISCARD = 0xa, |
||
2092 | + DPSW_CNT_EGR_STP_FRAME_DISCARD = 0xb |
||
2093 | +}; |
||
2094 | + |
||
2095 | +int dpsw_if_get_counter(struct fsl_mc_io *mc_io, |
||
2096 | + u32 cmd_flags, |
||
2097 | + u16 token, |
||
2098 | + u16 if_id, |
||
2099 | + enum dpsw_counter type, |
||
2100 | + u64 *counter); |
||
2101 | + |
||
2102 | +int dpsw_if_enable(struct fsl_mc_io *mc_io, |
||
2103 | + u32 cmd_flags, |
||
2104 | + u16 token, |
||
2105 | + u16 if_id); |
||
2106 | + |
||
2107 | +int dpsw_if_disable(struct fsl_mc_io *mc_io, |
||
2108 | + u32 cmd_flags, |
||
2109 | + u16 token, |
||
2110 | + u16 if_id); |
||
2111 | + |
||
2112 | +int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, |
||
2113 | + u32 cmd_flags, |
||
2114 | + u16 token, |
||
2115 | + u16 if_id, |
||
2116 | + u16 frame_length); |
||
2117 | + |
||
2118 | +/** |
||
2119 | + * struct dpsw_vlan_cfg - VLAN Configuration |
||
2120 | + * @fdb_id: Forwarding Data Base |
||
2121 | + */ |
||
2122 | +struct dpsw_vlan_cfg { |
||
2123 | + u16 fdb_id; |
||
2124 | +}; |
||
2125 | + |
||
2126 | +int dpsw_vlan_add(struct fsl_mc_io *mc_io, |
||
2127 | + u32 cmd_flags, |
||
2128 | + u16 token, |
||
2129 | + u16 vlan_id, |
||
2130 | + const struct dpsw_vlan_cfg *cfg); |
||
2131 | + |
||
2132 | +/** |
||
2133 | + * struct dpsw_vlan_if_cfg - Set of VLAN Interfaces |
||
2134 | + * @num_ifs: The number of interfaces that are assigned to the egress |
||
2135 | + * list for this VLAN |
||
2136 | + * @if_id: The set of interfaces that are |
||
2137 | + * assigned to the egress list for this VLAN |
||
2138 | + */ |
||
2139 | +struct dpsw_vlan_if_cfg { |
||
2140 | + u16 num_ifs; |
||
2141 | + u16 if_id[DPSW_MAX_IF]; |
||
2142 | +}; |
||
2143 | + |
||
2144 | +int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, |
||
2145 | + u32 cmd_flags, |
||
2146 | + u16 token, |
||
2147 | + u16 vlan_id, |
||
2148 | + const struct dpsw_vlan_if_cfg *cfg); |
||
2149 | + |
||
2150 | +int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, |
||
2151 | + u32 cmd_flags, |
||
2152 | + u16 token, |
||
2153 | + u16 vlan_id, |
||
2154 | + const struct dpsw_vlan_if_cfg *cfg); |
||
2155 | + |
||
2156 | +int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, |
||
2157 | + u32 cmd_flags, |
||
2158 | + u16 token, |
||
2159 | + u16 vlan_id, |
||
2160 | + const struct dpsw_vlan_if_cfg *cfg); |
||
2161 | + |
||
2162 | +int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, |
||
2163 | + u32 cmd_flags, |
||
2164 | + u16 token, |
||
2165 | + u16 vlan_id, |
||
2166 | + const struct dpsw_vlan_if_cfg *cfg); |
||
2167 | + |
||
2168 | +int dpsw_vlan_remove(struct fsl_mc_io *mc_io, |
||
2169 | + u32 cmd_flags, |
||
2170 | + u16 token, |
||
2171 | + u16 vlan_id); |
||
2172 | + |
||
2173 | +/** |
||
2174 | + * enum dpsw_fdb_entry_type - FDB Entry type - Static/Dynamic |
||
2175 | + * @DPSW_FDB_ENTRY_STATIC: Static entry |
||
2176 | + * @DPSW_FDB_ENTRY_DINAMIC: Dynamic entry |
||
2177 | + */ |
||
2178 | +enum dpsw_fdb_entry_type { |
||
2179 | + DPSW_FDB_ENTRY_STATIC = 0, |
||
2180 | + DPSW_FDB_ENTRY_DINAMIC = 1 |
||
2181 | +}; |
||
2182 | + |
||
2183 | +/** |
||
2184 | + * struct dpsw_fdb_unicast_cfg - Unicast entry configuration |
||
2185 | + * @type: Select static or dynamic entry |
||
2186 | + * @mac_addr: MAC address |
||
2187 | + * @if_egress: Egress interface ID |
||
2188 | + */ |
||
2189 | +struct dpsw_fdb_unicast_cfg { |
||
2190 | + enum dpsw_fdb_entry_type type; |
||
2191 | + u8 mac_addr[6]; |
||
2192 | + u16 if_egress; |
||
2193 | +}; |
||
2194 | + |
||
2195 | +int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, |
||
2196 | + u32 cmd_flags, |
||
2197 | + u16 token, |
||
2198 | + u16 fdb_id, |
||
2199 | + const struct dpsw_fdb_unicast_cfg *cfg); |
||
2200 | + |
||
2201 | +int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, |
||
2202 | + u32 cmd_flags, |
||
2203 | + u16 token, |
||
2204 | + u16 fdb_id, |
||
2205 | + const struct dpsw_fdb_unicast_cfg *cfg); |
||
2206 | + |
||
2207 | +/** |
||
2208 | + * struct dpsw_fdb_multicast_cfg - Multi-cast entry configuration |
||
2209 | + * @type: Select static or dynamic entry |
||
2210 | + * @mac_addr: MAC address |
||
2211 | + * @num_ifs: Number of external and internal interfaces |
||
2212 | + * @if_id: Egress interface IDs |
||
2213 | + */ |
||
2214 | +struct dpsw_fdb_multicast_cfg { |
||
2215 | + enum dpsw_fdb_entry_type type; |
||
2216 | + u8 mac_addr[6]; |
||
2217 | + u16 num_ifs; |
||
2218 | + u16 if_id[DPSW_MAX_IF]; |
||
2219 | +}; |
||
2220 | + |
||
2221 | +int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, |
||
2222 | + u32 cmd_flags, |
||
2223 | + u16 token, |
||
2224 | + u16 fdb_id, |
||
2225 | + const struct dpsw_fdb_multicast_cfg *cfg); |
||
2226 | + |
||
2227 | +int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, |
||
2228 | + u32 cmd_flags, |
||
2229 | + u16 token, |
||
2230 | + u16 fdb_id, |
||
2231 | + const struct dpsw_fdb_multicast_cfg *cfg); |
||
2232 | + |
||
2233 | +/** |
||
2234 | + * enum dpsw_fdb_learning_mode - Auto-learning modes |
||
2235 | + * @DPSW_FDB_LEARNING_MODE_DIS: Disable Auto-learning |
||
2236 | + * @DPSW_FDB_LEARNING_MODE_HW: Enable HW auto-Learning |
||
2237 | + * @DPSW_FDB_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU |
||
2238 | + * @DPSW_FDB_LEARNING_MODE_SECURE: Enable secure learning by CPU |
||
2239 | + * |
||
2240 | + * NONE - SECURE LEARNING |
||
2241 | + * SMAC found DMAC found CTLU Action |
||
2242 | + * v v Forward frame to |
||
2243 | + * 1. DMAC destination |
||
2244 | + * - v Forward frame to |
||
2245 | + * 1. DMAC destination |
||
2246 | + * 2. Control interface |
||
2247 | + * v - Forward frame to |
||
2248 | + * 1. Flooding list of interfaces |
||
2249 | + * - - Forward frame to |
||
2250 | + * 1. Flooding list of interfaces |
||
2251 | + * 2. Control interface |
||
2252 | + * SECURE LEARING |
||
2253 | + * SMAC found DMAC found CTLU Action |
||
2254 | + * v v Forward frame to |
||
2255 | + * 1. DMAC destination |
||
2256 | + * - v Forward frame to |
||
2257 | + * 1. Control interface |
||
2258 | + * v - Forward frame to |
||
2259 | + * 1. Flooding list of interfaces |
||
2260 | + * - - Forward frame to |
||
2261 | + * 1. Control interface |
||
2262 | + */ |
||
2263 | +enum dpsw_fdb_learning_mode { |
||
2264 | + DPSW_FDB_LEARNING_MODE_DIS = 0, |
||
2265 | + DPSW_FDB_LEARNING_MODE_HW = 1, |
||
2266 | + DPSW_FDB_LEARNING_MODE_NON_SECURE = 2, |
||
2267 | + DPSW_FDB_LEARNING_MODE_SECURE = 3 |
||
2268 | +}; |
||
2269 | + |
||
2270 | +int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io, |
||
2271 | + u32 cmd_flags, |
||
2272 | + u16 token, |
||
2273 | + u16 fdb_id, |
||
2274 | + enum dpsw_fdb_learning_mode mode); |
||
2275 | + |
||
2276 | +/** |
||
2277 | + * struct dpsw_fdb_attr - FDB Attributes |
||
2278 | + * @max_fdb_entries: Number of FDB entries |
||
2279 | + * @fdb_aging_time: Aging time in seconds |
||
2280 | + * @learning_mode: Learning mode |
||
2281 | + * @num_fdb_mc_groups: Current number of multicast groups |
||
2282 | + * @max_fdb_mc_groups: Maximum number of multicast groups |
||
2283 | + */ |
||
2284 | +struct dpsw_fdb_attr { |
||
2285 | + u16 max_fdb_entries; |
||
2286 | + u16 fdb_aging_time; |
||
2287 | + enum dpsw_fdb_learning_mode learning_mode; |
||
2288 | + u16 num_fdb_mc_groups; |
||
2289 | + u16 max_fdb_mc_groups; |
||
2290 | +}; |
||
2291 | + |
||
2292 | +int dpsw_get_api_version(struct fsl_mc_io *mc_io, |
||
2293 | + u32 cmd_flags, |
||
2294 | + u16 *major_ver, |
||
2295 | + u16 *minor_ver); |
||
2296 | + |
||
2297 | +#endif /* __FSL_DPSW_H */ |
||
2298 | --- /dev/null |
||
2299 | +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c |
||
2300 | @@ -0,0 +1,206 @@ |
||
2301 | +/* Copyright 2014-2016 Freescale Semiconductor Inc. |
||
2302 | + * Copyright 2017 NXP |
||
2303 | + * |
||
2304 | + * Redistribution and use in source and binary forms, with or without |
||
2305 | + * modification, are permitted provided that the following conditions are met: |
||
2306 | + * * Redistributions of source code must retain the above copyright |
||
2307 | + * notice, this list of conditions and the following disclaimer. |
||
2308 | + * * Redistributions in binary form must reproduce the above copyright |
||
2309 | + * notice, this list of conditions and the following disclaimer in the |
||
2310 | + * documentation and/or other materials provided with the distribution. |
||
2311 | + * * Neither the name of the above-listed copyright holders nor the |
||
2312 | + * names of any contributors may be used to endorse or promote products |
||
2313 | + * derived from this software without specific prior written permission. |
||
2314 | + * |
||
2315 | + * |
||
2316 | + * ALTERNATIVELY, this software may be distributed under the terms of the |
||
2317 | + * GNU General Public License ("GPL") as published by the Free Software |
||
2318 | + * Foundation, either version 2 of that License or (at your option) any |
||
2319 | + * later version. |
||
2320 | + * |
||
2321 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
2322 | + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
2323 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
2324 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE |
||
2325 | + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
2326 | + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
2327 | + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
2328 | + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
2329 | + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
2330 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
2331 | + * POSSIBILITY OF SUCH DAMAGE. |
||
2332 | + */ |
||
2333 | + |
||
2334 | +#include "ethsw.h" |
||
2335 | + |
||
2336 | +static struct { |
||
2337 | + enum dpsw_counter id; |
||
2338 | + char name[ETH_GSTRING_LEN]; |
||
2339 | +} ethsw_ethtool_counters[] = { |
||
2340 | + {DPSW_CNT_ING_FRAME, "rx frames"}, |
||
2341 | + {DPSW_CNT_ING_BYTE, "rx bytes"}, |
||
2342 | + {DPSW_CNT_ING_FLTR_FRAME, "rx filtered frames"}, |
||
2343 | + {DPSW_CNT_ING_FRAME_DISCARD, "rx discarded frames"}, |
||
2344 | + {DPSW_CNT_ING_BCAST_FRAME, "rx b-cast frames"}, |
||
2345 | + {DPSW_CNT_ING_BCAST_BYTES, "rx b-cast bytes"}, |
||
2346 | + {DPSW_CNT_ING_MCAST_FRAME, "rx m-cast frames"}, |
||
2347 | + {DPSW_CNT_ING_MCAST_BYTE, "rx m-cast bytes"}, |
||
2348 | + {DPSW_CNT_EGR_FRAME, "tx frames"}, |
||
2349 | + {DPSW_CNT_EGR_BYTE, "tx bytes"}, |
||
2350 | + {DPSW_CNT_EGR_FRAME_DISCARD, "tx discarded frames"}, |
||
2351 | + |
||
2352 | +}; |
||
2353 | + |
||
2354 | +#define ETHSW_NUM_COUNTERS ARRAY_SIZE(ethsw_ethtool_counters) |
||
2355 | + |
||
2356 | +static void ethsw_get_drvinfo(struct net_device *netdev, |
||
2357 | + struct ethtool_drvinfo *drvinfo) |
||
2358 | +{ |
||
2359 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2360 | + u16 version_major, version_minor; |
||
2361 | + int err; |
||
2362 | + |
||
2363 | + strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); |
||
2364 | + |
||
2365 | + err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0, |
||
2366 | + &version_major, |
||
2367 | + &version_minor); |
||
2368 | + if (err) |
||
2369 | + strlcpy(drvinfo->fw_version, "N/A", |
||
2370 | + sizeof(drvinfo->fw_version)); |
||
2371 | + else |
||
2372 | + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), |
||
2373 | + "%u.%u", version_major, version_minor); |
||
2374 | + |
||
2375 | + strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent), |
||
2376 | + sizeof(drvinfo->bus_info)); |
||
2377 | +} |
||
2378 | + |
||
2379 | +static int |
||
2380 | +ethsw_get_link_ksettings(struct net_device *netdev, |
||
2381 | + struct ethtool_link_ksettings *link_ksettings) |
||
2382 | +{ |
||
2383 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2384 | + struct dpsw_link_state state = {0}; |
||
2385 | + int err = 0; |
||
2386 | + |
||
2387 | + err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, |
||
2388 | + port_priv->ethsw_data->dpsw_handle, |
||
2389 | + port_priv->idx, |
||
2390 | + &state); |
||
2391 | + if (err) { |
||
2392 | + netdev_err(netdev, "ERROR %d getting link state", err); |
||
2393 | + goto out; |
||
2394 | + } |
||
2395 | + |
||
2396 | + /* At the moment, we have no way of interrogating the DPMAC |
||
2397 | + * from the DPSW side or there may not exist a DPMAC at all. |
||
2398 | + * Report only autoneg state, duplexity and speed. |
||
2399 | + */ |
||
2400 | + if (state.options & DPSW_LINK_OPT_AUTONEG) |
||
2401 | + link_ksettings->base.autoneg = AUTONEG_ENABLE; |
||
2402 | + if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX)) |
||
2403 | + link_ksettings->base.duplex = DUPLEX_FULL; |
||
2404 | + link_ksettings->base.speed = state.rate; |
||
2405 | + |
||
2406 | +out: |
||
2407 | + return err; |
||
2408 | +} |
||
2409 | + |
||
2410 | +static int |
||
2411 | +ethsw_set_link_ksettings(struct net_device *netdev, |
||
2412 | + const struct ethtool_link_ksettings *link_ksettings) |
||
2413 | +{ |
||
2414 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2415 | + struct dpsw_link_cfg cfg = {0}; |
||
2416 | + int err = 0; |
||
2417 | + |
||
2418 | + netdev_dbg(netdev, "Setting link parameters..."); |
||
2419 | + |
||
2420 | + /* Due to a temporary MC limitation, the DPSW port must be down |
||
2421 | + * in order to be able to change link settings. Taking steps to let |
||
2422 | + * the user know that. |
||
2423 | + */ |
||
2424 | + if (netif_running(netdev)) { |
||
2425 | + netdev_info(netdev, "Sorry, interface must be brought down first.\n"); |
||
2426 | + return -EACCES; |
||
2427 | + } |
||
2428 | + |
||
2429 | + cfg.rate = link_ksettings->base.speed; |
||
2430 | + if (link_ksettings->base.autoneg == AUTONEG_ENABLE) |
||
2431 | + cfg.options |= DPSW_LINK_OPT_AUTONEG; |
||
2432 | + else |
||
2433 | + cfg.options &= ~DPSW_LINK_OPT_AUTONEG; |
||
2434 | + if (link_ksettings->base.duplex == DUPLEX_HALF) |
||
2435 | + cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX; |
||
2436 | + else |
||
2437 | + cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX; |
||
2438 | + |
||
2439 | + err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0, |
||
2440 | + port_priv->ethsw_data->dpsw_handle, |
||
2441 | + port_priv->idx, |
||
2442 | + &cfg); |
||
2443 | + if (err) |
||
2444 | + /* ethtool will be loud enough if we return an error; no point |
||
2445 | + * in putting our own error message on the console by default |
||
2446 | + */ |
||
2447 | + netdev_dbg(netdev, "ERROR %d setting link cfg", err); |
||
2448 | + |
||
2449 | + return err; |
||
2450 | +} |
||
2451 | + |
||
2452 | +static int ethsw_ethtool_get_sset_count(struct net_device *dev, int sset) |
||
2453 | +{ |
||
2454 | + switch (sset) { |
||
2455 | + case ETH_SS_STATS: |
||
2456 | + return ETHSW_NUM_COUNTERS; |
||
2457 | + default: |
||
2458 | + return -EOPNOTSUPP; |
||
2459 | + } |
||
2460 | +} |
||
2461 | + |
||
2462 | +static void ethsw_ethtool_get_strings(struct net_device *netdev, |
||
2463 | + u32 stringset, u8 *data) |
||
2464 | +{ |
||
2465 | + int i; |
||
2466 | + |
||
2467 | + switch (stringset) { |
||
2468 | + case ETH_SS_STATS: |
||
2469 | + for (i = 0; i < ETHSW_NUM_COUNTERS; i++) |
||
2470 | + memcpy(data + i * ETH_GSTRING_LEN, |
||
2471 | + ethsw_ethtool_counters[i].name, ETH_GSTRING_LEN); |
||
2472 | + break; |
||
2473 | + } |
||
2474 | +} |
||
2475 | + |
||
2476 | +static void ethsw_ethtool_get_stats(struct net_device *netdev, |
||
2477 | + struct ethtool_stats *stats, |
||
2478 | + u64 *data) |
||
2479 | +{ |
||
2480 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2481 | + int i, err; |
||
2482 | + |
||
2483 | + memset(data, 0, |
||
2484 | + sizeof(u64) * ETHSW_NUM_COUNTERS); |
||
2485 | + |
||
2486 | + for (i = 0; i < ETHSW_NUM_COUNTERS; i++) { |
||
2487 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2488 | + port_priv->ethsw_data->dpsw_handle, |
||
2489 | + port_priv->idx, |
||
2490 | + ethsw_ethtool_counters[i].id, |
||
2491 | + &data[i]); |
||
2492 | + if (err) |
||
2493 | + netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n", |
||
2494 | + ethsw_ethtool_counters[i].name, err); |
||
2495 | + } |
||
2496 | +} |
||
2497 | + |
||
2498 | +const struct ethtool_ops ethsw_port_ethtool_ops = { |
||
2499 | + .get_drvinfo = ethsw_get_drvinfo, |
||
2500 | + .get_link = ethtool_op_get_link, |
||
2501 | + .get_link_ksettings = ethsw_get_link_ksettings, |
||
2502 | + .set_link_ksettings = ethsw_set_link_ksettings, |
||
2503 | + .get_strings = ethsw_ethtool_get_strings, |
||
2504 | + .get_ethtool_stats = ethsw_ethtool_get_stats, |
||
2505 | + .get_sset_count = ethsw_ethtool_get_sset_count, |
||
2506 | +}; |
||
2507 | --- /dev/null |
||
2508 | +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c |
||
2509 | @@ -0,0 +1,1438 @@ |
||
2510 | +/* Copyright 2014-2016 Freescale Semiconductor Inc. |
||
2511 | + * Copyright 2017 NXP |
||
2512 | + * |
||
2513 | + * Redistribution and use in source and binary forms, with or without |
||
2514 | + * modification, are permitted provided that the following conditions are met: |
||
2515 | + * * Redistributions of source code must retain the above copyright |
||
2516 | + * notice, this list of conditions and the following disclaimer. |
||
2517 | + * * Redistributions in binary form must reproduce the above copyright |
||
2518 | + * notice, this list of conditions and the following disclaimer in the |
||
2519 | + * documentation and/or other materials provided with the distribution. |
||
2520 | + * * Neither the name of the above-listed copyright holders nor the |
||
2521 | + * names of any contributors may be used to endorse or promote products |
||
2522 | + * derived from this software without specific prior written permission. |
||
2523 | + * |
||
2524 | + * |
||
2525 | + * ALTERNATIVELY, this software may be distributed under the terms of the |
||
2526 | + * GNU General Public License ("GPL") as published by the Free Software |
||
2527 | + * Foundation, either version 2 of that License or (at your option) any |
||
2528 | + * later version. |
||
2529 | + * |
||
2530 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
2531 | + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
2532 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
2533 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE |
||
2534 | + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
2535 | + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
2536 | + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
2537 | + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
2538 | + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
2539 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
2540 | + * POSSIBILITY OF SUCH DAMAGE. |
||
2541 | + */ |
||
2542 | + |
||
2543 | +#include <linux/module.h> |
||
2544 | + |
||
2545 | +#include <linux/interrupt.h> |
||
2546 | +#include <linux/msi.h> |
||
2547 | +#include <linux/kthread.h> |
||
2548 | +#include <linux/workqueue.h> |
||
2549 | + |
||
2550 | +#include <linux/fsl/mc.h> |
||
2551 | + |
||
2552 | +#include "ethsw.h" |
||
2553 | + |
||
2554 | +static struct workqueue_struct *ethsw_owq; |
||
2555 | + |
||
2556 | +/* Minimal supported DPSW version */ |
||
2557 | +#define DPSW_MIN_VER_MAJOR 8 |
||
2558 | +#define DPSW_MIN_VER_MINOR 0 |
||
2559 | + |
||
2560 | +#define DEFAULT_VLAN_ID 1 |
||
2561 | + |
||
2562 | +static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid) |
||
2563 | +{ |
||
2564 | + int err; |
||
2565 | + |
||
2566 | + struct dpsw_vlan_cfg vcfg = { |
||
2567 | + .fdb_id = 0, |
||
2568 | + }; |
||
2569 | + |
||
2570 | + if (ethsw->vlans[vid]) { |
||
2571 | + dev_err(ethsw->dev, "VLAN already configured\n"); |
||
2572 | + return -EEXIST; |
||
2573 | + } |
||
2574 | + |
||
2575 | + err = dpsw_vlan_add(ethsw->mc_io, 0, |
||
2576 | + ethsw->dpsw_handle, vid, &vcfg); |
||
2577 | + if (err) { |
||
2578 | + dev_err(ethsw->dev, "dpsw_vlan_add err %d\n", err); |
||
2579 | + return err; |
||
2580 | + } |
||
2581 | + ethsw->vlans[vid] = ETHSW_VLAN_MEMBER; |
||
2582 | + |
||
2583 | + return 0; |
||
2584 | +} |
||
2585 | + |
||
2586 | +static int ethsw_port_set_pvid(struct ethsw_port_priv *port_priv, u16 pvid) |
||
2587 | +{ |
||
2588 | + struct ethsw_core *ethsw = port_priv->ethsw_data; |
||
2589 | + struct net_device *netdev = port_priv->netdev; |
||
2590 | + struct dpsw_tci_cfg tci_cfg = { 0 }; |
||
2591 | + bool is_oper; |
||
2592 | + int err, ret; |
||
2593 | + |
||
2594 | + err = dpsw_if_get_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
2595 | + port_priv->idx, &tci_cfg); |
||
2596 | + if (err) { |
||
2597 | + netdev_err(netdev, "dpsw_if_get_tci err %d\n", err); |
||
2598 | + return err; |
||
2599 | + } |
||
2600 | + |
||
2601 | + tci_cfg.vlan_id = pvid; |
||
2602 | + |
||
2603 | + /* Interface needs to be down to change PVID */ |
||
2604 | + is_oper = netif_oper_up(netdev); |
||
2605 | + if (is_oper) { |
||
2606 | + err = dpsw_if_disable(ethsw->mc_io, 0, |
||
2607 | + ethsw->dpsw_handle, |
||
2608 | + port_priv->idx); |
||
2609 | + if (err) { |
||
2610 | + netdev_err(netdev, "dpsw_if_disable err %d\n", err); |
||
2611 | + return err; |
||
2612 | + } |
||
2613 | + } |
||
2614 | + |
||
2615 | + err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
2616 | + port_priv->idx, &tci_cfg); |
||
2617 | + if (err) { |
||
2618 | + netdev_err(netdev, "dpsw_if_set_tci err %d\n", err); |
||
2619 | + goto set_tci_error; |
||
2620 | + } |
||
2621 | + |
||
2622 | + /* Delete previous PVID info and mark the new one */ |
||
2623 | + port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID; |
||
2624 | + port_priv->vlans[pvid] |= ETHSW_VLAN_PVID; |
||
2625 | + port_priv->pvid = pvid; |
||
2626 | + |
||
2627 | +set_tci_error: |
||
2628 | + if (is_oper) { |
||
2629 | + ret = dpsw_if_enable(ethsw->mc_io, 0, |
||
2630 | + ethsw->dpsw_handle, |
||
2631 | + port_priv->idx); |
||
2632 | + if (ret) { |
||
2633 | + netdev_err(netdev, "dpsw_if_enable err %d\n", ret); |
||
2634 | + return ret; |
||
2635 | + } |
||
2636 | + } |
||
2637 | + |
||
2638 | + return err; |
||
2639 | +} |
||
2640 | + |
||
2641 | +static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv, |
||
2642 | + u16 vid, u16 flags) |
||
2643 | +{ |
||
2644 | + struct ethsw_core *ethsw = port_priv->ethsw_data; |
||
2645 | + struct net_device *netdev = port_priv->netdev; |
||
2646 | + struct dpsw_vlan_if_cfg vcfg; |
||
2647 | + int err; |
||
2648 | + |
||
2649 | + if (port_priv->vlans[vid]) { |
||
2650 | + netdev_warn(netdev, "VLAN %d already configured\n", vid); |
||
2651 | + return -EEXIST; |
||
2652 | + } |
||
2653 | + |
||
2654 | + vcfg.num_ifs = 1; |
||
2655 | + vcfg.if_id[0] = port_priv->idx; |
||
2656 | + err = dpsw_vlan_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle, vid, &vcfg); |
||
2657 | + if (err) { |
||
2658 | + netdev_err(netdev, "dpsw_vlan_add_if err %d\n", err); |
||
2659 | + return err; |
||
2660 | + } |
||
2661 | + |
||
2662 | + port_priv->vlans[vid] = ETHSW_VLAN_MEMBER; |
||
2663 | + |
||
2664 | + if (flags & BRIDGE_VLAN_INFO_UNTAGGED) { |
||
2665 | + err = dpsw_vlan_add_if_untagged(ethsw->mc_io, 0, |
||
2666 | + ethsw->dpsw_handle, |
||
2667 | + vid, &vcfg); |
||
2668 | + if (err) { |
||
2669 | + netdev_err(netdev, |
||
2670 | + "dpsw_vlan_add_if_untagged err %d\n", err); |
||
2671 | + return err; |
||
2672 | + } |
||
2673 | + port_priv->vlans[vid] |= ETHSW_VLAN_UNTAGGED; |
||
2674 | + } |
||
2675 | + |
||
2676 | + if (flags & BRIDGE_VLAN_INFO_PVID) { |
||
2677 | + err = ethsw_port_set_pvid(port_priv, vid); |
||
2678 | + if (err) |
||
2679 | + return err; |
||
2680 | + } |
||
2681 | + |
||
2682 | + return 0; |
||
2683 | +} |
||
2684 | + |
||
2685 | +static int ethsw_set_learning(struct ethsw_core *ethsw, u8 flag) |
||
2686 | +{ |
||
2687 | + enum dpsw_fdb_learning_mode learn_mode; |
||
2688 | + int err; |
||
2689 | + |
||
2690 | + if (flag) |
||
2691 | + learn_mode = DPSW_FDB_LEARNING_MODE_HW; |
||
2692 | + else |
||
2693 | + learn_mode = DPSW_FDB_LEARNING_MODE_DIS; |
||
2694 | + |
||
2695 | + err = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0, |
||
2696 | + learn_mode); |
||
2697 | + if (err) { |
||
2698 | + dev_err(ethsw->dev, "dpsw_fdb_set_learning_mode err %d\n", err); |
||
2699 | + return err; |
||
2700 | + } |
||
2701 | + ethsw->learning = !!flag; |
||
2702 | + |
||
2703 | + return 0; |
||
2704 | +} |
||
2705 | + |
||
2706 | +static int ethsw_port_set_flood(struct ethsw_port_priv *port_priv, u8 flag) |
||
2707 | +{ |
||
2708 | + int err; |
||
2709 | + |
||
2710 | + err = dpsw_if_set_flooding(port_priv->ethsw_data->mc_io, 0, |
||
2711 | + port_priv->ethsw_data->dpsw_handle, |
||
2712 | + port_priv->idx, flag); |
||
2713 | + if (err) { |
||
2714 | + netdev_err(port_priv->netdev, |
||
2715 | + "dpsw_fdb_set_learning_mode err %d\n", err); |
||
2716 | + return err; |
||
2717 | + } |
||
2718 | + port_priv->flood = !!flag; |
||
2719 | + |
||
2720 | + return 0; |
||
2721 | +} |
||
2722 | + |
||
2723 | +static int ethsw_port_set_stp_state(struct ethsw_port_priv *port_priv, u8 state) |
||
2724 | +{ |
||
2725 | + struct dpsw_stp_cfg stp_cfg = { |
||
2726 | + .vlan_id = DEFAULT_VLAN_ID, |
||
2727 | + .state = state, |
||
2728 | + }; |
||
2729 | + int err; |
||
2730 | + |
||
2731 | + if (!netif_oper_up(port_priv->netdev) || state == port_priv->stp_state) |
||
2732 | + return 0; /* Nothing to do */ |
||
2733 | + |
||
2734 | + err = dpsw_if_set_stp(port_priv->ethsw_data->mc_io, 0, |
||
2735 | + port_priv->ethsw_data->dpsw_handle, |
||
2736 | + port_priv->idx, &stp_cfg); |
||
2737 | + if (err) { |
||
2738 | + netdev_err(port_priv->netdev, |
||
2739 | + "dpsw_if_set_stp err %d\n", err); |
||
2740 | + return err; |
||
2741 | + } |
||
2742 | + |
||
2743 | + port_priv->stp_state = state; |
||
2744 | + |
||
2745 | + return 0; |
||
2746 | +} |
||
2747 | + |
||
2748 | +static int ethsw_dellink_switch(struct ethsw_core *ethsw, u16 vid) |
||
2749 | +{ |
||
2750 | + struct ethsw_port_priv *ppriv_local = NULL; |
||
2751 | + int i, err; |
||
2752 | + |
||
2753 | + if (!ethsw->vlans[vid]) |
||
2754 | + return -ENOENT; |
||
2755 | + |
||
2756 | + err = dpsw_vlan_remove(ethsw->mc_io, 0, ethsw->dpsw_handle, vid); |
||
2757 | + if (err) { |
||
2758 | + dev_err(ethsw->dev, "dpsw_vlan_remove err %d\n", err); |
||
2759 | + return err; |
||
2760 | + } |
||
2761 | + ethsw->vlans[vid] = 0; |
||
2762 | + |
||
2763 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { |
||
2764 | + ppriv_local = ethsw->ports[i]; |
||
2765 | + ppriv_local->vlans[vid] = 0; |
||
2766 | + } |
||
2767 | + |
||
2768 | + return 0; |
||
2769 | +} |
||
2770 | + |
||
2771 | +static int ethsw_port_fdb_add_uc(struct ethsw_port_priv *port_priv, |
||
2772 | + const unsigned char *addr) |
||
2773 | +{ |
||
2774 | + struct dpsw_fdb_unicast_cfg entry = {0}; |
||
2775 | + int err; |
||
2776 | + |
||
2777 | + entry.if_egress = port_priv->idx; |
||
2778 | + entry.type = DPSW_FDB_ENTRY_STATIC; |
||
2779 | + ether_addr_copy(entry.mac_addr, addr); |
||
2780 | + |
||
2781 | + err = dpsw_fdb_add_unicast(port_priv->ethsw_data->mc_io, 0, |
||
2782 | + port_priv->ethsw_data->dpsw_handle, |
||
2783 | + 0, &entry); |
||
2784 | + if (err) |
||
2785 | + netdev_err(port_priv->netdev, |
||
2786 | + "dpsw_fdb_add_unicast err %d\n", err); |
||
2787 | + return err; |
||
2788 | +} |
||
2789 | + |
||
2790 | +static int ethsw_port_fdb_del_uc(struct ethsw_port_priv *port_priv, |
||
2791 | + const unsigned char *addr) |
||
2792 | +{ |
||
2793 | + struct dpsw_fdb_unicast_cfg entry = {0}; |
||
2794 | + int err; |
||
2795 | + |
||
2796 | + entry.if_egress = port_priv->idx; |
||
2797 | + entry.type = DPSW_FDB_ENTRY_STATIC; |
||
2798 | + ether_addr_copy(entry.mac_addr, addr); |
||
2799 | + |
||
2800 | + err = dpsw_fdb_remove_unicast(port_priv->ethsw_data->mc_io, 0, |
||
2801 | + port_priv->ethsw_data->dpsw_handle, |
||
2802 | + 0, &entry); |
||
2803 | + /* Silently discard calling multiple times the del command */ |
||
2804 | + if (err && err != -ENXIO) |
||
2805 | + netdev_err(port_priv->netdev, |
||
2806 | + "dpsw_fdb_remove_unicast err %d\n", err); |
||
2807 | + return err; |
||
2808 | +} |
||
2809 | + |
||
2810 | +static int ethsw_port_fdb_add_mc(struct ethsw_port_priv *port_priv, |
||
2811 | + const unsigned char *addr) |
||
2812 | +{ |
||
2813 | + struct dpsw_fdb_multicast_cfg entry = {0}; |
||
2814 | + int err; |
||
2815 | + |
||
2816 | + ether_addr_copy(entry.mac_addr, addr); |
||
2817 | + entry.type = DPSW_FDB_ENTRY_STATIC; |
||
2818 | + entry.num_ifs = 1; |
||
2819 | + entry.if_id[0] = port_priv->idx; |
||
2820 | + |
||
2821 | + err = dpsw_fdb_add_multicast(port_priv->ethsw_data->mc_io, 0, |
||
2822 | + port_priv->ethsw_data->dpsw_handle, |
||
2823 | + 0, &entry); |
||
2824 | + /* Silently discard calling multiple times the add command */ |
||
2825 | + if (err && err != -ENXIO) |
||
2826 | + netdev_err(port_priv->netdev, "dpsw_fdb_add_multicast err %d\n", |
||
2827 | + err); |
||
2828 | + return err; |
||
2829 | +} |
||
2830 | + |
||
2831 | +static int ethsw_port_fdb_del_mc(struct ethsw_port_priv *port_priv, |
||
2832 | + const unsigned char *addr) |
||
2833 | +{ |
||
2834 | + struct dpsw_fdb_multicast_cfg entry = {0}; |
||
2835 | + int err; |
||
2836 | + |
||
2837 | + ether_addr_copy(entry.mac_addr, addr); |
||
2838 | + entry.type = DPSW_FDB_ENTRY_STATIC; |
||
2839 | + entry.num_ifs = 1; |
||
2840 | + entry.if_id[0] = port_priv->idx; |
||
2841 | + |
||
2842 | + err = dpsw_fdb_remove_multicast(port_priv->ethsw_data->mc_io, 0, |
||
2843 | + port_priv->ethsw_data->dpsw_handle, |
||
2844 | + 0, &entry); |
||
2845 | + /* Silently discard calling multiple times the del command */ |
||
2846 | + if (err && err != -ENAVAIL) |
||
2847 | + netdev_err(port_priv->netdev, |
||
2848 | + "dpsw_fdb_remove_multicast err %d\n", err); |
||
2849 | + return err; |
||
2850 | +} |
||
2851 | + |
||
2852 | +static void port_get_stats(struct net_device *netdev, |
||
2853 | + struct rtnl_link_stats64 *stats) |
||
2854 | +{ |
||
2855 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2856 | + u64 tmp; |
||
2857 | + int err; |
||
2858 | + |
||
2859 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2860 | + port_priv->ethsw_data->dpsw_handle, |
||
2861 | + port_priv->idx, |
||
2862 | + DPSW_CNT_ING_FRAME, &stats->rx_packets); |
||
2863 | + if (err) |
||
2864 | + goto error; |
||
2865 | + |
||
2866 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2867 | + port_priv->ethsw_data->dpsw_handle, |
||
2868 | + port_priv->idx, |
||
2869 | + DPSW_CNT_EGR_FRAME, &stats->tx_packets); |
||
2870 | + if (err) |
||
2871 | + goto error; |
||
2872 | + |
||
2873 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2874 | + port_priv->ethsw_data->dpsw_handle, |
||
2875 | + port_priv->idx, |
||
2876 | + DPSW_CNT_ING_BYTE, &stats->rx_bytes); |
||
2877 | + if (err) |
||
2878 | + goto error; |
||
2879 | + |
||
2880 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2881 | + port_priv->ethsw_data->dpsw_handle, |
||
2882 | + port_priv->idx, |
||
2883 | + DPSW_CNT_EGR_BYTE, &stats->tx_bytes); |
||
2884 | + if (err) |
||
2885 | + goto error; |
||
2886 | + |
||
2887 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2888 | + port_priv->ethsw_data->dpsw_handle, |
||
2889 | + port_priv->idx, |
||
2890 | + DPSW_CNT_ING_FRAME_DISCARD, |
||
2891 | + &stats->rx_dropped); |
||
2892 | + if (err) |
||
2893 | + goto error; |
||
2894 | + |
||
2895 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2896 | + port_priv->ethsw_data->dpsw_handle, |
||
2897 | + port_priv->idx, |
||
2898 | + DPSW_CNT_ING_FLTR_FRAME, |
||
2899 | + &tmp); |
||
2900 | + if (err) |
||
2901 | + goto error; |
||
2902 | + stats->rx_dropped += tmp; |
||
2903 | + |
||
2904 | + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, |
||
2905 | + port_priv->ethsw_data->dpsw_handle, |
||
2906 | + port_priv->idx, |
||
2907 | + DPSW_CNT_EGR_FRAME_DISCARD, |
||
2908 | + &stats->tx_dropped); |
||
2909 | + if (err) |
||
2910 | + goto error; |
||
2911 | + |
||
2912 | + return; |
||
2913 | + |
||
2914 | +error: |
||
2915 | + netdev_err(netdev, "dpsw_if_get_counter err %d\n", err); |
||
2916 | +} |
||
2917 | + |
||
2918 | +static bool port_has_offload_stats(const struct net_device *netdev, |
||
2919 | + int attr_id) |
||
2920 | +{ |
||
2921 | + return (attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT); |
||
2922 | +} |
||
2923 | + |
||
2924 | +static int port_get_offload_stats(int attr_id, |
||
2925 | + const struct net_device *netdev, |
||
2926 | + void *sp) |
||
2927 | +{ |
||
2928 | + switch (attr_id) { |
||
2929 | + case IFLA_OFFLOAD_XSTATS_CPU_HIT: |
||
2930 | + port_get_stats((struct net_device *)netdev, sp); |
||
2931 | + return 0; |
||
2932 | + } |
||
2933 | + |
||
2934 | + return -EINVAL; |
||
2935 | +} |
||
2936 | + |
||
2937 | +static int port_change_mtu(struct net_device *netdev, int mtu) |
||
2938 | +{ |
||
2939 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2940 | + int err; |
||
2941 | + |
||
2942 | + err = dpsw_if_set_max_frame_length(port_priv->ethsw_data->mc_io, |
||
2943 | + 0, |
||
2944 | + port_priv->ethsw_data->dpsw_handle, |
||
2945 | + port_priv->idx, |
||
2946 | + (u16)ETHSW_L2_MAX_FRM(mtu)); |
||
2947 | + if (err) { |
||
2948 | + netdev_err(netdev, |
||
2949 | + "dpsw_if_set_max_frame_length() err %d\n", err); |
||
2950 | + return err; |
||
2951 | + } |
||
2952 | + |
||
2953 | + netdev->mtu = mtu; |
||
2954 | + return 0; |
||
2955 | +} |
||
2956 | + |
||
2957 | +static int port_carrier_state_sync(struct net_device *netdev) |
||
2958 | +{ |
||
2959 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2960 | + struct dpsw_link_state state; |
||
2961 | + int err; |
||
2962 | + |
||
2963 | + err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, |
||
2964 | + port_priv->ethsw_data->dpsw_handle, |
||
2965 | + port_priv->idx, &state); |
||
2966 | + if (err) { |
||
2967 | + netdev_err(netdev, "dpsw_if_get_link_state() err %d\n", err); |
||
2968 | + return err; |
||
2969 | + } |
||
2970 | + |
||
2971 | + WARN_ONCE(state.up > 1, "Garbage read into link_state"); |
||
2972 | + |
||
2973 | + if (state.up != port_priv->link_state) { |
||
2974 | + if (state.up) |
||
2975 | + netif_carrier_on(netdev); |
||
2976 | + else |
||
2977 | + netif_carrier_off(netdev); |
||
2978 | + port_priv->link_state = state.up; |
||
2979 | + } |
||
2980 | + return 0; |
||
2981 | +} |
||
2982 | + |
||
2983 | +static int port_open(struct net_device *netdev) |
||
2984 | +{ |
||
2985 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
2986 | + int err; |
||
2987 | + |
||
2988 | + /* No need to allow Tx as control interface is disabled */ |
||
2989 | + netif_tx_stop_all_queues(netdev); |
||
2990 | + |
||
2991 | + err = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0, |
||
2992 | + port_priv->ethsw_data->dpsw_handle, |
||
2993 | + port_priv->idx); |
||
2994 | + if (err) { |
||
2995 | + netdev_err(netdev, "dpsw_if_enable err %d\n", err); |
||
2996 | + return err; |
||
2997 | + } |
||
2998 | + |
||
2999 | + /* sync carrier state */ |
||
3000 | + err = port_carrier_state_sync(netdev); |
||
3001 | + if (err) { |
||
3002 | + netdev_err(netdev, |
||
3003 | + "port_carrier_state_sync err %d\n", err); |
||
3004 | + goto err_carrier_sync; |
||
3005 | + } |
||
3006 | + |
||
3007 | + return 0; |
||
3008 | + |
||
3009 | +err_carrier_sync: |
||
3010 | + dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, |
||
3011 | + port_priv->ethsw_data->dpsw_handle, |
||
3012 | + port_priv->idx); |
||
3013 | + return err; |
||
3014 | +} |
||
3015 | + |
||
3016 | +static int port_stop(struct net_device *netdev) |
||
3017 | +{ |
||
3018 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3019 | + int err; |
||
3020 | + |
||
3021 | + err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, |
||
3022 | + port_priv->ethsw_data->dpsw_handle, |
||
3023 | + port_priv->idx); |
||
3024 | + if (err) { |
||
3025 | + netdev_err(netdev, "dpsw_if_disable err %d\n", err); |
||
3026 | + return err; |
||
3027 | + } |
||
3028 | + |
||
3029 | + return 0; |
||
3030 | +} |
||
3031 | + |
||
3032 | +static netdev_tx_t port_dropframe(struct sk_buff *skb, |
||
3033 | + struct net_device *netdev) |
||
3034 | +{ |
||
3035 | + /* we don't support I/O for now, drop the frame */ |
||
3036 | + dev_kfree_skb_any(skb); |
||
3037 | + |
||
3038 | + return NETDEV_TX_OK; |
||
3039 | +} |
||
3040 | + |
||
3041 | +static const struct net_device_ops ethsw_port_ops = { |
||
3042 | + .ndo_open = port_open, |
||
3043 | + .ndo_stop = port_stop, |
||
3044 | + |
||
3045 | + .ndo_set_mac_address = eth_mac_addr, |
||
3046 | + .ndo_change_mtu = port_change_mtu, |
||
3047 | + .ndo_has_offload_stats = port_has_offload_stats, |
||
3048 | + .ndo_get_offload_stats = port_get_offload_stats, |
||
3049 | + |
||
3050 | + .ndo_start_xmit = port_dropframe, |
||
3051 | +}; |
||
3052 | + |
||
3053 | +static void ethsw_links_state_update(struct ethsw_core *ethsw) |
||
3054 | +{ |
||
3055 | + int i; |
||
3056 | + |
||
3057 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) |
||
3058 | + port_carrier_state_sync(ethsw->ports[i]->netdev); |
||
3059 | +} |
||
3060 | + |
||
3061 | +static irqreturn_t ethsw_irq0_handler(int irq_num, void *arg) |
||
3062 | +{ |
||
3063 | + return IRQ_WAKE_THREAD; |
||
3064 | +} |
||
3065 | + |
||
3066 | +static irqreturn_t ethsw_irq0_handler_thread(int irq_num, void *arg) |
||
3067 | +{ |
||
3068 | + struct device *dev = (struct device *)arg; |
||
3069 | + struct ethsw_core *ethsw = dev_get_drvdata(dev); |
||
3070 | + |
||
3071 | + /* Mask the events and the if_id reserved bits to be cleared on read */ |
||
3072 | + u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000; |
||
3073 | + int err; |
||
3074 | + |
||
3075 | + err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3076 | + DPSW_IRQ_INDEX_IF, &status); |
||
3077 | + if (err) { |
||
3078 | + dev_err(dev, "Can't get irq status (err %d)", err); |
||
3079 | + |
||
3080 | + err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3081 | + DPSW_IRQ_INDEX_IF, 0xFFFFFFFF); |
||
3082 | + if (err) |
||
3083 | + dev_err(dev, "Can't clear irq status (err %d)", err); |
||
3084 | + goto out; |
||
3085 | + } |
||
3086 | + |
||
3087 | + if (status & DPSW_IRQ_EVENT_LINK_CHANGED) |
||
3088 | + ethsw_links_state_update(ethsw); |
||
3089 | + |
||
3090 | +out: |
||
3091 | + return IRQ_HANDLED; |
||
3092 | +} |
||
3093 | + |
||
3094 | +static int ethsw_setup_irqs(struct fsl_mc_device *sw_dev) |
||
3095 | +{ |
||
3096 | + struct device *dev = &sw_dev->dev; |
||
3097 | + struct ethsw_core *ethsw = dev_get_drvdata(dev); |
||
3098 | + u32 mask = DPSW_IRQ_EVENT_LINK_CHANGED; |
||
3099 | + struct fsl_mc_device_irq *irq; |
||
3100 | + int err; |
||
3101 | + |
||
3102 | + err = fsl_mc_allocate_irqs(sw_dev); |
||
3103 | + if (err) { |
||
3104 | + dev_err(dev, "MC irqs allocation failed\n"); |
||
3105 | + return err; |
||
3106 | + } |
||
3107 | + |
||
3108 | + if (WARN_ON(sw_dev->obj_desc.irq_count != DPSW_IRQ_NUM)) { |
||
3109 | + err = -EINVAL; |
||
3110 | + goto free_irq; |
||
3111 | + } |
||
3112 | + |
||
3113 | + err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3114 | + DPSW_IRQ_INDEX_IF, 0); |
||
3115 | + if (err) { |
||
3116 | + dev_err(dev, "dpsw_set_irq_enable err %d\n", err); |
||
3117 | + goto free_irq; |
||
3118 | + } |
||
3119 | + |
||
3120 | + irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF]; |
||
3121 | + |
||
3122 | + err = devm_request_threaded_irq(dev, irq->msi_desc->irq, |
||
3123 | + ethsw_irq0_handler, |
||
3124 | + ethsw_irq0_handler_thread, |
||
3125 | + IRQF_NO_SUSPEND | IRQF_ONESHOT, |
||
3126 | + dev_name(dev), dev); |
||
3127 | + if (err) { |
||
3128 | + dev_err(dev, "devm_request_threaded_irq(): %d", err); |
||
3129 | + goto free_irq; |
||
3130 | + } |
||
3131 | + |
||
3132 | + err = dpsw_set_irq_mask(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3133 | + DPSW_IRQ_INDEX_IF, mask); |
||
3134 | + if (err) { |
||
3135 | + dev_err(dev, "dpsw_set_irq_mask(): %d", err); |
||
3136 | + goto free_devm_irq; |
||
3137 | + } |
||
3138 | + |
||
3139 | + err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3140 | + DPSW_IRQ_INDEX_IF, 1); |
||
3141 | + if (err) { |
||
3142 | + dev_err(dev, "dpsw_set_irq_enable(): %d", err); |
||
3143 | + goto free_devm_irq; |
||
3144 | + } |
||
3145 | + |
||
3146 | + return 0; |
||
3147 | + |
||
3148 | +free_devm_irq: |
||
3149 | + devm_free_irq(dev, irq->msi_desc->irq, dev); |
||
3150 | +free_irq: |
||
3151 | + fsl_mc_free_irqs(sw_dev); |
||
3152 | + return err; |
||
3153 | +} |
||
3154 | + |
||
3155 | +static void ethsw_teardown_irqs(struct fsl_mc_device *sw_dev) |
||
3156 | +{ |
||
3157 | + struct device *dev = &sw_dev->dev; |
||
3158 | + struct ethsw_core *ethsw = dev_get_drvdata(dev); |
||
3159 | + struct fsl_mc_device_irq *irq; |
||
3160 | + int err; |
||
3161 | + |
||
3162 | + irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF]; |
||
3163 | + err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3164 | + DPSW_IRQ_INDEX_IF, 0); |
||
3165 | + if (err) |
||
3166 | + dev_err(dev, "dpsw_set_irq_enable err %d\n", err); |
||
3167 | + |
||
3168 | + fsl_mc_free_irqs(sw_dev); |
||
3169 | +} |
||
3170 | + |
||
3171 | +static int swdev_port_attr_get(struct net_device *netdev, |
||
3172 | + struct switchdev_attr *attr) |
||
3173 | +{ |
||
3174 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3175 | + |
||
3176 | + switch (attr->id) { |
||
3177 | + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: |
||
3178 | + attr->u.ppid.id_len = 1; |
||
3179 | + attr->u.ppid.id[0] = port_priv->ethsw_data->dev_id; |
||
3180 | + break; |
||
3181 | + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: |
||
3182 | + attr->u.brport_flags = |
||
3183 | + (port_priv->ethsw_data->learning ? BR_LEARNING : 0) | |
||
3184 | + (port_priv->flood ? BR_FLOOD : 0); |
||
3185 | + break; |
||
3186 | + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: |
||
3187 | + attr->u.brport_flags_support = BR_LEARNING | BR_FLOOD; |
||
3188 | + break; |
||
3189 | + default: |
||
3190 | + return -EOPNOTSUPP; |
||
3191 | + } |
||
3192 | + |
||
3193 | + return 0; |
||
3194 | +} |
||
3195 | + |
||
3196 | +static int port_attr_stp_state_set(struct net_device *netdev, |
||
3197 | + struct switchdev_trans *trans, |
||
3198 | + u8 state) |
||
3199 | +{ |
||
3200 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3201 | + |
||
3202 | + if (switchdev_trans_ph_prepare(trans)) |
||
3203 | + return 0; |
||
3204 | + |
||
3205 | + return ethsw_port_set_stp_state(port_priv, state); |
||
3206 | +} |
||
3207 | + |
||
3208 | +static int port_attr_br_flags_set(struct net_device *netdev, |
||
3209 | + struct switchdev_trans *trans, |
||
3210 | + unsigned long flags) |
||
3211 | +{ |
||
3212 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3213 | + int err = 0; |
||
3214 | + |
||
3215 | + if (switchdev_trans_ph_prepare(trans)) |
||
3216 | + return 0; |
||
3217 | + |
||
3218 | + /* Learning is enabled per switch */ |
||
3219 | + err = ethsw_set_learning(port_priv->ethsw_data, !!(flags & BR_LEARNING)); |
||
3220 | + if (err) |
||
3221 | + goto exit; |
||
3222 | + |
||
3223 | + err = ethsw_port_set_flood(port_priv, !!(flags & BR_FLOOD)); |
||
3224 | + |
||
3225 | +exit: |
||
3226 | + return err; |
||
3227 | +} |
||
3228 | + |
||
3229 | +static int swdev_port_attr_set(struct net_device *netdev, |
||
3230 | + const struct switchdev_attr *attr, |
||
3231 | + struct switchdev_trans *trans) |
||
3232 | +{ |
||
3233 | + int err = 0; |
||
3234 | + |
||
3235 | + switch (attr->id) { |
||
3236 | + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: |
||
3237 | + err = port_attr_stp_state_set(netdev, trans, |
||
3238 | + attr->u.stp_state); |
||
3239 | + break; |
||
3240 | + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: |
||
3241 | + err = port_attr_br_flags_set(netdev, trans, |
||
3242 | + attr->u.brport_flags); |
||
3243 | + break; |
||
3244 | + case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: |
||
3245 | + /* VLANs are supported by default */ |
||
3246 | + break; |
||
3247 | + default: |
||
3248 | + err = -EOPNOTSUPP; |
||
3249 | + break; |
||
3250 | + } |
||
3251 | + |
||
3252 | + return err; |
||
3253 | +} |
||
3254 | + |
||
3255 | +static int port_vlans_add(struct net_device *netdev, |
||
3256 | + const struct switchdev_obj_port_vlan *vlan, |
||
3257 | + struct switchdev_trans *trans) |
||
3258 | +{ |
||
3259 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3260 | + int vid, err; |
||
3261 | + |
||
3262 | + if (switchdev_trans_ph_prepare(trans)) |
||
3263 | + return 0; |
||
3264 | + |
||
3265 | + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { |
||
3266 | + if (!port_priv->ethsw_data->vlans[vid]) { |
||
3267 | + /* this is a new VLAN */ |
||
3268 | + err = ethsw_add_vlan(port_priv->ethsw_data, vid); |
||
3269 | + if (err) |
||
3270 | + return err; |
||
3271 | + |
||
3272 | + port_priv->ethsw_data->vlans[vid] |= ETHSW_VLAN_GLOBAL; |
||
3273 | + } |
||
3274 | + err = ethsw_port_add_vlan(port_priv, vid, vlan->flags); |
||
3275 | + if (err) |
||
3276 | + break; |
||
3277 | + } |
||
3278 | + |
||
3279 | + return err; |
||
3280 | +} |
||
3281 | + |
||
3282 | +static int swdev_port_obj_add(struct net_device *netdev, |
||
3283 | + const struct switchdev_obj *obj, |
||
3284 | + struct switchdev_trans *trans) |
||
3285 | +{ |
||
3286 | + int err; |
||
3287 | + |
||
3288 | + switch (obj->id) { |
||
3289 | + case SWITCHDEV_OBJ_ID_PORT_VLAN: |
||
3290 | + err = port_vlans_add(netdev, |
||
3291 | + SWITCHDEV_OBJ_PORT_VLAN(obj), |
||
3292 | + trans); |
||
3293 | + break; |
||
3294 | + default: |
||
3295 | + err = -EOPNOTSUPP; |
||
3296 | + break; |
||
3297 | + } |
||
3298 | + |
||
3299 | + return err; |
||
3300 | +} |
||
3301 | + |
||
3302 | +static int ethsw_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid) |
||
3303 | +{ |
||
3304 | + struct ethsw_core *ethsw = port_priv->ethsw_data; |
||
3305 | + struct net_device *netdev = port_priv->netdev; |
||
3306 | + struct dpsw_vlan_if_cfg vcfg; |
||
3307 | + int i, err; |
||
3308 | + |
||
3309 | + if (!port_priv->vlans[vid]) |
||
3310 | + return -ENOENT; |
||
3311 | + |
||
3312 | + if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) { |
||
3313 | + err = ethsw_port_set_pvid(port_priv, 0); |
||
3314 | + if (err) |
||
3315 | + return err; |
||
3316 | + } |
||
3317 | + |
||
3318 | + vcfg.num_ifs = 1; |
||
3319 | + vcfg.if_id[0] = port_priv->idx; |
||
3320 | + if (port_priv->vlans[vid] & ETHSW_VLAN_UNTAGGED) { |
||
3321 | + err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, |
||
3322 | + ethsw->dpsw_handle, |
||
3323 | + vid, &vcfg); |
||
3324 | + if (err) { |
||
3325 | + netdev_err(netdev, |
||
3326 | + "dpsw_vlan_remove_if_untagged err %d\n", |
||
3327 | + err); |
||
3328 | + } |
||
3329 | + port_priv->vlans[vid] &= ~ETHSW_VLAN_UNTAGGED; |
||
3330 | + } |
||
3331 | + |
||
3332 | + if (port_priv->vlans[vid] & ETHSW_VLAN_MEMBER) { |
||
3333 | + err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3334 | + vid, &vcfg); |
||
3335 | + if (err) { |
||
3336 | + netdev_err(netdev, |
||
3337 | + "dpsw_vlan_remove_if err %d\n", err); |
||
3338 | + return err; |
||
3339 | + } |
||
3340 | + port_priv->vlans[vid] &= ~ETHSW_VLAN_MEMBER; |
||
3341 | + |
||
3342 | + /* Delete VLAN from switch if it is no longer configured on |
||
3343 | + * any port |
||
3344 | + */ |
||
3345 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) |
||
3346 | + if (ethsw->ports[i]->vlans[vid] & ETHSW_VLAN_MEMBER) |
||
3347 | + return 0; /* Found a port member in VID */ |
||
3348 | + |
||
3349 | + ethsw->vlans[vid] &= ~ETHSW_VLAN_GLOBAL; |
||
3350 | + |
||
3351 | + err = ethsw_dellink_switch(ethsw, vid); |
||
3352 | + if (err) |
||
3353 | + return err; |
||
3354 | + } |
||
3355 | + |
||
3356 | + return 0; |
||
3357 | +} |
||
3358 | + |
||
3359 | +static int port_vlans_del(struct net_device *netdev, |
||
3360 | + const struct switchdev_obj_port_vlan *vlan) |
||
3361 | +{ |
||
3362 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3363 | + int vid, err; |
||
3364 | + |
||
3365 | + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { |
||
3366 | + err = ethsw_port_del_vlan(port_priv, vid); |
||
3367 | + if (err) |
||
3368 | + break; |
||
3369 | + } |
||
3370 | + |
||
3371 | + return err; |
||
3372 | +} |
||
3373 | + |
||
3374 | +static int swdev_port_obj_del(struct net_device *netdev, |
||
3375 | + const struct switchdev_obj *obj) |
||
3376 | +{ |
||
3377 | + int err; |
||
3378 | + |
||
3379 | + switch (obj->id) { |
||
3380 | + case SWITCHDEV_OBJ_ID_PORT_VLAN: |
||
3381 | + err = port_vlans_del(netdev, SWITCHDEV_OBJ_PORT_VLAN(obj)); |
||
3382 | + break; |
||
3383 | + default: |
||
3384 | + err = -EOPNOTSUPP; |
||
3385 | + break; |
||
3386 | + } |
||
3387 | + return err; |
||
3388 | +} |
||
3389 | + |
||
3390 | +static const struct switchdev_ops ethsw_port_switchdev_ops = { |
||
3391 | + .switchdev_port_attr_get = swdev_port_attr_get, |
||
3392 | + .switchdev_port_attr_set = swdev_port_attr_set, |
||
3393 | + .switchdev_port_obj_add = swdev_port_obj_add, |
||
3394 | + .switchdev_port_obj_del = swdev_port_obj_del, |
||
3395 | +}; |
||
3396 | + |
||
3397 | +/* For the moment, only flood setting needs to be updated */ |
||
3398 | +static int port_bridge_join(struct net_device *netdev) |
||
3399 | +{ |
||
3400 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3401 | + |
||
3402 | + /* Enable flooding */ |
||
3403 | + return ethsw_port_set_flood(port_priv, 1); |
||
3404 | +} |
||
3405 | + |
||
3406 | +static int port_bridge_leave(struct net_device *netdev) |
||
3407 | +{ |
||
3408 | + struct ethsw_port_priv *port_priv = netdev_priv(netdev); |
||
3409 | + |
||
3410 | + /* Disable flooding */ |
||
3411 | + return ethsw_port_set_flood(port_priv, 0); |
||
3412 | +} |
||
3413 | + |
||
3414 | +static int port_netdevice_event(struct notifier_block *unused, |
||
3415 | + unsigned long event, void *ptr) |
||
3416 | +{ |
||
3417 | + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); |
||
3418 | + struct netdev_notifier_changeupper_info *info = ptr; |
||
3419 | + struct net_device *upper_dev; |
||
3420 | + int err = 0; |
||
3421 | + |
||
3422 | + if (netdev->netdev_ops != ðsw_port_ops) |
||
3423 | + return NOTIFY_DONE; |
||
3424 | + |
||
3425 | + /* Handle just upper dev link/unlink for the moment */ |
||
3426 | + if (event == NETDEV_CHANGEUPPER) { |
||
3427 | + upper_dev = info->upper_dev; |
||
3428 | + if (netif_is_bridge_master(upper_dev)) { |
||
3429 | + if (info->linking) |
||
3430 | + err = port_bridge_join(netdev); |
||
3431 | + else |
||
3432 | + err = port_bridge_leave(netdev); |
||
3433 | + } |
||
3434 | + } |
||
3435 | + |
||
3436 | + return notifier_from_errno(err); |
||
3437 | +} |
||
3438 | + |
||
3439 | +static struct notifier_block port_nb __read_mostly = { |
||
3440 | + .notifier_call = port_netdevice_event, |
||
3441 | +}; |
||
3442 | + |
||
3443 | +struct ethsw_switchdev_event_work { |
||
3444 | + struct work_struct work; |
||
3445 | + struct switchdev_notifier_fdb_info fdb_info; |
||
3446 | + struct net_device *dev; |
||
3447 | + unsigned long event; |
||
3448 | +}; |
||
3449 | + |
||
3450 | +static void ethsw_switchdev_event_work(struct work_struct *work) |
||
3451 | +{ |
||
3452 | + struct ethsw_switchdev_event_work *switchdev_work = |
||
3453 | + container_of(work, struct ethsw_switchdev_event_work, work); |
||
3454 | + struct net_device *dev = switchdev_work->dev; |
||
3455 | + struct switchdev_notifier_fdb_info *fdb_info; |
||
3456 | + struct ethsw_port_priv *port_priv; |
||
3457 | + |
||
3458 | + rtnl_lock(); |
||
3459 | + port_priv = netdev_priv(dev); |
||
3460 | + fdb_info = &switchdev_work->fdb_info; |
||
3461 | + |
||
3462 | + switch (switchdev_work->event) { |
||
3463 | + case SWITCHDEV_FDB_ADD_TO_DEVICE: |
||
3464 | + if (is_unicast_ether_addr(fdb_info->addr)) |
||
3465 | + ethsw_port_fdb_add_uc(netdev_priv(dev), fdb_info->addr); |
||
3466 | + else |
||
3467 | + ethsw_port_fdb_add_mc(netdev_priv(dev), fdb_info->addr); |
||
3468 | + break; |
||
3469 | + case SWITCHDEV_FDB_DEL_TO_DEVICE: |
||
3470 | + if (is_unicast_ether_addr(fdb_info->addr)) |
||
3471 | + ethsw_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr); |
||
3472 | + else |
||
3473 | + ethsw_port_fdb_del_mc(netdev_priv(dev), fdb_info->addr); |
||
3474 | + break; |
||
3475 | + } |
||
3476 | + |
||
3477 | + rtnl_unlock(); |
||
3478 | + kfree(switchdev_work->fdb_info.addr); |
||
3479 | + kfree(switchdev_work); |
||
3480 | + dev_put(dev); |
||
3481 | +} |
||
3482 | + |
||
3483 | +/* Called under rcu_read_lock() */ |
||
3484 | +static int port_switchdev_event(struct notifier_block *unused, |
||
3485 | + unsigned long event, void *ptr) |
||
3486 | +{ |
||
3487 | + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); |
||
3488 | + struct ethsw_switchdev_event_work *switchdev_work; |
||
3489 | + struct switchdev_notifier_fdb_info *fdb_info = ptr; |
||
3490 | + |
||
3491 | + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); |
||
3492 | + if (!switchdev_work) |
||
3493 | + return NOTIFY_BAD; |
||
3494 | + |
||
3495 | + INIT_WORK(&switchdev_work->work, ethsw_switchdev_event_work); |
||
3496 | + switchdev_work->dev = dev; |
||
3497 | + switchdev_work->event = event; |
||
3498 | + |
||
3499 | + switch (event) { |
||
3500 | + case SWITCHDEV_FDB_ADD_TO_DEVICE: |
||
3501 | + case SWITCHDEV_FDB_DEL_TO_DEVICE: |
||
3502 | + memcpy(&switchdev_work->fdb_info, ptr, |
||
3503 | + sizeof(switchdev_work->fdb_info)); |
||
3504 | + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); |
||
3505 | + if (!switchdev_work->fdb_info.addr) |
||
3506 | + goto err_addr_alloc; |
||
3507 | + |
||
3508 | + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, |
||
3509 | + fdb_info->addr); |
||
3510 | + |
||
3511 | + /* Take a reference on the device to avoid being freed. */ |
||
3512 | + dev_hold(dev); |
||
3513 | + break; |
||
3514 | + default: |
||
3515 | + return NOTIFY_DONE; |
||
3516 | + } |
||
3517 | + |
||
3518 | + queue_work(ethsw_owq, &switchdev_work->work); |
||
3519 | + |
||
3520 | + return NOTIFY_DONE; |
||
3521 | + |
||
3522 | +err_addr_alloc: |
||
3523 | + kfree(switchdev_work); |
||
3524 | + return NOTIFY_BAD; |
||
3525 | +} |
||
3526 | + |
||
3527 | +static struct notifier_block port_switchdev_nb = { |
||
3528 | + .notifier_call = port_switchdev_event, |
||
3529 | +}; |
||
3530 | + |
||
3531 | +static int ethsw_register_notifier(struct device *dev) |
||
3532 | +{ |
||
3533 | + int err; |
||
3534 | + |
||
3535 | + err = register_netdevice_notifier(&port_nb); |
||
3536 | + if (err) { |
||
3537 | + dev_err(dev, "Failed to register netdev notifier\n"); |
||
3538 | + return err; |
||
3539 | + } |
||
3540 | + |
||
3541 | + err = register_switchdev_notifier(&port_switchdev_nb); |
||
3542 | + if (err) { |
||
3543 | + dev_err(dev, "Failed to register switchdev notifier\n"); |
||
3544 | + goto err_switchdev_nb; |
||
3545 | + } |
||
3546 | + |
||
3547 | + return 0; |
||
3548 | + |
||
3549 | +err_switchdev_nb: |
||
3550 | + unregister_netdevice_notifier(&port_nb); |
||
3551 | + return err; |
||
3552 | +} |
||
3553 | + |
||
3554 | +static int ethsw_open(struct ethsw_core *ethsw) |
||
3555 | +{ |
||
3556 | + struct ethsw_port_priv *port_priv = NULL; |
||
3557 | + int i, err; |
||
3558 | + |
||
3559 | + err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle); |
||
3560 | + if (err) { |
||
3561 | + dev_err(ethsw->dev, "dpsw_enable err %d\n", err); |
||
3562 | + return err; |
||
3563 | + } |
||
3564 | + |
||
3565 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { |
||
3566 | + port_priv = ethsw->ports[i]; |
||
3567 | + err = dev_open(port_priv->netdev); |
||
3568 | + if (err) { |
||
3569 | + netdev_err(port_priv->netdev, "dev_open err %d\n", err); |
||
3570 | + return err; |
||
3571 | + } |
||
3572 | + } |
||
3573 | + |
||
3574 | + return 0; |
||
3575 | +} |
||
3576 | + |
||
3577 | +static int ethsw_stop(struct ethsw_core *ethsw) |
||
3578 | +{ |
||
3579 | + struct ethsw_port_priv *port_priv = NULL; |
||
3580 | + int i, err; |
||
3581 | + |
||
3582 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { |
||
3583 | + port_priv = ethsw->ports[i]; |
||
3584 | + dev_close(port_priv->netdev); |
||
3585 | + } |
||
3586 | + |
||
3587 | + err = dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); |
||
3588 | + if (err) { |
||
3589 | + dev_err(ethsw->dev, "dpsw_disable err %d\n", err); |
||
3590 | + return err; |
||
3591 | + } |
||
3592 | + |
||
3593 | + return 0; |
||
3594 | +} |
||
3595 | + |
||
3596 | +static int ethsw_init(struct fsl_mc_device *sw_dev) |
||
3597 | +{ |
||
3598 | + struct device *dev = &sw_dev->dev; |
||
3599 | + struct ethsw_core *ethsw = dev_get_drvdata(dev); |
||
3600 | + u16 version_major, version_minor, i; |
||
3601 | + struct dpsw_stp_cfg stp_cfg; |
||
3602 | + int err; |
||
3603 | + |
||
3604 | + ethsw->dev_id = sw_dev->obj_desc.id; |
||
3605 | + |
||
3606 | + err = dpsw_open(ethsw->mc_io, 0, ethsw->dev_id, ðsw->dpsw_handle); |
||
3607 | + if (err) { |
||
3608 | + dev_err(dev, "dpsw_open err %d\n", err); |
||
3609 | + return err; |
||
3610 | + } |
||
3611 | + |
||
3612 | + err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3613 | + ðsw->sw_attr); |
||
3614 | + if (err) { |
||
3615 | + dev_err(dev, "dpsw_get_attributes err %d\n", err); |
||
3616 | + goto err_close; |
||
3617 | + } |
||
3618 | + |
||
3619 | + err = dpsw_get_api_version(ethsw->mc_io, 0, |
||
3620 | + &version_major, |
||
3621 | + &version_minor); |
||
3622 | + if (err) { |
||
3623 | + dev_err(dev, "dpsw_get_api_version err %d\n", err); |
||
3624 | + goto err_close; |
||
3625 | + } |
||
3626 | + |
||
3627 | + /* Minimum supported DPSW version check */ |
||
3628 | + if (version_major < DPSW_MIN_VER_MAJOR || |
||
3629 | + (version_major == DPSW_MIN_VER_MAJOR && |
||
3630 | + version_minor < DPSW_MIN_VER_MINOR)) { |
||
3631 | + dev_err(dev, "DPSW version %d:%d not supported. Use %d.%d or greater.\n", |
||
3632 | + version_major, |
||
3633 | + version_minor, |
||
3634 | + DPSW_MIN_VER_MAJOR, DPSW_MIN_VER_MINOR); |
||
3635 | + err = -ENOTSUPP; |
||
3636 | + goto err_close; |
||
3637 | + } |
||
3638 | + |
||
3639 | + err = dpsw_reset(ethsw->mc_io, 0, ethsw->dpsw_handle); |
||
3640 | + if (err) { |
||
3641 | + dev_err(dev, "dpsw_reset err %d\n", err); |
||
3642 | + goto err_close; |
||
3643 | + } |
||
3644 | + |
||
3645 | + err = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0, |
||
3646 | + DPSW_FDB_LEARNING_MODE_HW); |
||
3647 | + if (err) { |
||
3648 | + dev_err(dev, "dpsw_fdb_set_learning_mode err %d\n", err); |
||
3649 | + goto err_close; |
||
3650 | + } |
||
3651 | + |
||
3652 | + stp_cfg.vlan_id = DEFAULT_VLAN_ID; |
||
3653 | + stp_cfg.state = DPSW_STP_STATE_FORWARDING; |
||
3654 | + |
||
3655 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { |
||
3656 | + err = dpsw_if_set_stp(ethsw->mc_io, 0, ethsw->dpsw_handle, i, |
||
3657 | + &stp_cfg); |
||
3658 | + if (err) { |
||
3659 | + dev_err(dev, "dpsw_if_set_stp err %d for port %d\n", |
||
3660 | + err, i); |
||
3661 | + goto err_close; |
||
3662 | + } |
||
3663 | + |
||
3664 | + err = dpsw_if_set_broadcast(ethsw->mc_io, 0, |
||
3665 | + ethsw->dpsw_handle, i, 1); |
||
3666 | + if (err) { |
||
3667 | + dev_err(dev, |
||
3668 | + "dpsw_if_set_broadcast err %d for port %d\n", |
||
3669 | + err, i); |
||
3670 | + goto err_close; |
||
3671 | + } |
||
3672 | + } |
||
3673 | + |
||
3674 | + ethsw_owq = alloc_ordered_workqueue("%s_ordered", WQ_MEM_RECLAIM, |
||
3675 | + "ethsw"); |
||
3676 | + if (!ethsw_owq) { |
||
3677 | + err = -ENOMEM; |
||
3678 | + goto err_close; |
||
3679 | + } |
||
3680 | + |
||
3681 | + err = ethsw_register_notifier(dev); |
||
3682 | + if (err) |
||
3683 | + goto err_destroy_ordered_workqueue; |
||
3684 | + |
||
3685 | + return 0; |
||
3686 | + |
||
3687 | +err_destroy_ordered_workqueue: |
||
3688 | + destroy_workqueue(ethsw_owq); |
||
3689 | + |
||
3690 | +err_close: |
||
3691 | + dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); |
||
3692 | + return err; |
||
3693 | +} |
||
3694 | + |
||
3695 | +static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port) |
||
3696 | +{ |
||
3697 | + const char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01}; |
||
3698 | + struct net_device *netdev = port_priv->netdev; |
||
3699 | + struct ethsw_core *ethsw = port_priv->ethsw_data; |
||
3700 | + struct dpsw_vlan_if_cfg vcfg; |
||
3701 | + int err; |
||
3702 | + |
||
3703 | + /* Switch starts with all ports configured to VLAN 1. Need to |
||
3704 | + * remove this setting to allow configuration at bridge join |
||
3705 | + */ |
||
3706 | + vcfg.num_ifs = 1; |
||
3707 | + vcfg.if_id[0] = port_priv->idx; |
||
3708 | + |
||
3709 | + err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3710 | + DEFAULT_VLAN_ID, &vcfg); |
||
3711 | + if (err) { |
||
3712 | + netdev_err(netdev, "dpsw_vlan_remove_if_untagged err %d\n", |
||
3713 | + err); |
||
3714 | + return err; |
||
3715 | + } |
||
3716 | + |
||
3717 | + err = ethsw_port_set_pvid(port_priv, 0); |
||
3718 | + if (err) |
||
3719 | + return err; |
||
3720 | + |
||
3721 | + err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle, |
||
3722 | + DEFAULT_VLAN_ID, &vcfg); |
||
3723 | + if (err) { |
||
3724 | + netdev_err(netdev, "dpsw_vlan_remove_if err %d\n", err); |
||
3725 | + return err; |
||
3726 | + } |
||
3727 | + |
||
3728 | + err = ethsw_port_fdb_add_mc(port_priv, def_mcast); |
||
3729 | + |
||
3730 | + return err; |
||
3731 | +} |
||
3732 | + |
||
3733 | +static void ethsw_unregister_notifier(struct device *dev) |
||
3734 | +{ |
||
3735 | + int err; |
||
3736 | + |
||
3737 | + err = unregister_switchdev_notifier(&port_switchdev_nb); |
||
3738 | + if (err) |
||
3739 | + dev_err(dev, |
||
3740 | + "Failed to unregister switchdev notifier (%d)\n", err); |
||
3741 | + |
||
3742 | + err = unregister_netdevice_notifier(&port_nb); |
||
3743 | + if (err) |
||
3744 | + dev_err(dev, |
||
3745 | + "Failed to unregister netdev notifier (%d)\n", err); |
||
3746 | +} |
||
3747 | + |
||
3748 | +static void ethsw_takedown(struct fsl_mc_device *sw_dev) |
||
3749 | +{ |
||
3750 | + struct device *dev = &sw_dev->dev; |
||
3751 | + struct ethsw_core *ethsw = dev_get_drvdata(dev); |
||
3752 | + int err; |
||
3753 | + |
||
3754 | + ethsw_unregister_notifier(dev); |
||
3755 | + |
||
3756 | + err = dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); |
||
3757 | + if (err) |
||
3758 | + dev_warn(dev, "dpsw_close err %d\n", err); |
||
3759 | +} |
||
3760 | + |
||
3761 | +static int ethsw_remove(struct fsl_mc_device *sw_dev) |
||
3762 | +{ |
||
3763 | + struct ethsw_port_priv *port_priv; |
||
3764 | + struct ethsw_core *ethsw; |
||
3765 | + struct device *dev; |
||
3766 | + int i; |
||
3767 | + |
||
3768 | + dev = &sw_dev->dev; |
||
3769 | + ethsw = dev_get_drvdata(dev); |
||
3770 | + |
||
3771 | + ethsw_teardown_irqs(sw_dev); |
||
3772 | + |
||
3773 | + destroy_workqueue(ethsw_owq); |
||
3774 | + |
||
3775 | + rtnl_lock(); |
||
3776 | + ethsw_stop(ethsw); |
||
3777 | + rtnl_unlock(); |
||
3778 | + |
||
3779 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { |
||
3780 | + port_priv = ethsw->ports[i]; |
||
3781 | + unregister_netdev(port_priv->netdev); |
||
3782 | + free_netdev(port_priv->netdev); |
||
3783 | + } |
||
3784 | + kfree(ethsw->ports); |
||
3785 | + |
||
3786 | + ethsw_takedown(sw_dev); |
||
3787 | + fsl_mc_portal_free(ethsw->mc_io); |
||
3788 | + |
||
3789 | + kfree(ethsw); |
||
3790 | + |
||
3791 | + dev_set_drvdata(dev, NULL); |
||
3792 | + |
||
3793 | + return 0; |
||
3794 | +} |
||
3795 | + |
||
3796 | +static int ethsw_probe_port(struct ethsw_core *ethsw, u16 port_idx) |
||
3797 | +{ |
||
3798 | + struct ethsw_port_priv *port_priv; |
||
3799 | + struct device *dev = ethsw->dev; |
||
3800 | + struct net_device *port_netdev; |
||
3801 | + int err; |
||
3802 | + |
||
3803 | + port_netdev = alloc_etherdev(sizeof(struct ethsw_port_priv)); |
||
3804 | + if (!port_netdev) { |
||
3805 | + dev_err(dev, "alloc_etherdev error\n"); |
||
3806 | + return -ENOMEM; |
||
3807 | + } |
||
3808 | + |
||
3809 | + port_priv = netdev_priv(port_netdev); |
||
3810 | + port_priv->netdev = port_netdev; |
||
3811 | + port_priv->ethsw_data = ethsw; |
||
3812 | + |
||
3813 | + port_priv->idx = port_idx; |
||
3814 | + port_priv->stp_state = BR_STATE_FORWARDING; |
||
3815 | + |
||
3816 | + /* Flooding is implicitly enabled */ |
||
3817 | + port_priv->flood = true; |
||
3818 | + |
||
3819 | + SET_NETDEV_DEV(port_netdev, dev); |
||
3820 | + port_netdev->netdev_ops = ðsw_port_ops; |
||
3821 | + port_netdev->ethtool_ops = ðsw_port_ethtool_ops; |
||
3822 | + port_netdev->switchdev_ops = ðsw_port_switchdev_ops; |
||
3823 | + |
||
3824 | + /* Set MTU limits */ |
||
3825 | + port_netdev->min_mtu = ETH_MIN_MTU; |
||
3826 | + port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH; |
||
3827 | + |
||
3828 | + err = register_netdev(port_netdev); |
||
3829 | + if (err < 0) { |
||
3830 | + dev_err(dev, "register_netdev error %d\n", err); |
||
3831 | + free_netdev(port_netdev); |
||
3832 | + return err; |
||
3833 | + } |
||
3834 | + |
||
3835 | + ethsw->ports[port_idx] = port_priv; |
||
3836 | + |
||
3837 | + return ethsw_port_init(port_priv, port_idx); |
||
3838 | +} |
||
3839 | + |
||
3840 | +static int ethsw_probe(struct fsl_mc_device *sw_dev) |
||
3841 | +{ |
||
3842 | + struct device *dev = &sw_dev->dev; |
||
3843 | + struct ethsw_core *ethsw; |
||
3844 | + int i, err; |
||
3845 | + |
||
3846 | + /* Allocate switch core*/ |
||
3847 | + ethsw = kzalloc(sizeof(*ethsw), GFP_KERNEL); |
||
3848 | + |
||
3849 | + if (!ethsw) |
||
3850 | + return -ENOMEM; |
||
3851 | + |
||
3852 | + ethsw->dev = dev; |
||
3853 | + dev_set_drvdata(dev, ethsw); |
||
3854 | + |
||
3855 | + err = fsl_mc_portal_allocate(sw_dev, 0, ðsw->mc_io); |
||
3856 | + if (err) { |
||
3857 | + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); |
||
3858 | + goto err_free_drvdata; |
||
3859 | + } |
||
3860 | + |
||
3861 | + err = ethsw_init(sw_dev); |
||
3862 | + if (err) |
||
3863 | + goto err_free_cmdport; |
||
3864 | + |
||
3865 | + /* DEFAULT_VLAN_ID is implicitly configured on the switch */ |
||
3866 | + ethsw->vlans[DEFAULT_VLAN_ID] = ETHSW_VLAN_MEMBER; |
||
3867 | + |
||
3868 | + /* Learning is implicitly enabled */ |
||
3869 | + ethsw->learning = true; |
||
3870 | + |
||
3871 | + ethsw->ports = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->ports), |
||
3872 | + GFP_KERNEL); |
||
3873 | + if (!(ethsw->ports)) { |
||
3874 | + err = -ENOMEM; |
||
3875 | + goto err_takedown; |
||
3876 | + } |
||
3877 | + |
||
3878 | + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { |
||
3879 | + err = ethsw_probe_port(ethsw, i); |
||
3880 | + if (err) |
||
3881 | + goto err_free_ports; |
||
3882 | + } |
||
3883 | + |
||
3884 | + /* Switch starts up enabled */ |
||
3885 | + rtnl_lock(); |
||
3886 | + err = ethsw_open(ethsw); |
||
3887 | + rtnl_unlock(); |
||
3888 | + if (err) |
||
3889 | + goto err_free_ports; |
||
3890 | + |
||
3891 | + /* Setup IRQs */ |
||
3892 | + err = ethsw_setup_irqs(sw_dev); |
||
3893 | + if (err) |
||
3894 | + goto err_stop; |
||
3895 | + |
||
3896 | + dev_info(dev, "probed %d port switch\n", ethsw->sw_attr.num_ifs); |
||
3897 | + return 0; |
||
3898 | + |
||
3899 | +err_stop: |
||
3900 | + rtnl_lock(); |
||
3901 | + ethsw_stop(ethsw); |
||
3902 | + rtnl_unlock(); |
||
3903 | + |
||
3904 | +err_free_ports: |
||
3905 | + /* Cleanup registered ports only */ |
||
3906 | + for (i--; i >= 0; i--) { |
||
3907 | + unregister_netdev(ethsw->ports[i]->netdev); |
||
3908 | + free_netdev(ethsw->ports[i]->netdev); |
||
3909 | + } |
||
3910 | + kfree(ethsw->ports); |
||
3911 | + |
||
3912 | +err_takedown: |
||
3913 | + ethsw_takedown(sw_dev); |
||
3914 | + |
||
3915 | +err_free_cmdport: |
||
3916 | + fsl_mc_portal_free(ethsw->mc_io); |
||
3917 | + |
||
3918 | +err_free_drvdata: |
||
3919 | + kfree(ethsw); |
||
3920 | + dev_set_drvdata(dev, NULL); |
||
3921 | + |
||
3922 | + return err; |
||
3923 | +} |
||
3924 | + |
||
3925 | +static const struct fsl_mc_device_id ethsw_match_id_table[] = { |
||
3926 | + { |
||
3927 | + .vendor = FSL_MC_VENDOR_FREESCALE, |
||
3928 | + .obj_type = "dpsw", |
||
3929 | + }, |
||
3930 | + { .vendor = 0x0 } |
||
3931 | +}; |
||
3932 | +MODULE_DEVICE_TABLE(fslmc, ethsw_match_id_table); |
||
3933 | + |
||
3934 | +static struct fsl_mc_driver eth_sw_drv = { |
||
3935 | + .driver = { |
||
3936 | + .name = KBUILD_MODNAME, |
||
3937 | + .owner = THIS_MODULE, |
||
3938 | + }, |
||
3939 | + .probe = ethsw_probe, |
||
3940 | + .remove = ethsw_remove, |
||
3941 | + .match_id_table = ethsw_match_id_table |
||
3942 | +}; |
||
3943 | + |
||
3944 | +module_fsl_mc_driver(eth_sw_drv); |
||
3945 | + |
||
3946 | +MODULE_LICENSE("Dual BSD/GPL"); |
||
3947 | +MODULE_DESCRIPTION("DPAA2 Ethernet Switch Driver"); |
||
3948 | --- /dev/null |
||
3949 | +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h |
||
3950 | @@ -0,0 +1,90 @@ |
||
3951 | +/* Copyright 2014-2017 Freescale Semiconductor Inc. |
||
3952 | + * Copyright 2017 NXP |
||
3953 | + * |
||
3954 | + * Redistribution and use in source and binary forms, with or without |
||
3955 | + * modification, are permitted provided that the following conditions are met: |
||
3956 | + * * Redistributions of source code must retain the above copyright |
||
3957 | + * notice, this list of conditions and the following disclaimer. |
||
3958 | + * * Redistributions in binary form must reproduce the above copyright |
||
3959 | + * notice, this list of conditions and the following disclaimer in the |
||
3960 | + * documentation and/or other materials provided with the distribution. |
||
3961 | + * * Neither the name of the above-listed copyright holders nor the |
||
3962 | + * names of any contributors may be used to endorse or promote products |
||
3963 | + * derived from this software without specific prior written permission. |
||
3964 | + * |
||
3965 | + * |
||
3966 | + * ALTERNATIVELY, this software may be distributed under the terms of the |
||
3967 | + * GNU General Public License ("GPL") as published by the Free Software |
||
3968 | + * Foundation, either version 2 of that License or (at your option) any |
||
3969 | + * later version. |
||
3970 | + * |
||
3971 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
3972 | + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
3973 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
3974 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE |
||
3975 | + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
3976 | + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
3977 | + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
3978 | + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
3979 | + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
3980 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
3981 | + * POSSIBILITY OF SUCH DAMAGE. |
||
3982 | + */ |
||
3983 | + |
||
3984 | +#ifndef __ETHSW_H |
||
3985 | +#define __ETHSW_H |
||
3986 | + |
||
3987 | +#include <linux/netdevice.h> |
||
3988 | +#include <linux/etherdevice.h> |
||
3989 | +#include <linux/rtnetlink.h> |
||
3990 | +#include <linux/if_vlan.h> |
||
3991 | +#include <uapi/linux/if_bridge.h> |
||
3992 | +#include <net/switchdev.h> |
||
3993 | +#include <linux/if_bridge.h> |
||
3994 | + |
||
3995 | +#include "dpsw.h" |
||
3996 | + |
||
3997 | +/* Number of IRQs supported */ |
||
3998 | +#define DPSW_IRQ_NUM 2 |
||
3999 | + |
||
4000 | +#define ETHSW_VLAN_MEMBER 1 |
||
4001 | +#define ETHSW_VLAN_UNTAGGED 2 |
||
4002 | +#define ETHSW_VLAN_PVID 4 |
||
4003 | +#define ETHSW_VLAN_GLOBAL 8 |
||
4004 | + |
||
4005 | +/* Maximum Frame Length supported by HW (currently 10k) */ |
||
4006 | +#define DPAA2_MFL (10 * 1024) |
||
4007 | +#define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN) |
||
4008 | +#define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN) |
||
4009 | + |
||
4010 | +extern const struct ethtool_ops ethsw_port_ethtool_ops; |
||
4011 | + |
||
4012 | +struct ethsw_core; |
||
4013 | + |
||
4014 | +/* Per port private data */ |
||
4015 | +struct ethsw_port_priv { |
||
4016 | + struct net_device *netdev; |
||
4017 | + u16 idx; |
||
4018 | + struct ethsw_core *ethsw_data; |
||
4019 | + u8 link_state; |
||
4020 | + u8 stp_state; |
||
4021 | + bool flood; |
||
4022 | + |
||
4023 | + u8 vlans[VLAN_VID_MASK + 1]; |
||
4024 | + u16 pvid; |
||
4025 | +}; |
||
4026 | + |
||
4027 | +/* Switch data */ |
||
4028 | +struct ethsw_core { |
||
4029 | + struct device *dev; |
||
4030 | + struct fsl_mc_io *mc_io; |
||
4031 | + u16 dpsw_handle; |
||
4032 | + struct dpsw_attr sw_attr; |
||
4033 | + int dev_id; |
||
4034 | + struct ethsw_port_priv **ports; |
||
4035 | + |
||
4036 | + u8 vlans[VLAN_VID_MASK + 1]; |
||
4037 | + bool learning; |
||
4038 | +}; |
||
4039 | + |
||
4040 | +#endif /* __ETHSW_H */ |