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
6 This is an integrated patch of dpaa2-virtualbridge for layerscape
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>
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
27 +++ b/drivers/staging/fsl-dpaa2/evb/Kconfig
30 + tristate "DPAA2 Edge Virtual Bridge"
31 + depends on FSL_MC_BUS && FSL_DPAA2
35 + Prototype driver for DPAA2 Edge Virtual Bridge.
37 +++ b/drivers/staging/fsl-dpaa2/evb/Makefile
40 +obj-$(CONFIG_FSL_DPAA2_EVB) += dpaa2-evb.o
42 +dpaa2-evb-objs := evb.o dpdmux.o
45 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
48 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
50 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
52 +/* Copyright 2013-2016 Freescale Semiconductor Inc.
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.
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
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.
83 +#ifndef _FSL_DPDMUX_CMD_H
84 +#define _FSL_DPDMUX_CMD_H
87 +#define DPDMUX_VER_MAJOR 6
88 +#define DPDMUX_VER_MINOR 1
90 +#define DPDMUX_CMD_BASE_VER 1
91 +#define DPDMUX_CMD_ID_OFFSET 4
93 +#define DPDMUX_CMD(id) (((id) << DPDMUX_CMD_ID_OFFSET) | DPDMUX_CMD_BASE_VER)
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)
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)
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)
115 +#define DPDMUX_CMDID_SET_MAX_FRAME_LENGTH DPDMUX_CMD(0x0a1)
117 +#define DPDMUX_CMDID_UL_RESET_COUNTERS DPDMUX_CMD(0x0a3)
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)
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)
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)
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)
142 +struct dpdmux_cmd_open {
146 +struct dpdmux_cmd_create {
152 + u16 adv_max_dmat_entries;
153 + u16 adv_max_mc_groups;
154 + u16 adv_max_vlan_ids;
160 +struct dpdmux_cmd_destroy {
164 +#define DPDMUX_ENABLE_SHIFT 0
165 +#define DPDMUX_ENABLE_SIZE 1
167 +struct dpdmux_rsp_is_enabled {
171 +struct dpdmux_cmd_set_irq_enable {
177 +struct dpdmux_cmd_get_irq_enable {
182 +struct dpdmux_rsp_get_irq_enable {
186 +struct dpdmux_cmd_set_irq_mask {
191 +struct dpdmux_cmd_get_irq_mask {
196 +struct dpdmux_rsp_get_irq_mask {
200 +struct dpdmux_cmd_get_irq_status {
205 +struct dpdmux_rsp_get_irq_status {
209 +struct dpdmux_cmd_clear_irq_status {
214 +struct dpdmux_rsp_get_attr {
229 +struct dpdmux_cmd_set_max_frame_length {
230 + u16 max_frame_length;
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
238 +struct dpdmux_cmd_if_set_accepted_frames {
243 +struct dpdmux_cmd_if {
247 +struct dpdmux_rsp_if_get_attr {
251 + u8 accepted_frames_type;
255 +struct dpdmux_cmd_if_l2_rule {
268 +struct dpdmux_cmd_if_get_counter {
273 +struct dpdmux_rsp_if_get_counter {
278 +struct dpdmux_cmd_if_set_link_cfg {
288 +struct dpdmux_cmd_if_get_link_state {
292 +struct dpdmux_rsp_if_get_link_state {
303 +struct dpdmux_rsp_get_api_version {
308 +struct dpdmux_set_custom_key {
313 +struct dpdmux_cmd_add_custom_cls_entry {
322 +struct dpdmux_cmd_remove_custom_cls_entry {
330 +#endif /* _FSL_DPDMUX_CMD_H */
332 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c
334 +/* Copyright 2013-2016 Freescale Semiconductor Inc.
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.
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
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.
365 +#include <linux/fsl/mc.h>
367 +#include "dpdmux-cmd.h"
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
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.
384 + * Return: '0' on Success; Error code otherwise.
386 +int dpdmux_open(struct fsl_mc_io *mc_io,
391 + struct fsl_mc_command cmd = { 0 };
392 + struct dpdmux_cmd_open *cmd_params;
395 + /* prepare command */
396 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_OPEN,
399 + cmd_params = (struct dpdmux_cmd_open *)cmd.params;
400 + cmd_params->dpdmux_id = cpu_to_le32(dpdmux_id);
402 + /* send command to mc*/
403 + err = mc_send_command(mc_io, &cmd);
407 + /* retrieve response parameters */
408 + *token = mc_cmd_hdr_read_token(&cmd);
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
419 + * After this function is called, no further operations are
420 + * allowed on the object without opening a new control session.
422 + * Return: '0' on Success; Error code otherwise.
424 +int dpdmux_close(struct fsl_mc_io *mc_io,
428 + struct fsl_mc_command cmd = { 0 };
430 + /* prepare command */
431 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLOSE,
435 + /* send command to mc*/
436 + return mc_send_command(mc_io, &cmd);
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
447 + * Create the DPDMUX object, allocate required resources and
448 + * perform required initialization.
450 + * The object can be created either by declaring it in the
451 + * DPL file, or by calling this function.
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.
459 + * Return: '0' on Success; Error code otherwise.
461 +int dpdmux_create(struct fsl_mc_io *mc_io,
464 + const struct dpdmux_cfg *cfg,
467 + struct fsl_mc_command cmd = { 0 };
468 + struct dpdmux_cmd_create *cmd_params;
471 + /* prepare command */
472 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CREATE,
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);
485 + /* send command to mc*/
486 + err = mc_send_command(mc_io, &cmd);
490 + /* retrieve response parameters */
491 + *obj_id = mc_cmd_hdr_read_token(&cmd);
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;
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.
509 + * Return: '0' on Success; error code otherwise.
511 +int dpdmux_destroy(struct fsl_mc_io *mc_io,
516 + struct fsl_mc_command cmd = { 0 };
517 + struct dpdmux_cmd_destroy *cmd_params;
519 + /* prepare command */
520 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DESTROY,
523 + cmd_params = (struct dpdmux_cmd_destroy *)cmd.params;
524 + cmd_params->dpdmux_id = cpu_to_le32(object_id);
526 + /* send command to mc*/
527 + return mc_send_command(mc_io, &cmd);
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
536 + * Return: '0' on Success; Error code otherwise.
538 +int dpdmux_enable(struct fsl_mc_io *mc_io,
542 + struct fsl_mc_command cmd = { 0 };
544 + /* prepare command */
545 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ENABLE,
549 + /* send command to mc*/
550 + return mc_send_command(mc_io, &cmd);
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
559 + * Return: '0' on Success; Error code otherwise.
561 +int dpdmux_disable(struct fsl_mc_io *mc_io,
565 + struct fsl_mc_command cmd = { 0 };
567 + /* prepare command */
568 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DISABLE,
572 + /* send command to mc*/
573 + return mc_send_command(mc_io, &cmd);
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
583 + * Return: '0' on Success; Error code otherwise.
585 +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
590 + struct fsl_mc_command cmd = { 0 };
591 + struct dpdmux_rsp_is_enabled *rsp_params;
594 + /* prepare command */
595 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IS_ENABLED,
599 + /* send command to mc*/
600 + err = mc_send_command(mc_io, &cmd);
604 + /* retrieve response parameters */
605 + rsp_params = (struct dpdmux_rsp_is_enabled *)cmd.params;
606 + *en = dpdmux_get_field(rsp_params->en, ENABLE);
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
617 + * Return: '0' on Success; Error code otherwise.
619 +int dpdmux_reset(struct fsl_mc_io *mc_io,
623 + struct fsl_mc_command cmd = { 0 };
625 + /* prepare command */
626 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_RESET,
630 + /* send command to mc*/
631 + return mc_send_command(mc_io, &cmd);
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
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
647 + * Return: '0' on Success; Error code otherwise.
649 +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
655 + struct fsl_mc_command cmd = { 0 };
656 + struct dpdmux_cmd_set_irq_enable *cmd_params;
658 + /* prepare command */
659 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_ENABLE,
662 + cmd_params = (struct dpdmux_cmd_set_irq_enable *)cmd.params;
663 + cmd_params->enable = en;
664 + cmd_params->irq_index = irq_index;
666 + /* send command to mc*/
667 + return mc_send_command(mc_io, &cmd);
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
678 + * Return: '0' on Success; Error code otherwise.
680 +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
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;
691 + /* prepare command */
692 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_ENABLE,
695 + cmd_params = (struct dpdmux_cmd_get_irq_enable *)cmd.params;
696 + cmd_params->irq_index = irq_index;
698 + /* send command to mc*/
699 + err = mc_send_command(mc_io, &cmd);
703 + /* retrieve response parameters */
704 + rsp_params = (struct dpdmux_rsp_get_irq_enable *)cmd.params;
705 + *en = rsp_params->enable;
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;
719 + * 1 = consider event for asserting IRQ
721 + * Every interrupt can have up to 32 causes and the interrupt model supports
722 + * masking/unmasking each cause independently
724 + * Return: '0' on Success; Error code otherwise.
726 +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
732 + struct fsl_mc_command cmd = { 0 };
733 + struct dpdmux_cmd_set_irq_mask *cmd_params;
735 + /* prepare command */
736 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_MASK,
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;
743 + /* send command to mc*/
744 + return mc_send_command(mc_io, &cmd);
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
755 + * Every interrupt can have up to 32 causes and the interrupt model supports
756 + * masking/unmasking each cause independently
758 + * Return: '0' on Success; Error code otherwise.
760 +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
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;
771 + /* prepare command */
772 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_MASK,
775 + cmd_params = (struct dpdmux_cmd_get_irq_mask *)cmd.params;
776 + cmd_params->irq_index = irq_index;
778 + /* send command to mc*/
779 + err = mc_send_command(mc_io, &cmd);
783 + /* retrieve response parameters */
784 + rsp_params = (struct dpdmux_rsp_get_irq_mask *)cmd.params;
785 + *mask = le32_to_cpu(rsp_params->mask);
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
800 + * Return: '0' on Success; Error code otherwise.
802 +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
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;
813 + /* prepare command */
814 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_STATUS,
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;
821 + /* send command to mc*/
822 + err = mc_send_command(mc_io, &cmd);
826 + /* retrieve response parameters */
827 + rsp_params = (struct dpdmux_rsp_get_irq_status *)cmd.params;
828 + *status = le32_to_cpu(rsp_params->status);
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:
841 + * 1 = clear status bit
843 + * Return: '0' on Success; Error code otherwise.
845 +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
851 + struct fsl_mc_command cmd = { 0 };
852 + struct dpdmux_cmd_clear_irq_status *cmd_params;
854 + /* prepare command */
855 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLEAR_IRQ_STATUS,
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;
862 + /* send command to mc*/
863 + return mc_send_command(mc_io, &cmd);
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
873 + * Return: '0' on Success; Error code otherwise.
875 +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
878 + struct dpdmux_attr *attr)
880 + struct fsl_mc_command cmd = { 0 };
881 + struct dpdmux_rsp_get_attr *rsp_params;
884 + /* prepare command */
885 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_ATTR,
889 + /* send command to mc*/
890 + err = mc_send_command(mc_io, &cmd);
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);
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
913 + * Return: Completion status. '0' on Success; Error code otherwise.
915 +int dpdmux_if_enable(struct fsl_mc_io *mc_io,
920 + struct dpdmux_cmd_if *cmd_params;
921 + struct fsl_mc_command cmd = { 0 };
923 + /* prepare command */
924 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ENABLE,
927 + cmd_params = (struct dpdmux_cmd_if *)cmd.params;
928 + cmd_params->if_id = cpu_to_le16(if_id);
930 + /* send command to mc*/
931 + return mc_send_command(mc_io, &cmd);
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
941 + * Return: Completion status. '0' on Success; Error code otherwise.
943 +int dpdmux_if_disable(struct fsl_mc_io *mc_io,
948 + struct dpdmux_cmd_if *cmd_params;
949 + struct fsl_mc_command cmd = { 0 };
951 + /* prepare command */
952 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_DISABLE,
955 + cmd_params = (struct dpdmux_cmd_if *)cmd.params;
956 + cmd_params->if_id = cpu_to_le16(if_id);
958 + /* send command to mc*/
959 + return mc_send_command(mc_io, &cmd);
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
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.
974 + * Return: '0' on Success; Error code otherwise.
976 +int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io,
979 + u16 max_frame_length)
981 + struct fsl_mc_command cmd = { 0 };
982 + struct dpdmux_cmd_set_max_frame_length *cmd_params;
984 + /* prepare command */
985 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_MAX_FRAME_LENGTH,
988 + cmd_params = (struct dpdmux_cmd_set_max_frame_length *)cmd.params;
989 + cmd_params->max_frame_length = cpu_to_le16(max_frame_length);
991 + /* send command to mc*/
992 + return mc_send_command(mc_io, &cmd);
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
1001 + * Return: '0' on Success; Error code otherwise.
1003 +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
1007 + struct fsl_mc_command cmd = { 0 };
1009 + /* prepare command */
1010 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_RESET_COUNTERS,
1014 + /* send command to mc*/
1015 + return mc_send_command(mc_io, &cmd);
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
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;
1033 + * Return: '0' on Success; Error code otherwise.
1035 +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
1039 + const struct dpdmux_accepted_frames *cfg)
1041 + struct fsl_mc_command cmd = { 0 };
1042 + struct dpdmux_cmd_if_set_accepted_frames *cmd_params;
1044 + /* prepare command */
1045 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES,
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,
1052 + dpdmux_set_field(cmd_params->frames_options, UNACCEPTED_FRAMES_ACTION,
1053 + cfg->unaccept_act);
1055 + /* send command to mc*/
1056 + return mc_send_command(mc_io, &cmd);
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
1067 + * Return: '0' on Success; Error code otherwise.
1069 +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
1073 + struct dpdmux_if_attr *attr)
1075 + struct fsl_mc_command cmd = { 0 };
1076 + struct dpdmux_cmd_if *cmd_params;
1077 + struct dpdmux_rsp_if_get_attr *rsp_params;
1080 + /* prepare command */
1081 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_ATTR,
1084 + cmd_params = (struct dpdmux_cmd_if *)cmd.params;
1085 + cmd_params->if_id = cpu_to_le16(if_id);
1087 + /* send command to mc*/
1088 + err = mc_send_command(mc_io, &cmd);
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);
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
1111 + * Function removes a L2 rule from DPDMUX table
1112 + * or adds an interface to an existing multicast address
1114 + * Return: '0' on Success; Error code otherwise.
1116 +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
1120 + const struct dpdmux_l2_rule *rule)
1122 + struct fsl_mc_command cmd = { 0 };
1123 + struct dpdmux_cmd_if_l2_rule *cmd_params;
1125 + /* prepare command */
1126 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_REMOVE_L2_RULE,
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];
1139 + /* send command to mc*/
1140 + return mc_send_command(mc_io, &cmd);
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
1151 + * Function adds a L2 rule into DPDMUX table
1152 + * or adds an interface to an existing multicast address
1154 + * Return: '0' on Success; Error code otherwise.
1156 +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
1160 + const struct dpdmux_l2_rule *rule)
1162 + struct fsl_mc_command cmd = { 0 };
1163 + struct dpdmux_cmd_if_l2_rule *cmd_params;
1165 + /* prepare command */
1166 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ADD_L2_RULE,
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];
1179 + /* send command to mc*/
1180 + return mc_send_command(mc_io, &cmd);
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
1192 + * Return: '0' on Success; Error code otherwise.
1194 +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
1198 + enum dpdmux_counter_type counter_type,
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;
1206 + /* prepare command */
1207 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_COUNTER,
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;
1214 + /* send command to mc*/
1215 + err = mc_send_command(mc_io, &cmd);
1219 + /* retrieve response parameters */
1220 + rsp_params = (struct dpdmux_rsp_if_get_counter *)cmd.params;
1221 + *counter = le64_to_cpu(rsp_params->counter);
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
1234 + * Return: '0' on Success; Error code otherwise.
1236 +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
1240 + struct dpdmux_link_cfg *cfg)
1242 + struct fsl_mc_command cmd = { 0 };
1243 + struct dpdmux_cmd_if_set_link_cfg *cmd_params;
1245 + /* prepare command */
1246 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_LINK_CFG,
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);
1254 + /* send command to mc*/
1255 + return mc_send_command(mc_io, &cmd);
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
1266 + * @returns '0' on Success; Error code otherwise.
1268 +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
1272 + struct dpdmux_link_state *state)
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;
1279 + /* prepare command */
1280 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_LINK_STATE,
1283 + cmd_params = (struct dpdmux_cmd_if_get_link_state *)cmd.params;
1284 + cmd_params->if_id = cpu_to_le16(if_id);
1286 + /* send command to mc*/
1287 + err = mc_send_command(mc_io, &cmd);
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);
1301 + * dpdmux_set_custom_key - Set a custom classification key.
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.
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.
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.
1317 + * @returns '0' on Success; Error code otherwise.
1319 +int dpdmux_set_custom_key(struct fsl_mc_io *mc_io,
1324 + struct dpdmux_set_custom_key *cmd_params;
1325 + struct fsl_mc_command cmd = { 0 };
1327 + /* prepare command */
1328 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_CUSTOM_KEY,
1331 + cmd_params = (struct dpdmux_set_custom_key *)cmd.params;
1332 + cmd_params->key_cfg_iova = cpu_to_le64(key_cfg_iova);
1334 + /* send command to mc*/
1335 + return mc_send_command(mc_io, &cmd);
1339 + * dpdmux_add_custom_cls_entry - Adds a custom classification entry.
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.
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.
1352 + * @returns '0' on Success; Error code otherwise.
1354 +int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io,
1357 + struct dpdmux_rule_cfg *rule,
1358 + struct dpdmux_cls_action *action)
1360 + struct dpdmux_cmd_add_custom_cls_entry *cmd_params;
1361 + struct fsl_mc_command cmd = { 0 };
1363 + /* prepare command */
1364 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY,
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);
1374 + /* send command to mc*/
1375 + return mc_send_command(mc_io, &cmd);
1379 + * dpdmux_remove_custom_cls_entry - Removes a custom classification entry.
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.
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
1390 + * @returns '0' on Success; Error code otherwise.
1392 +int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io,
1395 + struct dpdmux_rule_cfg *rule)
1397 + struct dpdmux_cmd_remove_custom_cls_entry *cmd_params;
1398 + struct fsl_mc_command cmd = { 0 };
1400 + /* prepare command */
1401 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY,
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);
1409 + /* send command to mc*/
1410 + return mc_send_command(mc_io, &cmd);
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
1420 + * Return: '0' on Success; Error code otherwise.
1422 +int dpdmux_get_api_version(struct fsl_mc_io *mc_io,
1427 + struct fsl_mc_command cmd = { 0 };
1428 + struct dpdmux_rsp_get_api_version *rsp_params;
1431 + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_API_VERSION,
1435 + err = mc_send_command(mc_io, &cmd);
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);
1446 +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.h
1448 +/* Copyright 2013-2015 Freescale Semiconductor Inc.
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.
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
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.
1479 +#ifndef __FSL_DPDMUX_H
1480 +#define __FSL_DPDMUX_H
1484 +/* Data Path Demux API
1485 + * Contains API for handling DPDMUX topology and functionality
1488 +int dpdmux_open(struct fsl_mc_io *mc_io,
1493 +int dpdmux_close(struct fsl_mc_io *mc_io,
1498 + * DPDMUX general options
1502 + * Enable bridging between internal interfaces
1504 +#define DPDMUX_OPT_BRIDGE_EN 0x0000000000000002ULL
1507 + * Mask support for classification
1509 +#define DPDMUX_OPT_CLS_MASK_SUPPORT 0x0000000000000020ULL
1511 +#define DPDMUX_IRQ_INDEX_IF 0x0000
1512 +#define DPDMUX_IRQ_INDEX 0x0001
1515 + * IRQ event - Indicates that the link state changed
1517 +#define DPDMUX_IRQ_EVENT_LINK_CHANGED 0x0001
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
1524 +enum dpdmux_manip {
1525 + DPDMUX_MANIP_NONE = 0x0,
1526 + DPDMUX_MANIP_ADD_REMOVE_S_VLAN = 0x1
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
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
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
1554 +struct dpdmux_cfg {
1555 + enum dpdmux_method method;
1556 + enum dpdmux_manip manip;
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.
1571 + u16 max_dmat_entries;
1572 + u16 max_mc_groups;
1577 +int dpdmux_create(struct fsl_mc_io *mc_io,
1580 + const struct dpdmux_cfg *cfg,
1583 +int dpdmux_destroy(struct fsl_mc_io *mc_io,
1588 +int dpdmux_enable(struct fsl_mc_io *mc_io,
1592 +int dpdmux_disable(struct fsl_mc_io *mc_io,
1596 +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
1601 +int dpdmux_reset(struct fsl_mc_io *mc_io,
1605 +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
1611 +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
1617 +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
1623 +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
1629 +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
1635 +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
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
1650 +struct dpdmux_attr {
1653 + enum dpdmux_method method;
1654 + enum dpdmux_manip manip;
1659 +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
1662 + struct dpdmux_attr *attr);
1664 +int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io,
1667 + u16 max_frame_length);
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
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
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
1704 + * @DPDMUX_ADMIT_ONLY_UNTAGGED: Untagged frames or priority-tagged frames
1705 + * received on this interface are accepted
1707 +enum dpdmux_accepted_frames_type {
1708 + DPDMUX_ADMIT_ALL = 0,
1709 + DPDMUX_ADMIT_ONLY_VLAN_TAGGED = 1,
1710 + DPDMUX_ADMIT_ONLY_UNTAGGED = 2
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
1719 +enum dpdmux_action {
1720 + DPDMUX_ACTION_DROP = 0,
1721 + DPDMUX_ACTION_REDIRECT_TO_CTRL = 1
1725 + * struct dpdmux_accepted_frames - Frame types configuration
1726 + * @type: Defines ingress accepted frames
1727 + * @unaccept_act: Defines action on frames not accepted
1729 +struct dpdmux_accepted_frames {
1730 + enum dpdmux_accepted_frames_type type;
1731 + enum dpdmux_action unaccept_act;
1734 +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
1738 + const struct dpdmux_accepted_frames *cfg);
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
1746 +struct dpdmux_if_attr {
1749 + enum dpdmux_accepted_frames_type accept_frame_type;
1752 +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
1756 + struct dpdmux_if_attr *attr);
1758 +int dpdmux_if_enable(struct fsl_mc_io *mc_io,
1763 +int dpdmux_if_disable(struct fsl_mc_io *mc_io,
1769 + * struct dpdmux_l2_rule - Structure representing L2 rule
1770 + * @mac_addr: MAC address
1771 + * @vlan_id: VLAN ID
1773 +struct dpdmux_l2_rule {
1778 +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
1782 + const struct dpdmux_l2_rule *rule);
1784 +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
1788 + const struct dpdmux_l2_rule *rule);
1790 +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
1794 + enum dpdmux_counter_type counter_type,
1797 +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
1802 + * Enable auto-negotiation
1804 +#define DPDMUX_LINK_OPT_AUTONEG 0x0000000000000001ULL
1806 + * Enable half-duplex mode
1808 +#define DPDMUX_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL
1810 + * Enable pause frames
1812 +#define DPDMUX_LINK_OPT_PAUSE 0x0000000000000004ULL
1814 + * Enable a-symmetric pause frames
1816 +#define DPDMUX_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
1819 + * struct dpdmux_link_cfg - Structure representing DPDMUX link configuration
1821 + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
1823 +struct dpdmux_link_cfg {
1828 +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
1832 + struct dpdmux_link_cfg *cfg);
1834 + * struct dpdmux_link_state - Structure representing DPDMUX link state
1836 + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
1837 + * @up: 0 - down, 1 - up
1839 +struct dpdmux_link_state {
1845 +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
1849 + struct dpdmux_link_state *state);
1851 +int dpdmux_set_custom_key(struct fsl_mc_io *mc_io,
1854 + u64 key_cfg_iova);
1857 + * struct dpdmux_rule_cfg - Custom classification rule.
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
1865 +struct dpdmux_rule_cfg {
1872 + * struct dpdmux_cls_action - Action to execute for frames matching the
1873 + * classification entry
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.
1880 +struct dpdmux_cls_action {
1884 +int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io,
1887 + struct dpdmux_rule_cfg *rule,
1888 + struct dpdmux_cls_action *action);
1890 +int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io,
1893 + struct dpdmux_rule_cfg *rule);
1895 +int dpdmux_get_api_version(struct fsl_mc_io *mc_io,
1900 +#endif /* __FSL_DPDMUX_H */
1902 +++ b/drivers/staging/fsl-dpaa2/evb/evb.c
1904 +/* Copyright 2015 Freescale Semiconductor Inc.
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.
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
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.
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>
1941 +#include <uapi/linux/if_bridge.h>
1942 +#include <net/netlink.h>
1944 +#include <linux/fsl/mc.h>
1946 +#include "dpdmux.h"
1947 +#include "dpdmux-cmd.h"
1949 +static const char evb_drv_version[] = "0.1";
1951 +/* Minimal supported DPDMUX version */
1952 +#define DPDMUX_MIN_VER_MAJOR 6
1953 +#define DPDMUX_MIN_VER_MINOR 0
1956 +#define DPDMUX_MAX_IRQ_NUM 2
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
1963 +struct evb_port_priv {
1964 + struct net_device *netdev;
1965 + struct list_head list;
1967 + struct evb_priv *evb_priv;
1968 + u8 vlans[VLAN_VID_MASK + 1];
1973 + struct evb_port_priv uplink;
1975 + struct fsl_mc_io *mc_io;
1976 + struct list_head port_list;
1977 + struct dpdmux_attr attr;
1982 +static int _evb_port_carrier_state_sync(struct net_device *netdev)
1984 + struct evb_port_priv *port_priv = netdev_priv(netdev);
1985 + struct dpdmux_link_state state;
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);
1996 + WARN_ONCE(state.up > 1, "Garbage read into link_state");
1999 + netif_carrier_on(port_priv->netdev);
2001 + netif_carrier_off(port_priv->netdev);
2006 +static int evb_port_open(struct net_device *netdev)
2010 + /* FIXME: enable port when support added */
2012 + err = _evb_port_carrier_state_sync(netdev);
2014 + netdev_err(netdev, "ethsw_port_carrier_state_sync err %d\n",
2022 +static netdev_tx_t evb_dropframe(struct sk_buff *skb, struct net_device *dev)
2024 + /* we don't support I/O for now, drop the frame */
2025 + dev_kfree_skb_any(skb);
2026 + return NETDEV_TX_OK;
2029 +static int evb_links_state_update(struct evb_priv *priv)
2031 + struct evb_port_priv *port_priv;
2032 + struct list_head *pos;
2035 + list_for_each(pos, &priv->port_list) {
2036 + port_priv = list_entry(pos, struct evb_port_priv, list);
2038 + err = _evb_port_carrier_state_sync(port_priv->netdev);
2040 + netdev_err(port_priv->netdev,
2041 + "_evb_port_carrier_state_sync err %d\n",
2048 +static irqreturn_t evb_irq0_handler(int irq_num, void *arg)
2050 + return IRQ_WAKE_THREAD;
2053 +static irqreturn_t _evb_irq0_handler_thread(int irq_num, void *arg)
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;
2063 + /* Mask the events and the if_id reserved bits to be cleared on read */
2064 + u32 status = DPDMUX_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000;
2067 + /* Sanity check */
2068 + if (WARN_ON(!evb_dev || !evb_dev->irqs || !evb_dev->irqs[irq_index]))
2070 + if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != (u32)irq_num))
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,
2078 + if (unlikely(err))
2079 + netdev_err(netdev, "Can't clear irq status (err %d)",
2084 + if (status & DPDMUX_IRQ_EVENT_LINK_CHANGED) {
2085 + err = evb_links_state_update(priv);
2086 + if (unlikely(err))
2091 + return IRQ_HANDLED;
2094 +static int evb_setup_irqs(struct fsl_mc_device *evb_dev)
2096 + struct device *dev = &evb_dev->dev;
2097 + struct net_device *netdev = dev_get_drvdata(dev);
2098 + struct evb_priv *priv = netdev_priv(netdev);
2100 + struct fsl_mc_device_irq *irq;
2101 + const int irq_index = DPDMUX_IRQ_INDEX_IF;
2102 + u32 mask = DPDMUX_IRQ_EVENT_LINK_CHANGED;
2104 + err = fsl_mc_allocate_irqs(evb_dev);
2105 + if (unlikely(err)) {
2106 + dev_err(dev, "MC irqs allocation failed\n");
2110 + if (WARN_ON(evb_dev->obj_desc.irq_count != DPDMUX_MAX_IRQ_NUM)) {
2115 + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
2117 + if (unlikely(err)) {
2118 + dev_err(dev, "dpdmux_set_irq_enable err %d\n", err);
2122 + irq = evb_dev->irqs[irq_index];
2124 + err = devm_request_threaded_irq(dev, irq->msi_desc->irq,
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);
2134 + err = dpdmux_set_irq_mask(priv->mc_io, 0, priv->mux_handle,
2136 + if (unlikely(err)) {
2137 + dev_err(dev, "dpdmux_set_irq_mask(): %d", err);
2138 + goto free_devm_irq;
2141 + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
2143 + if (unlikely(err)) {
2144 + dev_err(dev, "dpdmux_set_irq_enable(): %d", err);
2145 + goto free_devm_irq;
2151 + devm_free_irq(dev, irq->msi_desc->irq, dev);
2153 + fsl_mc_free_irqs(evb_dev);
2157 +static void evb_teardown_irqs(struct fsl_mc_device *evb_dev)
2159 + struct device *dev = &evb_dev->dev;
2160 + struct net_device *netdev = dev_get_drvdata(dev);
2161 + struct evb_priv *priv = netdev_priv(netdev);
2163 + dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
2164 + DPDMUX_IRQ_INDEX_IF, 0);
2166 + devm_free_irq(dev,
2167 + evb_dev->irqs[DPDMUX_IRQ_INDEX_IF]->msi_desc->irq,
2169 + fsl_mc_free_irqs(evb_dev);
2172 +static int evb_port_add_rule(struct net_device *netdev,
2173 + const unsigned char *addr, u16 vid)
2175 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2176 + struct dpdmux_l2_rule rule = { .vlan_id = vid };
2180 + ether_addr_copy(rule.mac_addr, addr);
2182 + err = dpdmux_if_add_l2_rule(port_priv->evb_priv->mc_io,
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);
2191 +static int evb_port_del_rule(struct net_device *netdev,
2192 + const unsigned char *addr, u16 vid)
2194 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2195 + struct dpdmux_l2_rule rule = { .vlan_id = vid };
2199 + ether_addr_copy(rule.mac_addr, addr);
2201 + err = dpdmux_if_remove_l2_rule(port_priv->evb_priv->mc_io,
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);
2210 +static bool _lookup_address(struct net_device *netdev,
2211 + const unsigned char *addr)
2213 + struct netdev_hw_addr *ha;
2214 + struct netdev_hw_addr_list *list = (is_unicast_ether_addr(addr)) ?
2215 + &netdev->uc : &netdev->mc;
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);
2224 + netif_addr_unlock_bh(netdev);
2228 +static inline int evb_port_fdb_prep(struct nlattr *tb[],
2229 + struct net_device *netdev,
2230 + const unsigned char *addr, u16 *vid,
2233 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2234 + struct evb_priv *evb_priv = port_priv->evb_priv;
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;
2245 + /* check if the address is configured on this port */
2246 + if (_lookup_address(netdev, addr)) {
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]));
2261 + *vid = nla_get_u16(tb[NDA_VLAN]);
2263 + if (!*vid || *vid >= VLAN_VID_MASK) {
2264 + netdev_err(netdev, "invalid vid value 0x%04x\n", *vid);
2267 + } else if (evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
2268 + netdev_err(netdev,
2269 + "EVB mode requires explicit VLAN configuration\n");
2271 + } else if (tb[NDA_VLAN]) {
2272 + netdev_warn(netdev, "VLAN not supported, argument ignored\n");
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)
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",
2293 + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 0);
2294 + if (unlikely(err))
2297 + err = evb_port_add_rule(netdev, addr, _vid);
2298 + if (unlikely(err))
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);
2308 + err = dev_mc_add(netdev, addr);
2309 + if (unlikely(err)) {
2310 + netdev_err(netdev, "dev_mc_add err %d\n", err);
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)
2325 + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 1);
2326 + if (unlikely(err))
2329 + err = evb_port_del_rule(netdev, addr, _vid);
2330 + if (unlikely(err))
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);
2340 + err = dev_mc_del(netdev, addr);
2341 + if (unlikely(err)) {
2342 + netdev_err(netdev, "dev_mc_del err %d\n", err);
2350 +static int evb_change_mtu(struct net_device *netdev,
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;
2358 + /* This operation is not permitted on downlinks */
2359 + if (port_priv->port_index > 0)
2362 + err = dpdmux_set_max_frame_length(evb_priv->mc_io,
2364 + evb_priv->mux_handle,
2365 + (uint16_t)(mtu + VLAN_ETH_HLEN));
2367 + if (unlikely(err)) {
2368 + netdev_err(netdev, "dpdmux_ul_set_max_frame_length err %d\n",
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;
2379 + netdev->mtu = mtu;
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), },
2390 +static int evb_setlink_af_spec(struct net_device *netdev,
2391 + struct nlattr **tb)
2393 + struct bridge_vlan_info *vinfo;
2394 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2397 + if (!tb[IFLA_BRIDGE_VLAN_INFO]) {
2398 + netdev_err(netdev, "no VLAN INFO in nlmsg\n");
2399 + return -EOPNOTSUPP;
2402 + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
2404 + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
2407 + err = evb_port_add_rule(netdev, NULL, vinfo->vid);
2408 + if (unlikely(err))
2411 + port_priv->vlans[vinfo->vid] = 1;
2416 +static int evb_setlink(struct net_device *netdev,
2417 + struct nlmsghdr *nlh,
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];
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;
2434 + attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
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",
2445 + err = evb_setlink_af_spec(netdev, tb);
2449 + netdev_err(netdev, "nlmsg_find_attr found no AF_SPEC\n");
2450 + return -EOPNOTSUPP;
2453 +static int __nla_put_netdev(struct sk_buff *skb, struct net_device *netdev)
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;
2462 + err = nla_put_string(skb, IFLA_IFNAME, netdev->name);
2463 + if (unlikely(err))
2465 + err = nla_put_u32(skb, IFLA_MASTER, evb_priv->uplink.netdev->ifindex);
2466 + if (unlikely(err))
2468 + err = nla_put_u32(skb, IFLA_MTU, netdev->mtu);
2469 + if (unlikely(err))
2471 + err = nla_put_u8(skb, IFLA_OPERSTATE, operstate);
2472 + if (unlikely(err))
2474 + if (netdev->addr_len) {
2475 + err = nla_put(skb, IFLA_ADDRESS, netdev->addr_len,
2476 + netdev->dev_addr);
2477 + if (unlikely(err))
2481 + iflink = dev_get_iflink(netdev);
2482 + if (netdev->ifindex != iflink) {
2483 + err = nla_put_u32(skb, IFLA_LINK, iflink);
2484 + if (unlikely(err))
2491 + netdev_err(netdev, "nla_put_ err %d\n", err);
2495 +static int __nla_put_port(struct sk_buff *skb, struct net_device *netdev)
2497 + struct nlattr *nest;
2500 + nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
2502 + netdev_err(netdev, "nla_nest_start failed\n");
2506 + err = nla_put_u8(skb, IFLA_BRPORT_STATE, BR_STATE_FORWARDING);
2507 + if (unlikely(err))
2509 + err = nla_put_u16(skb, IFLA_BRPORT_PRIORITY, 0);
2510 + if (unlikely(err))
2512 + err = nla_put_u32(skb, IFLA_BRPORT_COST, 0);
2513 + if (unlikely(err))
2515 + err = nla_put_u8(skb, IFLA_BRPORT_MODE, 0);
2516 + if (unlikely(err))
2518 + err = nla_put_u8(skb, IFLA_BRPORT_GUARD, 0);
2519 + if (unlikely(err))
2521 + err = nla_put_u8(skb, IFLA_BRPORT_PROTECT, 0);
2522 + if (unlikely(err))
2524 + err = nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, 0);
2525 + if (unlikely(err))
2527 + err = nla_put_u8(skb, IFLA_BRPORT_LEARNING, 0);
2528 + if (unlikely(err))
2530 + err = nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, 1);
2531 + if (unlikely(err))
2533 + nla_nest_end(skb, nest);
2538 + netdev_err(netdev, "nla_put_ err %d\n", err);
2539 + nla_nest_cancel(skb, nest);
2543 +static int __nla_put_vlan(struct sk_buff *skb, struct net_device *netdev)
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;
2552 + nest = nla_nest_start(skb, IFLA_AF_SPEC);
2554 + netdev_err(netdev, "nla_nest_start failed");
2558 + for (i = 0; i < VLAN_VID_MASK + 1; i++) {
2565 + err = nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
2566 + sizeof(vinfo), &vinfo);
2567 + if (unlikely(err))
2571 + nla_nest_end(skb, nest);
2576 + netdev_err(netdev, "nla_put_ err %d\n", err);
2577 + nla_nest_cancel(skb, nest);
2581 +static int evb_getlink(struct sk_buff *skb, u32 pid, u32 seq,
2582 + struct net_device *netdev, u32 filter_mask, int nlflags)
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;
2590 + if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
2591 + evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
2595 + nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*hdr), NLM_F_MULTI);
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);
2606 + err = __nla_put_netdev(skb, netdev);
2607 + if (unlikely(err))
2610 + err = __nla_put_port(skb, netdev);
2611 + if (unlikely(err))
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))
2621 + nlmsg_end(skb, nlh);
2625 + nlmsg_cancel(skb, nlh);
2629 +static int evb_dellink(struct net_device *netdev,
2630 + struct nlmsghdr *nlh,
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);
2639 + spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2643 + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy, NULL);
2644 + if (unlikely(err))
2647 + if (!tb[IFLA_BRIDGE_VLAN_INFO])
2648 + return -EOPNOTSUPP;
2650 + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
2652 + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
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);
2660 + port_priv->vlans[vinfo->vid] = 0;
2665 +void evb_port_get_stats(struct net_device *netdev,
2666 + struct rtnl_link_stats64 *storage)
2668 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2672 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2674 + port_priv->evb_priv->mux_handle,
2675 + port_priv->port_index,
2676 + DPDMUX_CNT_ING_FRAME, &storage->rx_packets);
2677 + if (unlikely(err))
2680 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2682 + port_priv->evb_priv->mux_handle,
2683 + port_priv->port_index,
2684 + DPDMUX_CNT_ING_BYTE, &storage->rx_bytes);
2685 + if (unlikely(err))
2688 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2690 + port_priv->evb_priv->mux_handle,
2691 + port_priv->port_index,
2692 + DPDMUX_CNT_ING_FLTR_FRAME, &tmp);
2693 + if (unlikely(err))
2696 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
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;
2706 + storage->rx_dropped += tmp;
2708 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
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))
2717 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2719 + port_priv->evb_priv->mux_handle,
2720 + port_priv->port_index,
2721 + DPDMUX_CNT_EGR_FRAME, &storage->tx_packets);
2722 + if (unlikely(err))
2725 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2727 + port_priv->evb_priv->mux_handle,
2728 + port_priv->port_index,
2729 + DPDMUX_CNT_EGR_BYTE, &storage->tx_bytes);
2730 + if (unlikely(err))
2733 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
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))
2745 + netdev_err(netdev, "dpdmux_if_get_counter err %d\n", err);
2748 +static const struct net_device_ops evb_port_ops = {
2749 + .ndo_open = &evb_port_open,
2751 + .ndo_start_xmit = &evb_dropframe,
2753 + .ndo_fdb_add = &evb_port_fdb_add,
2754 + .ndo_fdb_del = &evb_port_fdb_del,
2756 + .ndo_get_stats64 = &evb_port_get_stats,
2757 + .ndo_change_mtu = &evb_change_mtu,
2760 +static void evb_get_drvinfo(struct net_device *netdev,
2761 + struct ethtool_drvinfo *drvinfo)
2763 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2764 + u16 version_major, version_minor;
2767 + strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
2768 + strlcpy(drvinfo->version, evb_drv_version, sizeof(drvinfo->version));
2770 + err = dpdmux_get_api_version(port_priv->evb_priv->mc_io, 0,
2774 + strlcpy(drvinfo->fw_version, "N/A",
2775 + sizeof(drvinfo->fw_version));
2777 + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
2778 + "%u.%u", version_major, version_minor);
2780 + strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent),
2781 + sizeof(drvinfo->bus_info));
2784 +static int evb_get_settings(struct net_device *netdev,
2785 + struct ethtool_cmd *cmd)
2787 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2788 + struct dpdmux_link_state state = {0};
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,
2796 + netdev_err(netdev, "ERROR %d getting link state", err);
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.
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);
2814 +static int evb_set_settings(struct net_device *netdev,
2815 + struct ethtool_cmd *cmd)
2817 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2818 + struct dpdmux_link_state state = {0};
2819 + struct dpdmux_link_cfg cfg = {0};
2822 + netdev_dbg(netdev, "Setting link parameters...");
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,
2829 + netdev_err(netdev, "ERROR %d getting link state", err);
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.
2837 + if (netif_running(netdev)) {
2838 + netdev_info(netdev,
2839 + "Sorry, interface must be brought down first.\n");
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;
2848 + cfg.options &= ~DPDMUX_LINK_OPT_AUTONEG;
2849 + if (cmd->duplex == DUPLEX_HALF)
2850 + cfg.options |= DPDMUX_LINK_OPT_HALF_DUPLEX;
2852 + cfg.options &= ~DPDMUX_LINK_OPT_HALF_DUPLEX;
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,
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
2862 + netdev_dbg(netdev, "ERROR %d setting link cfg", err);
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"},
2885 +static int evb_ethtool_get_sset_count(struct net_device *dev, int sset)
2888 + case ETH_SS_STATS:
2889 + return ARRAY_SIZE(evb_ethtool_counters);
2891 + return -EOPNOTSUPP;
2895 +static void evb_ethtool_get_strings(struct net_device *netdev,
2896 + u32 stringset, u8 *data)
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);
2909 +static void evb_ethtool_get_stats(struct net_device *netdev,
2910 + struct ethtool_stats *stats,
2913 + struct evb_port_priv *port_priv = netdev_priv(netdev);
2917 + for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) {
2918 + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
2920 + port_priv->evb_priv->mux_handle,
2921 + port_priv->port_index,
2922 + evb_ethtool_counters[i].id,
2925 + netdev_err(netdev, "dpdmux_if_get_counter[%s] err %d\n",
2926 + evb_ethtool_counters[i].name, err);
2930 +static const struct ethtool_ops evb_port_ethtool_ops = {
2931 + .get_drvinfo = &evb_get_drvinfo,
2932 + .get_link = ðtool_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,
2940 +static int evb_open(struct net_device *netdev)
2942 + struct evb_priv *priv = netdev_priv(netdev);
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);
2952 +static int evb_close(struct net_device *netdev)
2954 + struct evb_priv *priv = netdev_priv(netdev);
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);
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,
2969 + .ndo_bridge_setlink = &evb_setlink,
2970 + .ndo_bridge_getlink = &evb_getlink,
2971 + .ndo_bridge_dellink = &evb_dellink,
2973 + .ndo_get_stats64 = &evb_port_get_stats,
2974 + .ndo_change_mtu = &evb_change_mtu,
2977 +static int evb_takedown(struct fsl_mc_device *evb_dev)
2979 + struct device *dev = &evb_dev->dev;
2980 + struct net_device *netdev = dev_get_drvdata(dev);
2981 + struct evb_priv *priv = netdev_priv(netdev);
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);
2991 +static int evb_init(struct fsl_mc_device *evb_dev)
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;
3000 + priv->dev_id = evb_dev->obj_desc.id;
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);
3007 + if (!priv->mux_handle) {
3008 + dev_err(dev, "dpdmux_open returned null handle but no error\n");
3013 + err = dpdmux_get_attributes(priv->mc_io, 0, priv->mux_handle,
3015 + if (unlikely(err)) {
3016 + dev_err(dev, "dpdmux_get_attributes err %d\n", err);
3020 + err = dpdmux_get_api_version(priv->mc_io, 0,
3023 + if (unlikely(err)) {
3024 + dev_err(dev, "dpdmux_get_api_version err %d\n", err);
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);
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);
3048 + dpdmux_close(priv->mc_io, 0, priv->mux_handle);
3053 +static int evb_remove(struct fsl_mc_device *evb_dev)
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;
3061 + list_for_each(pos, &priv->port_list) {
3062 + port_priv = list_entry(pos, struct evb_port_priv, list);
3065 + netdev_upper_dev_unlink(port_priv->netdev, netdev);
3068 + unregister_netdev(port_priv->netdev);
3069 + free_netdev(port_priv->netdev);
3072 + evb_teardown_irqs(evb_dev);
3074 + unregister_netdev(netdev);
3076 + evb_takedown(evb_dev);
3077 + fsl_mc_portal_free(priv->mc_io);
3079 + dev_set_drvdata(dev, NULL);
3080 + free_netdev(netdev);
3085 +static int evb_probe(struct fsl_mc_device *evb_dev)
3087 + struct device *dev;
3088 + struct evb_priv *priv = NULL;
3089 + struct net_device *netdev = NULL;
3090 + char port_name[IFNAMSIZ];
3094 + dev = &evb_dev->dev;
3096 + /* register switch device, it's for management only - no I/O */
3097 + netdev = alloc_etherdev(sizeof(*priv));
3099 + dev_err(dev, "alloc_etherdev error\n");
3102 + netdev->netdev_ops = &evb_ops;
3104 + dev_set_drvdata(dev, netdev);
3106 + priv = netdev_priv(netdev);
3108 + err = fsl_mc_portal_allocate(evb_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
3111 + if (err == -ENXIO)
3112 + err = -EPROBE_DEFER;
3114 + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
3115 + goto err_free_netdev;
3118 + if (!priv->mc_io) {
3119 + dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n");
3121 + goto err_free_netdev;
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;
3130 + INIT_LIST_HEAD(&priv->port_list);
3131 + netdev->flags |= IFF_PROMISC | IFF_MASTER;
3133 + dev_alloc_name(netdev, "evb%d");
3135 + /* register switch ports */
3136 + snprintf(port_name, IFNAMSIZ, "%sp%%d", netdev->name);
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;
3145 + alloc_etherdev(sizeof(struct evb_port_priv));
3146 + if (!port_netdev) {
3147 + dev_err(dev, "alloc_etherdev error\n");
3148 + goto err_takedown;
3151 + port_priv = netdev_priv(port_netdev);
3153 + port_netdev->flags |= IFF_PROMISC | IFF_SLAVE;
3155 + dev_alloc_name(port_netdev, port_name);
3157 + port_netdev = netdev;
3158 + port_priv = &priv->uplink;
3161 + port_priv->netdev = port_netdev;
3162 + port_priv->evb_priv = priv;
3163 + port_priv->port_index = i;
3165 + SET_NETDEV_DEV(port_netdev, dev);
3168 + port_netdev->netdev_ops = &evb_port_ops;
3170 + err = register_netdev(port_netdev);
3172 + dev_err(dev, "register_netdev err %d\n", err);
3173 + free_netdev(port_netdev);
3174 + goto err_takedown;
3178 + err = netdev_master_upper_dev_link(port_netdev, netdev,
3180 + if (unlikely(err)) {
3181 + dev_err(dev, "netdev_master_upper_dev_link err %d\n",
3183 + unregister_netdev(port_netdev);
3184 + free_netdev(port_netdev);
3186 + goto err_takedown;
3188 + rtmsg_ifinfo(RTM_NEWLINK, port_netdev,
3189 + IFF_SLAVE, GFP_KERNEL);
3192 + list_add(&port_priv->list, &priv->port_list);
3194 + /* Set MTU limits only on uplink */
3195 + port_netdev->min_mtu = EVB_MIN_MTU;
3196 + port_netdev->max_mtu = EVB_MAX_MTU;
3198 + err = register_netdev(netdev);
3201 + dev_err(dev, "register_netdev error %d\n", err);
3202 + goto err_takedown;
3206 + port_netdev->ethtool_ops = &evb_port_ethtool_ops;
3208 + /* ports are up from init */
3210 + err = dev_open(port_netdev);
3212 + if (unlikely(err))
3213 + dev_warn(dev, "dev_open err %d\n", err);
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;
3223 + dev_info(dev, "probed evb device with %d ports\n",
3224 + priv->attr.num_ifs);
3228 + evb_remove(evb_dev);
3230 + fsl_mc_portal_free(priv->mc_io);
3235 +static const struct fsl_mc_device_id evb_match_id_table[] = {
3237 + .vendor = FSL_MC_VENDOR_FREESCALE,
3238 + .obj_type = "dpdmux",
3243 +static struct fsl_mc_driver evb_drv = {
3245 + .name = KBUILD_MODNAME,
3246 + .owner = THIS_MODULE,
3248 + .probe = evb_probe,
3249 + .remove = evb_remove,
3250 + .match_id_table = evb_match_id_table,
3253 +module_fsl_mc_driver(evb_drv);
3255 +MODULE_LICENSE("GPL");
3256 +MODULE_DESCRIPTION("Layerscape DPAA Edge Virtual Bridge driver (prototype)");