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