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