1 From 5d027b67938155d14814437c89fc535dff94cc10 Mon Sep 17 00:00:00 2001
2 From: Razvan Stefanescu <razvan.stefanescu@nxp.com>
3 Date: Thu, 13 Apr 2017 16:03:37 +0300
4 Subject: [PATCH] staging: dpaa2-evb: Add Edge Virtual Bridge driver
6 This contains the following patches migrated from sdk-v2.0.x branch:
8 dpaa2-evb: Added Edge Virtual Bridge driver
9 dpaa2-evb: Add VLAN_8021Q dependency
10 dpaa2-evb: Update dpdmux binary interface to 5.0
11 dpaa2-evb: Add support to set max frame length.
12 dpaa2-evb: Fix interrupt handling
13 dpaa2-evb: Add object version check
14 staging: dpaa2-evb: update dpdmux command ids set for MC v10.x
15 dpaa2-evb: replace uintX_t types by kernel preferred kernel uX types
16 dpaa2-evb: uprev binary interface to v6.0
17 dpaa2-evb: move comments from declaration to definition
18 dpaa2-evb: delete extraneous tabs
19 dpaa2-evb: align function parameters
20 dpaa2-evb: convert mc command build/parse to use C structs
22 Initial patches have been signed-off by:
23 Alex Marginean <alexandru.marginean@freescale.com>
24 J. German Rivera <German.Rivera@freescale.com>
25 Bogdan Hamciuc <bogdan.hamciuc@freescale.com>
26 Mihaela Panescu <mihaela.panescu@freescale.com>
27 Catalin Horghidan <catalin.horghidan@nxp.com>
28 Ioana Ciornei <ioana.ciornei@nxp.com>
29 Stuart Yoder <stuart.yoder@freescale.com>
31 Updated FLIBs to the latest available for MC 10.x and fixed check-patch
32 warnings. Updated maintainer to myself and removed the DPAA2 Ethernet
35 Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com>
37 drivers/staging/fsl-dpaa2/Kconfig | 1 +
38 drivers/staging/fsl-dpaa2/Makefile | 1 +
39 drivers/staging/fsl-dpaa2/evb/Kconfig | 7 +
40 drivers/staging/fsl-dpaa2/evb/Makefile | 10 +
41 drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h | 279 +++++++
42 drivers/staging/fsl-dpaa2/evb/dpdmux.c | 1111 +++++++++++++++++++++++++
43 drivers/staging/fsl-dpaa2/evb/dpdmux.h | 453 ++++++++++
44 drivers/staging/fsl-dpaa2/evb/evb.c | 1238 ++++++++++++++++++++++++++++
45 8 files changed, 3100 insertions(+)
46 create mode 100644 drivers/staging/fsl-dpaa2/evb/Kconfig
47 create mode 100644 drivers/staging/fsl-dpaa2/evb/Makefile
48 create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
49 create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.c
50 create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.h
51 create mode 100644 drivers/staging/fsl-dpaa2/evb/evb.c
53 --- a/drivers/staging/fsl-dpaa2/Kconfig
54 +++ b/drivers/staging/fsl-dpaa2/Kconfig
55 @@ -19,3 +19,4 @@ config FSL_DPAA2_ETHSW
56 BRIDGE to have support for bridge tools.
58 source "drivers/staging/fsl-dpaa2/mac/Kconfig"
59 +source "drivers/staging/fsl-dpaa2/evb/Kconfig"
60 --- a/drivers/staging/fsl-dpaa2/Makefile
61 +++ b/drivers/staging/fsl-dpaa2/Makefile
64 obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/
65 obj-$(CONFIG_FSL_DPAA2_MAC) += mac/
66 +obj-$(CONFIG_FSL_DPAA2_EVB) += evb/
68 +++ b/drivers/staging/fsl-dpaa2/evb/Kconfig
71 + tristate "DPAA2 Edge Virtual Bridge"
72 + depends on FSL_MC_BUS && FSL_DPAA2
76 + Prototype driver for DPAA2 Edge Virtual Bridge.
78 +++ b/drivers/staging/fsl-dpaa2/evb/Makefile
81 +obj-$(CONFIG_FSL_DPAA2_EVB) += dpaa2-evb.o
83 +dpaa2-evb-objs := evb.o dpdmux.o
86 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
89 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
91 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
93 +/* Copyright 2013-2016 Freescale Semiconductor Inc.
95 + * Redistribution and use in source and binary forms, with or without
96 + * modification, are permitted provided that the following conditions are met:
97 + * * Redistributions of source code must retain the above copyright
98 + * notice, this list of conditions and the following disclaimer.
99 + * * Redistributions in binary form must reproduce the above copyright
100 + * notice, this list of conditions and the following disclaimer in the
101 + * documentation and/or other materials provided with the distribution.
102 + * * Neither the name of the above-listed copyright holders nor the
103 + * names of any contributors may be used to endorse or promote products
104 + * derived from this software without specific prior written permission.
107 + * ALTERNATIVELY, this software may be distributed under the terms of the
108 + * GNU General Public License ("GPL") as published by the Free Software
109 + * Foundation, either version 2 of that License or (at your option) any
112 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
113 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
114 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
115 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
116 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
117 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
118 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
119 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
120 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
121 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
122 + * POSSIBILITY OF SUCH DAMAGE.
124 +#ifndef _FSL_DPDMUX_CMD_H
125 +#define _FSL_DPDMUX_CMD_H
127 +/* DPDMUX Version */
128 +#define DPDMUX_VER_MAJOR 6
129 +#define DPDMUX_VER_MINOR 1
131 +#define DPDMUX_CMD_BASE_VER 1
132 +#define DPDMUX_CMD_ID_OFFSET 4
134 +#define DPDMUX_CMD(id) (((id) << DPDMUX_CMD_ID_OFFSET) | DPDMUX_CMD_BASE_VER)
137 +#define DPDMUX_CMDID_CLOSE DPDMUX_CMD(0x800)
138 +#define DPDMUX_CMDID_OPEN DPDMUX_CMD(0x806)
139 +#define DPDMUX_CMDID_CREATE DPDMUX_CMD(0x906)
140 +#define DPDMUX_CMDID_DESTROY DPDMUX_CMD(0x986)
141 +#define DPDMUX_CMDID_GET_API_VERSION DPDMUX_CMD(0xa06)
143 +#define DPDMUX_CMDID_ENABLE DPDMUX_CMD(0x002)
144 +#define DPDMUX_CMDID_DISABLE DPDMUX_CMD(0x003)
145 +#define DPDMUX_CMDID_GET_ATTR DPDMUX_CMD(0x004)
146 +#define DPDMUX_CMDID_RESET DPDMUX_CMD(0x005)
147 +#define DPDMUX_CMDID_IS_ENABLED DPDMUX_CMD(0x006)
149 +#define DPDMUX_CMDID_SET_IRQ_ENABLE DPDMUX_CMD(0x012)
150 +#define DPDMUX_CMDID_GET_IRQ_ENABLE DPDMUX_CMD(0x013)
151 +#define DPDMUX_CMDID_SET_IRQ_MASK DPDMUX_CMD(0x014)
152 +#define DPDMUX_CMDID_GET_IRQ_MASK DPDMUX_CMD(0x015)
153 +#define DPDMUX_CMDID_GET_IRQ_STATUS DPDMUX_CMD(0x016)
154 +#define DPDMUX_CMDID_CLEAR_IRQ_STATUS DPDMUX_CMD(0x017)
156 +#define DPDMUX_CMDID_SET_MAX_FRAME_LENGTH DPDMUX_CMD(0x0a1)
158 +#define DPDMUX_CMDID_UL_RESET_COUNTERS DPDMUX_CMD(0x0a3)
160 +#define DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES DPDMUX_CMD(0x0a7)
161 +#define DPDMUX_CMDID_IF_GET_ATTR DPDMUX_CMD(0x0a8)
162 +#define DPDMUX_CMDID_IF_ENABLE DPDMUX_CMD(0x0a9)
163 +#define DPDMUX_CMDID_IF_DISABLE DPDMUX_CMD(0x0aa)
165 +#define DPDMUX_CMDID_IF_ADD_L2_RULE DPDMUX_CMD(0x0b0)
166 +#define DPDMUX_CMDID_IF_REMOVE_L2_RULE DPDMUX_CMD(0x0b1)
167 +#define DPDMUX_CMDID_IF_GET_COUNTER DPDMUX_CMD(0x0b2)
168 +#define DPDMUX_CMDID_IF_SET_LINK_CFG DPDMUX_CMD(0x0b3)
169 +#define DPDMUX_CMDID_IF_GET_LINK_STATE DPDMUX_CMD(0x0b4)
171 +#define DPDMUX_CMDID_SET_CUSTOM_KEY DPDMUX_CMD(0x0b5)
172 +#define DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY DPDMUX_CMD(0x0b6)
173 +#define DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY DPDMUX_CMD(0x0b7)
175 +#define DPDMUX_MASK(field) \
176 + GENMASK(DPDMUX_##field##_SHIFT + DPDMUX_##field##_SIZE - 1, \
177 + DPDMUX_##field##_SHIFT)
178 +#define dpdmux_set_field(var, field, val) \
179 + ((var) |= (((val) << DPDMUX_##field##_SHIFT) & DPDMUX_MASK(field)))
180 +#define dpdmux_get_field(var, field) \
181 + (((var) & DPDMUX_MASK(field)) >> DPDMUX_##field##_SHIFT)
183 +struct dpdmux_cmd_open {
187 +struct dpdmux_cmd_create {
193 + u16 adv_max_dmat_entries;
194 + u16 adv_max_mc_groups;
195 + u16 adv_max_vlan_ids;
201 +struct dpdmux_cmd_destroy {
205 +#define DPDMUX_ENABLE_SHIFT 0
206 +#define DPDMUX_ENABLE_SIZE 1
208 +struct dpdmux_rsp_is_enabled {
212 +struct dpdmux_cmd_set_irq_enable {
218 +struct dpdmux_cmd_get_irq_enable {
223 +struct dpdmux_rsp_get_irq_enable {
227 +struct dpdmux_cmd_set_irq_mask {
232 +struct dpdmux_cmd_get_irq_mask {
237 +struct dpdmux_rsp_get_irq_mask {
241 +struct dpdmux_cmd_get_irq_status {
246 +struct dpdmux_rsp_get_irq_status {
250 +struct dpdmux_cmd_clear_irq_status {
255 +struct dpdmux_rsp_get_attr {
270 +struct dpdmux_cmd_set_max_frame_length {
271 + u16 max_frame_length;
274 +#define DPDMUX_ACCEPTED_FRAMES_TYPE_SHIFT 0
275 +#define DPDMUX_ACCEPTED_FRAMES_TYPE_SIZE 4
276 +#define DPDMUX_UNACCEPTED_FRAMES_ACTION_SHIFT 4
277 +#define DPDMUX_UNACCEPTED_FRAMES_ACTION_SIZE 4
279 +struct dpdmux_cmd_if_set_accepted_frames {
284 +struct dpdmux_cmd_if {
288 +struct dpdmux_rsp_if_get_attr {
292 + u8 accepted_frames_type;
296 +struct dpdmux_cmd_if_l2_rule {
309 +struct dpdmux_cmd_if_get_counter {
314 +struct dpdmux_rsp_if_get_counter {
319 +struct dpdmux_cmd_if_set_link_cfg {
329 +struct dpdmux_cmd_if_get_link_state {
333 +struct dpdmux_rsp_if_get_link_state {
344 +struct dpdmux_rsp_get_api_version {
349 +struct dpdmux_set_custom_key {
354 +struct dpdmux_cmd_add_custom_cls_entry {
363 +struct dpdmux_cmd_remove_custom_cls_entry {
371 +#endif /* _FSL_DPDMUX_CMD_H */
373 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c
375 +/* Copyright 2013-2016 Freescale Semiconductor Inc.
377 + * Redistribution and use in source and binary forms, with or without
378 + * modification, are permitted provided that the following conditions are met:
379 + * * Redistributions of source code must retain the above copyright
380 + * notice, this list of conditions and the following disclaimer.
381 + * * Redistributions in binary form must reproduce the above copyright
382 + * notice, this list of conditions and the following disclaimer in the
383 + * documentation and/or other materials provided with the distribution.
384 + * * Neither the name of the above-listed copyright holders nor the
385 + * names of any contributors may be used to endorse or promote products
386 + * derived from this software without specific prior written permission.
389 + * ALTERNATIVELY, this software may be distributed under the terms of the
390 + * GNU General Public License ("GPL") as published by the Free Software
391 + * Foundation, either version 2 of that License or (at your option) any
394 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
395 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
396 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
397 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
398 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
399 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
400 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
401 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
402 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
403 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
404 + * POSSIBILITY OF SUCH DAMAGE.
406 +#include "../../fsl-mc/include/mc.h"
408 +#include "dpdmux-cmd.h"
411 + * dpdmux_open() - Open a control session for the specified object
412 + * @mc_io: Pointer to MC portal's I/O object
413 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
414 + * @dpdmux_id: DPDMUX unique ID
415 + * @token: Returned token; use in subsequent API calls
417 + * This function can be used to open a control session for an
418 + * already created object; an object may have been declared in
419 + * the DPL or by calling the dpdmux_create() function.
420 + * This function returns a unique authentication token,
421 + * associated with the specific object ID and the specific MC
422 + * portal; this token must be used in all subsequent commands for
423 + * this specific object.
425 + * Return: '0' on Success; Error code otherwise.
427 +int dpdmux_open(struct fsl_mc_io *mc_io,
432 + struct mc_command cmd = { 0 };
433 + struct dpdmux_cmd_open *cmd_params;
436 + /* prepare command */
437 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_OPEN,
440 + cmd_params = (struct dpdmux_cmd_open *)cmd.params;
441 + cmd_params->dpdmux_id = cpu_to_le32(dpdmux_id);
443 + /* send command to mc*/
444 + err = mc_send_command(mc_io, &cmd);
448 + /* retrieve response parameters */
449 + *token = mc_cmd_hdr_read_token(&cmd);
455 + * dpdmux_close() - Close the control session of the object
456 + * @mc_io: Pointer to MC portal's I/O object
457 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
458 + * @token: Token of DPDMUX object
460 + * After this function is called, no further operations are
461 + * allowed on the object without opening a new control session.
463 + * Return: '0' on Success; Error code otherwise.
465 +int dpdmux_close(struct fsl_mc_io *mc_io,
469 + struct mc_command cmd = { 0 };
471 + /* prepare command */
472 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLOSE,
476 + /* send command to mc*/
477 + return mc_send_command(mc_io, &cmd);
481 + * dpdmux_create() - Create the DPDMUX object
482 + * @mc_io: Pointer to MC portal's I/O object
483 + * @dprc_token: Parent container token; '0' for default container
484 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
485 + * @cfg: Configuration structure
486 + * @obj_id: returned object id
488 + * Create the DPDMUX object, allocate required resources and
489 + * perform required initialization.
491 + * The object can be created either by declaring it in the
492 + * DPL file, or by calling this function.
494 + * The function accepts an authentication token of a parent
495 + * container that this object should be assigned to. The token
496 + * can be '0' so the object will be assigned to the default container.
497 + * The newly created object can be opened with the returned
498 + * object id and using the container's associated tokens and MC portals.
500 + * Return: '0' on Success; Error code otherwise.
502 +int dpdmux_create(struct fsl_mc_io *mc_io,
505 + const struct dpdmux_cfg *cfg,
508 + struct mc_command cmd = { 0 };
509 + struct dpdmux_cmd_create *cmd_params;
512 + /* prepare command */
513 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CREATE,
516 + cmd_params = (struct dpdmux_cmd_create *)cmd.params;
517 + cmd_params->method = cfg->method;
518 + cmd_params->manip = cfg->manip;
519 + cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs);
520 + cmd_params->adv_max_dmat_entries =
521 + cpu_to_le16(cfg->adv.max_dmat_entries);
522 + cmd_params->adv_max_mc_groups = cpu_to_le16(cfg->adv.max_mc_groups);
523 + cmd_params->adv_max_vlan_ids = cpu_to_le16(cfg->adv.max_vlan_ids);
524 + cmd_params->options = cpu_to_le64(cfg->adv.options);
526 + /* send command to mc*/
527 + err = mc_send_command(mc_io, &cmd);
531 + /* retrieve response parameters */
532 + *obj_id = mc_cmd_hdr_read_token(&cmd);
538 + * dpdmux_destroy() - Destroy the DPDMUX object and release all its resources.
539 + * @mc_io: Pointer to MC portal's I/O object
540 + * @dprc_token: Parent container token; '0' for default container
541 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
542 + * @object_id: The object id; it must be a valid id within the container that
543 + * created this object;
545 + * The function accepts the authentication token of the parent container that
546 + * created the object (not the one that currently owns the object). The object
547 + * is searched within parent using the provided 'object_id'.
548 + * All tokens to the object must be closed before calling destroy.
550 + * Return: '0' on Success; error code otherwise.
552 +int dpdmux_destroy(struct fsl_mc_io *mc_io,
557 + struct mc_command cmd = { 0 };
558 + struct dpdmux_cmd_destroy *cmd_params;
560 + /* prepare command */
561 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DESTROY,
564 + cmd_params = (struct dpdmux_cmd_destroy *)cmd.params;
565 + cmd_params->dpdmux_id = cpu_to_le32(object_id);
567 + /* send command to mc*/
568 + return mc_send_command(mc_io, &cmd);
572 + * dpdmux_enable() - Enable DPDMUX functionality
573 + * @mc_io: Pointer to MC portal's I/O object
574 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
575 + * @token: Token of DPDMUX object
577 + * Return: '0' on Success; Error code otherwise.
579 +int dpdmux_enable(struct fsl_mc_io *mc_io,
583 + struct mc_command cmd = { 0 };
585 + /* prepare command */
586 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ENABLE,
590 + /* send command to mc*/
591 + return mc_send_command(mc_io, &cmd);
595 + * dpdmux_disable() - Disable DPDMUX functionality
596 + * @mc_io: Pointer to MC portal's I/O object
597 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
598 + * @token: Token of DPDMUX object
600 + * Return: '0' on Success; Error code otherwise.
602 +int dpdmux_disable(struct fsl_mc_io *mc_io,
606 + struct mc_command cmd = { 0 };
608 + /* prepare command */
609 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DISABLE,
613 + /* send command to mc*/
614 + return mc_send_command(mc_io, &cmd);
618 + * dpdmux_is_enabled() - Check if the DPDMUX is enabled.
619 + * @mc_io: Pointer to MC portal's I/O object
620 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
621 + * @token: Token of DPDMUX object
622 + * @en: Returns '1' if object is enabled; '0' otherwise
624 + * Return: '0' on Success; Error code otherwise.
626 +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
631 + struct mc_command cmd = { 0 };
632 + struct dpdmux_rsp_is_enabled *rsp_params;
635 + /* prepare command */
636 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IS_ENABLED,
640 + /* send command to mc*/
641 + err = mc_send_command(mc_io, &cmd);
645 + /* retrieve response parameters */
646 + rsp_params = (struct dpdmux_rsp_is_enabled *)cmd.params;
647 + *en = dpdmux_get_field(rsp_params->en, ENABLE);
653 + * dpdmux_reset() - Reset the DPDMUX, returns the object to initial state.
654 + * @mc_io: Pointer to MC portal's I/O object
655 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
656 + * @token: Token of DPDMUX object
658 + * Return: '0' on Success; Error code otherwise.
660 +int dpdmux_reset(struct fsl_mc_io *mc_io,
664 + struct mc_command cmd = { 0 };
666 + /* prepare command */
667 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_RESET,
671 + /* send command to mc*/
672 + return mc_send_command(mc_io, &cmd);
676 + * dpdmux_set_irq_enable() - Set overall interrupt state.
677 + * @mc_io: Pointer to MC portal's I/O object
678 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
679 + * @token: Token of DPDMUX object
680 + * @irq_index: The interrupt index to configure
681 + * @en: Interrupt state - enable = 1, disable = 0
683 + * Allows GPP software to control when interrupts are generated.
684 + * Each interrupt can have up to 32 causes. The enable/disable control's the
685 + * overall interrupt state. if the interrupt is disabled no causes will cause
688 + * Return: '0' on Success; Error code otherwise.
690 +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
696 + struct mc_command cmd = { 0 };
697 + struct dpdmux_cmd_set_irq_enable *cmd_params;
699 + /* prepare command */
700 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_ENABLE,
703 + cmd_params = (struct dpdmux_cmd_set_irq_enable *)cmd.params;
704 + cmd_params->enable = en;
705 + cmd_params->irq_index = irq_index;
707 + /* send command to mc*/
708 + return mc_send_command(mc_io, &cmd);
712 + * dpdmux_get_irq_enable() - Get overall interrupt state.
713 + * @mc_io: Pointer to MC portal's I/O object
714 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
715 + * @token: Token of DPDMUX object
716 + * @irq_index: The interrupt index to configure
717 + * @en: Returned interrupt state - enable = 1, disable = 0
719 + * Return: '0' on Success; Error code otherwise.
721 +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
727 + struct mc_command cmd = { 0 };
728 + struct dpdmux_cmd_get_irq_enable *cmd_params;
729 + struct dpdmux_rsp_get_irq_enable *rsp_params;
732 + /* prepare command */
733 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_ENABLE,
736 + cmd_params = (struct dpdmux_cmd_get_irq_enable *)cmd.params;
737 + cmd_params->irq_index = irq_index;
739 + /* send command to mc*/
740 + err = mc_send_command(mc_io, &cmd);
744 + /* retrieve response parameters */
745 + rsp_params = (struct dpdmux_rsp_get_irq_enable *)cmd.params;
746 + *en = rsp_params->enable;
752 + * dpdmux_set_irq_mask() - Set interrupt mask.
753 + * @mc_io: Pointer to MC portal's I/O object
754 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
755 + * @token: Token of DPDMUX object
756 + * @irq_index: The interrupt index to configure
757 + * @mask: event mask to trigger interrupt;
760 + * 1 = consider event for asserting IRQ
762 + * Every interrupt can have up to 32 causes and the interrupt model supports
763 + * masking/unmasking each cause independently
765 + * Return: '0' on Success; Error code otherwise.
767 +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
773 + struct mc_command cmd = { 0 };
774 + struct dpdmux_cmd_set_irq_mask *cmd_params;
776 + /* prepare command */
777 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_MASK,
780 + cmd_params = (struct dpdmux_cmd_set_irq_mask *)cmd.params;
781 + cmd_params->mask = cpu_to_le32(mask);
782 + cmd_params->irq_index = irq_index;
784 + /* send command to mc*/
785 + return mc_send_command(mc_io, &cmd);
789 + * dpdmux_get_irq_mask() - Get interrupt mask.
790 + * @mc_io: Pointer to MC portal's I/O object
791 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
792 + * @token: Token of DPDMUX object
793 + * @irq_index: The interrupt index to configure
794 + * @mask: Returned event mask to trigger interrupt
796 + * Every interrupt can have up to 32 causes and the interrupt model supports
797 + * masking/unmasking each cause independently
799 + * Return: '0' on Success; Error code otherwise.
801 +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
807 + struct mc_command cmd = { 0 };
808 + struct dpdmux_cmd_get_irq_mask *cmd_params;
809 + struct dpdmux_rsp_get_irq_mask *rsp_params;
812 + /* prepare command */
813 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_MASK,
816 + cmd_params = (struct dpdmux_cmd_get_irq_mask *)cmd.params;
817 + cmd_params->irq_index = irq_index;
819 + /* send command to mc*/
820 + err = mc_send_command(mc_io, &cmd);
824 + /* retrieve response parameters */
825 + rsp_params = (struct dpdmux_rsp_get_irq_mask *)cmd.params;
826 + *mask = le32_to_cpu(rsp_params->mask);
832 + * dpdmux_get_irq_status() - Get the current status of any pending interrupts.
833 + * @mc_io: Pointer to MC portal's I/O object
834 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
835 + * @token: Token of DPDMUX object
836 + * @irq_index: The interrupt index to configure
837 + * @status: Returned interrupts status - one bit per cause:
838 + * 0 = no interrupt pending
839 + * 1 = interrupt pending
841 + * Return: '0' on Success; Error code otherwise.
843 +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
849 + struct mc_command cmd = { 0 };
850 + struct dpdmux_cmd_get_irq_status *cmd_params;
851 + struct dpdmux_rsp_get_irq_status *rsp_params;
854 + /* prepare command */
855 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_STATUS,
858 + cmd_params = (struct dpdmux_cmd_get_irq_status *)cmd.params;
859 + cmd_params->status = cpu_to_le32(*status);
860 + cmd_params->irq_index = irq_index;
862 + /* send command to mc*/
863 + err = mc_send_command(mc_io, &cmd);
867 + /* retrieve response parameters */
868 + rsp_params = (struct dpdmux_rsp_get_irq_status *)cmd.params;
869 + *status = le32_to_cpu(rsp_params->status);
875 + * dpdmux_clear_irq_status() - Clear a pending interrupt's status
876 + * @mc_io: Pointer to MC portal's I/O object
877 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
878 + * @token: Token of DPDMUX object
879 + * @irq_index: The interrupt index to configure
880 + * @status: bits to clear (W1C) - one bit per cause:
882 + * 1 = clear status bit
884 + * Return: '0' on Success; Error code otherwise.
886 +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
892 + struct mc_command cmd = { 0 };
893 + struct dpdmux_cmd_clear_irq_status *cmd_params;
895 + /* prepare command */
896 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLEAR_IRQ_STATUS,
899 + cmd_params = (struct dpdmux_cmd_clear_irq_status *)cmd.params;
900 + cmd_params->status = cpu_to_le32(status);
901 + cmd_params->irq_index = irq_index;
903 + /* send command to mc*/
904 + return mc_send_command(mc_io, &cmd);
908 + * dpdmux_get_attributes() - Retrieve DPDMUX attributes
909 + * @mc_io: Pointer to MC portal's I/O object
910 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
911 + * @token: Token of DPDMUX object
912 + * @attr: Returned object's attributes
914 + * Return: '0' on Success; Error code otherwise.
916 +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
919 + struct dpdmux_attr *attr)
921 + struct mc_command cmd = { 0 };
922 + struct dpdmux_rsp_get_attr *rsp_params;
925 + /* prepare command */
926 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_ATTR,
930 + /* send command to mc*/
931 + err = mc_send_command(mc_io, &cmd);
935 + /* retrieve response parameters */
936 + rsp_params = (struct dpdmux_rsp_get_attr *)cmd.params;
937 + attr->id = le32_to_cpu(rsp_params->id);
938 + attr->options = le64_to_cpu(rsp_params->options);
939 + attr->method = rsp_params->method;
940 + attr->manip = rsp_params->manip;
941 + attr->num_ifs = le16_to_cpu(rsp_params->num_ifs);
942 + attr->mem_size = le16_to_cpu(rsp_params->mem_size);
948 + * dpdmux_if_enable() - Enable Interface
949 + * @mc_io: Pointer to MC portal's I/O object
950 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
951 + * @token: Token of DPDMUX object
952 + * @if_id: Interface Identifier
954 + * Return: Completion status. '0' on Success; Error code otherwise.
956 +int dpdmux_if_enable(struct fsl_mc_io *mc_io,
961 + struct dpdmux_cmd_if *cmd_params;
962 + struct mc_command cmd = { 0 };
964 + /* prepare command */
965 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ENABLE,
968 + cmd_params = (struct dpdmux_cmd_if *)cmd.params;
969 + cmd_params->if_id = cpu_to_le16(if_id);
971 + /* send command to mc*/
972 + return mc_send_command(mc_io, &cmd);
976 + * dpdmux_if_disable() - Disable Interface
977 + * @mc_io: Pointer to MC portal's I/O object
978 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
979 + * @token: Token of DPDMUX object
980 + * @if_id: Interface Identifier
982 + * Return: Completion status. '0' on Success; Error code otherwise.
984 +int dpdmux_if_disable(struct fsl_mc_io *mc_io,
989 + struct dpdmux_cmd_if *cmd_params;
990 + struct mc_command cmd = { 0 };
992 + /* prepare command */
993 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_DISABLE,
996 + cmd_params = (struct dpdmux_cmd_if *)cmd.params;
997 + cmd_params->if_id = cpu_to_le16(if_id);
999 + /* send command to mc*/
1000 + return mc_send_command(mc_io, &cmd);
1004 + * dpdmux_set_max_frame_length() - Set the maximum frame length in DPDMUX
1005 + * @mc_io: Pointer to MC portal's I/O object
1006 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1007 + * @token: Token of DPDMUX object
1008 + * @max_frame_length: The required maximum frame length
1010 + * Update the maximum frame length on all DMUX interfaces.
1011 + * In case of VEPA, the maximum frame length on all dmux interfaces
1012 + * will be updated with the minimum value of the mfls of the connected
1013 + * dpnis and the actual value of dmux mfl.
1015 + * Return: '0' on Success; Error code otherwise.
1017 +int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io,
1020 + u16 max_frame_length)
1022 + struct mc_command cmd = { 0 };
1023 + struct dpdmux_cmd_set_max_frame_length *cmd_params;
1025 + /* prepare command */
1026 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_MAX_FRAME_LENGTH,
1029 + cmd_params = (struct dpdmux_cmd_set_max_frame_length *)cmd.params;
1030 + cmd_params->max_frame_length = cpu_to_le16(max_frame_length);
1032 + /* send command to mc*/
1033 + return mc_send_command(mc_io, &cmd);
1037 + * dpdmux_ul_reset_counters() - Function resets the uplink counter
1038 + * @mc_io: Pointer to MC portal's I/O object
1039 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1040 + * @token: Token of DPDMUX object
1042 + * Return: '0' on Success; Error code otherwise.
1044 +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
1048 + struct mc_command cmd = { 0 };
1050 + /* prepare command */
1051 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_RESET_COUNTERS,
1055 + /* send command to mc*/
1056 + return mc_send_command(mc_io, &cmd);
1060 + * dpdmux_if_set_accepted_frames() - Set the accepted frame types
1061 + * @mc_io: Pointer to MC portal's I/O object
1062 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1063 + * @token: Token of DPDMUX object
1064 + * @if_id: Interface ID (0 for uplink, or 1-num_ifs);
1065 + * @cfg: Frame types configuration
1067 + * if 'DPDMUX_ADMIT_ONLY_VLAN_TAGGED' is set - untagged frames or
1068 + * priority-tagged frames are discarded.
1069 + * if 'DPDMUX_ADMIT_ONLY_UNTAGGED' is set - untagged frames or
1070 + * priority-tagged frames are accepted.
1071 + * if 'DPDMUX_ADMIT_ALL' is set (default mode) - all VLAN tagged,
1072 + * untagged and priority-tagged frame are accepted;
1074 + * Return: '0' on Success; Error code otherwise.
1076 +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
1080 + const struct dpdmux_accepted_frames *cfg)
1082 + struct mc_command cmd = { 0 };
1083 + struct dpdmux_cmd_if_set_accepted_frames *cmd_params;
1085 + /* prepare command */
1086 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES,
1089 + cmd_params = (struct dpdmux_cmd_if_set_accepted_frames *)cmd.params;
1090 + cmd_params->if_id = cpu_to_le16(if_id);
1091 + dpdmux_set_field(cmd_params->frames_options, ACCEPTED_FRAMES_TYPE,
1093 + dpdmux_set_field(cmd_params->frames_options, UNACCEPTED_FRAMES_ACTION,
1094 + cfg->unaccept_act);
1096 + /* send command to mc*/
1097 + return mc_send_command(mc_io, &cmd);
1101 + * dpdmux_if_get_attributes() - Obtain DPDMUX interface attributes
1102 + * @mc_io: Pointer to MC portal's I/O object
1103 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1104 + * @token: Token of DPDMUX object
1105 + * @if_id: Interface ID (0 for uplink, or 1-num_ifs);
1106 + * @attr: Interface attributes
1108 + * Return: '0' on Success; Error code otherwise.
1110 +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
1114 + struct dpdmux_if_attr *attr)
1116 + struct mc_command cmd = { 0 };
1117 + struct dpdmux_cmd_if *cmd_params;
1118 + struct dpdmux_rsp_if_get_attr *rsp_params;
1121 + /* prepare command */
1122 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_ATTR,
1125 + cmd_params = (struct dpdmux_cmd_if *)cmd.params;
1126 + cmd_params->if_id = cpu_to_le16(if_id);
1128 + /* send command to mc*/
1129 + err = mc_send_command(mc_io, &cmd);
1133 + /* retrieve response parameters */
1134 + rsp_params = (struct dpdmux_rsp_if_get_attr *)cmd.params;
1135 + attr->rate = le32_to_cpu(rsp_params->rate);
1136 + attr->enabled = dpdmux_get_field(rsp_params->enabled, ENABLE);
1137 + attr->accept_frame_type =
1138 + dpdmux_get_field(rsp_params->accepted_frames_type,
1139 + ACCEPTED_FRAMES_TYPE);
1145 + * dpdmux_if_remove_l2_rule() - Remove L2 rule from DPDMUX table
1146 + * @mc_io: Pointer to MC portal's I/O object
1147 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1148 + * @token: Token of DPDMUX object
1149 + * @if_id: Destination interface ID
1152 + * Function removes a L2 rule from DPDMUX table
1153 + * or adds an interface to an existing multicast address
1155 + * Return: '0' on Success; Error code otherwise.
1157 +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
1161 + const struct dpdmux_l2_rule *rule)
1163 + struct mc_command cmd = { 0 };
1164 + struct dpdmux_cmd_if_l2_rule *cmd_params;
1166 + /* prepare command */
1167 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_REMOVE_L2_RULE,
1170 + cmd_params = (struct dpdmux_cmd_if_l2_rule *)cmd.params;
1171 + cmd_params->if_id = cpu_to_le16(if_id);
1172 + cmd_params->vlan_id = cpu_to_le16(rule->vlan_id);
1173 + cmd_params->mac_addr5 = rule->mac_addr[5];
1174 + cmd_params->mac_addr4 = rule->mac_addr[4];
1175 + cmd_params->mac_addr3 = rule->mac_addr[3];
1176 + cmd_params->mac_addr2 = rule->mac_addr[2];
1177 + cmd_params->mac_addr1 = rule->mac_addr[1];
1178 + cmd_params->mac_addr0 = rule->mac_addr[0];
1180 + /* send command to mc*/
1181 + return mc_send_command(mc_io, &cmd);
1185 + * dpdmux_if_add_l2_rule() - Add L2 rule into DPDMUX table
1186 + * @mc_io: Pointer to MC portal's I/O object
1187 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1188 + * @token: Token of DPDMUX object
1189 + * @if_id: Destination interface ID
1192 + * Function adds a L2 rule into DPDMUX table
1193 + * or adds an interface to an existing multicast address
1195 + * Return: '0' on Success; Error code otherwise.
1197 +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
1201 + const struct dpdmux_l2_rule *rule)
1203 + struct mc_command cmd = { 0 };
1204 + struct dpdmux_cmd_if_l2_rule *cmd_params;
1206 + /* prepare command */
1207 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ADD_L2_RULE,
1210 + cmd_params = (struct dpdmux_cmd_if_l2_rule *)cmd.params;
1211 + cmd_params->if_id = cpu_to_le16(if_id);
1212 + cmd_params->vlan_id = cpu_to_le16(rule->vlan_id);
1213 + cmd_params->mac_addr5 = rule->mac_addr[5];
1214 + cmd_params->mac_addr4 = rule->mac_addr[4];
1215 + cmd_params->mac_addr3 = rule->mac_addr[3];
1216 + cmd_params->mac_addr2 = rule->mac_addr[2];
1217 + cmd_params->mac_addr1 = rule->mac_addr[1];
1218 + cmd_params->mac_addr0 = rule->mac_addr[0];
1220 + /* send command to mc*/
1221 + return mc_send_command(mc_io, &cmd);
1225 + * dpdmux_if_get_counter() - Functions obtains specific counter of an interface
1226 + * @mc_io: Pointer to MC portal's I/O object
1227 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1228 + * @token: Token of DPDMUX object
1229 + * @if_id: Interface Id
1230 + * @counter_type: counter type
1231 + * @counter: Returned specific counter information
1233 + * Return: '0' on Success; Error code otherwise.
1235 +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
1239 + enum dpdmux_counter_type counter_type,
1242 + struct mc_command cmd = { 0 };
1243 + struct dpdmux_cmd_if_get_counter *cmd_params;
1244 + struct dpdmux_rsp_if_get_counter *rsp_params;
1247 + /* prepare command */
1248 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_COUNTER,
1251 + cmd_params = (struct dpdmux_cmd_if_get_counter *)cmd.params;
1252 + cmd_params->if_id = cpu_to_le16(if_id);
1253 + cmd_params->counter_type = counter_type;
1255 + /* send command to mc*/
1256 + err = mc_send_command(mc_io, &cmd);
1260 + /* retrieve response parameters */
1261 + rsp_params = (struct dpdmux_rsp_if_get_counter *)cmd.params;
1262 + *counter = le64_to_cpu(rsp_params->counter);
1268 + * dpdmux_if_set_link_cfg() - set the link configuration.
1269 + * @mc_io: Pointer to MC portal's I/O object
1270 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1271 + * @token: Token of DPSW object
1272 + * @if_id: interface id
1273 + * @cfg: Link configuration
1275 + * Return: '0' on Success; Error code otherwise.
1277 +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
1281 + struct dpdmux_link_cfg *cfg)
1283 + struct mc_command cmd = { 0 };
1284 + struct dpdmux_cmd_if_set_link_cfg *cmd_params;
1286 + /* prepare command */
1287 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_LINK_CFG,
1290 + cmd_params = (struct dpdmux_cmd_if_set_link_cfg *)cmd.params;
1291 + cmd_params->if_id = cpu_to_le16(if_id);
1292 + cmd_params->rate = cpu_to_le32(cfg->rate);
1293 + cmd_params->options = cpu_to_le64(cfg->options);
1295 + /* send command to mc*/
1296 + return mc_send_command(mc_io, &cmd);
1300 + * dpdmux_if_get_link_state - Return the link state
1301 + * @mc_io: Pointer to MC portal's I/O object
1302 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1303 + * @token: Token of DPSW object
1304 + * @if_id: interface id
1305 + * @state: link state
1307 + * @returns '0' on Success; Error code otherwise.
1309 +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
1313 + struct dpdmux_link_state *state)
1315 + struct mc_command cmd = { 0 };
1316 + struct dpdmux_cmd_if_get_link_state *cmd_params;
1317 + struct dpdmux_rsp_if_get_link_state *rsp_params;
1320 + /* prepare command */
1321 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_LINK_STATE,
1324 + cmd_params = (struct dpdmux_cmd_if_get_link_state *)cmd.params;
1325 + cmd_params->if_id = cpu_to_le16(if_id);
1327 + /* send command to mc*/
1328 + err = mc_send_command(mc_io, &cmd);
1332 + /* retrieve response parameters */
1333 + rsp_params = (struct dpdmux_rsp_if_get_link_state *)cmd.params;
1334 + state->rate = le32_to_cpu(rsp_params->rate);
1335 + state->options = le64_to_cpu(rsp_params->options);
1336 + state->up = dpdmux_get_field(rsp_params->up, ENABLE);
1342 + * dpdmux_set_custom_key - Set a custom classification key.
1344 + * This API is only available for DPDMUX instance created with
1345 + * DPDMUX_METHOD_CUSTOM. This API must be called before populating the
1346 + * classification table using dpdmux_add_custom_cls_entry.
1348 + * Calls to dpdmux_set_custom_key remove all existing classification entries
1349 + * that may have been added previously using dpdmux_add_custom_cls_entry.
1351 + * @mc_io: Pointer to MC portal's I/O object
1352 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1353 + * @token: Token of DPSW object
1354 + * @if_id: interface id
1355 + * @key_cfg_iova: DMA address of a configuration structure set up using
1356 + * dpkg_prepare_key_cfg. Maximum key size is 24 bytes.
1358 + * @returns '0' on Success; Error code otherwise.
1360 +int dpdmux_set_custom_key(struct fsl_mc_io *mc_io,
1365 + struct dpdmux_set_custom_key *cmd_params;
1366 + struct mc_command cmd = { 0 };
1368 + /* prepare command */
1369 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_CUSTOM_KEY,
1372 + cmd_params = (struct dpdmux_set_custom_key *)cmd.params;
1373 + cmd_params->key_cfg_iova = cpu_to_le64(key_cfg_iova);
1375 + /* send command to mc*/
1376 + return mc_send_command(mc_io, &cmd);
1380 + * dpdmux_add_custom_cls_entry - Adds a custom classification entry.
1382 + * This API is only available for DPDMUX instances created with
1383 + * DPDMUX_METHOD_CUSTOM. Before calling this function a classification key
1384 + * composition rule must be set up using dpdmux_set_custom_key.
1386 + * @mc_io: Pointer to MC portal's I/O object
1387 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1388 + * @token: Token of DPSW object
1389 + * @rule: Classification rule to insert. Rules cannot be duplicated, if a
1390 + * matching rule already exists, the action will be replaced.
1391 + * @action: Action to perform for matching traffic.
1393 + * @returns '0' on Success; Error code otherwise.
1395 +int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io,
1398 + struct dpdmux_rule_cfg *rule,
1399 + struct dpdmux_cls_action *action)
1401 + struct dpdmux_cmd_add_custom_cls_entry *cmd_params;
1402 + struct mc_command cmd = { 0 };
1404 + /* prepare command */
1405 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY,
1409 + cmd_params = (struct dpdmux_cmd_add_custom_cls_entry *)cmd.params;
1410 + cmd_params->key_size = rule->key_size;
1411 + cmd_params->dest_if = cpu_to_le16(action->dest_if);
1412 + cmd_params->key_iova = cpu_to_le64(rule->key_iova);
1413 + cmd_params->mask_iova = cpu_to_le64(rule->mask_iova);
1415 + /* send command to mc*/
1416 + return mc_send_command(mc_io, &cmd);
1420 + * dpdmux_remove_custom_cls_entry - Removes a custom classification entry.
1422 + * This API is only available for DPDMUX instances created with
1423 + * DPDMUX_METHOD_CUSTOM. The API can be used to remove classification
1424 + * entries previously inserted using dpdmux_add_custom_cls_entry.
1426 + * @mc_io: Pointer to MC portal's I/O object
1427 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1428 + * @token: Token of DPSW object
1429 + * @rule: Classification rule to remove
1431 + * @returns '0' on Success; Error code otherwise.
1433 +int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io,
1436 + struct dpdmux_rule_cfg *rule)
1438 + struct dpdmux_cmd_remove_custom_cls_entry *cmd_params;
1439 + struct mc_command cmd = { 0 };
1441 + /* prepare command */
1442 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY,
1445 + cmd_params = (struct dpdmux_cmd_remove_custom_cls_entry *)cmd.params;
1446 + cmd_params->key_size = rule->key_size;
1447 + cmd_params->key_iova = cpu_to_le64(rule->key_iova);
1448 + cmd_params->mask_iova = cpu_to_le64(rule->mask_iova);
1450 + /* send command to mc*/
1451 + return mc_send_command(mc_io, &cmd);
1455 + * dpdmux_get_api_version() - Get Data Path Demux API version
1456 + * @mc_io: Pointer to MC portal's I/O object
1457 + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
1458 + * @major_ver: Major version of data path demux API
1459 + * @minor_ver: Minor version of data path demux API
1461 + * Return: '0' on Success; Error code otherwise.
1463 +int dpdmux_get_api_version(struct fsl_mc_io *mc_io,
1468 + struct mc_command cmd = { 0 };
1469 + struct dpdmux_rsp_get_api_version *rsp_params;
1472 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_API_VERSION,
1476 + err = mc_send_command(mc_io, &cmd);
1480 + rsp_params = (struct dpdmux_rsp_get_api_version *)cmd.params;
1481 + *major_ver = le16_to_cpu(rsp_params->major);
1482 + *minor_ver = le16_to_cpu(rsp_params->minor);
1487 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.h
1489 +/* Copyright 2013-2015 Freescale Semiconductor Inc.
1491 + * Redistribution and use in source and binary forms, with or without
1492 + * modification, are permitted provided that the following conditions are met:
1493 + * * Redistributions of source code must retain the above copyright
1494 + * notice, this list of conditions and the following disclaimer.
1495 + * * Redistributions in binary form must reproduce the above copyright
1496 + * notice, this list of conditions and the following disclaimer in the
1497 + * documentation and/or other materials provided with the distribution.
1498 + * * Neither the name of the above-listed copyright holders nor the
1499 + * names of any contributors may be used to endorse or promote products
1500 + * derived from this software without specific prior written permission.
1503 + * ALTERNATIVELY, this software may be distributed under the terms of the
1504 + * GNU General Public License ("GPL") as published by the Free Software
1505 + * Foundation, either version 2 of that License or (at your option) any
1508 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1509 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1510 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1511 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
1512 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1513 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1514 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1515 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1516 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1517 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1518 + * POSSIBILITY OF SUCH DAMAGE.
1520 +#ifndef __FSL_DPDMUX_H
1521 +#define __FSL_DPDMUX_H
1525 +/* Data Path Demux API
1526 + * Contains API for handling DPDMUX topology and functionality
1529 +int dpdmux_open(struct fsl_mc_io *mc_io,
1534 +int dpdmux_close(struct fsl_mc_io *mc_io,
1539 + * DPDMUX general options
1543 + * Enable bridging between internal interfaces
1545 +#define DPDMUX_OPT_BRIDGE_EN 0x0000000000000002ULL
1548 + * Mask support for classification
1550 +#define DPDMUX_OPT_CLS_MASK_SUPPORT 0x0000000000000020ULL
1552 +#define DPDMUX_IRQ_INDEX_IF 0x0000
1553 +#define DPDMUX_IRQ_INDEX 0x0001
1556 + * IRQ event - Indicates that the link state changed
1558 +#define DPDMUX_IRQ_EVENT_LINK_CHANGED 0x0001
1561 + * enum dpdmux_manip - DPDMUX manipulation operations
1562 + * @DPDMUX_MANIP_NONE: No manipulation on frames
1563 + * @DPDMUX_MANIP_ADD_REMOVE_S_VLAN: Add S-VLAN on egress, remove it on ingress
1565 +enum dpdmux_manip {
1566 + DPDMUX_MANIP_NONE = 0x0,
1567 + DPDMUX_MANIP_ADD_REMOVE_S_VLAN = 0x1
1571 + * enum dpdmux_method - DPDMUX method options
1572 + * @DPDMUX_METHOD_NONE: no DPDMUX method
1573 + * @DPDMUX_METHOD_C_VLAN_MAC: DPDMUX based on C-VLAN and MAC address
1574 + * @DPDMUX_METHOD_MAC: DPDMUX based on MAC address
1575 + * @DPDMUX_METHOD_C_VLAN: DPDMUX based on C-VLAN
1576 + * @DPDMUX_METHOD_S_VLAN: DPDMUX based on S-VLAN
1578 +enum dpdmux_method {
1579 + DPDMUX_METHOD_NONE = 0x0,
1580 + DPDMUX_METHOD_C_VLAN_MAC = 0x1,
1581 + DPDMUX_METHOD_MAC = 0x2,
1582 + DPDMUX_METHOD_C_VLAN = 0x3,
1583 + DPDMUX_METHOD_S_VLAN = 0x4,
1584 + DPDMUX_METHOD_CUSTOM = 0x5
1588 + * struct dpdmux_cfg - DPDMUX configuration parameters
1589 + * @method: Defines the operation method for the DPDMUX address table
1590 + * @manip: Required manipulation operation
1591 + * @num_ifs: Number of interfaces (excluding the uplink interface)
1592 + * @adv: Advanced parameters; default is all zeros;
1593 + * use this structure to change default settings
1595 +struct dpdmux_cfg {
1596 + enum dpdmux_method method;
1597 + enum dpdmux_manip manip;
1600 + * struct adv - Advanced parameters
1601 + * @options: DPDMUX options - combination of 'DPDMUX_OPT_<X>' flags
1602 + * @max_dmat_entries: Maximum entries in DPDMUX address table
1603 + * 0 - indicates default: 64 entries per interface.
1604 + * @max_mc_groups: Number of multicast groups in DPDMUX table
1605 + * 0 - indicates default: 32 multicast groups
1606 + * @max_vlan_ids: max vlan ids allowed in the system -
1607 + * relevant only case of working in mac+vlan method.
1608 + * 0 - indicates default 16 vlan ids.
1612 + u16 max_dmat_entries;
1613 + u16 max_mc_groups;
1618 +int dpdmux_create(struct fsl_mc_io *mc_io,
1621 + const struct dpdmux_cfg *cfg,
1624 +int dpdmux_destroy(struct fsl_mc_io *mc_io,
1629 +int dpdmux_enable(struct fsl_mc_io *mc_io,
1633 +int dpdmux_disable(struct fsl_mc_io *mc_io,
1637 +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
1642 +int dpdmux_reset(struct fsl_mc_io *mc_io,
1646 +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
1652 +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
1658 +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
1664 +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
1670 +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
1676 +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
1683 + * struct dpdmux_attr - Structure representing DPDMUX attributes
1684 + * @id: DPDMUX object ID
1685 + * @options: Configuration options (bitmap)
1686 + * @method: DPDMUX address table method
1687 + * @manip: DPDMUX manipulation type
1688 + * @num_ifs: Number of interfaces (excluding the uplink interface)
1689 + * @mem_size: DPDMUX frame storage memory size
1691 +struct dpdmux_attr {
1694 + enum dpdmux_method method;
1695 + enum dpdmux_manip manip;
1700 +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
1703 + struct dpdmux_attr *attr);
1705 +int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io,
1708 + u16 max_frame_length);
1711 + * enum dpdmux_counter_type - Counter types
1712 + * @DPDMUX_CNT_ING_FRAME: Counts ingress frames
1713 + * @DPDMUX_CNT_ING_BYTE: Counts ingress bytes
1714 + * @DPDMUX_CNT_ING_FLTR_FRAME: Counts filtered ingress frames
1715 + * @DPDMUX_CNT_ING_FRAME_DISCARD: Counts discarded ingress frames
1716 + * @DPDMUX_CNT_ING_MCAST_FRAME: Counts ingress multicast frames
1717 + * @DPDMUX_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes
1718 + * @DPDMUX_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames
1719 + * @DPDMUX_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes
1720 + * @DPDMUX_CNT_EGR_FRAME: Counts egress frames
1721 + * @DPDMUX_CNT_EGR_BYTE: Counts egress bytes
1722 + * @DPDMUX_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames
1724 +enum dpdmux_counter_type {
1725 + DPDMUX_CNT_ING_FRAME = 0x0,
1726 + DPDMUX_CNT_ING_BYTE = 0x1,
1727 + DPDMUX_CNT_ING_FLTR_FRAME = 0x2,
1728 + DPDMUX_CNT_ING_FRAME_DISCARD = 0x3,
1729 + DPDMUX_CNT_ING_MCAST_FRAME = 0x4,
1730 + DPDMUX_CNT_ING_MCAST_BYTE = 0x5,
1731 + DPDMUX_CNT_ING_BCAST_FRAME = 0x6,
1732 + DPDMUX_CNT_ING_BCAST_BYTES = 0x7,
1733 + DPDMUX_CNT_EGR_FRAME = 0x8,
1734 + DPDMUX_CNT_EGR_BYTE = 0x9,
1735 + DPDMUX_CNT_EGR_FRAME_DISCARD = 0xa
1739 + * enum dpdmux_accepted_frames_type - DPDMUX frame types
1740 + * @DPDMUX_ADMIT_ALL: The device accepts VLAN tagged, untagged and
1741 + * priority-tagged frames
1742 + * @DPDMUX_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or
1743 + * priority-tagged frames that are received on this
1745 + * @DPDMUX_ADMIT_ONLY_UNTAGGED: Untagged frames or priority-tagged frames
1746 + * received on this interface are accepted
1748 +enum dpdmux_accepted_frames_type {
1749 + DPDMUX_ADMIT_ALL = 0,
1750 + DPDMUX_ADMIT_ONLY_VLAN_TAGGED = 1,
1751 + DPDMUX_ADMIT_ONLY_UNTAGGED = 2
1755 + * enum dpdmux_action - DPDMUX action for un-accepted frames
1756 + * @DPDMUX_ACTION_DROP: Drop un-accepted frames
1757 + * @DPDMUX_ACTION_REDIRECT_TO_CTRL: Redirect un-accepted frames to the
1758 + * control interface
1760 +enum dpdmux_action {
1761 + DPDMUX_ACTION_DROP = 0,
1762 + DPDMUX_ACTION_REDIRECT_TO_CTRL = 1
1766 + * struct dpdmux_accepted_frames - Frame types configuration
1767 + * @type: Defines ingress accepted frames
1768 + * @unaccept_act: Defines action on frames not accepted
1770 +struct dpdmux_accepted_frames {
1771 + enum dpdmux_accepted_frames_type type;
1772 + enum dpdmux_action unaccept_act;
1775 +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
1779 + const struct dpdmux_accepted_frames *cfg);
1782 + * struct dpdmux_if_attr - Structure representing frame types configuration
1783 + * @rate: Configured interface rate (in bits per second)
1784 + * @enabled: Indicates if interface is enabled
1785 + * @accept_frame_type: Indicates type of accepted frames for the interface
1787 +struct dpdmux_if_attr {
1790 + enum dpdmux_accepted_frames_type accept_frame_type;
1793 +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
1797 + struct dpdmux_if_attr *attr);
1799 +int dpdmux_if_enable(struct fsl_mc_io *mc_io,
1804 +int dpdmux_if_disable(struct fsl_mc_io *mc_io,
1810 + * struct dpdmux_l2_rule - Structure representing L2 rule
1811 + * @mac_addr: MAC address
1812 + * @vlan_id: VLAN ID
1814 +struct dpdmux_l2_rule {
1819 +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
1823 + const struct dpdmux_l2_rule *rule);
1825 +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
1829 + const struct dpdmux_l2_rule *rule);
1831 +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
1835 + enum dpdmux_counter_type counter_type,
1838 +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
1843 + * Enable auto-negotiation
1845 +#define DPDMUX_LINK_OPT_AUTONEG 0x0000000000000001ULL
1847 + * Enable half-duplex mode
1849 +#define DPDMUX_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL
1851 + * Enable pause frames
1853 +#define DPDMUX_LINK_OPT_PAUSE 0x0000000000000004ULL
1855 + * Enable a-symmetric pause frames
1857 +#define DPDMUX_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
1860 + * struct dpdmux_link_cfg - Structure representing DPDMUX link configuration
1862 + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
1864 +struct dpdmux_link_cfg {
1869 +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
1873 + struct dpdmux_link_cfg *cfg);
1875 + * struct dpdmux_link_state - Structure representing DPDMUX link state
1877 + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
1878 + * @up: 0 - down, 1 - up
1880 +struct dpdmux_link_state {
1886 +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
1890 + struct dpdmux_link_state *state);
1892 +int dpdmux_set_custom_key(struct fsl_mc_io *mc_io,
1895 + u64 key_cfg_iova);
1898 + * struct dpdmux_rule_cfg - Custom classification rule.
1900 + * @key_iova: DMA address of buffer storing the look-up value
1901 + * @mask_iova: DMA address of the mask used for TCAM classification
1902 + * @key_size: size, in bytes, of the look-up value. This must match the size
1903 + * of the look-up key defined using dpdmux_set_custom_key, otherwise the
1904 + * entry will never be hit
1906 +struct dpdmux_rule_cfg {
1913 + * struct dpdmux_cls_action - Action to execute for frames matching the
1914 + * classification entry
1916 + * @dest_if: Interface to forward the frames to. Port numbering is similar to
1917 + * the one used to connect interfaces:
1918 + * - 0 is the uplink port,
1919 + * - all others are downlink ports.
1921 +struct dpdmux_cls_action {
1925 +int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io,
1928 + struct dpdmux_rule_cfg *rule,
1929 + struct dpdmux_cls_action *action);
1931 +int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io,
1934 + struct dpdmux_rule_cfg *rule);
1936 +int dpdmux_get_api_version(struct fsl_mc_io *mc_io,
1941 +#endif /* __FSL_DPDMUX_H */
1943 +++ b/drivers/staging/fsl-dpaa2/evb/evb.c
1945 +/* Copyright 2015 Freescale Semiconductor Inc.
1947 + * Redistribution and use in source and binary forms, with or without
1948 + * modification, are permitted provided that the following conditions are met:
1949 + * * Redistributions of source code must retain the above copyright
1950 + * notice, this list of conditions and the following disclaimer.
1951 + * * Redistributions in binary form must reproduce the above copyright
1952 + * notice, this list of conditions and the following disclaimer in the
1953 + * documentation and/or other materials provided with the distribution.
1954 + * * Neither the name of Freescale Semiconductor nor the
1955 + * names of its contributors may be used to endorse or promote products
1956 + * derived from this software without specific prior written permission.
1959 + * ALTERNATIVELY, this software may be distributed under the terms of the
1960 + * GNU General Public License ("GPL") as published by the Free Software
1961 + * Foundation, either version 2 of that License or (at your option) any
1964 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
1965 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1966 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1967 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
1968 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1969 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1970 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1971 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1972 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1973 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1975 +#include <linux/module.h>
1976 +#include <linux/msi.h>
1977 +#include <linux/netdevice.h>
1978 +#include <linux/etherdevice.h>
1979 +#include <linux/rtnetlink.h>
1980 +#include <linux/if_vlan.h>
1982 +#include <uapi/linux/if_bridge.h>
1983 +#include <net/netlink.h>
1985 +#include "../../fsl-mc/include/mc.h"
1987 +#include "dpdmux.h"
1988 +#include "dpdmux-cmd.h"
1990 +/* Minimal supported DPDMUX version */
1991 +#define DPDMUX_MIN_VER_MAJOR 6
1992 +#define DPDMUX_MIN_VER_MINOR 0
1995 +#define DPDMUX_MAX_IRQ_NUM 2
1997 +/* MAX FRAME LENGTH (currently 10k) */
1998 +#define EVB_MAX_FRAME_LENGTH (10 * 1024)
1999 +/* MIN FRAME LENGTH (64 bytes + 4 bytes CRC) */
2000 +#define EVB_MIN_FRAME_LENGTH 68
2002 +struct evb_port_priv {
2003 + struct net_device *netdev;
2004 + struct list_head list;
2006 + struct evb_priv *evb_priv;
2007 + u8 vlans[VLAN_VID_MASK + 1];
2012 + struct evb_port_priv uplink;
2014 + struct fsl_mc_io *mc_io;
2015 + struct list_head port_list;
2016 + struct dpdmux_attr attr;
2021 +static int _evb_port_carrier_state_sync(struct net_device *netdev)
2023 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2024 + struct dpdmux_link_state state;
2027 + err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0,
2028 + port_priv->evb_priv->mux_handle,
2029 + port_priv->port_index, &state);
2030 + if (unlikely(err)) {
2031 + netdev_err(netdev, "dpdmux_if_get_link_state() err %d\n", err);
2035 + WARN_ONCE(state.up > 1, "Garbage read into link_state");
2038 + netif_carrier_on(port_priv->netdev);
2040 + netif_carrier_off(port_priv->netdev);
2045 +static int evb_port_open(struct net_device *netdev)
2049 + /* FIXME: enable port when support added */
2051 + err = _evb_port_carrier_state_sync(netdev);
2053 + netdev_err(netdev, "ethsw_port_carrier_state_sync err %d\n",
2061 +static netdev_tx_t evb_dropframe(struct sk_buff *skb, struct net_device *dev)
2063 + /* we don't support I/O for now, drop the frame */
2064 + dev_kfree_skb_any(skb);
2065 + return NETDEV_TX_OK;
2068 +static int evb_links_state_update(struct evb_priv *priv)
2070 + struct evb_port_priv *port_priv;
2071 + struct list_head *pos;
2074 + list_for_each(pos, &priv->port_list) {
2075 + port_priv = list_entry(pos, struct evb_port_priv, list);
2077 + err = _evb_port_carrier_state_sync(port_priv->netdev);
2079 + netdev_err(port_priv->netdev,
2080 + "_evb_port_carrier_state_sync err %d\n",
2087 +static irqreturn_t evb_irq0_handler(int irq_num, void *arg)
2089 + return IRQ_WAKE_THREAD;
2092 +static irqreturn_t _evb_irq0_handler_thread(int irq_num, void *arg)
2094 + struct device *dev = (struct device *)arg;
2095 + struct fsl_mc_device *evb_dev = to_fsl_mc_device(dev);
2096 + struct net_device *netdev = dev_get_drvdata(dev);
2097 + struct evb_priv *priv = netdev_priv(netdev);
2098 + struct fsl_mc_io *io = priv->mc_io;
2099 + u16 token = priv->mux_handle;
2100 + int irq_index = DPDMUX_IRQ_INDEX_IF;
2102 + /* Mask the events and the if_id reserved bits to be cleared on read */
2103 + u32 status = DPDMUX_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000;
2106 + /* Sanity check */
2107 + if (WARN_ON(!evb_dev || !evb_dev->irqs || !evb_dev->irqs[irq_index]))
2109 + if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != irq_num))
2112 + err = dpdmux_get_irq_status(io, 0, token, irq_index, &status);
2113 + if (unlikely(err)) {
2114 + netdev_err(netdev, "Can't get irq status (err %d)", err);
2115 + err = dpdmux_clear_irq_status(io, 0, token, irq_index,
2117 + if (unlikely(err))
2118 + netdev_err(netdev, "Can't clear irq status (err %d)",
2123 + if (status & DPDMUX_IRQ_EVENT_LINK_CHANGED) {
2124 + err = evb_links_state_update(priv);
2125 + if (unlikely(err))
2130 + return IRQ_HANDLED;
2133 +static int evb_setup_irqs(struct fsl_mc_device *evb_dev)
2135 + struct device *dev = &evb_dev->dev;
2136 + struct net_device *netdev = dev_get_drvdata(dev);
2137 + struct evb_priv *priv = netdev_priv(netdev);
2139 + struct fsl_mc_device_irq *irq;
2140 + const int irq_index = DPDMUX_IRQ_INDEX_IF;
2141 + u32 mask = DPDMUX_IRQ_EVENT_LINK_CHANGED;
2143 + err = fsl_mc_allocate_irqs(evb_dev);
2144 + if (unlikely(err)) {
2145 + dev_err(dev, "MC irqs allocation failed\n");
2149 + if (WARN_ON(evb_dev->obj_desc.irq_count != DPDMUX_MAX_IRQ_NUM)) {
2154 + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
2156 + if (unlikely(err)) {
2157 + dev_err(dev, "dpdmux_set_irq_enable err %d\n", err);
2161 + irq = evb_dev->irqs[irq_index];
2163 + err = devm_request_threaded_irq(dev, irq->msi_desc->irq,
2165 + _evb_irq0_handler_thread,
2166 + IRQF_NO_SUSPEND | IRQF_ONESHOT,
2167 + dev_name(dev), dev);
2168 + if (unlikely(err)) {
2169 + dev_err(dev, "devm_request_threaded_irq(): %d", err);
2173 + err = dpdmux_set_irq_mask(priv->mc_io, 0, priv->mux_handle,
2175 + if (unlikely(err)) {
2176 + dev_err(dev, "dpdmux_set_irq_mask(): %d", err);
2177 + goto free_devm_irq;
2180 + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
2182 + if (unlikely(err)) {
2183 + dev_err(dev, "dpdmux_set_irq_enable(): %d", err);
2184 + goto free_devm_irq;
2190 + devm_free_irq(dev, irq->msi_desc->irq, dev);
2192 + fsl_mc_free_irqs(evb_dev);
2196 +static void evb_teardown_irqs(struct fsl_mc_device *evb_dev)
2198 + struct device *dev = &evb_dev->dev;
2199 + struct net_device *netdev = dev_get_drvdata(dev);
2200 + struct evb_priv *priv = netdev_priv(netdev);
2202 + dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
2203 + DPDMUX_IRQ_INDEX_IF, 0);
2205 + devm_free_irq(dev,
2206 + evb_dev->irqs[DPDMUX_IRQ_INDEX_IF]->msi_desc->irq,
2208 + fsl_mc_free_irqs(evb_dev);
2211 +static int evb_port_add_rule(struct net_device *netdev,
2212 + const unsigned char *addr, u16 vid)
2214 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2215 + struct dpdmux_l2_rule rule = { .vlan_id = vid };
2219 + ether_addr_copy(rule.mac_addr, addr);
2221 + err = dpdmux_if_add_l2_rule(port_priv->evb_priv->mc_io,
2223 + port_priv->evb_priv->mux_handle,
2224 + port_priv->port_index, &rule);
2225 + if (unlikely(err))
2226 + netdev_err(netdev, "dpdmux_if_add_l2_rule err %d\n", err);
2230 +static int evb_port_del_rule(struct net_device *netdev,
2231 + const unsigned char *addr, u16 vid)
2233 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2234 + struct dpdmux_l2_rule rule = { .vlan_id = vid };
2238 + ether_addr_copy(rule.mac_addr, addr);
2240 + err = dpdmux_if_remove_l2_rule(port_priv->evb_priv->mc_io,
2242 + port_priv->evb_priv->mux_handle,
2243 + port_priv->port_index, &rule);
2244 + if (unlikely(err))
2245 + netdev_err(netdev, "dpdmux_if_remove_l2_rule err %d\n", err);
2249 +static bool _lookup_address(struct net_device *netdev,
2250 + const unsigned char *addr)
2252 + struct netdev_hw_addr *ha;
2253 + struct netdev_hw_addr_list *list = (is_unicast_ether_addr(addr)) ?
2254 + &netdev->uc : &netdev->mc;
2256 + netif_addr_lock_bh(netdev);
2257 + list_for_each_entry(ha, &list->list, list) {
2258 + if (ether_addr_equal(ha->addr, addr)) {
2259 + netif_addr_unlock_bh(netdev);
2263 + netif_addr_unlock_bh(netdev);
2267 +static inline int evb_port_fdb_prep(struct nlattr *tb[],
2268 + struct net_device *netdev,
2269 + const unsigned char *addr, u16 *vid,
2272 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2273 + struct evb_priv *evb_priv = port_priv->evb_priv;
2277 + if (evb_priv->attr.method != DPDMUX_METHOD_MAC &&
2278 + evb_priv->attr.method != DPDMUX_METHOD_C_VLAN_MAC) {
2279 + netdev_err(netdev,
2280 + "EVB mode does not support MAC classification\n");
2281 + return -EOPNOTSUPP;
2284 + /* check if the address is configured on this port */
2285 + if (_lookup_address(netdev, addr)) {
2293 + if (tb[NDA_VLAN] && evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
2294 + if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
2295 + netdev_err(netdev, "invalid vlan size %d\n",
2296 + nla_len(tb[NDA_VLAN]));
2300 + *vid = nla_get_u16(tb[NDA_VLAN]);
2302 + if (!*vid || *vid >= VLAN_VID_MASK) {
2303 + netdev_err(netdev, "invalid vid value 0x%04x\n", *vid);
2306 + } else if (evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
2307 + netdev_err(netdev,
2308 + "EVB mode requires explicit VLAN configuration\n");
2310 + } else if (tb[NDA_VLAN]) {
2311 + netdev_warn(netdev, "VLAN not supported, argument ignored\n");
2317 +static int evb_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
2318 + struct net_device *netdev,
2319 + const unsigned char *addr, u16 vid, u16 flags,
2320 + struct netlink_ext_ack *extack)
2325 + /* TODO: add replace support when added to iproute bridge */
2326 + if (!(flags & NLM_F_REQUEST)) {
2327 + netdev_err(netdev,
2328 + "evb_port_fdb_add unexpected flags value %08x\n",
2333 + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 0);
2334 + if (unlikely(err))
2337 + err = evb_port_add_rule(netdev, addr, _vid);
2338 + if (unlikely(err))
2341 + if (is_unicast_ether_addr(addr)) {
2342 + err = dev_uc_add(netdev, addr);
2343 + if (unlikely(err)) {
2344 + netdev_err(netdev, "dev_uc_add err %d\n", err);
2348 + err = dev_mc_add(netdev, addr);
2349 + if (unlikely(err)) {
2350 + netdev_err(netdev, "dev_mc_add err %d\n", err);
2358 +static int evb_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
2359 + struct net_device *netdev,
2360 + const unsigned char *addr, u16 vid)
2365 + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 1);
2366 + if (unlikely(err))
2369 + err = evb_port_del_rule(netdev, addr, _vid);
2370 + if (unlikely(err))
2373 + if (is_unicast_ether_addr(addr)) {
2374 + err = dev_uc_del(netdev, addr);
2375 + if (unlikely(err)) {
2376 + netdev_err(netdev, "dev_uc_del err %d\n", err);
2380 + err = dev_mc_del(netdev, addr);
2381 + if (unlikely(err)) {
2382 + netdev_err(netdev, "dev_mc_del err %d\n", err);
2390 +static int evb_change_mtu(struct net_device *netdev,
2393 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2394 + struct evb_priv *evb_priv = port_priv->evb_priv;
2395 + struct list_head *pos;
2398 + /* This operation is not permitted on downlinks */
2399 + if (port_priv->port_index > 0)
2402 + if (mtu < EVB_MIN_FRAME_LENGTH || mtu > EVB_MAX_FRAME_LENGTH) {
2403 + netdev_err(netdev, "Invalid MTU %d. Valid range is: %d..%d\n",
2404 + mtu, EVB_MIN_FRAME_LENGTH, EVB_MAX_FRAME_LENGTH);
2408 + err = dpdmux_set_max_frame_length(evb_priv->mc_io,
2410 + evb_priv->mux_handle,
2413 + if (unlikely(err)) {
2414 + netdev_err(netdev, "dpdmux_ul_set_max_frame_length err %d\n",
2419 + /* Update the max frame length for downlinks */
2420 + list_for_each(pos, &evb_priv->port_list) {
2421 + port_priv = list_entry(pos, struct evb_port_priv, list);
2422 + port_priv->netdev->mtu = mtu;
2425 + netdev->mtu = mtu;
2429 +static const struct nla_policy ifla_br_policy[IFLA_MAX + 1] = {
2430 + [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 },
2431 + [IFLA_BRIDGE_MODE] = { .type = NLA_U16 },
2432 + [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
2433 + .len = sizeof(struct bridge_vlan_info), },
2436 +static int evb_setlink_af_spec(struct net_device *netdev,
2437 + struct nlattr **tb)
2439 + struct bridge_vlan_info *vinfo;
2440 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2443 + if (!tb[IFLA_BRIDGE_VLAN_INFO]) {
2444 + netdev_err(netdev, "no VLAN INFO in nlmsg\n");
2445 + return -EOPNOTSUPP;
2448 + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
2450 + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
2453 + err = evb_port_add_rule(netdev, NULL, vinfo->vid);
2454 + if (unlikely(err))
2457 + port_priv->vlans[vinfo->vid] = 1;
2462 +static int evb_setlink(struct net_device *netdev,
2463 + struct nlmsghdr *nlh,
2465 + struct netlink_ext_ack *extack)
2467 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2468 + struct evb_priv *evb_priv = port_priv->evb_priv;
2469 + struct nlattr *attr;
2470 + struct nlattr *tb[(IFLA_BRIDGE_MAX > IFLA_BRPORT_MAX) ?
2471 + IFLA_BRIDGE_MAX : IFLA_BRPORT_MAX + 1];
2474 + if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
2475 + evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
2476 + netdev_err(netdev,
2477 + "EVB mode does not support VLAN only classification\n");
2478 + return -EOPNOTSUPP;
2481 + attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2483 + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr,
2485 + if (unlikely(err)) {
2486 + netdev_err(netdev,
2487 + "nla_parse_nested for br_policy err %d\n",
2492 + err = evb_setlink_af_spec(netdev, tb);
2496 + netdev_err(netdev, "nlmsg_find_attr found no AF_SPEC\n");
2497 + return -EOPNOTSUPP;
2500 +static int __nla_put_netdev(struct sk_buff *skb, struct net_device *netdev)
2502 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2503 + struct evb_priv *evb_priv = port_priv->evb_priv;
2504 + u8 operstate = netif_running(netdev) ?
2505 + netdev->operstate : IF_OPER_DOWN;
2509 + err = nla_put_string(skb, IFLA_IFNAME, netdev->name);
2510 + if (unlikely(err))
2512 + err = nla_put_u32(skb, IFLA_MASTER, evb_priv->uplink.netdev->ifindex);
2513 + if (unlikely(err))
2515 + err = nla_put_u32(skb, IFLA_MTU, netdev->mtu);
2516 + if (unlikely(err))
2518 + err = nla_put_u8(skb, IFLA_OPERSTATE, operstate);
2519 + if (unlikely(err))
2521 + if (netdev->addr_len) {
2522 + err = nla_put(skb, IFLA_ADDRESS, netdev->addr_len,
2523 + netdev->dev_addr);
2524 + if (unlikely(err))
2528 + iflink = dev_get_iflink(netdev);
2529 + if (netdev->ifindex != iflink) {
2530 + err = nla_put_u32(skb, IFLA_LINK, iflink);
2531 + if (unlikely(err))
2538 + netdev_err(netdev, "nla_put_ err %d\n", err);
2542 +static int __nla_put_port(struct sk_buff *skb, struct net_device *netdev)
2544 + struct nlattr *nest;
2547 + nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
2549 + netdev_err(netdev, "nla_nest_start failed\n");
2553 + err = nla_put_u8(skb, IFLA_BRPORT_STATE, BR_STATE_FORWARDING);
2554 + if (unlikely(err))
2556 + err = nla_put_u16(skb, IFLA_BRPORT_PRIORITY, 0);
2557 + if (unlikely(err))
2559 + err = nla_put_u32(skb, IFLA_BRPORT_COST, 0);
2560 + if (unlikely(err))
2562 + err = nla_put_u8(skb, IFLA_BRPORT_MODE, 0);
2563 + if (unlikely(err))
2565 + err = nla_put_u8(skb, IFLA_BRPORT_GUARD, 0);
2566 + if (unlikely(err))
2568 + err = nla_put_u8(skb, IFLA_BRPORT_PROTECT, 0);
2569 + if (unlikely(err))
2571 + err = nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, 0);
2572 + if (unlikely(err))
2574 + err = nla_put_u8(skb, IFLA_BRPORT_LEARNING, 0);
2575 + if (unlikely(err))
2577 + err = nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, 1);
2578 + if (unlikely(err))
2580 + nla_nest_end(skb, nest);
2585 + netdev_err(netdev, "nla_put_ err %d\n", err);
2586 + nla_nest_cancel(skb, nest);
2590 +static int __nla_put_vlan(struct sk_buff *skb, struct net_device *netdev)
2592 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2593 + struct nlattr *nest;
2594 + struct bridge_vlan_info vinfo;
2595 + const u8 *vlans = port_priv->vlans;
2599 + nest = nla_nest_start(skb, IFLA_AF_SPEC);
2601 + netdev_err(netdev, "nla_nest_start failed");
2605 + for (i = 0; i < VLAN_VID_MASK + 1; i++) {
2612 + err = nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
2613 + sizeof(vinfo), &vinfo);
2614 + if (unlikely(err))
2618 + nla_nest_end(skb, nest);
2623 + netdev_err(netdev, "nla_put_ err %d\n", err);
2624 + nla_nest_cancel(skb, nest);
2628 +static int evb_getlink(struct sk_buff *skb, u32 pid, u32 seq,
2629 + struct net_device *netdev, u32 filter_mask, int nlflags)
2631 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2632 + struct evb_priv *evb_priv = port_priv->evb_priv;
2633 + struct ifinfomsg *hdr;
2634 + struct nlmsghdr *nlh;
2637 + if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
2638 + evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
2642 + nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*hdr), NLM_F_MULTI);
2646 + hdr = nlmsg_data(nlh);
2647 + memset(hdr, 0, sizeof(*hdr));
2648 + hdr->ifi_family = AF_BRIDGE;
2649 + hdr->ifi_type = netdev->type;
2650 + hdr->ifi_index = netdev->ifindex;
2651 + hdr->ifi_flags = dev_get_flags(netdev);
2653 + err = __nla_put_netdev(skb, netdev);
2654 + if (unlikely(err))
2657 + err = __nla_put_port(skb, netdev);
2658 + if (unlikely(err))
2661 + /* Check if the VID information is requested */
2662 + if (filter_mask & RTEXT_FILTER_BRVLAN) {
2663 + err = __nla_put_vlan(skb, netdev);
2664 + if (unlikely(err))
2668 + nlmsg_end(skb, nlh);
2672 + nlmsg_cancel(skb, nlh);
2676 +static int evb_dellink(struct net_device *netdev,
2677 + struct nlmsghdr *nlh,
2680 + struct nlattr *tb[IFLA_BRIDGE_MAX + 1];
2681 + struct nlattr *spec;
2682 + struct bridge_vlan_info *vinfo;
2683 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2686 + spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2690 + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy);
2691 + if (unlikely(err))
2694 + if (!tb[IFLA_BRIDGE_VLAN_INFO])
2695 + return -EOPNOTSUPP;
2697 + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
2699 + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
2702 + err = evb_port_del_rule(netdev, NULL, vinfo->vid);
2703 + if (unlikely(err)) {
2704 + netdev_err(netdev, "evb_port_del_rule err %d\n", err);
2707 + port_priv->vlans[vinfo->vid] = 0;
2712 +void evb_port_get_stats(struct net_device *netdev,
2713 + struct rtnl_link_stats64 *storage)
2715 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2719 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2721 + port_priv->evb_priv->mux_handle,
2722 + port_priv->port_index,
2723 + DPDMUX_CNT_ING_FRAME, &storage->rx_packets);
2724 + if (unlikely(err))
2727 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2729 + port_priv->evb_priv->mux_handle,
2730 + port_priv->port_index,
2731 + DPDMUX_CNT_ING_BYTE, &storage->rx_bytes);
2732 + if (unlikely(err))
2735 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2737 + port_priv->evb_priv->mux_handle,
2738 + port_priv->port_index,
2739 + DPDMUX_CNT_ING_FLTR_FRAME, &tmp);
2740 + if (unlikely(err))
2743 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2745 + port_priv->evb_priv->mux_handle,
2746 + port_priv->port_index,
2747 + DPDMUX_CNT_ING_FRAME_DISCARD,
2748 + &storage->rx_dropped);
2749 + if (unlikely(err)) {
2750 + storage->rx_dropped = tmp;
2753 + storage->rx_dropped += tmp;
2755 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2757 + port_priv->evb_priv->mux_handle,
2758 + port_priv->port_index,
2759 + DPDMUX_CNT_ING_MCAST_FRAME,
2760 + &storage->multicast);
2761 + if (unlikely(err))
2764 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2766 + port_priv->evb_priv->mux_handle,
2767 + port_priv->port_index,
2768 + DPDMUX_CNT_EGR_FRAME, &storage->tx_packets);
2769 + if (unlikely(err))
2772 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2774 + port_priv->evb_priv->mux_handle,
2775 + port_priv->port_index,
2776 + DPDMUX_CNT_EGR_BYTE, &storage->tx_bytes);
2777 + if (unlikely(err))
2780 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2782 + port_priv->evb_priv->mux_handle,
2783 + port_priv->port_index,
2784 + DPDMUX_CNT_EGR_FRAME_DISCARD,
2785 + &storage->tx_dropped);
2786 + if (unlikely(err))
2792 + netdev_err(netdev, "dpdmux_if_get_counter err %d\n", err);
2795 +static const struct net_device_ops evb_port_ops = {
2796 + .ndo_open = &evb_port_open,
2798 + .ndo_start_xmit = &evb_dropframe,
2800 + .ndo_fdb_add = &evb_port_fdb_add,
2801 + .ndo_fdb_del = &evb_port_fdb_del,
2803 + .ndo_get_stats64 = &evb_port_get_stats,
2804 + .ndo_change_mtu = &evb_change_mtu,
2808 + enum dpdmux_counter_type id;
2809 + char name[ETH_GSTRING_LEN];
2810 +} evb_ethtool_counters[] = {
2811 + {DPDMUX_CNT_ING_FRAME, "rx frames"},
2812 + {DPDMUX_CNT_ING_BYTE, "rx bytes"},
2813 + {DPDMUX_CNT_ING_FLTR_FRAME, "rx filtered frames"},
2814 + {DPDMUX_CNT_ING_FRAME_DISCARD, "rx discarded frames"},
2815 + {DPDMUX_CNT_ING_BCAST_FRAME, "rx b-cast frames"},
2816 + {DPDMUX_CNT_ING_BCAST_BYTES, "rx b-cast bytes"},
2817 + {DPDMUX_CNT_ING_MCAST_FRAME, "rx m-cast frames"},
2818 + {DPDMUX_CNT_ING_MCAST_BYTE, "rx m-cast bytes"},
2819 + {DPDMUX_CNT_EGR_FRAME, "tx frames"},
2820 + {DPDMUX_CNT_EGR_BYTE, "tx bytes"},
2821 + {DPDMUX_CNT_EGR_FRAME_DISCARD, "tx discarded frames"},
2824 +static int evb_ethtool_get_sset_count(struct net_device *dev, int sset)
2827 + case ETH_SS_STATS:
2828 + return ARRAY_SIZE(evb_ethtool_counters);
2830 + return -EOPNOTSUPP;
2834 +static void evb_ethtool_get_strings(struct net_device *netdev,
2835 + u32 stringset, u8 *data)
2839 + switch (stringset) {
2840 + case ETH_SS_STATS:
2841 + for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++)
2842 + memcpy(data + i * ETH_GSTRING_LEN,
2843 + evb_ethtool_counters[i].name, ETH_GSTRING_LEN);
2848 +static void evb_ethtool_get_stats(struct net_device *netdev,
2849 + struct ethtool_stats *stats,
2852 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2856 + for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) {
2857 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2859 + port_priv->evb_priv->mux_handle,
2860 + port_priv->port_index,
2861 + evb_ethtool_counters[i].id,
2864 + netdev_err(netdev, "dpdmux_if_get_counter[%s] err %d\n",
2865 + evb_ethtool_counters[i].name, err);
2869 +static const struct ethtool_ops evb_port_ethtool_ops = {
2870 + .get_strings = &evb_ethtool_get_strings,
2871 + .get_ethtool_stats = &evb_ethtool_get_stats,
2872 + .get_sset_count = &evb_ethtool_get_sset_count,
2875 +static int evb_open(struct net_device *netdev)
2877 + struct evb_priv *priv = netdev_priv(netdev);
2880 + err = dpdmux_enable(priv->mc_io, 0, priv->mux_handle);
2881 + if (unlikely(err))
2882 + netdev_err(netdev, "dpdmux_enable err %d\n", err);
2887 +static int evb_close(struct net_device *netdev)
2889 + struct evb_priv *priv = netdev_priv(netdev);
2892 + err = dpdmux_disable(priv->mc_io, 0, priv->mux_handle);
2893 + if (unlikely(err))
2894 + netdev_err(netdev, "dpdmux_disable err %d\n", err);
2899 +static const struct net_device_ops evb_ops = {
2900 + .ndo_start_xmit = &evb_dropframe,
2901 + .ndo_open = &evb_open,
2902 + .ndo_stop = &evb_close,
2904 + .ndo_bridge_setlink = &evb_setlink,
2905 + .ndo_bridge_getlink = &evb_getlink,
2906 + .ndo_bridge_dellink = &evb_dellink,
2908 + .ndo_get_stats64 = &evb_port_get_stats,
2909 + .ndo_change_mtu = &evb_change_mtu,
2912 +static int evb_takedown(struct fsl_mc_device *evb_dev)
2914 + struct device *dev = &evb_dev->dev;
2915 + struct net_device *netdev = dev_get_drvdata(dev);
2916 + struct evb_priv *priv = netdev_priv(netdev);
2919 + err = dpdmux_close(priv->mc_io, 0, priv->mux_handle);
2920 + if (unlikely(err))
2921 + dev_warn(dev, "dpdmux_close err %d\n", err);
2926 +static int evb_init(struct fsl_mc_device *evb_dev)
2928 + struct device *dev = &evb_dev->dev;
2929 + struct net_device *netdev = dev_get_drvdata(dev);
2930 + struct evb_priv *priv = netdev_priv(netdev);
2931 + u16 version_major;
2932 + u16 version_minor;
2935 + priv->dev_id = evb_dev->obj_desc.id;
2937 + err = dpdmux_open(priv->mc_io, 0, priv->dev_id, &priv->mux_handle);
2938 + if (unlikely(err)) {
2939 + dev_err(dev, "dpdmux_open err %d\n", err);
2942 + if (!priv->mux_handle) {
2943 + dev_err(dev, "dpdmux_open returned null handle but no error\n");
2948 + err = dpdmux_get_attributes(priv->mc_io, 0, priv->mux_handle,
2950 + if (unlikely(err)) {
2951 + dev_err(dev, "dpdmux_get_attributes err %d\n", err);
2955 + err = dpdmux_get_api_version(priv->mc_io, 0,
2958 + if (unlikely(err)) {
2959 + dev_err(dev, "dpdmux_get_api_version err %d\n", err);
2963 + /* Minimum supported DPDMUX version check */
2964 + if (version_major < DPDMUX_MIN_VER_MAJOR ||
2965 + (version_major == DPDMUX_MIN_VER_MAJOR &&
2966 + version_minor < DPDMUX_MIN_VER_MINOR)) {
2967 + dev_err(dev, "DPDMUX version %d.%d not supported. Use %d.%d or greater.\n",
2968 + version_major, version_minor,
2969 + DPDMUX_MIN_VER_MAJOR, DPDMUX_MIN_VER_MAJOR);
2974 + err = dpdmux_reset(priv->mc_io, 0, priv->mux_handle);
2975 + if (unlikely(err)) {
2976 + dev_err(dev, "dpdmux_reset err %d\n", err);
2983 + dpdmux_close(priv->mc_io, 0, priv->mux_handle);
2988 +static int evb_remove(struct fsl_mc_device *evb_dev)
2990 + struct device *dev = &evb_dev->dev;
2991 + struct net_device *netdev = dev_get_drvdata(dev);
2992 + struct evb_priv *priv = netdev_priv(netdev);
2993 + struct evb_port_priv *port_priv;
2994 + struct list_head *pos;
2996 + list_for_each(pos, &priv->port_list) {
2997 + port_priv = list_entry(pos, struct evb_port_priv, list);
3000 + netdev_upper_dev_unlink(port_priv->netdev, netdev);
3003 + unregister_netdev(port_priv->netdev);
3004 + free_netdev(port_priv->netdev);
3007 + evb_teardown_irqs(evb_dev);
3009 + unregister_netdev(netdev);
3011 + evb_takedown(evb_dev);
3012 + fsl_mc_portal_free(priv->mc_io);
3014 + dev_set_drvdata(dev, NULL);
3015 + free_netdev(netdev);
3020 +static int evb_probe(struct fsl_mc_device *evb_dev)
3022 + struct device *dev;
3023 + struct evb_priv *priv = NULL;
3024 + struct net_device *netdev = NULL;
3025 + char port_name[IFNAMSIZ];
3029 + dev = &evb_dev->dev;
3031 + /* register switch device, it's for management only - no I/O */
3032 + netdev = alloc_etherdev(sizeof(*priv));
3034 + dev_err(dev, "alloc_etherdev error\n");
3037 + netdev->netdev_ops = &evb_ops;
3039 + dev_set_drvdata(dev, netdev);
3041 + priv = netdev_priv(netdev);
3043 + err = fsl_mc_portal_allocate(evb_dev, 0, &priv->mc_io);
3044 + if (unlikely(err)) {
3045 + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
3046 + goto err_free_netdev;
3048 + if (!priv->mc_io) {
3049 + dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n");
3051 + goto err_free_netdev;
3054 + err = evb_init(evb_dev);
3055 + if (unlikely(err)) {
3056 + dev_err(dev, "evb init err %d\n", err);
3057 + goto err_free_cmdport;
3060 + INIT_LIST_HEAD(&priv->port_list);
3061 + netdev->flags |= IFF_PROMISC | IFF_MASTER;
3063 + dev_alloc_name(netdev, "evb%d");
3065 + /* register switch ports */
3066 + snprintf(port_name, IFNAMSIZ, "%sp%%d", netdev->name);
3068 + /* only register downlinks? */
3069 + for (i = 0; i < priv->attr.num_ifs + 1; i++) {
3070 + struct net_device *port_netdev;
3071 + struct evb_port_priv *port_priv;
3075 + alloc_etherdev(sizeof(struct evb_port_priv));
3076 + if (!port_netdev) {
3077 + dev_err(dev, "alloc_etherdev error\n");
3078 + goto err_takedown;
3081 + port_priv = netdev_priv(port_netdev);
3083 + port_netdev->flags |= IFF_PROMISC | IFF_SLAVE;
3085 + dev_alloc_name(port_netdev, port_name);
3087 + port_netdev = netdev;
3088 + port_priv = &priv->uplink;
3091 + port_priv->netdev = port_netdev;
3092 + port_priv->evb_priv = priv;
3093 + port_priv->port_index = i;
3095 + SET_NETDEV_DEV(port_netdev, dev);
3098 + port_netdev->netdev_ops = &evb_port_ops;
3100 + err = register_netdev(port_netdev);
3102 + dev_err(dev, "register_netdev err %d\n", err);
3103 + free_netdev(port_netdev);
3104 + goto err_takedown;
3108 + err = netdev_master_upper_dev_link(port_netdev, netdev,
3110 + if (unlikely(err)) {
3111 + dev_err(dev, "netdev_master_upper_dev_link err %d\n",
3113 + unregister_netdev(port_netdev);
3114 + free_netdev(port_netdev);
3116 + goto err_takedown;
3118 + rtmsg_ifinfo(RTM_NEWLINK, port_netdev,
3119 + IFF_SLAVE, GFP_KERNEL);
3122 + list_add(&port_priv->list, &priv->port_list);
3124 + err = register_netdev(netdev);
3127 + dev_err(dev, "register_netdev error %d\n", err);
3128 + goto err_takedown;
3132 + port_netdev->ethtool_ops = &evb_port_ethtool_ops;
3134 + /* ports are up from init */
3136 + err = dev_open(port_netdev, NULL);
3138 + if (unlikely(err))
3139 + dev_warn(dev, "dev_open err %d\n", err);
3143 + err = evb_setup_irqs(evb_dev);
3144 + if (unlikely(err)) {
3145 + dev_warn(dev, "evb_setup_irqs err %d\n", err);
3146 + goto err_takedown;
3149 + dev_info(dev, "probed evb device with %d ports\n",
3150 + priv->attr.num_ifs);
3154 + evb_remove(evb_dev);
3156 + fsl_mc_portal_free(priv->mc_io);
3161 +static const struct fsl_mc_device_id evb_match_id_table[] = {
3163 + .vendor = FSL_MC_VENDOR_FREESCALE,
3164 + .obj_type = "dpdmux",
3169 +static struct fsl_mc_driver evb_drv = {
3171 + .name = KBUILD_MODNAME,
3172 + .owner = THIS_MODULE,
3174 + .probe = evb_probe,
3175 + .remove = evb_remove,
3176 + .match_id_table = evb_match_id_table,
3179 +module_fsl_mc_driver(evb_drv);
3181 +MODULE_LICENSE("GPL");
3182 +MODULE_DESCRIPTION("Layerscape DPAA Edge Virtual Bridge driver (prototype)");