layerscape: add ls1088ardb device support
[openwrt/staging/lynxis/omap.git] / target / linux / layerscape / patches-4.4 / 7215-dpaa2-evb-Added-Edge-Virtual-Bridge-driver.patch
1 From 54bcaca10728c1a1c8adfa48124ea79cce4ef929 Mon Sep 17 00:00:00 2001
2 From: Razvan Stefanescu <razvan.stefanescu@freescale.com>
3 Date: Tue, 22 Sep 2015 08:43:08 +0300
4 Subject: [PATCH 215/226] dpaa2-evb: Added Edge Virtual Bridge driver
5
6 This is a commit of the cummulative, squashed dpaa2-evb patches.
7 All the commit logs are preserved below.
8
9 Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com>
10
11 ----------------------------------------------------------------
12
13 dpaa2-evb: Added Edge Virtual Bridge driver
14
15 This contains the following patches migrated from linux-v4.0:
16 staging: fsl-dpaa2: evb: Added Edge Virtual Bridge driver
17 staging: fsl-dpaa2: evb: Added ethtool port counters
18 staging: fsl-dpaa2: evb: Include by default in configuration
19 staging: fsl-dpaa2: evb: Rebasing onto kernel 4.0
20 staging: fsl-dpaa2: evb: Port to MC-0.7 FLibs
21 dpaa2-evb: Set carrier state on port open
22 dpaa2-evb: Add support for link state update
23 dpaa2-evb: Update flib to MC 8.0.1
24 staging: fsl-mc: migrated remaining flibs for MC fw 8.0.0 (split)
25
26 Inital patches have been signed-off by:
27 Alex Marginean <alexandru.marginean@freescale.com>
28 J. German Rivera <German.Rivera@freescale.com>
29 Bogdan Hamciuc <bogdan.hamciuc@freescale.com>
30 Razvan Stefanescu <razvan.stefanescu@freescale.com>
31
32 And reviewed by:
33 Stuart Yoder <stuart.yoder@freescale.com>
34
35 Porting to linux-v4.1 requires changes related to iflink usage and
36 ndo_bridge_getlink() parameters list.
37
38 Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
39
40 dpaa2-evb: Port to linux-v4.1
41
42 Update iflink usage.
43 Update evb_getlink() parameter list to match ndo_bridge_getlink().
44
45 Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
46
47 dpaa2-evb: Add VLAN_8021Q dependency
48
49 EVB traffic steering methods related to VLAN require VLAN support in kernel.
50
51 Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
52
53 dpaa2-evb: Update dpdmux binary interface to 5.0
54
55 This corresponds to MC release 0.8.0.
56
57 Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
58
59 dpaa2-evb: Add support to set max frame length.
60
61 All the packets bigger than max_frame_length will be dropped.
62
63 Signed-off-by: Mihaela Panescu <mihaela.panescu@freescale.com>
64
65 dpaa2-evb: resolve compile issues on uprev to 4.5
66
67 -irq_number field no longer exists in fsl-mc interrupt
68 struct
69 -netdev_master_upper_dev_link() has 2 new parameters, which
70 are set to NULL for now
71
72 Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com>
73 ---
74 MAINTAINERS | 6 +
75 drivers/staging/fsl-dpaa2/Kconfig | 1 +
76 drivers/staging/fsl-dpaa2/Makefile | 1 +
77 drivers/staging/fsl-dpaa2/evb/Kconfig | 8 +
78 drivers/staging/fsl-dpaa2/evb/Makefile | 10 +
79 drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h | 256 ++++++
80 drivers/staging/fsl-dpaa2/evb/dpdmux.c | 567 +++++++++++++
81 drivers/staging/fsl-dpaa2/evb/dpdmux.h | 724 +++++++++++++++++
82 drivers/staging/fsl-dpaa2/evb/evb.c | 1216 ++++++++++++++++++++++++++++
83 9 files changed, 2789 insertions(+)
84 create mode 100644 drivers/staging/fsl-dpaa2/evb/Kconfig
85 create mode 100644 drivers/staging/fsl-dpaa2/evb/Makefile
86 create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
87 create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.c
88 create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.h
89 create mode 100644 drivers/staging/fsl-dpaa2/evb/evb.c
90
91 --- a/MAINTAINERS
92 +++ b/MAINTAINERS
93 @@ -4560,6 +4560,12 @@ L: linux-kernel@vger.kernel.org
94 S: Maintained
95 F: drivers/staging/fsl-dpaa2/mac/
96
97 ++FREESCALE DPAA2 EDGE VIRTUAL BRIDGE DRIVER
98 +M: Alex Marginean <Alexandru.Marginean@freescale.com>
99 +L: linux-kernel@vger.kernel.org
100 +S: Maintained
101 +F: drivers/staging/fsl-dpaa2/evb/
102 +
103 FREEVXFS FILESYSTEM
104 M: Christoph Hellwig <hch@infradead.org>
105 W: ftp://ftp.openlinux.org/pub/people/hch/vxfs
106 --- a/drivers/staging/fsl-dpaa2/Kconfig
107 +++ b/drivers/staging/fsl-dpaa2/Kconfig
108 @@ -10,3 +10,4 @@ config FSL_DPAA2
109 # TODO move DPIO driver in-here?
110 source "drivers/staging/fsl-dpaa2/ethernet/Kconfig"
111 source "drivers/staging/fsl-dpaa2/mac/Kconfig"
112 +source "drivers/staging/fsl-dpaa2/evb/Kconfig"
113 --- a/drivers/staging/fsl-dpaa2/Makefile
114 +++ b/drivers/staging/fsl-dpaa2/Makefile
115 @@ -4,3 +4,4 @@
116
117 obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/
118 obj-$(CONFIG_FSL_DPAA2_MAC) += mac/
119 +obj-$(CONFIG_FSL_DPAA2_EVB) += evb/
120 --- /dev/null
121 +++ b/drivers/staging/fsl-dpaa2/evb/Kconfig
122 @@ -0,0 +1,8 @@
123 +config FSL_DPAA2_EVB
124 + tristate "DPAA2 Edge Virtual Bridge"
125 + depends on FSL_MC_BUS && FSL_DPAA2 && FSL_DPAA2_ETH
126 + select FSL_DPAA2_MAC
127 + select VLAN_8021Q
128 + default y
129 + ---help---
130 + Prototype driver for DPAA2 Edge Virtual Bridge.
131 --- /dev/null
132 +++ b/drivers/staging/fsl-dpaa2/evb/Makefile
133 @@ -0,0 +1,10 @@
134 +
135 +obj-$(CONFIG_FSL_DPAA2_EVB) += dpaa2-evb.o
136 +
137 +dpaa2-evb-objs := evb.o dpdmux.o
138 +
139 +all:
140 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
141 +
142 +clean:
143 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
144 --- /dev/null
145 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
146 @@ -0,0 +1,256 @@
147 +/* Copyright 2013-2015 Freescale Semiconductor Inc.
148 + *
149 + * Redistribution and use in source and binary forms, with or without
150 + * modification, are permitted provided that the following conditions are met:
151 + * * Redistributions of source code must retain the above copyright
152 + * notice, this list of conditions and the following disclaimer.
153 + * * Redistributions in binary form must reproduce the above copyright
154 + * notice, this list of conditions and the following disclaimer in the
155 + * documentation and/or other materials provided with the distribution.
156 + * * Neither the name of the above-listed copyright holders nor the
157 + * names of any contributors may be used to endorse or promote products
158 + * derived from this software without specific prior written permission.
159 + *
160 + *
161 + * ALTERNATIVELY, this software may be distributed under the terms of the
162 + * GNU General Public License ("GPL") as published by the Free Software
163 + * Foundation, either version 2 of that License or (at your option) any
164 + * later version.
165 + *
166 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
167 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
169 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
170 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
171 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
172 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
173 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
174 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
175 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
176 + * POSSIBILITY OF SUCH DAMAGE.
177 + */
178 +#ifndef _FSL_DPDMUX_CMD_H
179 +#define _FSL_DPDMUX_CMD_H
180 +
181 +/* DPDMUX Version */
182 +#define DPDMUX_VER_MAJOR 5
183 +#define DPDMUX_VER_MINOR 0
184 +
185 +/* Command IDs */
186 +#define DPDMUX_CMDID_CLOSE 0x800
187 +#define DPDMUX_CMDID_OPEN 0x806
188 +#define DPDMUX_CMDID_CREATE 0x906
189 +#define DPDMUX_CMDID_DESTROY 0x900
190 +
191 +#define DPDMUX_CMDID_ENABLE 0x002
192 +#define DPDMUX_CMDID_DISABLE 0x003
193 +#define DPDMUX_CMDID_GET_ATTR 0x004
194 +#define DPDMUX_CMDID_RESET 0x005
195 +#define DPDMUX_CMDID_IS_ENABLED 0x006
196 +
197 +#define DPDMUX_CMDID_SET_IRQ 0x010
198 +#define DPDMUX_CMDID_GET_IRQ 0x011
199 +#define DPDMUX_CMDID_SET_IRQ_ENABLE 0x012
200 +#define DPDMUX_CMDID_GET_IRQ_ENABLE 0x013
201 +#define DPDMUX_CMDID_SET_IRQ_MASK 0x014
202 +#define DPDMUX_CMDID_GET_IRQ_MASK 0x015
203 +#define DPDMUX_CMDID_GET_IRQ_STATUS 0x016
204 +#define DPDMUX_CMDID_CLEAR_IRQ_STATUS 0x017
205 +
206 +#define DPDMUX_CMDID_UL_SET_MAX_FRAME_LENGTH 0x0a1
207 +
208 +#define DPDMUX_CMDID_UL_RESET_COUNTERS 0x0a3
209 +
210 +#define DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES 0x0a7
211 +#define DPDMUX_CMDID_IF_GET_ATTR 0x0a8
212 +
213 +#define DPDMUX_CMDID_IF_ADD_L2_RULE 0x0b0
214 +#define DPDMUX_CMDID_IF_REMOVE_L2_RULE 0x0b1
215 +#define DPDMUX_CMDID_IF_GET_COUNTER 0x0b2
216 +#define DPDMUX_CMDID_IF_SET_LINK_CFG 0x0b3
217 +#define DPDMUX_CMDID_IF_GET_LINK_STATE 0x0b4
218 +
219 +/* cmd, param, offset, width, type, arg_name */
220 +#define DPDMUX_CMD_OPEN(cmd, dpdmux_id) \
221 + MC_CMD_OP(cmd, 0, 0, 32, int, dpdmux_id)
222 +
223 +/* cmd, param, offset, width, type, arg_name */
224 +#define DPDMUX_CMD_CREATE(cmd, cfg) \
225 +do { \
226 + MC_CMD_OP(cmd, 0, 0, 8, enum dpdmux_method, cfg->method);\
227 + MC_CMD_OP(cmd, 0, 8, 8, enum dpdmux_manip, cfg->manip);\
228 + MC_CMD_OP(cmd, 0, 16, 16, uint16_t, cfg->num_ifs);\
229 + MC_CMD_OP(cmd, 1, 0, 16, uint16_t, cfg->adv.max_dmat_entries);\
230 + MC_CMD_OP(cmd, 1, 16, 16, uint16_t, cfg->adv.max_mc_groups);\
231 + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, cfg->adv.max_vlan_ids);\
232 + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->adv.options);\
233 +} while (0)
234 +
235 +/* cmd, param, offset, width, type, arg_name */
236 +#define DPDMUX_RSP_IS_ENABLED(cmd, en) \
237 + MC_RSP_OP(cmd, 0, 0, 1, int, en)
238 +
239 +/* cmd, param, offset, width, type, arg_name */
240 +#define DPDMUX_CMD_SET_IRQ(cmd, irq_index, irq_cfg) \
241 +do { \
242 + MC_CMD_OP(cmd, 0, 0, 8, uint8_t, irq_index);\
243 + MC_CMD_OP(cmd, 0, 32, 32, uint32_t, irq_cfg->val);\
244 + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr);\
245 + MC_CMD_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \
246 +} while (0)
247 +
248 +/* cmd, param, offset, width, type, arg_name */
249 +#define DPDMUX_CMD_GET_IRQ(cmd, irq_index) \
250 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
251 +
252 +/* cmd, param, offset, width, type, arg_name */
253 +#define DPDMUX_RSP_GET_IRQ(cmd, type, irq_cfg) \
254 +do { \
255 + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, irq_cfg->val); \
256 + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr); \
257 + MC_RSP_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \
258 + MC_RSP_OP(cmd, 2, 32, 32, int, type); \
259 +} while (0)
260 +
261 +/* cmd, param, offset, width, type, arg_name */
262 +#define DPDMUX_CMD_SET_IRQ_ENABLE(cmd, irq_index, en) \
263 +do { \
264 + MC_CMD_OP(cmd, 0, 0, 8, uint8_t, en);\
265 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\
266 +} while (0)
267 +
268 +/* cmd, param, offset, width, type, arg_name */
269 +#define DPDMUX_CMD_GET_IRQ_ENABLE(cmd, irq_index) \
270 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
271 +
272 +/* cmd, param, offset, width, type, arg_name */
273 +#define DPDMUX_RSP_GET_IRQ_ENABLE(cmd, en) \
274 + MC_RSP_OP(cmd, 0, 0, 8, uint8_t, en)
275 +
276 +/* cmd, param, offset, width, type, arg_name */
277 +#define DPDMUX_CMD_SET_IRQ_MASK(cmd, irq_index, mask) \
278 +do { \
279 + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, mask); \
280 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \
281 +} while (0)
282 +
283 +/* cmd, param, offset, width, type, arg_name */
284 +#define DPDMUX_CMD_GET_IRQ_MASK(cmd, irq_index) \
285 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
286 +
287 +/* cmd, param, offset, width, type, arg_name */
288 +#define DPDMUX_RSP_GET_IRQ_MASK(cmd, mask) \
289 + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, mask)
290 +
291 +/* cmd, param, offset, width, type, arg_name */
292 +#define DPDMUX_CMD_GET_IRQ_STATUS(cmd, irq_index, status) \
293 +do { \
294 + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status);\
295 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\
296 +} while (0)
297 +
298 +/* cmd, param, offset, width, type, arg_name */
299 +#define DPDMUX_RSP_GET_IRQ_STATUS(cmd, status) \
300 + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, status) \
301 +
302 +/* cmd, param, offset, width, type, arg_name */
303 +#define DPDMUX_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status) \
304 +do { \
305 + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status); \
306 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \
307 +} while (0)
308 +
309 +#define DPDMUX_RSP_GET_ATTR(cmd, attr) \
310 +do { \
311 + MC_RSP_OP(cmd, 0, 0, 8, enum dpdmux_method, attr->method);\
312 + MC_RSP_OP(cmd, 0, 8, 8, enum dpdmux_manip, attr->manip);\
313 + MC_RSP_OP(cmd, 0, 16, 16, uint16_t, attr->num_ifs);\
314 + MC_RSP_OP(cmd, 0, 32, 16, uint16_t, attr->mem_size);\
315 + MC_RSP_OP(cmd, 2, 0, 32, int, attr->id);\
316 + MC_RSP_OP(cmd, 3, 0, 64, uint64_t, attr->options);\
317 + MC_RSP_OP(cmd, 4, 0, 16, uint16_t, attr->version.major);\
318 + MC_RSP_OP(cmd, 4, 16, 16, uint16_t, attr->version.minor);\
319 +} while (0)
320 +
321 +/* cmd, param, offset, width, type, arg_name */
322 +#define DPDMUX_CMD_UL_SET_MAX_FRAME_LENGTH(cmd, max_frame_length) \
323 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, max_frame_length)
324 +
325 +/* cmd, param, offset, width, type, arg_name */
326 +#define DPDMUX_CMD_IF_SET_ACCEPTED_FRAMES(cmd, if_id, cfg) \
327 +do { \
328 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
329 + MC_CMD_OP(cmd, 0, 16, 4, enum dpdmux_accepted_frames_type, cfg->type);\
330 + MC_CMD_OP(cmd, 0, 20, 4, enum dpdmux_unaccepted_frames_action, \
331 + cfg->unaccept_act);\
332 +} while (0)
333 +
334 +/* cmd, param, offset, width, type, arg_name */
335 +#define DPDMUX_CMD_IF_GET_ATTR(cmd, if_id) \
336 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id)
337 +
338 +/* cmd, param, offset, width, type, arg_name */
339 +#define DPDMUX_RSP_IF_GET_ATTR(cmd, attr) \
340 +do { \
341 + MC_RSP_OP(cmd, 0, 56, 4, enum dpdmux_accepted_frames_type, \
342 + attr->accept_frame_type);\
343 + MC_RSP_OP(cmd, 0, 24, 1, int, attr->enabled);\
344 + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, attr->rate);\
345 +} while (0)
346 +
347 +#define DPDMUX_CMD_IF_REMOVE_L2_RULE(cmd, if_id, l2_rule) \
348 +do { \
349 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
350 + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, l2_rule->mac_addr[5]);\
351 + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, l2_rule->mac_addr[4]);\
352 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, l2_rule->mac_addr[3]);\
353 + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, l2_rule->mac_addr[2]);\
354 + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, l2_rule->mac_addr[1]);\
355 + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, l2_rule->mac_addr[0]);\
356 + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, l2_rule->vlan_id);\
357 +} while (0)
358 +
359 +#define DPDMUX_CMD_IF_ADD_L2_RULE(cmd, if_id, l2_rule) \
360 +do { \
361 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
362 + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, l2_rule->mac_addr[5]);\
363 + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, l2_rule->mac_addr[4]);\
364 + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, l2_rule->mac_addr[3]);\
365 + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, l2_rule->mac_addr[2]);\
366 + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, l2_rule->mac_addr[1]);\
367 + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, l2_rule->mac_addr[0]);\
368 + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, l2_rule->vlan_id);\
369 +} while (0)
370 +
371 +/* cmd, param, offset, width, type, arg_name */
372 +#define DPDMUX_CMD_IF_GET_COUNTER(cmd, if_id, counter_type) \
373 +do { \
374 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
375 + MC_CMD_OP(cmd, 0, 16, 8, enum dpdmux_counter_type, counter_type);\
376 +} while (0)
377 +
378 +/* cmd, param, offset, width, type, arg_name */
379 +#define DPDMUX_RSP_IF_GET_COUNTER(cmd, counter) \
380 + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, counter)
381 +
382 +/* cmd, param, offset, width, type, arg_name */
383 +#define DPDMUX_CMD_IF_SET_LINK_CFG(cmd, if_id, cfg) \
384 +do { \
385 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
386 + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->rate);\
387 + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->options);\
388 +} while (0)
389 +
390 +/* cmd, param, offset, width, type, arg_name */
391 +#define DPDMUX_CMD_IF_GET_LINK_STATE(cmd, if_id) \
392 + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id)
393 +
394 +/* cmd, param, offset, width, type, arg_name */
395 +#define DPDMUX_RSP_IF_GET_LINK_STATE(cmd, state) \
396 +do { \
397 + MC_RSP_OP(cmd, 0, 32, 1, int, state->up);\
398 + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, state->rate);\
399 + MC_RSP_OP(cmd, 2, 0, 64, uint64_t, state->options);\
400 +} while (0)
401 +
402 +#endif /* _FSL_DPDMUX_CMD_H */
403 --- /dev/null
404 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c
405 @@ -0,0 +1,567 @@
406 +/* Copyright 2013-2015 Freescale Semiconductor Inc.
407 + *
408 + * Redistribution and use in source and binary forms, with or without
409 + * modification, are permitted provided that the following conditions are met:
410 + * * Redistributions of source code must retain the above copyright
411 + * notice, this list of conditions and the following disclaimer.
412 + * * Redistributions in binary form must reproduce the above copyright
413 + * notice, this list of conditions and the following disclaimer in the
414 + * documentation and/or other materials provided with the distribution.
415 + * * Neither the name of the above-listed copyright holders nor the
416 + * names of any contributors may be used to endorse or promote products
417 + * derived from this software without specific prior written permission.
418 + *
419 + *
420 + * ALTERNATIVELY, this software may be distributed under the terms of the
421 + * GNU General Public License ("GPL") as published by the Free Software
422 + * Foundation, either version 2 of that License or (at your option) any
423 + * later version.
424 + *
425 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
426 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
427 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
428 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
429 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
430 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
431 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
432 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
433 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
434 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
435 + * POSSIBILITY OF SUCH DAMAGE.
436 + */
437 +#include "../../fsl-mc/include/mc-sys.h"
438 +#include "../../fsl-mc/include/mc-cmd.h"
439 +#include "dpdmux.h"
440 +#include "dpdmux-cmd.h"
441 +
442 +int dpdmux_open(struct fsl_mc_io *mc_io,
443 + uint32_t cmd_flags,
444 + int dpdmux_id,
445 + uint16_t *token)
446 +{
447 + struct mc_command cmd = { 0 };
448 + int err;
449 +
450 + /* prepare command */
451 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_OPEN,
452 + cmd_flags,
453 + 0);
454 + DPDMUX_CMD_OPEN(cmd, dpdmux_id);
455 +
456 + /* send command to mc*/
457 + err = mc_send_command(mc_io, &cmd);
458 + if (err)
459 + return err;
460 +
461 + /* retrieve response parameters */
462 + *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
463 +
464 + return 0;
465 +}
466 +
467 +int dpdmux_close(struct fsl_mc_io *mc_io,
468 + uint32_t cmd_flags,
469 + uint16_t token)
470 +{
471 + struct mc_command cmd = { 0 };
472 +
473 + /* prepare command */
474 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLOSE,
475 + cmd_flags,
476 + token);
477 +
478 + /* send command to mc*/
479 + return mc_send_command(mc_io, &cmd);
480 +}
481 +
482 +int dpdmux_create(struct fsl_mc_io *mc_io,
483 + uint32_t cmd_flags,
484 + const struct dpdmux_cfg *cfg,
485 + uint16_t *token)
486 +{
487 + struct mc_command cmd = { 0 };
488 + int err;
489 +
490 + /* prepare command */
491 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CREATE,
492 + cmd_flags,
493 + 0);
494 + DPDMUX_CMD_CREATE(cmd, cfg);
495 +
496 + /* send command to mc*/
497 + err = mc_send_command(mc_io, &cmd);
498 + if (err)
499 + return err;
500 +
501 + /* retrieve response parameters */
502 + *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
503 +
504 + return 0;
505 +}
506 +
507 +int dpdmux_destroy(struct fsl_mc_io *mc_io,
508 + uint32_t cmd_flags,
509 + uint16_t token)
510 +{
511 + struct mc_command cmd = { 0 };
512 +
513 + /* prepare command */
514 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DESTROY,
515 + cmd_flags,
516 + token);
517 +
518 + /* send command to mc*/
519 + return mc_send_command(mc_io, &cmd);
520 +}
521 +
522 +int dpdmux_enable(struct fsl_mc_io *mc_io,
523 + uint32_t cmd_flags,
524 + uint16_t token)
525 +{
526 + struct mc_command cmd = { 0 };
527 +
528 + /* prepare command */
529 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ENABLE,
530 + cmd_flags,
531 + token);
532 +
533 + /* send command to mc*/
534 + return mc_send_command(mc_io, &cmd);
535 +}
536 +
537 +int dpdmux_disable(struct fsl_mc_io *mc_io,
538 + uint32_t cmd_flags,
539 + uint16_t token)
540 +{
541 + struct mc_command cmd = { 0 };
542 +
543 + /* prepare command */
544 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DISABLE,
545 + cmd_flags,
546 + token);
547 +
548 + /* send command to mc*/
549 + return mc_send_command(mc_io, &cmd);
550 +}
551 +
552 +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
553 + uint32_t cmd_flags,
554 + uint16_t token,
555 + int *en)
556 +{
557 + struct mc_command cmd = { 0 };
558 + int err;
559 + /* prepare command */
560 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IS_ENABLED,
561 + cmd_flags,
562 + token);
563 +
564 + /* send command to mc*/
565 + err = mc_send_command(mc_io, &cmd);
566 + if (err)
567 + return err;
568 +
569 + /* retrieve response parameters */
570 + DPDMUX_RSP_IS_ENABLED(cmd, *en);
571 +
572 + return 0;
573 +}
574 +
575 +int dpdmux_reset(struct fsl_mc_io *mc_io,
576 + uint32_t cmd_flags,
577 + uint16_t token)
578 +{
579 + struct mc_command cmd = { 0 };
580 +
581 + /* prepare command */
582 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_RESET,
583 + cmd_flags,
584 + token);
585 +
586 + /* send command to mc*/
587 + return mc_send_command(mc_io, &cmd);
588 +}
589 +
590 +int dpdmux_set_irq(struct fsl_mc_io *mc_io,
591 + uint32_t cmd_flags,
592 + uint16_t token,
593 + uint8_t irq_index,
594 + struct dpdmux_irq_cfg *irq_cfg)
595 +{
596 + struct mc_command cmd = { 0 };
597 +
598 + /* prepare command */
599 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ,
600 + cmd_flags,
601 + token);
602 + DPDMUX_CMD_SET_IRQ(cmd, irq_index, irq_cfg);
603 +
604 + /* send command to mc*/
605 + return mc_send_command(mc_io, &cmd);
606 +}
607 +
608 +int dpdmux_get_irq(struct fsl_mc_io *mc_io,
609 + uint32_t cmd_flags,
610 + uint16_t token,
611 + uint8_t irq_index,
612 + int *type,
613 + struct dpdmux_irq_cfg *irq_cfg)
614 +{
615 + struct mc_command cmd = { 0 };
616 + int err;
617 +
618 + /* prepare command */
619 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ,
620 + cmd_flags,
621 + token);
622 + DPDMUX_CMD_GET_IRQ(cmd, irq_index);
623 +
624 + /* send command to mc*/
625 + err = mc_send_command(mc_io, &cmd);
626 + if (err)
627 + return err;
628 +
629 + /* retrieve response parameters */
630 + DPDMUX_RSP_GET_IRQ(cmd, *type, irq_cfg);
631 +
632 + return 0;
633 +}
634 +
635 +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
636 + uint32_t cmd_flags,
637 + uint16_t token,
638 + uint8_t irq_index,
639 + uint8_t en)
640 +{
641 + struct mc_command cmd = { 0 };
642 +
643 + /* prepare command */
644 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_ENABLE,
645 + cmd_flags,
646 + token);
647 + DPDMUX_CMD_SET_IRQ_ENABLE(cmd, irq_index, en);
648 +
649 + /* send command to mc*/
650 + return mc_send_command(mc_io, &cmd);
651 +}
652 +
653 +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
654 + uint32_t cmd_flags,
655 + uint16_t token,
656 + uint8_t irq_index,
657 + uint8_t *en)
658 +{
659 + struct mc_command cmd = { 0 };
660 + int err;
661 +
662 + /* prepare command */
663 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_ENABLE,
664 + cmd_flags,
665 + token);
666 + DPDMUX_CMD_GET_IRQ_ENABLE(cmd, irq_index);
667 +
668 + /* send command to mc*/
669 + err = mc_send_command(mc_io, &cmd);
670 + if (err)
671 + return err;
672 +
673 + /* retrieve response parameters */
674 + DPDMUX_RSP_GET_IRQ_ENABLE(cmd, *en);
675 +
676 + return 0;
677 +}
678 +
679 +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
680 + uint32_t cmd_flags,
681 + uint16_t token,
682 + uint8_t irq_index,
683 + uint32_t mask)
684 +{
685 + struct mc_command cmd = { 0 };
686 +
687 + /* prepare command */
688 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_MASK,
689 + cmd_flags,
690 + token);
691 + DPDMUX_CMD_SET_IRQ_MASK(cmd, irq_index, mask);
692 +
693 + /* send command to mc*/
694 + return mc_send_command(mc_io, &cmd);
695 +}
696 +
697 +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
698 + uint32_t cmd_flags,
699 + uint16_t token,
700 + uint8_t irq_index,
701 + uint32_t *mask)
702 +{
703 + struct mc_command cmd = { 0 };
704 + int err;
705 +
706 + /* prepare command */
707 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_MASK,
708 + cmd_flags,
709 + token);
710 + DPDMUX_CMD_GET_IRQ_MASK(cmd, irq_index);
711 +
712 + /* send command to mc*/
713 + err = mc_send_command(mc_io, &cmd);
714 + if (err)
715 + return err;
716 +
717 + /* retrieve response parameters */
718 + DPDMUX_RSP_GET_IRQ_MASK(cmd, *mask);
719 +
720 + return 0;
721 +}
722 +
723 +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
724 + uint32_t cmd_flags,
725 + uint16_t token,
726 + uint8_t irq_index,
727 + uint32_t *status)
728 +{
729 + struct mc_command cmd = { 0 };
730 + int err;
731 +
732 + /* prepare command */
733 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_STATUS,
734 + cmd_flags,
735 + token);
736 + DPDMUX_CMD_GET_IRQ_STATUS(cmd, irq_index, *status);
737 +
738 + /* send command to mc*/
739 + err = mc_send_command(mc_io, &cmd);
740 + if (err)
741 + return err;
742 +
743 + /* retrieve response parameters */
744 + DPDMUX_RSP_GET_IRQ_STATUS(cmd, *status);
745 +
746 + return 0;
747 +}
748 +
749 +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
750 + uint32_t cmd_flags,
751 + uint16_t token,
752 + uint8_t irq_index,
753 + uint32_t status)
754 +{
755 + struct mc_command cmd = { 0 };
756 +
757 + /* prepare command */
758 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLEAR_IRQ_STATUS,
759 + cmd_flags,
760 + token);
761 + DPDMUX_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status);
762 +
763 + /* send command to mc*/
764 + return mc_send_command(mc_io, &cmd);
765 +}
766 +
767 +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
768 + uint32_t cmd_flags,
769 + uint16_t token,
770 + struct dpdmux_attr *attr)
771 +{
772 + struct mc_command cmd = { 0 };
773 + int err;
774 +
775 + /* prepare command */
776 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_ATTR,
777 + cmd_flags,
778 + token);
779 +
780 + /* send command to mc*/
781 + err = mc_send_command(mc_io, &cmd);
782 + if (err)
783 + return err;
784 +
785 + /* retrieve response parameters */
786 + DPDMUX_RSP_GET_ATTR(cmd, attr);
787 +
788 + return 0;
789 +}
790 +
791 +int dpdmux_ul_set_max_frame_length(struct fsl_mc_io *mc_io,
792 + uint32_t cmd_flags,
793 + uint16_t token,
794 + uint16_t max_frame_length)
795 +{
796 + struct mc_command cmd = { 0 };
797 +
798 + /* prepare command */
799 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_SET_MAX_FRAME_LENGTH,
800 + cmd_flags,
801 + token);
802 + DPDMUX_CMD_UL_SET_MAX_FRAME_LENGTH(cmd, max_frame_length);
803 +
804 + /* send command to mc*/
805 + return mc_send_command(mc_io, &cmd);
806 +}
807 +
808 +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
809 + uint32_t cmd_flags,
810 + uint16_t token)
811 +{
812 + struct mc_command cmd = { 0 };
813 +
814 + /* prepare command */
815 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_RESET_COUNTERS,
816 + cmd_flags,
817 + token);
818 +
819 + /* send command to mc*/
820 + return mc_send_command(mc_io, &cmd);
821 +}
822 +
823 +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
824 + uint32_t cmd_flags,
825 + uint16_t token,
826 + uint16_t if_id,
827 + const struct dpdmux_accepted_frames *cfg)
828 +{
829 + struct mc_command cmd = { 0 };
830 +
831 + /* prepare command */
832 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES,
833 + cmd_flags,
834 + token);
835 + DPDMUX_CMD_IF_SET_ACCEPTED_FRAMES(cmd, if_id, cfg);
836 +
837 + /* send command to mc*/
838 + return mc_send_command(mc_io, &cmd);
839 +}
840 +
841 +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
842 + uint32_t cmd_flags,
843 + uint16_t token,
844 + uint16_t if_id,
845 + struct dpdmux_if_attr *attr)
846 +{
847 + struct mc_command cmd = { 0 };
848 + int err;
849 +
850 + /* prepare command */
851 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_ATTR,
852 + cmd_flags,
853 + token);
854 + DPDMUX_CMD_IF_GET_ATTR(cmd, if_id);
855 +
856 + /* send command to mc*/
857 + err = mc_send_command(mc_io, &cmd);
858 + if (err)
859 + return err;
860 +
861 + /* retrieve response parameters */
862 + DPDMUX_RSP_IF_GET_ATTR(cmd, attr);
863 +
864 + return 0;
865 +}
866 +
867 +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
868 + uint32_t cmd_flags,
869 + uint16_t token,
870 + uint16_t if_id,
871 + const struct dpdmux_l2_rule *rule)
872 +{
873 + struct mc_command cmd = { 0 };
874 +
875 + /* prepare command */
876 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_REMOVE_L2_RULE,
877 + cmd_flags,
878 + token);
879 + DPDMUX_CMD_IF_REMOVE_L2_RULE(cmd, if_id, rule);
880 +
881 + /* send command to mc*/
882 + return mc_send_command(mc_io, &cmd);
883 +}
884 +
885 +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
886 + uint32_t cmd_flags,
887 + uint16_t token,
888 + uint16_t if_id,
889 + const struct dpdmux_l2_rule *rule)
890 +{
891 + struct mc_command cmd = { 0 };
892 +
893 + /* prepare command */
894 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ADD_L2_RULE,
895 + cmd_flags,
896 + token);
897 + DPDMUX_CMD_IF_ADD_L2_RULE(cmd, if_id, rule);
898 +
899 + /* send command to mc*/
900 + return mc_send_command(mc_io, &cmd);
901 +}
902 +
903 +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
904 + uint32_t cmd_flags,
905 + uint16_t token,
906 + uint16_t if_id,
907 + enum dpdmux_counter_type counter_type,
908 + uint64_t *counter)
909 +{
910 + struct mc_command cmd = { 0 };
911 + int err;
912 +
913 + /* prepare command */
914 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_COUNTER,
915 + cmd_flags,
916 + token);
917 + DPDMUX_CMD_IF_GET_COUNTER(cmd, if_id, counter_type);
918 +
919 + /* send command to mc*/
920 + err = mc_send_command(mc_io, &cmd);
921 + if (err)
922 + return err;
923 +
924 + /* retrieve response parameters */
925 + DPDMUX_RSP_IF_GET_COUNTER(cmd, *counter);
926 +
927 + return 0;
928 +}
929 +
930 +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
931 + uint32_t cmd_flags,
932 + uint16_t token,
933 + uint16_t if_id,
934 + struct dpdmux_link_cfg *cfg)
935 +{
936 + struct mc_command cmd = { 0 };
937 +
938 + /* prepare command */
939 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_LINK_CFG,
940 + cmd_flags,
941 + token);
942 + DPDMUX_CMD_IF_SET_LINK_CFG(cmd, if_id, cfg);
943 +
944 + /* send command to mc*/
945 + return mc_send_command(mc_io, &cmd);
946 +}
947 +
948 +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
949 + uint32_t cmd_flags,
950 + uint16_t token,
951 + uint16_t if_id,
952 + struct dpdmux_link_state *state)
953 +{
954 + struct mc_command cmd = { 0 };
955 + int err;
956 +
957 + /* prepare command */
958 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_LINK_STATE,
959 + cmd_flags,
960 + token);
961 + DPDMUX_CMD_IF_GET_LINK_STATE(cmd, if_id);
962 +
963 + /* send command to mc*/
964 + err = mc_send_command(mc_io, &cmd);
965 + if (err)
966 + return err;
967 +
968 + /* retrieve response parameters */
969 + DPDMUX_RSP_IF_GET_LINK_STATE(cmd, state);
970 +
971 + return 0;
972 +}
973 --- /dev/null
974 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.h
975 @@ -0,0 +1,724 @@
976 +/* Copyright 2013-2015 Freescale Semiconductor Inc.
977 + *
978 + * Redistribution and use in source and binary forms, with or without
979 + * modification, are permitted provided that the following conditions are met:
980 + * * Redistributions of source code must retain the above copyright
981 + * notice, this list of conditions and the following disclaimer.
982 + * * Redistributions in binary form must reproduce the above copyright
983 + * notice, this list of conditions and the following disclaimer in the
984 + * documentation and/or other materials provided with the distribution.
985 + * * Neither the name of the above-listed copyright holders nor the
986 + * names of any contributors may be used to endorse or promote products
987 + * derived from this software without specific prior written permission.
988 + *
989 + *
990 + * ALTERNATIVELY, this software may be distributed under the terms of the
991 + * GNU General Public License ("GPL") as published by the Free Software
992 + * Foundation, either version 2 of that License or (at your option) any
993 + * later version.
994 + *
995 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
996 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
997 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
998 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
999 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1000 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1001 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1002 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1003 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1004 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1005 + * POSSIBILITY OF SUCH DAMAGE.
1006 + */
1007 +#ifndef __FSL_DPDMUX_H
1008 +#define __FSL_DPDMUX_H
1009 +
1010 +#include "../../fsl-mc/include/net.h"
1011 +
1012 +struct fsl_mc_io;
1013 +
1014 +/* Data Path Demux API
1015 + * Contains API for handling DPDMUX topology and functionality
1016 + */
1017 +
1018 +/**
1019 + * dpdmux_open() - Open a control session for the specified object
1020 + * @mc_io: Pointer to MC portal's I/O object
1021 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1022 + * @dpdmux_id: DPDMUX unique ID
1023 + * @token: Returned token; use in subsequent API calls
1024 + *
1025 + * This function can be used to open a control session for an
1026 + * already created object; an object may have been declared in
1027 + * the DPL or by calling the dpdmux_create() function.
1028 + * This function returns a unique authentication token,
1029 + * associated with the specific object ID and the specific MC
1030 + * portal; this token must be used in all subsequent commands for
1031 + * this specific object.
1032 + *
1033 + * Return: '0' on Success; Error code otherwise.
1034 + */
1035 +int dpdmux_open(struct fsl_mc_io *mc_io,
1036 + uint32_t cmd_flags,
1037 + int dpdmux_id,
1038 + uint16_t *token);
1039 +
1040 +/**
1041 + * dpdmux_close() - Close the control session of the object
1042 + * @mc_io: Pointer to MC portal's I/O object
1043 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1044 + * @token: Token of DPDMUX object
1045 + *
1046 + * After this function is called, no further operations are
1047 + * allowed on the object without opening a new control session.
1048 + *
1049 + * Return: '0' on Success; Error code otherwise.
1050 + */
1051 +int dpdmux_close(struct fsl_mc_io *mc_io,
1052 + uint32_t cmd_flags,
1053 + uint16_t token);
1054 +
1055 +/**
1056 + * DPDMUX general options
1057 + */
1058 +
1059 +/**
1060 + * Enable bridging between internal interfaces
1061 + */
1062 +#define DPDMUX_OPT_BRIDGE_EN 0x0000000000000002ULL
1063 +
1064 +#define DPDMUX_IRQ_INDEX_IF 0x0000
1065 +#define DPDMUX_IRQ_INDEX 0x0001
1066 +
1067 +/**
1068 + * IRQ event - Indicates that the link state changed
1069 + */
1070 +#define DPDMUX_IRQ_EVENT_LINK_CHANGED 0x0001
1071 +
1072 +/**
1073 + * enum dpdmux_manip - DPDMUX manipulation operations
1074 + * @DPDMUX_MANIP_NONE: No manipulation on frames
1075 + * @DPDMUX_MANIP_ADD_REMOVE_S_VLAN: Add S-VLAN on egress, remove it on ingress
1076 + */
1077 +enum dpdmux_manip {
1078 + DPDMUX_MANIP_NONE = 0x0,
1079 + DPDMUX_MANIP_ADD_REMOVE_S_VLAN = 0x1
1080 +};
1081 +
1082 +/**
1083 + * enum dpdmux_method - DPDMUX method options
1084 + * @DPDMUX_METHOD_NONE: no DPDMUX method
1085 + * @DPDMUX_METHOD_C_VLAN_MAC: DPDMUX based on C-VLAN and MAC address
1086 + * @DPDMUX_METHOD_MAC: DPDMUX based on MAC address
1087 + * @DPDMUX_METHOD_C_VLAN: DPDMUX based on C-VLAN
1088 + * @DPDMUX_METHOD_S_VLAN: DPDMUX based on S-VLAN
1089 + */
1090 +enum dpdmux_method {
1091 + DPDMUX_METHOD_NONE = 0x0,
1092 + DPDMUX_METHOD_C_VLAN_MAC = 0x1,
1093 + DPDMUX_METHOD_MAC = 0x2,
1094 + DPDMUX_METHOD_C_VLAN = 0x3,
1095 + DPDMUX_METHOD_S_VLAN = 0x4
1096 +};
1097 +
1098 +/**
1099 + * struct dpdmux_cfg - DPDMUX configuration parameters
1100 + * @method: Defines the operation method for the DPDMUX address table
1101 + * @manip: Required manipulation operation
1102 + * @num_ifs: Number of interfaces (excluding the uplink interface)
1103 + * @adv: Advanced parameters; default is all zeros;
1104 + * use this structure to change default settings
1105 + */
1106 +struct dpdmux_cfg {
1107 + enum dpdmux_method method;
1108 + enum dpdmux_manip manip;
1109 + uint16_t num_ifs;
1110 + /**
1111 + * struct adv - Advanced parameters
1112 + * @options: DPDMUX options - combination of 'DPDMUX_OPT_<X>' flags
1113 + * @max_dmat_entries: Maximum entries in DPDMUX address table
1114 + * 0 - indicates default: 64 entries per interface.
1115 + * @max_mc_groups: Number of multicast groups in DPDMUX table
1116 + * 0 - indicates default: 32 multicast groups
1117 + * @max_vlan_ids: max vlan ids allowed in the system -
1118 + * relevant only case of working in mac+vlan method.
1119 + * 0 - indicates default 16 vlan ids.
1120 + */
1121 + struct {
1122 + uint64_t options;
1123 + uint16_t max_dmat_entries;
1124 + uint16_t max_mc_groups;
1125 + uint16_t max_vlan_ids;
1126 + } adv;
1127 +};
1128 +
1129 +/**
1130 + * dpdmux_create() - Create the DPDMUX object
1131 + * @mc_io: Pointer to MC portal's I/O object
1132 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1133 + * @cfg: Configuration structure
1134 + * @token: Returned token; use in subsequent API calls
1135 + *
1136 + * Create the DPDMUX object, allocate required resources and
1137 + * perform required initialization.
1138 + *
1139 + * The object can be created either by declaring it in the
1140 + * DPL file, or by calling this function.
1141 + *
1142 + * This function returns a unique authentication token,
1143 + * associated with the specific object ID and the specific MC
1144 + * portal; this token must be used in all subsequent calls to
1145 + * this specific object. For objects that are created using the
1146 + * DPL file, call dpdmux_open() function to get an authentication
1147 + * token first.
1148 + *
1149 + * Return: '0' on Success; Error code otherwise.
1150 + */
1151 +int dpdmux_create(struct fsl_mc_io *mc_io,
1152 + uint32_t cmd_flags,
1153 + const struct dpdmux_cfg *cfg,
1154 + uint16_t *token);
1155 +
1156 +/**
1157 + * dpdmux_destroy() - Destroy the DPDMUX object and release all its resources.
1158 + * @mc_io: Pointer to MC portal's I/O object
1159 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1160 + * @token: Token of DPDMUX object
1161 + *
1162 + * Return: '0' on Success; error code otherwise.
1163 + */
1164 +int dpdmux_destroy(struct fsl_mc_io *mc_io,
1165 + uint32_t cmd_flags,
1166 + uint16_t token);
1167 +
1168 +/**
1169 + * dpdmux_enable() - Enable DPDMUX functionality
1170 + * @mc_io: Pointer to MC portal's I/O object
1171 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1172 + * @token: Token of DPDMUX object
1173 + *
1174 + * Return: '0' on Success; Error code otherwise.
1175 + */
1176 +int dpdmux_enable(struct fsl_mc_io *mc_io,
1177 + uint32_t cmd_flags,
1178 + uint16_t token);
1179 +
1180 +/**
1181 + * dpdmux_disable() - Disable DPDMUX functionality
1182 + * @mc_io: Pointer to MC portal's I/O object
1183 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1184 + * @token: Token of DPDMUX object
1185 + *
1186 + * Return: '0' on Success; Error code otherwise.
1187 + */
1188 +int dpdmux_disable(struct fsl_mc_io *mc_io,
1189 + uint32_t cmd_flags,
1190 + uint16_t token);
1191 +
1192 +/**
1193 + * dpdmux_is_enabled() - Check if the DPDMUX is enabled.
1194 + * @mc_io: Pointer to MC portal's I/O object
1195 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1196 + * @token: Token of DPDMUX object
1197 + * @en: Returns '1' if object is enabled; '0' otherwise
1198 + *
1199 + * Return: '0' on Success; Error code otherwise.
1200 + */
1201 +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
1202 + uint32_t cmd_flags,
1203 + uint16_t token,
1204 + int *en);
1205 +
1206 +/**
1207 + * dpdmux_reset() - Reset the DPDMUX, returns the object to initial state.
1208 + * @mc_io: Pointer to MC portal's I/O object
1209 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1210 + * @token: Token of DPDMUX object
1211 + *
1212 + * Return: '0' on Success; Error code otherwise.
1213 + */
1214 +int dpdmux_reset(struct fsl_mc_io *mc_io,
1215 + uint32_t cmd_flags,
1216 + uint16_t token);
1217 +
1218 +/**
1219 + * struct dpdmux_irq_cfg - IRQ configuration
1220 + * @addr: Address that must be written to signal a message-based interrupt
1221 + * @val: Value to write into irq_addr address
1222 + * @irq_num: A user defined number associated with this IRQ
1223 + */
1224 +struct dpdmux_irq_cfg {
1225 + uint64_t addr;
1226 + uint32_t val;
1227 + int irq_num;
1228 +};
1229 +
1230 +/**
1231 + * dpdmux_set_irq() - Set IRQ information for the DPDMUX to trigger an interrupt.
1232 + * @mc_io: Pointer to MC portal's I/O object
1233 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1234 + * @token: Token of DPDMUX object
1235 + * @irq_index: Identifies the interrupt index to configure
1236 + * @irq_cfg: IRQ configuration
1237 + *
1238 + * Return: '0' on Success; Error code otherwise.
1239 + */
1240 +int dpdmux_set_irq(struct fsl_mc_io *mc_io,
1241 + uint32_t cmd_flags,
1242 + uint16_t token,
1243 + uint8_t irq_index,
1244 + struct dpdmux_irq_cfg *irq_cfg);
1245 +
1246 +/**
1247 + * dpdmux_get_irq() - Get IRQ information from the DPDMUX.
1248 + * @mc_io: Pointer to MC portal's I/O object
1249 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1250 + * @token: Token of DPDMUX object
1251 + * @irq_index: The interrupt index to configure
1252 + * @type: Interrupt type: 0 represents message interrupt
1253 + * type (both irq_addr and irq_val are valid)
1254 + * @irq_cfg: IRQ attributes
1255 + *
1256 + * Return: '0' on Success; Error code otherwise.
1257 + */
1258 +int dpdmux_get_irq(struct fsl_mc_io *mc_io,
1259 + uint32_t cmd_flags,
1260 + uint16_t token,
1261 + uint8_t irq_index,
1262 + int *type,
1263 + struct dpdmux_irq_cfg *irq_cfg);
1264 +
1265 +/**
1266 + * dpdmux_set_irq_enable() - Set overall interrupt state.
1267 + * @mc_io: Pointer to MC portal's I/O object
1268 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1269 + * @token: Token of DPDMUX object
1270 + * @irq_index: The interrupt index to configure
1271 + * @en: Interrupt state - enable = 1, disable = 0
1272 + *
1273 + * Allows GPP software to control when interrupts are generated.
1274 + * Each interrupt can have up to 32 causes. The enable/disable control's the
1275 + * overall interrupt state. if the interrupt is disabled no causes will cause
1276 + * an interrupt.
1277 + *
1278 + * Return: '0' on Success; Error code otherwise.
1279 + */
1280 +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
1281 + uint32_t cmd_flags,
1282 + uint16_t token,
1283 + uint8_t irq_index,
1284 + uint8_t en);
1285 +
1286 +/**
1287 + * dpdmux_get_irq_enable() - Get overall interrupt state.
1288 + * @mc_io: Pointer to MC portal's I/O object
1289 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1290 + * @token: Token of DPDMUX object
1291 + * @irq_index: The interrupt index to configure
1292 + * @en: Returned interrupt state - enable = 1, disable = 0
1293 + *
1294 + * Return: '0' on Success; Error code otherwise.
1295 + */
1296 +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
1297 + uint32_t cmd_flags,
1298 + uint16_t token,
1299 + uint8_t irq_index,
1300 + uint8_t *en);
1301 +
1302 +/**
1303 + * dpdmux_set_irq_mask() - Set interrupt mask.
1304 + * @mc_io: Pointer to MC portal's I/O object
1305 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1306 + * @token: Token of DPDMUX object
1307 + * @irq_index: The interrupt index to configure
1308 + * @mask: event mask to trigger interrupt;
1309 + * each bit:
1310 + * 0 = ignore event
1311 + * 1 = consider event for asserting IRQ
1312 + *
1313 + * Every interrupt can have up to 32 causes and the interrupt model supports
1314 + * masking/unmasking each cause independently
1315 + *
1316 + * Return: '0' on Success; Error code otherwise.
1317 + */
1318 +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
1319 + uint32_t cmd_flags,
1320 + uint16_t token,
1321 + uint8_t irq_index,
1322 + uint32_t mask);
1323 +
1324 +/**
1325 + * dpdmux_get_irq_mask() - Get interrupt mask.
1326 + * @mc_io: Pointer to MC portal's I/O object
1327 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1328 + * @token: Token of DPDMUX object
1329 + * @irq_index: The interrupt index to configure
1330 + * @mask: Returned event mask to trigger interrupt
1331 + *
1332 + * Every interrupt can have up to 32 causes and the interrupt model supports
1333 + * masking/unmasking each cause independently
1334 + *
1335 + * Return: '0' on Success; Error code otherwise.
1336 + */
1337 +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
1338 + uint32_t cmd_flags,
1339 + uint16_t token,
1340 + uint8_t irq_index,
1341 + uint32_t *mask);
1342 +
1343 +/**
1344 + * dpdmux_get_irq_status() - Get the current status of any pending interrupts.
1345 + * @mc_io: Pointer to MC portal's I/O object
1346 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1347 + * @token: Token of DPDMUX object
1348 + * @irq_index: The interrupt index to configure
1349 + * @status: Returned interrupts status - one bit per cause:
1350 + * 0 = no interrupt pending
1351 + * 1 = interrupt pending
1352 + *
1353 + * Return: '0' on Success; Error code otherwise.
1354 + */
1355 +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
1356 + uint32_t cmd_flags,
1357 + uint16_t token,
1358 + uint8_t irq_index,
1359 + uint32_t *status);
1360 +
1361 +/**
1362 + * dpdmux_clear_irq_status() - Clear a pending interrupt's status
1363 + * @mc_io: Pointer to MC portal's I/O object
1364 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1365 + * @token: Token of DPDMUX object
1366 + * @irq_index: The interrupt index to configure
1367 + * @status: bits to clear (W1C) - one bit per cause:
1368 + * 0 = don't change
1369 + * 1 = clear status bit
1370 + *
1371 + * Return: '0' on Success; Error code otherwise.
1372 + */
1373 +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
1374 + uint32_t cmd_flags,
1375 + uint16_t token,
1376 + uint8_t irq_index,
1377 + uint32_t status);
1378 +
1379 +/**
1380 + * struct dpdmux_attr - Structure representing DPDMUX attributes
1381 + * @id: DPDMUX object ID
1382 + * @version: DPDMUX version
1383 + * @options: Configuration options (bitmap)
1384 + * @method: DPDMUX address table method
1385 + * @manip: DPDMUX manipulation type
1386 + * @num_ifs: Number of interfaces (excluding the uplink interface)
1387 + * @mem_size: DPDMUX frame storage memory size
1388 + */
1389 +struct dpdmux_attr {
1390 + int id;
1391 + /**
1392 + * struct version - DPDMUX version
1393 + * @major: DPDMUX major version
1394 + * @minor: DPDMUX minor version
1395 + */
1396 + struct {
1397 + uint16_t major;
1398 + uint16_t minor;
1399 + } version;
1400 + uint64_t options;
1401 + enum dpdmux_method method;
1402 + enum dpdmux_manip manip;
1403 + uint16_t num_ifs;
1404 + uint16_t mem_size;
1405 +};
1406 +
1407 +/**
1408 + * dpdmux_get_attributes() - Retrieve DPDMUX attributes
1409 + * @mc_io: Pointer to MC portal's I/O object
1410 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1411 + * @token: Token of DPDMUX object
1412 + * @attr: Returned object's attributes
1413 + *
1414 + * Return: '0' on Success; Error code otherwise.
1415 + */
1416 +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
1417 + uint32_t cmd_flags,
1418 + uint16_t token,
1419 + struct dpdmux_attr *attr);
1420 +
1421 +/**
1422 + * dpdmux_ul_set_max_frame_length() - Set the maximum frame length in DPDMUX
1423 + * @mc_io: Pointer to MC portal's I/O object
1424 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1425 + * @token: Token of DPDMUX object
1426 + * @max_frame_length: The required maximum frame length
1427 + *
1428 + * Return: '0' on Success; Error code otherwise.
1429 + */
1430 +int dpdmux_ul_set_max_frame_length(struct fsl_mc_io *mc_io,
1431 + uint32_t cmd_flags,
1432 + uint16_t token,
1433 + uint16_t max_frame_length);
1434 +
1435 +/**
1436 + * enum dpdmux_counter_type - Counter types
1437 + * @DPDMUX_CNT_ING_FRAME: Counts ingress frames
1438 + * @DPDMUX_CNT_ING_BYTE: Counts ingress bytes
1439 + * @DPDMUX_CNT_ING_FLTR_FRAME: Counts filtered ingress frames
1440 + * @DPDMUX_CNT_ING_FRAME_DISCARD: Counts discarded ingress frames
1441 + * @DPDMUX_CNT_ING_MCAST_FRAME: Counts ingress multicast frames
1442 + * @DPDMUX_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes
1443 + * @DPDMUX_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames
1444 + * @DPDMUX_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes
1445 + * @DPDMUX_CNT_EGR_FRAME: Counts egress frames
1446 + * @DPDMUX_CNT_EGR_BYTE: Counts egress bytes
1447 + * @DPDMUX_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames
1448 + */
1449 +enum dpdmux_counter_type {
1450 + DPDMUX_CNT_ING_FRAME = 0x0,
1451 + DPDMUX_CNT_ING_BYTE = 0x1,
1452 + DPDMUX_CNT_ING_FLTR_FRAME = 0x2,
1453 + DPDMUX_CNT_ING_FRAME_DISCARD = 0x3,
1454 + DPDMUX_CNT_ING_MCAST_FRAME = 0x4,
1455 + DPDMUX_CNT_ING_MCAST_BYTE = 0x5,
1456 + DPDMUX_CNT_ING_BCAST_FRAME = 0x6,
1457 + DPDMUX_CNT_ING_BCAST_BYTES = 0x7,
1458 + DPDMUX_CNT_EGR_FRAME = 0x8,
1459 + DPDMUX_CNT_EGR_BYTE = 0x9,
1460 + DPDMUX_CNT_EGR_FRAME_DISCARD = 0xa
1461 +};
1462 +
1463 +/**
1464 + * enum dpdmux_accepted_frames_type - DPDMUX frame types
1465 + * @DPDMUX_ADMIT_ALL: The device accepts VLAN tagged, untagged and
1466 + * priority-tagged frames
1467 + * @DPDMUX_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or
1468 + * priority-tagged frames that are received on this
1469 + * interface
1470 + * @DPDMUX_ADMIT_ONLY_UNTAGGED: Untagged frames or priority-tagged frames
1471 + * received on this interface are accepted
1472 + */
1473 +enum dpdmux_accepted_frames_type {
1474 + DPDMUX_ADMIT_ALL = 0,
1475 + DPDMUX_ADMIT_ONLY_VLAN_TAGGED = 1,
1476 + DPDMUX_ADMIT_ONLY_UNTAGGED = 2
1477 +};
1478 +
1479 +/**
1480 + * enum dpdmux_action - DPDMUX action for un-accepted frames
1481 + * @DPDMUX_ACTION_DROP: Drop un-accepted frames
1482 + * @DPDMUX_ACTION_REDIRECT_TO_CTRL: Redirect un-accepted frames to the
1483 + * control interface
1484 + */
1485 +enum dpdmux_action {
1486 + DPDMUX_ACTION_DROP = 0,
1487 + DPDMUX_ACTION_REDIRECT_TO_CTRL = 1
1488 +};
1489 +
1490 +/**
1491 + * struct dpdmux_accepted_frames - Frame types configuration
1492 + * @type: Defines ingress accepted frames
1493 + * @unaccept_act: Defines action on frames not accepted
1494 + */
1495 +struct dpdmux_accepted_frames {
1496 + enum dpdmux_accepted_frames_type type;
1497 + enum dpdmux_action unaccept_act;
1498 +};
1499 +
1500 +/**
1501 + * dpdmux_if_set_accepted_frames() - Set the accepted frame types
1502 + * @mc_io: Pointer to MC portal's I/O object
1503 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1504 + * @token: Token of DPDMUX object
1505 + * @if_id: Interface ID (0 for uplink, or 1-num_ifs);
1506 + * @cfg: Frame types configuration
1507 + *
1508 + * if 'DPDMUX_ADMIT_ONLY_VLAN_TAGGED' is set - untagged frames or
1509 + * priority-tagged frames are discarded.
1510 + * if 'DPDMUX_ADMIT_ONLY_UNTAGGED' is set - untagged frames or
1511 + * priority-tagged frames are accepted.
1512 + * if 'DPDMUX_ADMIT_ALL' is set (default mode) - all VLAN tagged,
1513 + * untagged and priority-tagged frame are accepted;
1514 + *
1515 + * Return: '0' on Success; Error code otherwise.
1516 + */
1517 +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
1518 + uint32_t cmd_flags,
1519 + uint16_t token,
1520 + uint16_t if_id,
1521 + const struct dpdmux_accepted_frames *cfg);
1522 +
1523 +/**
1524 + * struct dpdmux_if_attr - Structure representing frame types configuration
1525 + * @rate: Configured interface rate (in bits per second)
1526 + * @enabled: Indicates if interface is enabled
1527 + * @accept_frame_type: Indicates type of accepted frames for the interface
1528 + */
1529 +struct dpdmux_if_attr {
1530 + uint32_t rate;
1531 + int enabled;
1532 + enum dpdmux_accepted_frames_type accept_frame_type;
1533 +};
1534 +
1535 +/**
1536 + * dpdmux_if_get_attributes() - Obtain DPDMUX interface attributes
1537 + * @mc_io: Pointer to MC portal's I/O object
1538 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1539 + * @token: Token of DPDMUX object
1540 + * @if_id: Interface ID (0 for uplink, or 1-num_ifs);
1541 + * @attr: Interface attributes
1542 + *
1543 + * Return: '0' on Success; Error code otherwise.
1544 + */
1545 +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
1546 + uint32_t cmd_flags,
1547 + uint16_t token,
1548 + uint16_t if_id,
1549 + struct dpdmux_if_attr *attr);
1550 +
1551 +/**
1552 + * struct dpdmux_l2_rule - Structure representing L2 rule
1553 + * @mac_addr: MAC address
1554 + * @vlan_id: VLAN ID
1555 + */
1556 +struct dpdmux_l2_rule {
1557 + uint8_t mac_addr[6];
1558 + uint16_t vlan_id;
1559 +};
1560 +
1561 +/**
1562 + * dpdmux_if_remove_l2_rule() - Remove L2 rule from DPDMUX table
1563 + * @mc_io: Pointer to MC portal's I/O object
1564 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1565 + * @token: Token of DPDMUX object
1566 + * @if_id: Destination interface ID
1567 + * @rule: L2 rule
1568 + *
1569 + * Function removes a L2 rule from DPDMUX table
1570 + * or adds an interface to an existing multicast address
1571 + *
1572 + * Return: '0' on Success; Error code otherwise.
1573 + */
1574 +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
1575 + uint32_t cmd_flags,
1576 + uint16_t token,
1577 + uint16_t if_id,
1578 + const struct dpdmux_l2_rule *rule);
1579 +
1580 +/**
1581 + * dpdmux_if_add_l2_rule() - Add L2 rule into DPDMUX table
1582 + * @mc_io: Pointer to MC portal's I/O object
1583 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1584 + * @token: Token of DPDMUX object
1585 + * @if_id: Destination interface ID
1586 + * @rule: L2 rule
1587 + *
1588 + * Function adds a L2 rule into DPDMUX table
1589 + * or adds an interface to an existing multicast address
1590 + *
1591 + * Return: '0' on Success; Error code otherwise.
1592 + */
1593 +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
1594 + uint32_t cmd_flags,
1595 + uint16_t token,
1596 + uint16_t if_id,
1597 + const struct dpdmux_l2_rule *rule);
1598 +
1599 +/**
1600 +* dpdmux_if_get_counter() - Functions obtains specific counter of an interface
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 DPDMUX object
1604 +* @if_id: Interface Id
1605 +* @counter_type: counter type
1606 +* @counter: Returned specific counter information
1607 +*
1608 +* Return: '0' on Success; Error code otherwise.
1609 +*/
1610 +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
1611 + uint32_t cmd_flags,
1612 + uint16_t token,
1613 + uint16_t if_id,
1614 + enum dpdmux_counter_type counter_type,
1615 + uint64_t *counter);
1616 +
1617 +/**
1618 +* dpdmux_ul_reset_counters() - Function resets the uplink counter
1619 +* @mc_io: Pointer to MC portal's I/O object
1620 +* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1621 +* @token: Token of DPDMUX object
1622 +*
1623 +* Return: '0' on Success; Error code otherwise.
1624 +*/
1625 +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
1626 + uint32_t cmd_flags,
1627 + uint16_t token);
1628 +
1629 +/**
1630 + * Enable auto-negotiation
1631 + */
1632 +#define DPDMUX_LINK_OPT_AUTONEG 0x0000000000000001ULL
1633 +/**
1634 + * Enable half-duplex mode
1635 + */
1636 +#define DPDMUX_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL
1637 +/**
1638 + * Enable pause frames
1639 + */
1640 +#define DPDMUX_LINK_OPT_PAUSE 0x0000000000000004ULL
1641 +/**
1642 + * Enable a-symmetric pause frames
1643 + */
1644 +#define DPDMUX_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
1645 +
1646 +/**
1647 + * struct dpdmux_link_cfg - Structure representing DPDMUX link configuration
1648 + * @rate: Rate
1649 + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
1650 + */
1651 +struct dpdmux_link_cfg {
1652 + uint32_t rate;
1653 + uint64_t options;
1654 +};
1655 +
1656 +/**
1657 + * dpdmux_if_set_link_cfg() - set the link configuration.
1658 + * @mc_io: Pointer to MC portal's I/O object
1659 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1660 + * @token: Token of DPSW object
1661 + * @if_id: interface id
1662 + * @cfg: Link configuration
1663 + *
1664 + * Return: '0' on Success; Error code otherwise.
1665 + */
1666 +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
1667 + uint32_t cmd_flags,
1668 + uint16_t token,
1669 + uint16_t if_id,
1670 + struct dpdmux_link_cfg *cfg);
1671 +/**
1672 + * struct dpdmux_link_state - Structure representing DPDMUX link state
1673 + * @rate: Rate
1674 + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
1675 + * @up: 0 - down, 1 - up
1676 + */
1677 +struct dpdmux_link_state {
1678 + uint32_t rate;
1679 + uint64_t options;
1680 + int up;
1681 +};
1682 +
1683 +/**
1684 + * dpdmux_if_get_link_state - Return the link state
1685 + * @mc_io: Pointer to MC portal's I/O object
1686 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1687 + * @token: Token of DPSW object
1688 + * @if_id: interface id
1689 + * @state: link state
1690 + *
1691 + * @returns '0' on Success; Error code otherwise.
1692 + */
1693 +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
1694 + uint32_t cmd_flags,
1695 + uint16_t token,
1696 + uint16_t if_id,
1697 + struct dpdmux_link_state *state);
1698 +
1699 +#endif /* __FSL_DPDMUX_H */
1700 --- /dev/null
1701 +++ b/drivers/staging/fsl-dpaa2/evb/evb.c
1702 @@ -0,0 +1,1216 @@
1703 +/* Copyright 2015 Freescale Semiconductor Inc.
1704 + *
1705 + * Redistribution and use in source and binary forms, with or without
1706 + * modification, are permitted provided that the following conditions are met:
1707 + * * Redistributions of source code must retain the above copyright
1708 + * notice, this list of conditions and the following disclaimer.
1709 + * * Redistributions in binary form must reproduce the above copyright
1710 + * notice, this list of conditions and the following disclaimer in the
1711 + * documentation and/or other materials provided with the distribution.
1712 + * * Neither the name of Freescale Semiconductor nor the
1713 + * names of its contributors may be used to endorse or promote products
1714 + * derived from this software without specific prior written permission.
1715 + *
1716 + *
1717 + * ALTERNATIVELY, this software may be distributed under the terms of the
1718 + * GNU General Public License ("GPL") as published by the Free Software
1719 + * Foundation, either version 2 of that License or (at your option) any
1720 + * later version.
1721 + *
1722 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
1723 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1724 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1725 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
1726 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1727 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1728 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1729 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1730 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1731 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1732 + */
1733 +#include <linux/module.h>
1734 +#include <linux/netdevice.h>
1735 +#include <linux/etherdevice.h>
1736 +#include <linux/rtnetlink.h>
1737 +#include <linux/if_vlan.h>
1738 +#include <linux/interrupt.h>
1739 +#include <linux/msi.h>
1740 +
1741 +#include <uapi/linux/if_bridge.h>
1742 +#include <net/netlink.h>
1743 +
1744 +#include "../../fsl-mc/include/mc.h"
1745 +
1746 +#include "dpdmux.h"
1747 +#include "dpdmux-cmd.h"
1748 +
1749 +/* IRQ index */
1750 +#define DPDMUX_MAX_IRQ_NUM 2
1751 +
1752 +/* MAX FRAME LENGTH (currently 10k) */
1753 +#define EVB_MAX_FRAME_LENGTH (10 * 1024)
1754 +/* MIN FRAME LENGTH (64 bytes + 4 bytes CRC) */
1755 +#define EVB_MIN_FRAME_LENGTH 68
1756 +
1757 +struct evb_port_priv {
1758 + struct net_device *netdev;
1759 + struct list_head list;
1760 + u16 port_index;
1761 + struct evb_priv *evb_priv;
1762 + u8 vlans[VLAN_VID_MASK+1];
1763 +};
1764 +
1765 +struct evb_priv {
1766 + /* keep first */
1767 + struct evb_port_priv uplink;
1768 +
1769 + struct fsl_mc_io *mc_io;
1770 + struct list_head port_list;
1771 + struct dpdmux_attr attr;
1772 + uint16_t mux_handle;
1773 + int dev_id;
1774 +};
1775 +
1776 +static int _evb_port_carrier_state_sync(struct net_device *netdev)
1777 +{
1778 + struct evb_port_priv *port_priv = netdev_priv(netdev);
1779 + struct dpdmux_link_state state;
1780 + int err;
1781 +
1782 + err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0,
1783 + port_priv->evb_priv->mux_handle,
1784 + port_priv->port_index, &state);
1785 + if (unlikely(err)) {
1786 + netdev_err(netdev, "dpdmux_if_get_link_state() err %d\n", err);
1787 + return err;
1788 + }
1789 +
1790 + WARN_ONCE(state.up > 1, "Garbage read into link_state");
1791 +
1792 + if (state.up)
1793 + netif_carrier_on(port_priv->netdev);
1794 + else
1795 + netif_carrier_off(port_priv->netdev);
1796 +
1797 + return 0;
1798 +}
1799 +
1800 +static int evb_port_open(struct net_device *netdev)
1801 +{
1802 + int err;
1803 +
1804 + /* FIXME: enable port when support added */
1805 +
1806 + err = _evb_port_carrier_state_sync(netdev);
1807 + if (err) {
1808 + netdev_err(netdev, "ethsw_port_carrier_state_sync err %d\n",
1809 + err);
1810 + return err;
1811 + }
1812 +
1813 + return 0;
1814 +}
1815 +
1816 +static netdev_tx_t evb_dropframe(struct sk_buff *skb, struct net_device *dev)
1817 +{
1818 + /* we don't support I/O for now, drop the frame */
1819 + dev_kfree_skb_any(skb);
1820 + return NETDEV_TX_OK;
1821 +}
1822 +
1823 +static int evb_links_state_update(struct evb_priv *priv)
1824 +{
1825 + struct evb_port_priv *port_priv;
1826 + struct list_head *pos;
1827 + int err;
1828 +
1829 + list_for_each(pos, &priv->port_list) {
1830 + port_priv = list_entry(pos, struct evb_port_priv, list);
1831 +
1832 + err = _evb_port_carrier_state_sync(port_priv->netdev);
1833 + if (err)
1834 + netdev_err(port_priv->netdev,
1835 + "_evb_port_carrier_state_sync err %d\n",
1836 + err);
1837 + }
1838 +
1839 + return 0;
1840 +}
1841 +
1842 +static irqreturn_t evb_irq0_handler(int irq_num, void *arg)
1843 +{
1844 + return IRQ_WAKE_THREAD;
1845 +}
1846 +
1847 +static irqreturn_t _evb_irq0_handler_thread(int irq_num, void *arg)
1848 +{
1849 + struct device *dev = (struct device *)arg;
1850 + struct fsl_mc_device *evb_dev = to_fsl_mc_device(dev);
1851 + struct net_device *netdev = dev_get_drvdata(dev);
1852 + struct evb_priv *priv = netdev_priv(netdev);
1853 + struct fsl_mc_io *io = priv->mc_io;
1854 + uint16_t token = priv->mux_handle;
1855 + int irq_index = DPDMUX_IRQ_INDEX_IF;
1856 + uint32_t status = 0, clear = 0;
1857 + int err;
1858 +
1859 + /* Sanity check */
1860 + if (WARN_ON(!evb_dev || !evb_dev->irqs || !evb_dev->irqs[irq_index]))
1861 + goto out;
1862 + if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != irq_num))
1863 + goto out;
1864 +
1865 + err = dpdmux_get_irq_status(io, 0, token, irq_index, &status);
1866 + if (unlikely(err)) {
1867 + netdev_err(netdev, "Can't get irq status (err %d)", err);
1868 + clear = 0xffffffff;
1869 + goto out;
1870 + }
1871 +
1872 + /* FIXME clear irq status */
1873 +
1874 + if (status & DPDMUX_IRQ_EVENT_LINK_CHANGED) {
1875 + clear |= DPDMUX_IRQ_EVENT_LINK_CHANGED;
1876 +
1877 + err = evb_links_state_update(priv);
1878 + if (unlikely(err))
1879 + goto out;
1880 + }
1881 +out:
1882 + err = dpdmux_clear_irq_status(io, 0, token, irq_index, clear);
1883 + if (unlikely(err))
1884 + netdev_err(netdev, "Can't clear irq status (err %d)", err);
1885 + return IRQ_HANDLED;
1886 +}
1887 +
1888 +static int evb_setup_irqs(struct fsl_mc_device *evb_dev)
1889 +{
1890 + struct device *dev = &evb_dev->dev;
1891 + struct net_device *netdev = dev_get_drvdata(dev);
1892 + struct evb_priv *priv = netdev_priv(netdev);
1893 + int err = 0;
1894 + struct fsl_mc_device_irq *irq;
1895 + const int irq_index = DPDMUX_IRQ_INDEX_IF;
1896 + uint32_t mask = ~0x0u; /* FIXME: unmask handled irqs */
1897 +
1898 + err = fsl_mc_allocate_irqs(evb_dev);
1899 + if (unlikely(err)) {
1900 + dev_err(dev, "MC irqs allocation failed\n");
1901 + return err;
1902 + }
1903 +
1904 + if (WARN_ON(evb_dev->obj_desc.irq_count != DPDMUX_MAX_IRQ_NUM)) {
1905 + err = -EINVAL;
1906 + goto free_irq;
1907 + }
1908 +
1909 + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
1910 + irq_index, 0);
1911 + if (unlikely(err)) {
1912 + dev_err(dev, "dpdmux_set_irq_enable err %d\n", err);
1913 + goto free_irq;
1914 + }
1915 +
1916 + irq = evb_dev->irqs[irq_index];
1917 +
1918 + err = devm_request_threaded_irq(dev, irq->msi_desc->irq,
1919 + evb_irq0_handler,
1920 + _evb_irq0_handler_thread,
1921 + IRQF_NO_SUSPEND | IRQF_ONESHOT,
1922 + dev_name(dev), dev);
1923 + if (unlikely(err)) {
1924 + dev_err(dev, "devm_request_threaded_irq(): %d", err);
1925 + goto free_irq;
1926 + }
1927 +
1928 + err = dpdmux_set_irq_mask(priv->mc_io, 0, priv->mux_handle,
1929 + irq_index, mask);
1930 + if (unlikely(err)) {
1931 + dev_err(dev, "dpdmux_set_irq_mask(): %d", err);
1932 + goto free_devm_irq;
1933 + }
1934 +
1935 + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
1936 + irq_index, 1);
1937 + if (unlikely(err)) {
1938 + dev_err(dev, "dpdmux_set_irq_enable(): %d", err);
1939 + goto free_devm_irq;
1940 + }
1941 +
1942 + return 0;
1943 +
1944 +free_devm_irq:
1945 + devm_free_irq(dev, irq->msi_desc->irq, dev);
1946 +free_irq:
1947 + fsl_mc_free_irqs(evb_dev);
1948 + return err;
1949 +}
1950 +
1951 +static void evb_teardown_irqs(struct fsl_mc_device *evb_dev)
1952 +{
1953 + struct device *dev = &evb_dev->dev;
1954 + struct net_device *netdev = dev_get_drvdata(dev);
1955 + struct evb_priv *priv = netdev_priv(netdev);
1956 +
1957 + dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
1958 + DPDMUX_IRQ_INDEX_IF, 0);
1959 +
1960 + devm_free_irq(dev,
1961 + evb_dev->irqs[DPDMUX_IRQ_INDEX_IF]->msi_desc->irq,
1962 + dev);
1963 + fsl_mc_free_irqs(evb_dev);
1964 +}
1965 +
1966 +static int evb_port_add_rule(struct net_device *netdev,
1967 + const unsigned char *addr, u16 vid)
1968 +{
1969 + struct evb_port_priv *port_priv = netdev_priv(netdev);
1970 + struct dpdmux_l2_rule rule = { .vlan_id = vid };
1971 + int err;
1972 +
1973 + if (addr)
1974 + ether_addr_copy(rule.mac_addr, addr);
1975 +
1976 + err = dpdmux_if_add_l2_rule(port_priv->evb_priv->mc_io,
1977 + 0,
1978 + port_priv->evb_priv->mux_handle,
1979 + port_priv->port_index, &rule);
1980 + if (unlikely(err))
1981 + netdev_err(netdev, "dpdmux_if_add_l2_rule err %d\n", err);
1982 + return err;
1983 +}
1984 +
1985 +static int evb_port_del_rule(struct net_device *netdev,
1986 + const unsigned char *addr, u16 vid)
1987 +{
1988 + struct evb_port_priv *port_priv = netdev_priv(netdev);
1989 + struct dpdmux_l2_rule rule = { .vlan_id = vid };
1990 + int err;
1991 +
1992 + if (addr)
1993 + ether_addr_copy(rule.mac_addr, addr);
1994 +
1995 + err = dpdmux_if_remove_l2_rule(port_priv->evb_priv->mc_io,
1996 + 0,
1997 + port_priv->evb_priv->mux_handle,
1998 + port_priv->port_index, &rule);
1999 + if (unlikely(err))
2000 + netdev_err(netdev, "dpdmux_if_remove_l2_rule err %d\n", err);
2001 + return err;
2002 +}
2003 +
2004 +static bool _lookup_address(struct net_device *netdev,
2005 + const unsigned char *addr)
2006 +{
2007 + struct netdev_hw_addr *ha;
2008 + struct netdev_hw_addr_list *list = (is_unicast_ether_addr(addr)) ?
2009 + &netdev->uc : &netdev->mc;
2010 +
2011 + netif_addr_lock_bh(netdev);
2012 + list_for_each_entry(ha, &list->list, list) {
2013 + if (ether_addr_equal(ha->addr, addr)) {
2014 + netif_addr_unlock_bh(netdev);
2015 + return true;
2016 + }
2017 + }
2018 + netif_addr_unlock_bh(netdev);
2019 + return false;
2020 +}
2021 +
2022 +static inline int evb_port_fdb_prep(struct nlattr *tb[],
2023 + struct net_device *netdev,
2024 + const unsigned char *addr, u16 *vid,
2025 + bool del)
2026 +{
2027 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2028 + struct evb_priv *evb_priv = port_priv->evb_priv;
2029 +
2030 + *vid = 0;
2031 +
2032 + if (evb_priv->attr.method != DPDMUX_METHOD_MAC &&
2033 + evb_priv->attr.method != DPDMUX_METHOD_C_VLAN_MAC) {
2034 + netdev_err(netdev,
2035 + "EVB mode does not support MAC classification\n");
2036 + return -EOPNOTSUPP;
2037 + }
2038 +
2039 + /* check if the address is configured on this port */
2040 + if (_lookup_address(netdev, addr)) {
2041 + if (!del)
2042 + return -EEXIST;
2043 + } else {
2044 + if (del)
2045 + return -ENOENT;
2046 + }
2047 +
2048 + if (tb[NDA_VLAN] && evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
2049 + if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
2050 + netdev_err(netdev, "invalid vlan size %d\n",
2051 + nla_len(tb[NDA_VLAN]));
2052 + return -EINVAL;
2053 + }
2054 +
2055 + *vid = nla_get_u16(tb[NDA_VLAN]);
2056 +
2057 + if (!*vid || *vid >= VLAN_VID_MASK) {
2058 + netdev_err(netdev, "invalid vid value 0x%04x\n", *vid);
2059 + return -EINVAL;
2060 + }
2061 + } else if (evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
2062 + netdev_err(netdev,
2063 + "EVB mode requires explicit VLAN configuration\n");
2064 + return -EINVAL;
2065 + } else if (tb[NDA_VLAN]) {
2066 + netdev_warn(netdev, "VLAN not supported, argument ignored\n");
2067 + }
2068 +
2069 + return 0;
2070 +}
2071 +
2072 +static int evb_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
2073 + struct net_device *netdev,
2074 + const unsigned char *addr, u16 vid, u16 flags)
2075 +{
2076 + u16 _vid;
2077 + int err;
2078 +
2079 + /* TODO: add replace support when added to iproute bridge */
2080 + if (!(flags & NLM_F_REQUEST)) {
2081 + netdev_err(netdev,
2082 + "evb_port_fdb_add unexpected flags value %08x\n",
2083 + flags);
2084 + return -EINVAL;
2085 + }
2086 +
2087 + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 0);
2088 + if (unlikely(err))
2089 + return err;
2090 +
2091 +
2092 + err = evb_port_add_rule(netdev, addr, _vid);
2093 + if (unlikely(err))
2094 + return err;
2095 +
2096 + if (is_unicast_ether_addr(addr)) {
2097 + err = dev_uc_add(netdev, addr);
2098 + if (unlikely(err)) {
2099 + netdev_err(netdev, "dev_uc_add err %d\n", err);
2100 + return err;
2101 + }
2102 + } else {
2103 + err = dev_mc_add(netdev, addr);
2104 + if (unlikely(err)) {
2105 + netdev_err(netdev, "dev_mc_add err %d\n", err);
2106 + return err;
2107 + }
2108 + }
2109 +
2110 + return 0;
2111 +}
2112 +
2113 +static int evb_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
2114 + struct net_device *netdev,
2115 + const unsigned char *addr, u16 vid)
2116 +{
2117 + u16 _vid;
2118 + int err;
2119 +
2120 + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 1);
2121 + if (unlikely(err))
2122 + return err;
2123 +
2124 + err = evb_port_del_rule(netdev, addr, _vid);
2125 + if (unlikely(err))
2126 + return err;
2127 +
2128 + if (is_unicast_ether_addr(addr)) {
2129 + err = dev_uc_del(netdev, addr);
2130 + if (unlikely(err)) {
2131 + netdev_err(netdev, "dev_uc_del err %d\n", err);
2132 + return err;
2133 + }
2134 + } else {
2135 + err = dev_mc_del(netdev, addr);
2136 + if (unlikely(err)) {
2137 + netdev_err(netdev, "dev_mc_del err %d\n", err);
2138 + return err;
2139 + }
2140 + }
2141 +
2142 + return 0;
2143 +}
2144 +
2145 +static int evb_change_mtu(struct net_device *netdev,
2146 + int mtu)
2147 +{
2148 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2149 + struct evb_priv *evb_priv = port_priv->evb_priv;
2150 + struct list_head *pos;
2151 + int err = 0;
2152 +
2153 + /* This operation is not permitted on downlinks */
2154 + if (port_priv->port_index > 0)
2155 + return -EPERM;
2156 +
2157 + if (mtu < EVB_MIN_FRAME_LENGTH || mtu > EVB_MAX_FRAME_LENGTH) {
2158 + netdev_err(netdev, "Invalid MTU %d. Valid range is: %d..%d\n",
2159 + mtu, EVB_MIN_FRAME_LENGTH, EVB_MAX_FRAME_LENGTH);
2160 + return -EINVAL;
2161 + }
2162 +
2163 + err = dpdmux_ul_set_max_frame_length(evb_priv->mc_io,
2164 + 0,
2165 + evb_priv->mux_handle,
2166 + (uint16_t)mtu);
2167 +
2168 + if (unlikely(err)) {
2169 + netdev_err(netdev, "dpdmux_ul_set_max_frame_length err %d\n",
2170 + err);
2171 + return err;
2172 + }
2173 +
2174 + /* Update the max frame length for downlinks */
2175 + list_for_each(pos, &evb_priv->port_list) {
2176 + port_priv = list_entry(pos, struct evb_port_priv, list);
2177 + port_priv->netdev->mtu = mtu;
2178 + }
2179 +
2180 + netdev->mtu = mtu;
2181 + return 0;
2182 +}
2183 +
2184 +static const struct nla_policy ifla_br_policy[IFLA_MAX+1] = {
2185 + [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 },
2186 + [IFLA_BRIDGE_MODE] = { .type = NLA_U16 },
2187 + [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
2188 + .len = sizeof(struct bridge_vlan_info), },
2189 +};
2190 +
2191 +static int evb_setlink_af_spec(struct net_device *netdev,
2192 + struct nlattr **tb)
2193 +{
2194 + struct bridge_vlan_info *vinfo;
2195 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2196 + int err = 0;
2197 +
2198 + if (!tb[IFLA_BRIDGE_VLAN_INFO]) {
2199 + netdev_err(netdev, "no VLAN INFO in nlmsg\n");
2200 + return -EOPNOTSUPP;
2201 + }
2202 +
2203 + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
2204 +
2205 + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
2206 + return -EINVAL;
2207 +
2208 + err = evb_port_add_rule(netdev, NULL, vinfo->vid);
2209 + if (unlikely(err))
2210 + return err;
2211 +
2212 + port_priv->vlans[vinfo->vid] = 1;
2213 +
2214 + return 0;
2215 +}
2216 +
2217 +static int evb_setlink(struct net_device *netdev,
2218 + struct nlmsghdr *nlh,
2219 + u16 flags)
2220 +{
2221 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2222 + struct evb_priv *evb_priv = port_priv->evb_priv;
2223 + struct nlattr *attr;
2224 + struct nlattr *tb[(IFLA_BRIDGE_MAX > IFLA_BRPORT_MAX) ?
2225 + IFLA_BRIDGE_MAX : IFLA_BRPORT_MAX+1];
2226 + int err = 0;
2227 +
2228 + if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
2229 + evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
2230 + netdev_err(netdev,
2231 + "EVB mode does not support VLAN only classification\n");
2232 + return -EOPNOTSUPP;
2233 + }
2234 +
2235 + attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2236 + if (attr) {
2237 + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr,
2238 + ifla_br_policy);
2239 + if (unlikely(err)) {
2240 + netdev_err(netdev,
2241 + "nla_parse_nested for br_policy err %d\n",
2242 + err);
2243 + return err;
2244 + }
2245 +
2246 + err = evb_setlink_af_spec(netdev, tb);
2247 + return err;
2248 + }
2249 +
2250 + netdev_err(netdev, "nlmsg_find_attr found no AF_SPEC\n");
2251 + return -EOPNOTSUPP;
2252 +}
2253 +
2254 +static int __nla_put_netdev(struct sk_buff *skb, struct net_device *netdev)
2255 +{
2256 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2257 + struct evb_priv *evb_priv = port_priv->evb_priv;
2258 + u8 operstate = netif_running(netdev) ?
2259 + netdev->operstate : IF_OPER_DOWN;
2260 + int iflink;
2261 + int err;
2262 +
2263 + err = nla_put_string(skb, IFLA_IFNAME, netdev->name);
2264 + if (unlikely(err))
2265 + goto nla_put_err;
2266 + err = nla_put_u32(skb, IFLA_MASTER, evb_priv->uplink.netdev->ifindex);
2267 + if (unlikely(err))
2268 + goto nla_put_err;
2269 + err = nla_put_u32(skb, IFLA_MTU, netdev->mtu);
2270 + if (unlikely(err))
2271 + goto nla_put_err;
2272 + err = nla_put_u8(skb, IFLA_OPERSTATE, operstate);
2273 + if (unlikely(err))
2274 + goto nla_put_err;
2275 + if (netdev->addr_len) {
2276 + err = nla_put(skb, IFLA_ADDRESS, netdev->addr_len,
2277 + netdev->dev_addr);
2278 + if (unlikely(err))
2279 + goto nla_put_err;
2280 + }
2281 +
2282 + iflink = dev_get_iflink(netdev);
2283 + if (netdev->ifindex != iflink) {
2284 + err = nla_put_u32(skb, IFLA_LINK, iflink);
2285 + if (unlikely(err))
2286 + goto nla_put_err;
2287 + }
2288 +
2289 + return 0;
2290 +
2291 +nla_put_err:
2292 + netdev_err(netdev, "nla_put_ err %d\n", err);
2293 + return err;
2294 +}
2295 +
2296 +static int __nla_put_port(struct sk_buff *skb, struct net_device *netdev)
2297 +{
2298 + struct nlattr *nest;
2299 + int err;
2300 +
2301 + nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
2302 + if (!nest) {
2303 + netdev_err(netdev, "nla_nest_start failed\n");
2304 + return -ENOMEM;
2305 + }
2306 +
2307 + err = nla_put_u8(skb, IFLA_BRPORT_STATE, BR_STATE_FORWARDING);
2308 + if (unlikely(err))
2309 + goto nla_put_err;
2310 + err = nla_put_u16(skb, IFLA_BRPORT_PRIORITY, 0);
2311 + if (unlikely(err))
2312 + goto nla_put_err;
2313 + err = nla_put_u32(skb, IFLA_BRPORT_COST, 0);
2314 + if (unlikely(err))
2315 + goto nla_put_err;
2316 + err = nla_put_u8(skb, IFLA_BRPORT_MODE, 0);
2317 + if (unlikely(err))
2318 + goto nla_put_err;
2319 + err = nla_put_u8(skb, IFLA_BRPORT_GUARD, 0);
2320 + if (unlikely(err))
2321 + goto nla_put_err;
2322 + err = nla_put_u8(skb, IFLA_BRPORT_PROTECT, 0);
2323 + if (unlikely(err))
2324 + goto nla_put_err;
2325 + err = nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, 0);
2326 + if (unlikely(err))
2327 + goto nla_put_err;
2328 + err = nla_put_u8(skb, IFLA_BRPORT_LEARNING, 0);
2329 + if (unlikely(err))
2330 + goto nla_put_err;
2331 + err = nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, 1);
2332 + if (unlikely(err))
2333 + goto nla_put_err;
2334 + nla_nest_end(skb, nest);
2335 +
2336 + return 0;
2337 +
2338 +nla_put_err:
2339 + netdev_err(netdev, "nla_put_ err %d\n", err);
2340 + nla_nest_cancel(skb, nest);
2341 + return err;
2342 +}
2343 +
2344 +static int __nla_put_vlan(struct sk_buff *skb, struct net_device *netdev)
2345 +{
2346 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2347 + struct nlattr *nest;
2348 + struct bridge_vlan_info vinfo;
2349 + const u8 *vlans = port_priv->vlans;
2350 + u16 i;
2351 + int err;
2352 +
2353 + nest = nla_nest_start(skb, IFLA_AF_SPEC);
2354 + if (!nest) {
2355 + netdev_err(netdev, "nla_nest_start failed");
2356 + return -ENOMEM;
2357 + }
2358 +
2359 + for (i = 0; i < VLAN_VID_MASK+1; i++) {
2360 + if (!vlans[i])
2361 + continue;
2362 +
2363 + vinfo.flags = 0;
2364 + vinfo.vid = i;
2365 +
2366 + err = nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
2367 + sizeof(vinfo), &vinfo);
2368 + if (unlikely(err))
2369 + goto nla_put_err;
2370 + }
2371 +
2372 + nla_nest_end(skb, nest);
2373 +
2374 + return 0;
2375 +
2376 +nla_put_err:
2377 + netdev_err(netdev, "nla_put_ err %d\n", err);
2378 + nla_nest_cancel(skb, nest);
2379 + return err;
2380 +}
2381 +
2382 +static int evb_getlink(struct sk_buff *skb, u32 pid, u32 seq,
2383 + struct net_device *netdev, u32 filter_mask, int nlflags)
2384 +{
2385 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2386 + struct evb_priv *evb_priv = port_priv->evb_priv;
2387 + struct ifinfomsg *hdr;
2388 + struct nlmsghdr *nlh;
2389 + int err;
2390 +
2391 + if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
2392 + evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
2393 + return 0;
2394 + }
2395 +
2396 + nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*hdr), NLM_F_MULTI);
2397 + if (!nlh)
2398 + return -EMSGSIZE;
2399 +
2400 + hdr = nlmsg_data(nlh);
2401 + memset(hdr, 0, sizeof(*hdr));
2402 + hdr->ifi_family = AF_BRIDGE;
2403 + hdr->ifi_type = netdev->type;
2404 + hdr->ifi_index = netdev->ifindex;
2405 + hdr->ifi_flags = dev_get_flags(netdev);
2406 +
2407 + err = __nla_put_netdev(skb, netdev);
2408 + if (unlikely(err))
2409 + goto nla_put_err;
2410 +
2411 + err = __nla_put_port(skb, netdev);
2412 + if (unlikely(err))
2413 + goto nla_put_err;
2414 +
2415 + /* Check if the VID information is requested */
2416 + if (filter_mask & RTEXT_FILTER_BRVLAN) {
2417 + err = __nla_put_vlan(skb, netdev);
2418 + if (unlikely(err))
2419 + goto nla_put_err;
2420 + }
2421 +
2422 + nlmsg_end(skb, nlh);
2423 + return skb->len;
2424 +
2425 +nla_put_err:
2426 + nlmsg_cancel(skb, nlh);
2427 + return -EMSGSIZE;
2428 +}
2429 +
2430 +static int evb_dellink(struct net_device *netdev,
2431 + struct nlmsghdr *nlh,
2432 + u16 flags)
2433 +{
2434 + struct nlattr *tb[IFLA_BRIDGE_MAX+1];
2435 + struct nlattr *spec;
2436 + struct bridge_vlan_info *vinfo;
2437 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2438 + int err = 0;
2439 +
2440 + spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2441 + if (!spec)
2442 + return 0;
2443 +
2444 + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy);
2445 + if (unlikely(err))
2446 + return err;
2447 +
2448 + if (!tb[IFLA_BRIDGE_VLAN_INFO])
2449 + return -EOPNOTSUPP;
2450 +
2451 + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
2452 +
2453 + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
2454 + return -EINVAL;
2455 +
2456 + err = evb_port_del_rule(netdev, NULL, vinfo->vid);
2457 + if (unlikely(err)) {
2458 + netdev_err(netdev, "evb_port_del_rule err %d\n", err);
2459 + return err;
2460 + }
2461 + port_priv->vlans[vinfo->vid] = 0;
2462 +
2463 + return 0;
2464 +}
2465 +
2466 +static struct rtnl_link_stats64 *
2467 +evb_port_get_stats(struct net_device *netdev,
2468 + struct rtnl_link_stats64 *storage)
2469 +{
2470 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2471 + u64 tmp;
2472 + int err;
2473 +
2474 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2475 + 0,
2476 + port_priv->evb_priv->mux_handle,
2477 + port_priv->port_index,
2478 + DPDMUX_CNT_ING_FRAME, &storage->rx_packets);
2479 + if (unlikely(err))
2480 + goto error;
2481 +
2482 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2483 + 0,
2484 + port_priv->evb_priv->mux_handle,
2485 + port_priv->port_index,
2486 + DPDMUX_CNT_ING_BYTE, &storage->rx_bytes);
2487 + if (unlikely(err))
2488 + goto error;
2489 +
2490 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2491 + 0,
2492 + port_priv->evb_priv->mux_handle,
2493 + port_priv->port_index,
2494 + DPDMUX_CNT_ING_FLTR_FRAME, &tmp);
2495 + if (unlikely(err))
2496 + goto error;
2497 +
2498 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2499 + 0,
2500 + port_priv->evb_priv->mux_handle,
2501 + port_priv->port_index,
2502 + DPDMUX_CNT_ING_FRAME_DISCARD,
2503 + &storage->rx_dropped);
2504 + if (unlikely(err)) {
2505 + storage->rx_dropped = tmp;
2506 + goto error;
2507 + }
2508 + storage->rx_dropped += tmp;
2509 +
2510 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2511 + 0,
2512 + port_priv->evb_priv->mux_handle,
2513 + port_priv->port_index,
2514 + DPDMUX_CNT_ING_MCAST_FRAME,
2515 + &storage->multicast);
2516 + if (unlikely(err))
2517 + goto error;
2518 +
2519 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2520 + 0,
2521 + port_priv->evb_priv->mux_handle,
2522 + port_priv->port_index,
2523 + DPDMUX_CNT_EGR_FRAME, &storage->tx_packets);
2524 + if (unlikely(err))
2525 + goto error;
2526 +
2527 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2528 + 0,
2529 + port_priv->evb_priv->mux_handle,
2530 + port_priv->port_index,
2531 + DPDMUX_CNT_EGR_BYTE, &storage->tx_bytes);
2532 + if (unlikely(err))
2533 + goto error;
2534 +
2535 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2536 + 0,
2537 + port_priv->evb_priv->mux_handle,
2538 + port_priv->port_index,
2539 + DPDMUX_CNT_EGR_FRAME_DISCARD,
2540 + &storage->tx_dropped);
2541 + if (unlikely(err))
2542 + goto error;
2543 +
2544 + return storage;
2545 +
2546 +error:
2547 + netdev_err(netdev, "dpdmux_if_get_counter err %d\n", err);
2548 + return storage;
2549 +}
2550 +
2551 +static const struct net_device_ops evb_port_ops = {
2552 + .ndo_open = &evb_port_open,
2553 +
2554 + .ndo_start_xmit = &evb_dropframe,
2555 +
2556 + .ndo_fdb_add = &evb_port_fdb_add,
2557 + .ndo_fdb_del = &evb_port_fdb_del,
2558 +
2559 + .ndo_get_stats64 = &evb_port_get_stats,
2560 + .ndo_change_mtu = &evb_change_mtu,
2561 +};
2562 +
2563 +static struct {
2564 + enum dpdmux_counter_type id;
2565 + char name[ETH_GSTRING_LEN];
2566 +} evb_ethtool_counters[] = {
2567 + {DPDMUX_CNT_ING_FRAME, "rx frames"},
2568 + {DPDMUX_CNT_ING_BYTE, "rx bytes"},
2569 + {DPDMUX_CNT_ING_FLTR_FRAME, "rx filtered frames"},
2570 + {DPDMUX_CNT_ING_FRAME_DISCARD, "rx discarded frames"},
2571 + {DPDMUX_CNT_ING_BCAST_FRAME, "rx b-cast frames"},
2572 + {DPDMUX_CNT_ING_BCAST_BYTES, "rx b-cast bytes"},
2573 + {DPDMUX_CNT_ING_MCAST_FRAME, "rx m-cast frames"},
2574 + {DPDMUX_CNT_ING_MCAST_BYTE, "rx m-cast bytes"},
2575 + {DPDMUX_CNT_EGR_FRAME, "tx frames"},
2576 + {DPDMUX_CNT_EGR_BYTE, "tx bytes"},
2577 + {DPDMUX_CNT_EGR_FRAME_DISCARD, "tx discarded frames"},
2578 +};
2579 +
2580 +static int evb_ethtool_get_sset_count(struct net_device *dev, int sset)
2581 +{
2582 + switch (sset) {
2583 + case ETH_SS_STATS:
2584 + return ARRAY_SIZE(evb_ethtool_counters);
2585 + default:
2586 + return -EOPNOTSUPP;
2587 + }
2588 +}
2589 +
2590 +static void evb_ethtool_get_strings(struct net_device *netdev,
2591 + u32 stringset, u8 *data)
2592 +{
2593 + int i;
2594 +
2595 + switch (stringset) {
2596 + case ETH_SS_STATS:
2597 + for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++)
2598 + memcpy(data + i * ETH_GSTRING_LEN,
2599 + evb_ethtool_counters[i].name, ETH_GSTRING_LEN);
2600 + break;
2601 + }
2602 +}
2603 +
2604 +static void evb_ethtool_get_stats(struct net_device *netdev,
2605 + struct ethtool_stats *stats,
2606 + u64 *data)
2607 +{
2608 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2609 + int i;
2610 + int err;
2611 +
2612 + for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) {
2613 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2614 + 0,
2615 + port_priv->evb_priv->mux_handle,
2616 + port_priv->port_index,
2617 + evb_ethtool_counters[i].id,
2618 + &data[i]);
2619 + if (err)
2620 + netdev_err(netdev, "dpdmux_if_get_counter[%s] err %d\n",
2621 + evb_ethtool_counters[i].name, err);
2622 + }
2623 +}
2624 +
2625 +static const struct ethtool_ops evb_port_ethtool_ops = {
2626 + .get_strings = &evb_ethtool_get_strings,
2627 + .get_ethtool_stats = &evb_ethtool_get_stats,
2628 + .get_sset_count = &evb_ethtool_get_sset_count,
2629 +};
2630 +
2631 +static int evb_open(struct net_device *netdev)
2632 +{
2633 + struct evb_priv *priv = netdev_priv(netdev);
2634 + int err = 0;
2635 +
2636 + err = dpdmux_enable(priv->mc_io, 0, priv->mux_handle);
2637 + if (unlikely(err))
2638 + netdev_err(netdev, "dpdmux_enable err %d\n", err);
2639 +
2640 + return err;
2641 +}
2642 +
2643 +static int evb_close(struct net_device *netdev)
2644 +{
2645 + struct evb_priv *priv = netdev_priv(netdev);
2646 + int err = 0;
2647 +
2648 + err = dpdmux_disable(priv->mc_io, 0, priv->mux_handle);
2649 + if (unlikely(err))
2650 + netdev_err(netdev, "dpdmux_disable err %d\n", err);
2651 +
2652 + return err;
2653 +}
2654 +
2655 +static const struct net_device_ops evb_ops = {
2656 + .ndo_start_xmit = &evb_dropframe,
2657 + .ndo_open = &evb_open,
2658 + .ndo_stop = &evb_close,
2659 +
2660 + .ndo_bridge_setlink = &evb_setlink,
2661 + .ndo_bridge_getlink = &evb_getlink,
2662 + .ndo_bridge_dellink = &evb_dellink,
2663 +
2664 + .ndo_get_stats64 = &evb_port_get_stats,
2665 + .ndo_change_mtu = &evb_change_mtu,
2666 +};
2667 +
2668 +static int evb_takedown(struct fsl_mc_device *evb_dev)
2669 +{
2670 + struct device *dev = &evb_dev->dev;
2671 + struct net_device *netdev = dev_get_drvdata(dev);
2672 + struct evb_priv *priv = netdev_priv(netdev);
2673 + int err;
2674 +
2675 + err = dpdmux_close(priv->mc_io, 0, priv->mux_handle);
2676 + if (unlikely(err))
2677 + dev_warn(dev, "dpdmux_close err %d\n", err);
2678 +
2679 + return 0;
2680 +}
2681 +
2682 +static int evb_init(struct fsl_mc_device *evb_dev)
2683 +{
2684 + struct device *dev = &evb_dev->dev;
2685 + struct net_device *netdev = dev_get_drvdata(dev);
2686 + struct evb_priv *priv = netdev_priv(netdev);
2687 + int err = 0;
2688 +
2689 + priv->dev_id = evb_dev->obj_desc.id;
2690 +
2691 + err = dpdmux_open(priv->mc_io, 0, priv->dev_id, &priv->mux_handle);
2692 + if (unlikely(err)) {
2693 + dev_err(dev, "dpdmux_open err %d\n", err);
2694 + goto err_exit;
2695 + }
2696 + if (!priv->mux_handle) {
2697 + dev_err(dev, "dpdmux_open returned null handle but no error\n");
2698 + err = -EFAULT;
2699 + goto err_exit;
2700 + }
2701 +
2702 + err = dpdmux_get_attributes(priv->mc_io, 0, priv->mux_handle,
2703 + &priv->attr);
2704 + if (unlikely(err)) {
2705 + dev_err(dev, "dpdmux_get_attributes err %d\n", err);
2706 + goto err_close;
2707 + }
2708 +
2709 + err = dpdmux_reset(priv->mc_io, 0, priv->mux_handle);
2710 + if (unlikely(err)) {
2711 + dev_err(dev, "dpdmux_reset err %d\n", err);
2712 + goto err_close;
2713 + }
2714 +
2715 + return 0;
2716 +
2717 +err_close:
2718 + dpdmux_close(priv->mc_io, 0, priv->mux_handle);
2719 +err_exit:
2720 + return err;
2721 +}
2722 +
2723 +static int evb_remove(struct fsl_mc_device *evb_dev)
2724 +{
2725 + struct device *dev = &evb_dev->dev;
2726 + struct net_device *netdev = dev_get_drvdata(dev);
2727 + struct evb_priv *priv = netdev_priv(netdev);
2728 + struct evb_port_priv *port_priv;
2729 + struct list_head *pos;
2730 +
2731 + list_for_each(pos, &priv->port_list) {
2732 + port_priv = list_entry(pos, struct evb_port_priv, list);
2733 +
2734 + rtnl_lock();
2735 + netdev_upper_dev_unlink(port_priv->netdev, netdev);
2736 + rtnl_unlock();
2737 +
2738 + unregister_netdev(port_priv->netdev);
2739 + free_netdev(port_priv->netdev);
2740 + }
2741 +
2742 + evb_teardown_irqs(evb_dev);
2743 +
2744 + unregister_netdev(netdev);
2745 +
2746 + evb_takedown(evb_dev);
2747 + fsl_mc_portal_free(priv->mc_io);
2748 +
2749 + dev_set_drvdata(dev, NULL);
2750 + free_netdev(netdev);
2751 +
2752 + return 0;
2753 +}
2754 +
2755 +static int evb_probe(struct fsl_mc_device *evb_dev)
2756 +{
2757 + struct device *dev;
2758 + struct evb_priv *priv = NULL;
2759 + struct net_device *netdev = NULL;
2760 + char port_name[IFNAMSIZ];
2761 + int i;
2762 + int err = 0;
2763 +
2764 + dev = &evb_dev->dev;
2765 +
2766 + /* register switch device, it's for management only - no I/O */
2767 + netdev = alloc_etherdev(sizeof(*priv));
2768 + if (!netdev) {
2769 + dev_err(dev, "alloc_etherdev error\n");
2770 + return -ENOMEM;
2771 + }
2772 + netdev->netdev_ops = &evb_ops;
2773 +
2774 + dev_set_drvdata(dev, netdev);
2775 +
2776 + priv = netdev_priv(netdev);
2777 +
2778 + err = fsl_mc_portal_allocate(evb_dev, 0, &priv->mc_io);
2779 + if (unlikely(err)) {
2780 + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
2781 + goto err_free_netdev;
2782 + }
2783 + if (!priv->mc_io) {
2784 + dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n");
2785 + err = -EFAULT;
2786 + goto err_free_netdev;
2787 + }
2788 +
2789 + err = evb_init(evb_dev);
2790 + if (unlikely(err)) {
2791 + dev_err(dev, "evb init err %d\n", err);
2792 + goto err_free_cmdport;
2793 + }
2794 +
2795 + INIT_LIST_HEAD(&priv->port_list);
2796 + netdev->flags |= IFF_PROMISC | IFF_MASTER;
2797 +
2798 + dev_alloc_name(netdev, "evb%d");
2799 +
2800 + /* register switch ports */
2801 + snprintf(port_name, IFNAMSIZ, "%sp%%d", netdev->name);
2802 +
2803 + /* only register downlinks? */
2804 + for (i = 0; i < priv->attr.num_ifs + 1; i++) {
2805 + struct net_device *port_netdev;
2806 + struct evb_port_priv *port_priv;
2807 +
2808 + if (i) {
2809 + port_netdev =
2810 + alloc_etherdev(sizeof(struct evb_port_priv));
2811 + if (!port_netdev) {
2812 + dev_err(dev, "alloc_etherdev error\n");
2813 + goto err_takedown;
2814 + }
2815 +
2816 + port_priv = netdev_priv(port_netdev);
2817 +
2818 + port_netdev->flags |= IFF_PROMISC | IFF_SLAVE;
2819 +
2820 + dev_alloc_name(port_netdev, port_name);
2821 + } else {
2822 + port_netdev = netdev;
2823 + port_priv = &priv->uplink;
2824 + }
2825 +
2826 + port_priv->netdev = port_netdev;
2827 + port_priv->evb_priv = priv;
2828 + port_priv->port_index = i;
2829 +
2830 + SET_NETDEV_DEV(port_netdev, dev);
2831 +
2832 + if (i) {
2833 + port_netdev->netdev_ops = &evb_port_ops;
2834 +
2835 + err = register_netdev(port_netdev);
2836 + if (err < 0) {
2837 + dev_err(dev, "register_netdev err %d\n", err);
2838 + free_netdev(port_netdev);
2839 + goto err_takedown;
2840 + }
2841 +
2842 + rtnl_lock();
2843 + err = netdev_master_upper_dev_link(port_netdev, netdev, NULL, NULL);
2844 + if (unlikely(err)) {
2845 + dev_err(dev, "netdev_master_upper_dev_link err %d\n",
2846 + err);
2847 + unregister_netdev(port_netdev);
2848 + free_netdev(port_netdev);
2849 + rtnl_unlock();
2850 + goto err_takedown;
2851 + }
2852 + rtmsg_ifinfo(RTM_NEWLINK, port_netdev,
2853 + IFF_SLAVE, GFP_KERNEL);
2854 + rtnl_unlock();
2855 +
2856 + list_add(&(port_priv->list), &(priv->port_list));
2857 + } else {
2858 + err = register_netdev(netdev);
2859 +
2860 + if (err < 0) {
2861 + dev_err(dev, "register_netdev error %d\n", err);
2862 + goto err_takedown;
2863 + }
2864 + }
2865 +
2866 + port_netdev->ethtool_ops = &evb_port_ethtool_ops;
2867 +
2868 + /* ports are up from init */
2869 + rtnl_lock();
2870 + err = dev_open(port_netdev);
2871 + rtnl_unlock();
2872 + if (unlikely(err))
2873 + dev_warn(dev, "dev_open err %d\n", err);
2874 + }
2875 +
2876 + /* setup irqs */
2877 + err = evb_setup_irqs(evb_dev);
2878 + if (unlikely(err)) {
2879 + dev_warn(dev, "evb_setup_irqs err %d\n", err);
2880 + goto err_takedown;
2881 + }
2882 +
2883 + dev_info(dev, "probed evb device with %d ports\n",
2884 + priv->attr.num_ifs);
2885 + return 0;
2886 +
2887 +err_takedown:
2888 + evb_remove(evb_dev);
2889 +err_free_cmdport:
2890 + fsl_mc_portal_free(priv->mc_io);
2891 +err_free_netdev:
2892 + return err;
2893 +}
2894 +
2895 +static const struct fsl_mc_device_match_id evb_match_id_table[] = {
2896 + {
2897 + .vendor = FSL_MC_VENDOR_FREESCALE,
2898 + .obj_type = "dpdmux",
2899 + .ver_major = DPDMUX_VER_MAJOR,
2900 + .ver_minor = DPDMUX_VER_MINOR,
2901 + },
2902 + {}
2903 +};
2904 +
2905 +static struct fsl_mc_driver evb_drv = {
2906 + .driver = {
2907 + .name = KBUILD_MODNAME,
2908 + .owner = THIS_MODULE,
2909 + },
2910 + .probe = evb_probe,
2911 + .remove = evb_remove,
2912 + .match_id_table = evb_match_id_table,
2913 +};
2914 +
2915 +module_fsl_mc_driver(evb_drv);
2916 +
2917 +MODULE_LICENSE("GPL");
2918 +MODULE_DESCRIPTION("Layerscape DPAA Edge Virtual Bridge driver (prototype)");