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