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