OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 = ðtool_op_get_link, |
||
2933 | + .get_settings = &evb_get_settings, |
||
2934 | + .set_settings = &evb_set_settings, |
||
2935 | + .get_strings = &evb_ethtool_get_strings, |
||
2936 | + .get_ethtool_stats = &evb_ethtool_get_stats, |
||
2937 | + .get_sset_count = &evb_ethtool_get_sset_count, |
||
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)"); |