[cavium-octeon] update to 2.6.30-rc5
[openwrt.git] / target / linux / cavium-octeon / patches / 006-octeon_mgmt_driver.patch
1 Signed-off-by: David Daney <ddaney@caviumnetworks.com>
2 ---
3  arch/mips/include/asm/octeon/cvmx-mdio.h |  577 +++++++++++++++++++++
4  drivers/net/Kconfig                      |    8 +
5  drivers/net/Makefile                     |    1 +
6  drivers/net/octeon/Makefile              |   11 +
7  drivers/net/octeon/cvmx-mgmt-port.c      |  818 ++++++++++++++++++++++++++++++
8  drivers/net/octeon/cvmx-mgmt-port.h      |  168 ++++++
9  drivers/net/octeon/octeon-mgmt-port.c    |  389 ++++++++++++++
10  7 files changed, 1972 insertions(+), 0 deletions(-)
11  create mode 100644 arch/mips/include/asm/octeon/cvmx-mdio.h
12  create mode 100644 drivers/net/octeon/Makefile
13  create mode 100644 drivers/net/octeon/cvmx-mgmt-port.c
14  create mode 100644 drivers/net/octeon/cvmx-mgmt-port.h
15  create mode 100644 drivers/net/octeon/octeon-mgmt-port.c
16
17 diff --git a/arch/mips/include/asm/octeon/cvmx-mdio.h b/arch/mips/include/asm/octeon/cvmx-mdio.h
18 new file mode 100644
19 index 0000000..89b0cc8
20 --- /dev/null
21 +++ b/arch/mips/include/asm/octeon/cvmx-mdio.h
22 @@ -0,0 +1,577 @@
23 +/***********************license start***************
24 + * Author: Cavium Networks
25 + *
26 + * Contact: support@caviumnetworks.com
27 + * This file is part of the OCTEON SDK
28 + *
29 + * Copyright (c) 2003-2008 Cavium Networks
30 + *
31 + * This file is free software; you can redistribute it and/or modify
32 + * it under the terms of the GNU General Public License, Version 2, as
33 + * published by the Free Software Foundation.
34 + *
35 + * This file is distributed in the hope that it will be useful, but
36 + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
37 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
38 + * NONINFRINGEMENT.  See the GNU General Public License for more
39 + * details.
40 + *
41 + * You should have received a copy of the GNU General Public License
42 + * along with this file; if not, write to the Free Software
43 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
44 + * or visit http://www.gnu.org/licenses/.
45 + *
46 + * This file may also be available under a different license from Cavium.
47 + * Contact Cavium Networks for more information
48 + ***********************license end**************************************/
49 +
50 +/**
51 + *
52 + * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3
53 + * clause 22 and clause 45 operations.
54 + *
55 + */
56 +
57 +#ifndef __CVMX_MIO_H__
58 +#define __CVMX_MIO_H__
59 +
60 +#include "cvmx-smix-defs.h"
61 +
62 +/**
63 + * PHY register 0 from the 802.3 spec
64 + */
65 +#define CVMX_MDIO_PHY_REG_CONTROL 0
66 +union cvmx_mdio_phy_reg_control {
67 +       uint16_t u16;
68 +       struct {
69 +               uint16_t reset:1;
70 +               uint16_t loopback:1;
71 +               uint16_t speed_lsb:1;
72 +               uint16_t autoneg_enable:1;
73 +               uint16_t power_down:1;
74 +               uint16_t isolate:1;
75 +               uint16_t restart_autoneg:1;
76 +               uint16_t duplex:1;
77 +               uint16_t collision_test:1;
78 +               uint16_t speed_msb:1;
79 +               uint16_t unidirectional_enable:1;
80 +               uint16_t reserved_0_4:5;
81 +       } s;
82 +};
83 +
84 +/**
85 + * PHY register 1 from the 802.3 spec
86 + */
87 +#define CVMX_MDIO_PHY_REG_STATUS 1
88 +union cvmx_mdio_phy_reg_status {
89 +       uint16_t u16;
90 +       struct {
91 +               uint16_t capable_100base_t4:1;
92 +               uint16_t capable_100base_x_full:1;
93 +               uint16_t capable_100base_x_half:1;
94 +               uint16_t capable_10_full:1;
95 +               uint16_t capable_10_half:1;
96 +               uint16_t capable_100base_t2_full:1;
97 +               uint16_t capable_100base_t2_half:1;
98 +               uint16_t capable_extended_status:1;
99 +               uint16_t capable_unidirectional:1;
100 +               uint16_t capable_mf_preamble_suppression:1;
101 +               uint16_t autoneg_complete:1;
102 +               uint16_t remote_fault:1;
103 +               uint16_t capable_autoneg:1;
104 +               uint16_t link_status:1;
105 +               uint16_t jabber_detect:1;
106 +               uint16_t capable_extended_registers:1;
107 +
108 +       } s;
109 +};
110 +
111 +/**
112 + * PHY register 2 from the 802.3 spec
113 + */
114 +#define CVMX_MDIO_PHY_REG_ID1 2
115 +union cvmx_mdio_phy_reg_id1 {
116 +       uint16_t u16;
117 +       struct {
118 +               uint16_t oui_bits_3_18;
119 +       } s;
120 +};
121 +
122 +/**
123 + * PHY register 3 from the 802.3 spec
124 + */
125 +#define CVMX_MDIO_PHY_REG_ID2 3
126 +union cvmx_mdio_phy_reg_id2 {
127 +       uint16_t u16;
128 +       struct {
129 +               uint16_t oui_bits_19_24:6;
130 +               uint16_t model:6;
131 +               uint16_t revision:4;
132 +       } s;
133 +};
134 +
135 +/**
136 + * PHY register 4 from the 802.3 spec
137 + */
138 +#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4
139 +union cvmx_mdio_phy_reg_autoneg_adver {
140 +       uint16_t u16;
141 +       struct {
142 +               uint16_t next_page:1;
143 +               uint16_t reserved_14:1;
144 +               uint16_t remote_fault:1;
145 +               uint16_t reserved_12:1;
146 +               uint16_t asymmetric_pause:1;
147 +               uint16_t pause:1;
148 +               uint16_t advert_100base_t4:1;
149 +               uint16_t advert_100base_tx_full:1;
150 +               uint16_t advert_100base_tx_half:1;
151 +               uint16_t advert_10base_tx_full:1;
152 +               uint16_t advert_10base_tx_half:1;
153 +               uint16_t selector:5;
154 +       } s;
155 +};
156 +
157 +/**
158 + * PHY register 5 from the 802.3 spec
159 + */
160 +#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5
161 +union cvmx_mdio_phy_reg_link_partner_ability {
162 +       uint16_t u16;
163 +       struct {
164 +               uint16_t next_page:1;
165 +               uint16_t ack:1;
166 +               uint16_t remote_fault:1;
167 +               uint16_t reserved_12:1;
168 +               uint16_t asymmetric_pause:1;
169 +               uint16_t pause:1;
170 +               uint16_t advert_100base_t4:1;
171 +               uint16_t advert_100base_tx_full:1;
172 +               uint16_t advert_100base_tx_half:1;
173 +               uint16_t advert_10base_tx_full:1;
174 +               uint16_t advert_10base_tx_half:1;
175 +               uint16_t selector:5;
176 +       } s;
177 +};
178 +
179 +/**
180 + * PHY register 6 from the 802.3 spec
181 + */
182 +#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6
183 +union cvmx_mdio_phy_reg_autoneg_expansion {
184 +       uint16_t u16;
185 +       struct {
186 +               uint16_t reserved_5_15:11;
187 +               uint16_t parallel_detection_fault:1;
188 +               uint16_t link_partner_next_page_capable:1;
189 +               uint16_t local_next_page_capable:1;
190 +               uint16_t page_received:1;
191 +               uint16_t link_partner_autoneg_capable:1;
192 +
193 +       } s;
194 +};
195 +
196 +/**
197 + * PHY register 9 from the 802.3 spec
198 + */
199 +#define CVMX_MDIO_PHY_REG_CONTROL_1000 9
200 +union cvmx_mdio_phy_reg_control_1000 {
201 +       uint16_t u16;
202 +       struct {
203 +               uint16_t test_mode:3;
204 +               uint16_t manual_master_slave:1;
205 +               uint16_t master:1;
206 +               uint16_t port_type:1;
207 +               uint16_t advert_1000base_t_full:1;
208 +               uint16_t advert_1000base_t_half:1;
209 +               uint16_t reserved_0_7:8;
210 +       } s;
211 +};
212 +
213 +/**
214 + * PHY register 10 from the 802.3 spec
215 + */
216 +#define CVMX_MDIO_PHY_REG_STATUS_1000 10
217 +union cvmx_mdio_phy_reg_status_1000 {
218 +       uint16_t u16;
219 +       struct {
220 +               uint16_t master_slave_fault:1;
221 +               uint16_t is_master:1;
222 +               uint16_t local_receiver_ok:1;
223 +               uint16_t remote_receiver_ok:1;
224 +               uint16_t remote_capable_1000base_t_full:1;
225 +               uint16_t remote_capable_1000base_t_half:1;
226 +               uint16_t reserved_8_9:2;
227 +               uint16_t idle_error_count:8;
228 +       } s;
229 +};
230 +
231 +/**
232 + * PHY register 15 from the 802.3 spec
233 + */
234 +#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15
235 +union cvmx_mdio_phy_reg_extended_status {
236 +       uint16_t u16;
237 +       struct {
238 +               uint16_t capable_1000base_x_full:1;
239 +               uint16_t capable_1000base_x_half:1;
240 +               uint16_t capable_1000base_t_full:1;
241 +               uint16_t capable_1000base_t_half:1;
242 +               uint16_t reserved_0_11:12;
243 +       } s;
244 +};
245 +
246 +/**
247 + * PHY register 13 from the 802.3 spec
248 + */
249 +#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13
250 +union cvmx_mdio_phy_reg_mmd_control {
251 +       uint16_t u16;
252 +       struct {
253 +               uint16_t function:2;
254 +               uint16_t reserved_5_13:9;
255 +               uint16_t devad:5;
256 +       } s;
257 +};
258 +
259 +/**
260 + * PHY register 14 from the 802.3 spec
261 + */
262 +#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14
263 +union cvmx_mdio_phy_reg_mmd_address_data {
264 +       uint16_t u16;
265 +       struct {
266 +               uint16_t address_data:16;
267 +       } s;
268 +};
269 +
270 +/* Operating request encodings. */
271 +#define MDIO_CLAUSE_22_WRITE    0
272 +#define MDIO_CLAUSE_22_READ     1
273 +
274 +#define MDIO_CLAUSE_45_ADDRESS  0
275 +#define MDIO_CLAUSE_45_WRITE    1
276 +#define MDIO_CLAUSE_45_READ_INC 2
277 +#define MDIO_CLAUSE_45_READ     3
278 +
279 +/* MMD identifiers, mostly for accessing devices withing XENPAK modules. */
280 +#define CVMX_MMD_DEVICE_PMA_PMD      1
281 +#define CVMX_MMD_DEVICE_WIS          2
282 +#define CVMX_MMD_DEVICE_PCS          3
283 +#define CVMX_MMD_DEVICE_PHY_XS       4
284 +#define CVMX_MMD_DEVICE_DTS_XS       5
285 +#define CVMX_MMD_DEVICE_TC           6
286 +#define CVMX_MMD_DEVICE_CL22_EXT     29
287 +#define CVMX_MMD_DEVICE_VENDOR_1     30
288 +#define CVMX_MMD_DEVICE_VENDOR_2     31
289 +
290 +/**
291 + * Perform an MII read. This function is used to read PHY
292 + * registers controlling auto negotiation.
293 + *
294 + * @bus_id:   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
295 + *                 support multiple busses.
296 + * @phy_id:   The MII phy id
297 + * @location: Register location to read
298 + *
299 + * Returns Result from the read or -1 on failure
300 + */
301 +static inline int cvmx_mdio_read(int bus_id, int phy_id, int location)
302 +{
303 +       union cvmx_smix_cmd smi_cmd;
304 +       union cvmx_smix_rd_dat smi_rd;
305 +       int timeout = 1000;
306 +
307 +       smi_cmd.u64 = 0;
308 +       smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ;
309 +       smi_cmd.s.phy_adr = phy_id;
310 +       smi_cmd.s.reg_adr = location;
311 +       cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
312 +
313 +       do {
314 +               cvmx_wait(1000);
315 +               smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id));
316 +       } while (smi_rd.s.pending && timeout--);
317 +
318 +       if (smi_rd.s.val)
319 +               return smi_rd.s.dat;
320 +       else
321 +               return -1;
322 +}
323 +
324 +/**
325 + * Perform an MII write. This function is used to write PHY
326 + * registers controlling auto negotiation.
327 + *
328 + * @bus_id:   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
329 + *                 support multiple busses.
330 + * @phy_id:   The MII phy id
331 + * @location: Register location to write
332 + * @val:      Value to write
333 + *
334 + * Returns -1 on error
335 + *         0 on success
336 + */
337 +static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val)
338 +{
339 +       union cvmx_smix_cmd smi_cmd;
340 +       union cvmx_smix_wr_dat smi_wr;
341 +       int timeout = 1000;
342 +
343 +       smi_wr.u64 = 0;
344 +       smi_wr.s.dat = val;
345 +       cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
346 +
347 +       smi_cmd.u64 = 0;
348 +       smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE;
349 +       smi_cmd.s.phy_adr = phy_id;
350 +       smi_cmd.s.reg_adr = location;
351 +       cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
352 +
353 +       do {
354 +               cvmx_wait(1000);
355 +               smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
356 +       } while (smi_wr.s.pending && --timeout);
357 +       if (timeout <= 0)
358 +               return -1;
359 +
360 +       return 0;
361 +}
362 +
363 +/**
364 + * Perform an IEEE 802.3 clause 45 MII read using clause 22 operations. This
365 + * function is used to read PHY registers controlling auto negotiation.
366 + *
367 + * @bus_id:   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
368 + *                 support multiple busses.
369 + * @phy_id:   The MII phy id
370 + * @device:   MDIO Managable Device (MMD) id
371 + * @location: Register location to read
372 + *
373 + * Returns Result from the read or -1 on failure
374 + */
375 +
376 +static inline int cvmx_mdio_45_via_22_read(int bus_id, int phy_id, int device,
377 +                                          int location)
378 +{
379 +       union cvmx_mdio_phy_reg_mmd_control mmd_control;
380 +
381 +       /*
382 +        * a) To Register 13, write the Function field to 00 (address)
383 +        *    and DEVAD field to the device address value for the
384 +        *    desired MMD;
385 +        */
386 +       mmd_control.u16 = 0;
387 +       mmd_control.s.function = MDIO_CLAUSE_45_ADDRESS;
388 +       mmd_control.s.devad = device;
389 +       cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_CONTROL,
390 +                       mmd_control.u16);
391 +
392 +       /*
393 +        *  b) To Register 14, write the desired address value to the
394 +        *     MMD's address register;
395 +        */
396 +       cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA,
397 +                       location);
398 +
399 +       /*
400 +        * c) To Register 13, write the Function field to 01 (Data, no
401 +        *    post increment) and DEVAD field to the same device
402 +        *    address value for the desired MMD;
403 +        */
404 +       mmd_control.u16 = 0;
405 +       mmd_control.s.function = MDIO_CLAUSE_45_READ;
406 +       mmd_control.s.devad = device;
407 +       cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_CONTROL,
408 +                       mmd_control.u16);
409 +
410 +       /*
411 +        * d) From Register 14, read the content of the MMD's selected
412 +        *    register.
413 +        */
414 +       return cvmx_mdio_read(bus_id, phy_id,
415 +                             CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA);
416 +}
417 +
418 +/**
419 + * Perform an IEEE 802.3 clause 45 MII write using clause 22
420 + * operations. This function is used to write PHY registers
421 + * controlling auto negotiation.
422 + *
423 + * @bus_id:   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
424 + *                 support multiple busses.
425 + * @phy_id:   The MII phy id
426 + * @device:   MDIO Managable Device (MMD) id
427 + * @location: Register location to write
428 + * @val:      Value to write
429 + *
430 + * Returns -1 on error
431 + *         0 on success
432 + */
433 +static inline int cvmx_mdio_45_via_22_write(int bus_id, int phy_id, int device,
434 +                                           int location, int val)
435 +{
436 +       union cvmx_mdio_phy_reg_mmd_control mmd_control;
437 +
438 +       /*
439 +        * a) To Register 13, write the Function field to 00 (address)
440 +        *    and DEVAD field to the device address value for the
441 +        *    desired MMD;
442 +        */
443 +       mmd_control.u16 = 0;
444 +       mmd_control.s.function = MDIO_CLAUSE_45_ADDRESS;
445 +       mmd_control.s.devad = device;
446 +       cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_CONTROL,
447 +                       mmd_control.u16);
448 +
449 +       /*
450 +        * b) To Register 14, write the desired address value to the
451 +        *    MMD's address register;
452 +        */
453 +       cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA,
454 +                       location);
455 +
456 +       /*
457 +        * c) To Register 13, write the Function field to 01 (Data, no
458 +        *    post increment) and DEVAD field to the same device
459 +        *    address value for the desired MMD;
460 +        */
461 +       mmd_control.u16 = 0;
462 +       mmd_control.s.function = MDIO_CLAUSE_45_READ;
463 +       mmd_control.s.devad = device;
464 +       cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_CONTROL,
465 +                       mmd_control.u16);
466 +
467 +       /*
468 +        * d) To Register 14, write the content of the MMD's selected
469 +        *    register.
470 +        */
471 +       return cvmx_mdio_write(bus_id, phy_id,
472 +                              CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA, val);
473 +
474 +       return 0;
475 +}
476 +
477 +/**
478 + * Perform an IEEE 802.3 clause 45 MII read. This function is used to read PHY
479 + * registers controlling auto negotiation.
480 + *
481 + * @bus_id:   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
482 + *                 support multiple busses.
483 + * @phy_id:   The MII phy id
484 + * @device:   MDIO Managable Device (MMD) id
485 + * @location: Register location to read
486 + *
487 + * Returns Result from the read or -1 on failure
488 + */
489 +
490 +static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device,
491 +                                   int location)
492 +{
493 +       union cvmx_smix_cmd smi_cmd;
494 +       union cvmx_smix_rd_dat smi_rd;
495 +       union cvmx_smix_wr_dat smi_wr;
496 +       int timeout = 1000;
497 +
498 +       smi_wr.u64 = 0;
499 +       smi_wr.s.dat = location;
500 +       cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
501 +
502 +       smi_cmd.u64 = 0;
503 +       smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
504 +       smi_cmd.s.phy_adr = phy_id;
505 +       smi_cmd.s.reg_adr = device;
506 +       cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
507 +
508 +       do {
509 +               cvmx_wait(1000);
510 +               smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
511 +       } while (smi_wr.s.pending && --timeout);
512 +       if (timeout <= 0)
513 +               return -1;
514 +
515 +       smi_cmd.u64 = 0;
516 +       smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ;
517 +       smi_cmd.s.phy_adr = phy_id;
518 +       smi_cmd.s.reg_adr = device;
519 +       cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
520 +
521 +       do {
522 +               cvmx_wait(1000);
523 +               smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id));
524 +       } while (smi_rd.s.pending && timeout--);
525 +
526 +       if (0 == timeout)
527 +               cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d "
528 +                            "device %2d register %2d   TIME OUT\n",
529 +                            bus_id, phy_id, device, location);
530 +
531 +       if (smi_rd.s.val)
532 +               return smi_rd.s.dat;
533 +       else {
534 +               cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d "
535 +                            "device %2d register %2d   INVALID READ\n",
536 +                            bus_id, phy_id, device, location);
537 +               return -1;
538 +       }
539 +}
540 +
541 +/**
542 + * Perform an IEEE 802.3 clause 45 MII write. This function is used to
543 + * write PHY registers controlling auto negotiation.
544 + *
545 + * @bus_id:   MDIO bus number. Zero on most chips, but some chips (ex CN56XX)
546 + *                 support multiple busses.
547 + * @phy_id:   The MII phy id
548 + * @device:   MDIO Managable Device (MMD) id
549 + * @location: Register location to write
550 + * @val:      Value to write
551 + *
552 + * Returns -1 on error
553 + *         0 on success
554 + */
555 +static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device,
556 +                                    int location, int val)
557 +{
558 +       union cvmx_smix_cmd smi_cmd;
559 +       union cvmx_smix_wr_dat smi_wr;
560 +       int timeout = 1000;
561 +
562 +       smi_wr.u64 = 0;
563 +       smi_wr.s.dat = location;
564 +       cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
565 +
566 +       smi_cmd.u64 = 0;
567 +       smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS;
568 +       smi_cmd.s.phy_adr = phy_id;
569 +       smi_cmd.s.reg_adr = device;
570 +       cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
571 +
572 +       do {
573 +               cvmx_wait(1000);
574 +               smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
575 +       } while (smi_wr.s.pending && --timeout);
576 +       if (timeout <= 0)
577 +               return -1;
578 +
579 +       smi_wr.u64 = 0;
580 +       smi_wr.s.dat = val;
581 +       cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
582 +
583 +       smi_cmd.u64 = 0;
584 +       smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE;
585 +       smi_cmd.s.phy_adr = phy_id;
586 +       smi_cmd.s.reg_adr = device;
587 +       cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64);
588 +
589 +       do {
590 +               cvmx_wait(1000);
591 +               smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
592 +       } while (smi_wr.s.pending && --timeout);
593 +       if (timeout <= 0)
594 +               return -1;
595 +
596 +       return 0;
597 +}
598 +
599 +#endif
600 diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
601 index e9625a5..8c9d29e 100644
602 --- a/drivers/net/Kconfig
603 +++ b/drivers/net/Kconfig
604 @@ -1864,6 +1864,14 @@ config ATL2
605           To compile this driver as a module, choose M here.  The module
606           will be called atl2.
607  
608 +config OCTEON_MGMT
609 +       tristate "OCTEON Management port ethernet driver (CN5XXX)"
610 +       depends on CPU_CAVIUM_OCTEON
611 +       default y
612 +       help
613 +         This option enables the ethernet driver for the management port on
614 +         CN52XX, CN57XX, CN56XX, CN55XX, and CN54XX chips.
615 +
616  source "drivers/net/fs_enet/Kconfig"
617  
618  endif # NET_ETHERNET
619 diff --git a/drivers/net/Makefile b/drivers/net/Makefile
620 index 4a92305..4cbc22e 100644
621 --- a/drivers/net/Makefile
622 +++ b/drivers/net/Makefile
623 @@ -234,6 +234,7 @@
624  obj-$(CONFIG_MLX4_CORE) += mlx4/
625  obj-$(CONFIG_ENC28J60) += enc28j60.o
626  obj-$(CONFIG_ETHOC) += ethoc.o
627 +obj-$(CONFIG_OCTEON_MGMT) += octeon/
628
629  obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
630
631 diff --git a/drivers/net/octeon/Makefile b/drivers/net/octeon/Makefile
632 new file mode 100644
633 index 0000000..f32f394
634 --- /dev/null
635 +++ b/drivers/net/octeon/Makefile
636 @@ -0,0 +1,11 @@
637 +# Makefile for the Cavium OCTEON Ethernet drivers.
638 +#
639 +# This file is subject to the terms and conditions of the GNU General Public
640 +# License.  See the file "COPYING" in the main directory of this archive
641 +# for more details.
642 +#
643 +# Copyright (C) 2008 Cavium Networks
644 +
645 +obj-$(CONFIG_OCTEON_MGMT) += octeon_mgmt.o
646 +
647 +octeon_mgmt-objs := octeon-mgmt-port.o cvmx-mgmt-port.o
648 \ No newline at end of file
649 diff --git a/drivers/net/octeon/cvmx-mgmt-port.c b/drivers/net/octeon/cvmx-mgmt-port.c
650 new file mode 100644
651 index 0000000..f60255a
652 --- /dev/null
653 +++ b/drivers/net/octeon/cvmx-mgmt-port.c
654 @@ -0,0 +1,818 @@
655 +/***********************license start***************
656 + * Author: Cavium Networks
657 + *
658 + * Contact: support@caviumnetworks.com
659 + * This file is part of the OCTEON SDK
660 + *
661 + * Copyright (c) 2003-2008 Cavium Networks
662 + *
663 + * This file is free software; you can redistribute it and/or modify
664 + * it under the terms of the GNU General Public License, Version 2, as
665 + * published by the Free Software Foundation.
666 + *
667 + * This file is distributed in the hope that it will be useful, but
668 + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
669 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
670 + * NONINFRINGEMENT.  See the GNU General Public License for more
671 + * details.
672 + *
673 + * You should have received a copy of the GNU General Public License
674 + * along with this file; if not, write to the Free Software
675 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
676 + * or visit http://www.gnu.org/licenses/.
677 + *
678 + * This file may also be available under a different license from Cavium.
679 + * Contact Cavium Networks for more information
680 + ***********************license end**************************************/
681 +
682 +/**
683 + *
684 + * Support functions for managing the MII management port
685 + *
686 + */
687 +
688 +#include <asm/octeon/octeon.h>
689 +#include <asm/octeon/cvmx-spinlock.h>
690 +#include <asm/octeon/cvmx-bootmem.h>
691 +#include <asm/octeon/cvmx-mdio.h>
692 +
693 +#include <asm/octeon/cvmx-mixx-defs.h>
694 +#include <asm/octeon/cvmx-agl-defs.h>
695 +
696 +#include "cvmx-mgmt-port.h"
697 +
698 +#define CVMX_MGMT_PORT_NUM_PORTS        2
699 +/* Number of TX ring buffer entries and buffers */
700 +#define CVMX_MGMT_PORT_NUM_TX_BUFFERS   16
701 +/* Number of RX ring buffer entries and buffers */
702 +#define CVMX_MGMT_PORT_NUM_RX_BUFFERS   128
703 +
704 +#define CVMX_MGMT_PORT_TX_BUFFER_SIZE   12288
705 +#define CVMX_MGMT_PORT_RX_BUFFER_SIZE   1536
706 +
707 +/**
708 + * Format of the TX/RX ring buffer entries
709 + */
710 +union cvmx_mgmt_port_ring_entry {
711 +       uint64_t u64;
712 +       struct {
713 +               uint64_t reserved_62_63:2;
714 +               /* Length of the buffer/packet in bytes */
715 +               uint64_t len:14;
716 +               /* The RX error code */
717 +               uint64_t code:8;
718 +               /* Physical address of the buffer */
719 +               uint64_t addr:40;
720 +       } s;
721 +};
722 +
723 +/**
724 + * Per port state required for each mgmt port
725 + */
726 +struct cvmx_mgmt_port_state {
727 +       /* Used for exclusive access to this structure */
728 +       cvmx_spinlock_t lock;
729 +       /* Where the next TX will write in the tx_ring and tx_buffers */
730 +       int tx_write_index;
731 +       /* Where the next RX will be in the rx_ring and rx_buffers */
732 +       int rx_read_index;
733 +       /* The SMI/MDIO PHY address */
734 +       int phy_id;
735 +       /* Our MAC address */
736 +       uint64_t mac;
737 +       union cvmx_mgmt_port_ring_entry tx_ring[CVMX_MGMT_PORT_NUM_TX_BUFFERS];
738 +       union cvmx_mgmt_port_ring_entry rx_ring[CVMX_MGMT_PORT_NUM_RX_BUFFERS];
739 +       char tx_buffers[CVMX_MGMT_PORT_NUM_TX_BUFFERS]
740 +           [CVMX_MGMT_PORT_TX_BUFFER_SIZE];
741 +       char rx_buffers[CVMX_MGMT_PORT_NUM_RX_BUFFERS]
742 +           [CVMX_MGMT_PORT_RX_BUFFER_SIZE];
743 +};
744 +
745 +/**
746 + * Pointers to each mgmt port's state
747 + */
748 +struct cvmx_mgmt_port_state *cvmx_mgmt_port_state_ptr;
749 +
750 +/**
751 + * Return the number of management ports supported by this chip
752 + *
753 + * Returns Number of ports
754 + */
755 +int __cvmx_mgmt_port_num_ports(void)
756 +{
757 +       if (OCTEON_IS_MODEL(OCTEON_CN56XX))
758 +               return 1;
759 +       else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
760 +               return 2;
761 +       else
762 +               return 0;
763 +}
764 +
765 +/**
766 + * Called to initialize a management port for use. Multiple calls
767 + * to this function accross applications is safe.
768 + *
769 + * @port:   Port to initialize
770 + *
771 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
772 + */
773 +enum cvmx_mgmt_port_result cvmx_mgmt_port_initialize(int port)
774 +{
775 +       char *alloc_name = "cvmx_mgmt_port";
776 +       union cvmx_mixx_oring1 oring1;
777 +       union cvmx_mixx_ctl mix_ctl;
778 +
779 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
780 +               return CVMX_MGMT_PORT_INVALID_PARAM;
781 +
782 +       cvmx_mgmt_port_state_ptr =
783 +           cvmx_bootmem_alloc_named(CVMX_MGMT_PORT_NUM_PORTS *
784 +                                    sizeof(struct cvmx_mgmt_port_state), 128,
785 +                                    alloc_name);
786 +       if (cvmx_mgmt_port_state_ptr) {
787 +               memset(cvmx_mgmt_port_state_ptr, 0,
788 +                      CVMX_MGMT_PORT_NUM_PORTS *
789 +                      sizeof(struct cvmx_mgmt_port_state));
790 +       } else {
791 +               struct cvmx_bootmem_named_block_desc *block_desc =
792 +                   cvmx_bootmem_find_named_block(alloc_name);
793 +               if (block_desc)
794 +                       cvmx_mgmt_port_state_ptr =
795 +                           cvmx_phys_to_ptr(block_desc->base_addr);
796 +               else {
797 +                       cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: "
798 +                                    "Unable to get named block %s.\n",
799 +                                    alloc_name);
800 +                       return CVMX_MGMT_PORT_NO_MEMORY;
801 +               }
802 +       }
803 +
804 +       /*
805 +        * Reset the MIX block if the previous user had a different TX
806 +        * ring size.
807 +        */
808 +       mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
809 +       if (!mix_ctl.s.reset) {
810 +               oring1.u64 = cvmx_read_csr(CVMX_MIXX_ORING1(port));
811 +               if (oring1.s.osize != CVMX_MGMT_PORT_NUM_TX_BUFFERS) {
812 +                       mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
813 +                       mix_ctl.s.en = 0;
814 +                       cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
815 +                       do {
816 +                               mix_ctl.u64 =
817 +                                   cvmx_read_csr(CVMX_MIXX_CTL(port));
818 +                       } while (mix_ctl.s.busy);
819 +                       mix_ctl.s.reset = 1;
820 +                       cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
821 +                       cvmx_read_csr(CVMX_MIXX_CTL(port));
822 +                       memset(cvmx_mgmt_port_state_ptr + port, 0,
823 +                              sizeof(struct cvmx_mgmt_port_state));
824 +               }
825 +       }
826 +
827 +       if (cvmx_mgmt_port_state_ptr[port].tx_ring[0].u64 == 0) {
828 +               struct cvmx_mgmt_port_state *state =
829 +                       cvmx_mgmt_port_state_ptr + port;
830 +               int i;
831 +               union cvmx_mixx_bist mix_bist;
832 +               union cvmx_agl_gmx_bist agl_gmx_bist;
833 +               union cvmx_mixx_oring1 oring1;
834 +               union cvmx_mixx_iring1 iring1;
835 +               union cvmx_mixx_ctl mix_ctl;
836 +
837 +               /* Make sure BIST passed */
838 +               mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(port));
839 +               if (mix_bist.u64)
840 +                       cvmx_dprintf("WARNING: cvmx_mgmt_port_initialize: "
841 +                                    "Managment port MIX failed BIST "
842 +                                    "(0x%016llx)\n",
843 +                                    (unsigned long long)mix_bist.u64);
844 +
845 +               agl_gmx_bist.u64 = cvmx_read_csr(CVMX_AGL_GMX_BIST);
846 +               if (agl_gmx_bist.u64)
847 +                       cvmx_dprintf("WARNING: cvmx_mgmt_port_initialize: "
848 +                                    "Managment port AGL failed BIST "
849 +                                    "(0x%016llx)\n",
850 +                                    (unsigned long long)agl_gmx_bist.u64);
851 +
852 +               /* Clear all state information */
853 +               memset(state, 0, sizeof(*state));
854 +
855 +               /* Take the control logic out of reset */
856 +               mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
857 +               mix_ctl.s.reset = 0;
858 +               cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
859 +
860 +               /* Set the PHY address */
861 +               if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
862 +                       state->phy_id = -1;
863 +               else
864 +                       /* Will need to be change to match the board */
865 +                       state->phy_id = port;
866 +
867 +               /* Create a default MAC address */
868 +               state->mac = 0x000000dead000000ull;
869 +               state->mac += 0xffffff & CAST64(state);
870 +
871 +               /* Setup the TX ring */
872 +               for (i = 0; i < CVMX_MGMT_PORT_NUM_TX_BUFFERS; i++) {
873 +                       state->tx_ring[i].s.len = CVMX_MGMT_PORT_TX_BUFFER_SIZE;
874 +                       state->tx_ring[i].s.addr =
875 +                           cvmx_ptr_to_phys(state->tx_buffers[i]);
876 +               }
877 +
878 +               /* Tell the HW where the TX ring is */
879 +               oring1.u64 = 0;
880 +               oring1.s.obase = cvmx_ptr_to_phys(state->tx_ring) >> 3;
881 +               oring1.s.osize = CVMX_MGMT_PORT_NUM_TX_BUFFERS;
882 +               CVMX_SYNCWS;
883 +               cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64);
884 +
885 +               /* Setup the RX ring */
886 +               for (i = 0; i < CVMX_MGMT_PORT_NUM_RX_BUFFERS; i++) {
887 +                       /* This size is -8 due to an errata for CN56XX pass 1 */
888 +                       state->rx_ring[i].s.len =
889 +                           CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8;
890 +                       state->rx_ring[i].s.addr =
891 +                           cvmx_ptr_to_phys(state->rx_buffers[i]);
892 +               }
893 +
894 +               /* Tell the HW where the RX ring is */
895 +               iring1.u64 = 0;
896 +               iring1.s.ibase = cvmx_ptr_to_phys(state->rx_ring) >> 3;
897 +               iring1.s.isize = CVMX_MGMT_PORT_NUM_RX_BUFFERS;
898 +               CVMX_SYNCWS;
899 +               cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64);
900 +               cvmx_write_csr(CVMX_MIXX_IRING2(port),
901 +                              CVMX_MGMT_PORT_NUM_RX_BUFFERS);
902 +
903 +               /* Disable the external input/output */
904 +               cvmx_mgmt_port_disable(port);
905 +
906 +               /* Set the MAC address filtering up */
907 +               cvmx_mgmt_port_set_mac(port, state->mac);
908 +
909 +               /*
910 +                * Set the default max size to an MTU of 1500 with L2
911 +                * and VLAN.
912 +                */
913 +               cvmx_mgmt_port_set_max_packet_size(port, 1518);
914 +
915 +               /*
916 +                * Enable the port HW. Packets are not allowed until
917 +                * cvmx_mgmt_port_enable() is called.
918 +                */
919 +               mix_ctl.u64 = 0;
920 +               /* Strip the ending CRC */
921 +               mix_ctl.s.crc_strip = 1;
922 +               /* Enable the port */
923 +               mix_ctl.s.en = 1;
924 +               /* Arbitration mode */
925 +               mix_ctl.s.nbtarb = 0;
926 +               /* MII CB-request FIFO programmable high watermark */
927 +               mix_ctl.s.mrq_hwm = 1;
928 +               cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
929 +
930 +               if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
931 +                   || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
932 +                       /*
933 +                        * Force compensation values, as they are not
934 +                        * determined properly by HW.
935 +                        */
936 +                       union cvmx_agl_gmx_drv_ctl drv_ctl;
937 +
938 +                       drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL);
939 +                       if (port) {
940 +                               drv_ctl.s.byp_en1 = 1;
941 +                               drv_ctl.s.nctl1 = 6;
942 +                               drv_ctl.s.pctl1 = 6;
943 +                       } else {
944 +                               drv_ctl.s.byp_en = 1;
945 +                               drv_ctl.s.nctl = 6;
946 +                               drv_ctl.s.pctl = 6;
947 +                       }
948 +                       cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64);
949 +               }
950 +       }
951 +       return CVMX_MGMT_PORT_SUCCESS;
952 +}
953 +
954 +/**
955 + * Shutdown a management port. This currently disables packet IO
956 + * but leaves all hardware and buffers. Another application can then
957 + * call initialize() without redoing the hardware setup.
958 + *
959 + * @port:   Management port
960 + *
961 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
962 + */
963 +enum cvmx_mgmt_port_result cvmx_mgmt_port_shutdown(int port)
964 +{
965 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
966 +               return CVMX_MGMT_PORT_INVALID_PARAM;
967 +
968 +       /* Stop packets from comming in */
969 +       cvmx_mgmt_port_disable(port);
970 +
971 +       /*
972 +        * We don't free any memory so the next intialize can reuse
973 +        * the HW setup.
974 +        */
975 +       return CVMX_MGMT_PORT_SUCCESS;
976 +}
977 +
978 +/**
979 + * Enable packet IO on a management port
980 + *
981 + * @port:   Management port
982 + *
983 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
984 + */
985 +enum cvmx_mgmt_port_result cvmx_mgmt_port_enable(int port)
986 +{
987 +       struct cvmx_mgmt_port_state *state;
988 +       union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
989 +       union cvmx_agl_gmx_inf_mode agl_gmx_inf_mode;
990 +       union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl;
991 +
992 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
993 +               return CVMX_MGMT_PORT_INVALID_PARAM;
994 +
995 +       state = cvmx_mgmt_port_state_ptr + port;
996 +
997 +       cvmx_spinlock_lock(&state->lock);
998 +
999 +       rxx_frm_ctl.u64 = 0;
1000 +       rxx_frm_ctl.s.pre_align = 1;
1001 +       /*
1002 +        * When set, disables the length check for non-min sized pkts
1003 +        * with padding in the client data.
1004 +        */
1005 +       rxx_frm_ctl.s.pad_len = 1;
1006 +       /* When set, disables the length check for VLAN pkts */
1007 +       rxx_frm_ctl.s.vlan_len = 1;
1008 +       /* When set, PREAMBLE checking is  less strict */
1009 +       rxx_frm_ctl.s.pre_free = 1;
1010 +       /* Control Pause Frames can match station SMAC */
1011 +       rxx_frm_ctl.s.ctl_smac = 0;
1012 +       /* Control Pause Frames can match globally assign Multicast address */
1013 +       rxx_frm_ctl.s.ctl_mcst = 1;
1014 +       /* Forward pause information to TX block */
1015 +       rxx_frm_ctl.s.ctl_bck = 1;
1016 +       /* Drop Control Pause Frames */
1017 +       rxx_frm_ctl.s.ctl_drp = 1;
1018 +       /* Strip off the preamble */
1019 +       rxx_frm_ctl.s.pre_strp = 1;
1020 +       /*
1021 +        * This port is configured to send PREAMBLE+SFD to begin every
1022 +        * frame.  GMX checks that the PREAMBLE is sent correctly.
1023 +        */
1024 +       rxx_frm_ctl.s.pre_chk = 1;
1025 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64);
1026 +
1027 +       /* Enable the AGL block */
1028 +       agl_gmx_inf_mode.u64 = 0;
1029 +       agl_gmx_inf_mode.s.en = 1;
1030 +       cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
1031 +
1032 +       /* Configure the port duplex and enables */
1033 +       agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
1034 +       agl_gmx_prtx.s.tx_en = 1;
1035 +       agl_gmx_prtx.s.rx_en = 1;
1036 +       if (cvmx_mgmt_port_get_link(port) < 0)
1037 +               agl_gmx_prtx.s.duplex = 0;
1038 +       else
1039 +               agl_gmx_prtx.s.duplex = 1;
1040 +       agl_gmx_prtx.s.en = 1;
1041 +       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
1042 +
1043 +       cvmx_spinlock_unlock(&state->lock);
1044 +       return CVMX_MGMT_PORT_SUCCESS;
1045 +}
1046 +
1047 +/**
1048 + * Disable packet IO on a management port
1049 + *
1050 + * @port:   Management port
1051 + *
1052 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1053 + */
1054 +enum cvmx_mgmt_port_result cvmx_mgmt_port_disable(int port)
1055 +{
1056 +       struct cvmx_mgmt_port_state *state;
1057 +       union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
1058 +
1059 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1060 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1061 +
1062 +       state = cvmx_mgmt_port_state_ptr + port;
1063 +
1064 +       cvmx_spinlock_lock(&state->lock);
1065 +
1066 +       agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
1067 +       agl_gmx_prtx.s.en = 0;
1068 +       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
1069 +
1070 +       cvmx_spinlock_unlock(&state->lock);
1071 +       return CVMX_MGMT_PORT_SUCCESS;
1072 +}
1073 +
1074 +/**
1075 + * Send a packet out the management port. The packet is copied so
1076 + * the input buffer isn't used after this call.
1077 + *
1078 + * @port:       Management port
1079 + * @packet_len: Length of the packet to send. It does not include the final CRC
1080 + * @buffer:     Packet data
1081 + *
1082 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1083 + */
1084 +enum cvmx_mgmt_port_result cvmx_mgmt_port_send(int port, int packet_len,
1085 +                                              void *buffer)
1086 +{
1087 +       struct cvmx_mgmt_port_state *state;
1088 +       union cvmx_mixx_oring2 mix_oring2;
1089 +
1090 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1091 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1092 +
1093 +       /* Max sure the packet size is valid */
1094 +       if ((packet_len < 1) || (packet_len > CVMX_MGMT_PORT_TX_BUFFER_SIZE))
1095 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1096 +
1097 +       if (buffer == NULL)
1098 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1099 +
1100 +       state = cvmx_mgmt_port_state_ptr + port;
1101 +
1102 +       cvmx_spinlock_lock(&state->lock);
1103 +
1104 +       mix_oring2.u64 = cvmx_read_csr(CVMX_MIXX_ORING2(port));
1105 +       if (mix_oring2.s.odbell >= CVMX_MGMT_PORT_NUM_TX_BUFFERS - 1) {
1106 +               /* No room for another packet */
1107 +               cvmx_spinlock_unlock(&state->lock);
1108 +               return CVMX_MGMT_PORT_NO_MEMORY;
1109 +       } else {
1110 +               /* Copy the packet into the output buffer */
1111 +               memcpy(state->tx_buffers[state->tx_write_index], buffer,
1112 +                      packet_len);
1113 +               /* Insert the source MAC */
1114 +               memcpy(state->tx_buffers[state->tx_write_index] + 6,
1115 +                      ((char *)&state->mac) + 2, 6);
1116 +               /* Update the TX ring buffer entry size */
1117 +               state->tx_ring[state->tx_write_index].s.len = packet_len;
1118 +               /* Increment our TX index */
1119 +               state->tx_write_index =
1120 +                   (state->tx_write_index + 1) % CVMX_MGMT_PORT_NUM_TX_BUFFERS;
1121 +               /* Ring the doorbell, send ing the packet */
1122 +               CVMX_SYNCWS;
1123 +               cvmx_write_csr(CVMX_MIXX_ORING2(port), 1);
1124 +               if (cvmx_read_csr(CVMX_MIXX_ORCNT(port)))
1125 +                       cvmx_write_csr(CVMX_MIXX_ORCNT(port),
1126 +                                      cvmx_read_csr(CVMX_MIXX_ORCNT(port)));
1127 +
1128 +               cvmx_spinlock_unlock(&state->lock);
1129 +               return CVMX_MGMT_PORT_SUCCESS;
1130 +       }
1131 +}
1132 +
1133 +/**
1134 + * Receive a packet from the management port.
1135 + *
1136 + * @port:       Management port
1137 + * @buffer_len: Size of the buffer to receive the packet into
1138 + * @buffer:     Buffer to receive the packet into
1139 + *
1140 + * Returns The size of the packet, or a negative erorr code on failure. Zero
1141 + *         means that no packets were available.
1142 + */
1143 +int cvmx_mgmt_port_receive(int port, int buffer_len, void *buffer)
1144 +{
1145 +       union cvmx_mixx_ircnt mix_ircnt;
1146 +       struct cvmx_mgmt_port_state *state;
1147 +       int result;
1148 +
1149 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1150 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1151 +
1152 +       /* Max sure the buffer size is valid */
1153 +       if (buffer_len < 1)
1154 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1155 +
1156 +       if (buffer == NULL)
1157 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1158 +
1159 +       state = cvmx_mgmt_port_state_ptr + port;
1160 +
1161 +       cvmx_spinlock_lock(&state->lock);
1162 +
1163 +       /* Find out how many RX packets are pending */
1164 +       mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
1165 +       if (mix_ircnt.s.ircnt) {
1166 +               void *source = state->rx_buffers[state->rx_read_index];
1167 +               uint64_t *zero_check = source;
1168 +               /*
1169 +                * CN56XX pass 1 has an errata where packets might
1170 +                * start 8 bytes into the buffer instead of at their
1171 +                * correct location. If the first 8 bytes is zero we
1172 +                * assume this has happened.
1173 +                */
1174 +               if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
1175 +                   && (*zero_check == 0))
1176 +                       source += 8;
1177 +               /* Start off with zero bytes received */
1178 +               result = 0;
1179 +               /*
1180 +                * While the completion code signals more data, copy
1181 +                * the buffers into the user's data.
1182 +                */
1183 +               while (state->rx_ring[state->rx_read_index].s.code == 16) {
1184 +                       /* Only copy what will fit in the user's buffer */
1185 +                       int length = state->rx_ring[state->rx_read_index].s.len;
1186 +                       if (length > buffer_len)
1187 +                               length = buffer_len;
1188 +                       memcpy(buffer, source, length);
1189 +                       /*
1190 +                        * Reduce the size of the buffer to the
1191 +                        * remaining space. If we run out we will
1192 +                        * signal an error when the code 15 buffer
1193 +                        * doesn't fit.
1194 +                        */
1195 +                       buffer += length;
1196 +                       buffer_len -= length;
1197 +                       result += length;
1198 +                       /*
1199 +                        * Update this buffer for reuse in future
1200 +                        * receives. This size is -8 due to an errata
1201 +                        * for CN56XX pass 1.
1202 +                        */
1203 +                       state->rx_ring[state->rx_read_index].s.code = 0;
1204 +                       state->rx_ring[state->rx_read_index].s.len =
1205 +                           CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8;
1206 +                       state->rx_read_index =
1207 +                           (state->rx_read_index +
1208 +                            1) % CVMX_MGMT_PORT_NUM_RX_BUFFERS;
1209 +                       /*
1210 +                        * Zero the beginning of the buffer for use by
1211 +                        * the errata check.
1212 +                        */
1213 +                       *zero_check = 0;
1214 +                       CVMX_SYNCWS;
1215 +                       /* Increment the number of RX buffers */
1216 +                       cvmx_write_csr(CVMX_MIXX_IRING2(port), 1);
1217 +                       source = state->rx_buffers[state->rx_read_index];
1218 +                       zero_check = source;
1219 +               }
1220 +
1221 +               /* Check for the final good completion code */
1222 +               if (state->rx_ring[state->rx_read_index].s.code == 15) {
1223 +                       if (buffer_len >=
1224 +                           state->rx_ring[state->rx_read_index].s.len) {
1225 +                               int length =
1226 +                                   state->rx_ring[state->rx_read_index].s.len;
1227 +                               memcpy(buffer, source, length);
1228 +                               result += length;
1229 +                       } else {
1230 +                               /* Not enough room for the packet */
1231 +                               cvmx_dprintf("ERROR: cvmx_mgmt_port_receive: "
1232 +                                       "Packet (%d) larger than "
1233 +                                       "supplied buffer (%d)\n",
1234 +                                       state->rx_ring[state->rx_read_index].s.len,
1235 +                                            buffer_len);
1236 +                               result = CVMX_MGMT_PORT_NO_MEMORY;
1237 +                       }
1238 +               } else {
1239 +                       union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
1240 +                       cvmx_dprintf("ERROR: cvmx_mgmt_port_receive: Receive "
1241 +                               "error code %d. Packet dropped(Len %d)\n",
1242 +                               state->rx_ring[state->rx_read_index].s.code,
1243 +                               state->rx_ring[state->rx_read_index].s.len +
1244 +                               result);
1245 +                       result = -state->rx_ring[state->rx_read_index].s.code;
1246 +
1247 +                       /* Check to see if we need to change the duplex. */
1248 +                       agl_gmx_prtx.u64 =
1249 +                           cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
1250 +                       if (cvmx_mgmt_port_get_link(port) < 0)
1251 +                               agl_gmx_prtx.s.duplex = 0;
1252 +                       else
1253 +                               agl_gmx_prtx.s.duplex = 1;
1254 +                       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port),
1255 +                                      agl_gmx_prtx.u64);
1256 +               }
1257 +
1258 +               /*
1259 +                * Clean out the ring buffer entry. This size is -8
1260 +                * due to an errata for CN56XX pass 1.
1261 +                */
1262 +               state->rx_ring[state->rx_read_index].s.code = 0;
1263 +               state->rx_ring[state->rx_read_index].s.len =
1264 +                   CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8;
1265 +               state->rx_read_index =
1266 +                   (state->rx_read_index + 1) % CVMX_MGMT_PORT_NUM_RX_BUFFERS;
1267 +               /*
1268 +                * Zero the beginning of the buffer for use by the
1269 +                * errata check.
1270 +                */
1271 +               *zero_check = 0;
1272 +               CVMX_SYNCWS;
1273 +               /* Increment the number of RX buffers */
1274 +               cvmx_write_csr(CVMX_MIXX_IRING2(port), 1);
1275 +               /* Decrement the pending RX count */
1276 +               cvmx_write_csr(CVMX_MIXX_IRCNT(port), 1);
1277 +       } else {
1278 +               /* No packets available */
1279 +               result = 0;
1280 +       }
1281 +       cvmx_spinlock_unlock(&state->lock);
1282 +       return result;
1283 +}
1284 +
1285 +/**
1286 + * Get the management port link status:
1287 + * 100 = 100Mbps, full duplex
1288 + * 10 = 10Mbps, full duplex
1289 + * 0 = Link down
1290 + * -10 = 10Mpbs, half duplex
1291 + * -100 = 100Mbps, half duplex
1292 + *
1293 + * @port:   Management port
1294 + *
1295 + * Returns
1296 + */
1297 +int cvmx_mgmt_port_get_link(int port)
1298 +{
1299 +       struct cvmx_mgmt_port_state *state;
1300 +       int phy_status;
1301 +       int duplex;
1302 +
1303 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1304 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1305 +
1306 +       state = cvmx_mgmt_port_state_ptr + port;
1307 +
1308 +       /* Assume 100Mbps if we don't know the PHY address */
1309 +       if (state->phy_id == -1)
1310 +               return 100;
1311 +
1312 +       /* Read the PHY state */
1313 +       phy_status =
1314 +           cvmx_mdio_read(state->phy_id >> 8, state->phy_id & 0xff, 17);
1315 +
1316 +       /* Only return a link if the PHY has finished auto negotiation
1317 +          and set the resolved bit (bit 11) */
1318 +       if (!(phy_status & (1 << 11)))
1319 +               return 0;
1320 +
1321 +       /* Create multiple factor to represent duplex */
1322 +       if ((phy_status >> 13) & 1)
1323 +               duplex = 1;
1324 +       else
1325 +               duplex = -1;
1326 +
1327 +       /* Speed is encoded on bits 15-14 */
1328 +       switch ((phy_status >> 14) & 3) {
1329 +       case 0:         /* 10 Mbps */
1330 +               return 10 * duplex;
1331 +       case 1:         /* 100 Mbps */
1332 +               return 100 * duplex;
1333 +       default:
1334 +               return 0;
1335 +       }
1336 +}
1337 +
1338 +/**
1339 + * Set the MAC address for a management port
1340 + *
1341 + * @port:   Management port
1342 + * @mac:    New MAC address. The lower 6 bytes are used.
1343 + *
1344 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1345 + */
1346 +enum cvmx_mgmt_port_result cvmx_mgmt_port_set_mac(int port, uint64_t mac)
1347 +{
1348 +       struct cvmx_mgmt_port_state *state;
1349 +       union cvmx_agl_gmx_rxx_adr_ctl agl_gmx_rxx_adr_ctl;
1350 +
1351 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1352 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1353 +
1354 +       state = cvmx_mgmt_port_state_ptr + port;
1355 +
1356 +       cvmx_spinlock_lock(&state->lock);
1357 +
1358 +       agl_gmx_rxx_adr_ctl.u64 = 0;
1359 +       /* Only accept matching MAC addresses */
1360 +       agl_gmx_rxx_adr_ctl.s.cam_mode = 1;
1361 +       /* Drop multicast */
1362 +       agl_gmx_rxx_adr_ctl.s.mcst = 0;
1363 +       /* Allow broadcast */
1364 +       agl_gmx_rxx_adr_ctl.s.bcst = 1;
1365 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), agl_gmx_rxx_adr_ctl.u64);
1366 +
1367 +       /* Only using one of the CAMs */
1368 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), (mac >> 40) & 0xff);
1369 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), (mac >> 32) & 0xff);
1370 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), (mac >> 24) & 0xff);
1371 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), (mac >> 16) & 0xff);
1372 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), (mac >> 8) & 0xff);
1373 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), (mac >> 0) & 0xff);
1374 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 1);
1375 +       state->mac = mac;
1376 +
1377 +       cvmx_spinlock_unlock(&state->lock);
1378 +       return CVMX_MGMT_PORT_SUCCESS;
1379 +}
1380 +
1381 +/**
1382 + * Get the MAC address for a management port
1383 + *
1384 + * @port:   Management port
1385 + *
1386 + * Returns MAC address
1387 + */
1388 +uint64_t cvmx_mgmt_port_get_mac(int port)
1389 +{
1390 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1391 +               return CVMX_MGMT_PORT_INVALID_PARAM;
1392 +
1393 +       return cvmx_mgmt_port_state_ptr[port].mac;
1394 +}
1395 +
1396 +/**
1397 + * Set the multicast list.
1398 + *
1399 + * @port:   Management port
1400 + * @flags:  Interface flags
1401 + *
1402 + * Returns
1403 + */
1404 +void cvmx_mgmt_port_set_multicast_list(int port, int flags)
1405 +{
1406 +       struct cvmx_mgmt_port_state *state;
1407 +       union cvmx_agl_gmx_rxx_adr_ctl agl_gmx_rxx_adr_ctl;
1408 +
1409 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1410 +               return;
1411 +
1412 +       state = cvmx_mgmt_port_state_ptr + port;
1413 +
1414 +       cvmx_spinlock_lock(&state->lock);
1415 +
1416 +       agl_gmx_rxx_adr_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port));
1417 +
1418 +       /* Allow broadcast MAC addresses */
1419 +       if (!agl_gmx_rxx_adr_ctl.s.bcst)
1420 +               agl_gmx_rxx_adr_ctl.s.bcst = 1;
1421 +
1422 +       if ((flags & CVMX_IFF_ALLMULTI) || (flags & CVMX_IFF_PROMISC))
1423 +               /* Force accept multicast packets */
1424 +               agl_gmx_rxx_adr_ctl.s.mcst = 2;
1425 +       else
1426 +               /* Force reject multicast packets */
1427 +               agl_gmx_rxx_adr_ctl.s.mcst = 1;
1428 +
1429 +       if (flags & CVMX_IFF_PROMISC)
1430 +               /*
1431 +                * Reject matches if promisc. Since CAM is shut off,
1432 +                * should accept everything.
1433 +                */
1434 +               agl_gmx_rxx_adr_ctl.s.cam_mode = 0;
1435 +       else
1436 +               /* Filter packets based on the CAM */
1437 +               agl_gmx_rxx_adr_ctl.s.cam_mode = 1;
1438 +
1439 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), agl_gmx_rxx_adr_ctl.u64);
1440 +
1441 +       if (flags & CVMX_IFF_PROMISC)
1442 +               cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 0);
1443 +       else
1444 +               cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 1);
1445 +
1446 +       cvmx_spinlock_unlock(&state->lock);
1447 +}
1448 +
1449 +/**
1450 + * Set the maximum packet allowed in. Size is specified
1451 + * including L2 but without FCS. A normal MTU would corespond
1452 + * to 1514 assuming the standard 14 byte L2 header.
1453 + *
1454 + * @port:   Management port
1455 + * @size_without_fcs:
1456 + *               Size in bytes without FCS
1457 + */
1458 +void cvmx_mgmt_port_set_max_packet_size(int port, int size_without_fcs)
1459 +{
1460 +       struct cvmx_mgmt_port_state *state;
1461 +
1462 +       if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1463 +               return;
1464 +
1465 +       state = cvmx_mgmt_port_state_ptr + port;
1466 +
1467 +       cvmx_spinlock_lock(&state->lock);
1468 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs);
1469 +       cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port),
1470 +                      (size_without_fcs + 7) & 0xfff8);
1471 +       cvmx_spinlock_unlock(&state->lock);
1472 +}
1473 diff --git a/drivers/net/octeon/cvmx-mgmt-port.h b/drivers/net/octeon/cvmx-mgmt-port.h
1474 new file mode 100644
1475 index 0000000..622168c
1476 --- /dev/null
1477 +++ b/drivers/net/octeon/cvmx-mgmt-port.h
1478 @@ -0,0 +1,168 @@
1479 +/***********************license start***************
1480 + * Author: Cavium Networks
1481 + *
1482 + * Contact: support@caviumnetworks.com
1483 + * This file is part of the OCTEON SDK
1484 + *
1485 + * Copyright (c) 2003-2008 Cavium Networks
1486 + *
1487 + * This file is free software; you can redistribute it and/or modify
1488 + * it under the terms of the GNU General Public License, Version 2, as
1489 + * published by the Free Software Foundation.
1490 + *
1491 + * This file is distributed in the hope that it will be useful, but
1492 + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
1493 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
1494 + * NONINFRINGEMENT.  See the GNU General Public License for more
1495 + * details.
1496 + *
1497 + * You should have received a copy of the GNU General Public License
1498 + * along with this file; if not, write to the Free Software
1499 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1500 + * or visit http://www.gnu.org/licenses/.
1501 + *
1502 + * This file may also be available under a different license from Cavium.
1503 + * Contact Cavium Networks for more information
1504 + ***********************license end**************************************/
1505 +
1506 +/**
1507 + *
1508 + * Support functions for managing the MII management port
1509 + *
1510 + */
1511 +
1512 +#ifndef __CVMX_MGMT_PORT_H__
1513 +#define __CVMX_MGMT_PORT_H__
1514 +
1515 +enum cvmx_mgmt_port_result {
1516 +       CVMX_MGMT_PORT_SUCCESS = 0,
1517 +       CVMX_MGMT_PORT_NO_MEMORY = -1,
1518 +       CVMX_MGMT_PORT_INVALID_PARAM = -2,
1519 +};
1520 +
1521 +/* Enumeration of Net Device interface flags. */
1522 +enum cvmx_mgmt_port_netdevice_flags {
1523 +       CVMX_IFF_PROMISC = 0x100,       /* receive all packets           */
1524 +       CVMX_IFF_ALLMULTI = 0x200,      /* receive all multicast packets */
1525 +};
1526 +
1527 +/**
1528 + * Called to initialize a management port for use. Multiple calls
1529 + * to this function accross applications is safe.
1530 + *
1531 + * @port:   Port to initialize
1532 + *
1533 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1534 + */
1535 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_initialize(int port);
1536 +
1537 +/**
1538 + * Shutdown a management port. This currently disables packet IO
1539 + * but leaves all hardware and buffers. Another application can then
1540 + * call initialize() without redoing the hardware setup.
1541 + *
1542 + * @port:   Management port
1543 + *
1544 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1545 + */
1546 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_shutdown(int port);
1547 +
1548 +/**
1549 + * Enable packet IO on a management port
1550 + *
1551 + * @port:   Management port
1552 + *
1553 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1554 + */
1555 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_enable(int port);
1556 +
1557 +/**
1558 + * Disable packet IO on a management port
1559 + *
1560 + * @port:   Management port
1561 + *
1562 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1563 + */
1564 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_disable(int port);
1565 +
1566 +/**
1567 + * Send a packet out the management port. The packet is copied so
1568 + * the input buffer isn't used after this call.
1569 + *
1570 + * @port:       Management port
1571 + * @packet_len: Length of the packet to send. It does not include the final CRC
1572 + * @buffer:     Packet data
1573 + *
1574 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1575 + */
1576 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_send(int port, int packet_len,
1577 +                                                     void *buffer);
1578 +
1579 +/**
1580 + * Receive a packet from the management port.
1581 + *
1582 + * @port:       Management port
1583 + * @buffer_len: Size of the buffer to receive the packet into
1584 + * @buffer:     Buffer to receive the packet into
1585 + *
1586 + * Returns The size of the packet, or a negative erorr code on failure. Zero
1587 + *         means that no packets were available.
1588 + */
1589 +extern int cvmx_mgmt_port_receive(int port, int buffer_len, void *buffer);
1590 +
1591 +/**
1592 + * Get the management port link status:
1593 + * 100 = 100Mbps, full duplex
1594 + * 10 = 10Mbps, full duplex
1595 + * 0 = Link down
1596 + * -10 = 10Mpbs, half duplex
1597 + * -100 = 100Mbps, half duplex
1598 + *
1599 + * @port:   Management port
1600 + *
1601 + * Returns
1602 + */
1603 +extern int cvmx_mgmt_port_get_link(int port);
1604 +
1605 +/**
1606 + * Set the MAC address for a management port
1607 + *
1608 + * @port:   Management port
1609 + * @mac:    New MAC address. The lower 6 bytes are used.
1610 + *
1611 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1612 + */
1613 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_set_mac(int port,
1614 +                                                        uint64_t mac);
1615 +
1616 +/**
1617 + * Get the MAC address for a management port
1618 + *
1619 + * @port:   Management port
1620 + *
1621 + * Returns MAC address
1622 + */
1623 +extern uint64_t cvmx_mgmt_port_get_mac(int port);
1624 +
1625 +/**
1626 + * Set the multicast list.
1627 + *
1628 + * @port:   Management port
1629 + * @flags:  Interface flags
1630 + *
1631 + * Returns
1632 + */
1633 +extern void cvmx_mgmt_port_set_multicast_list(int port, int flags);
1634 +
1635 +/**
1636 + * Set the maximum packet allowed in. Size is specified
1637 + * including L2 but without FCS. A normal MTU would corespond
1638 + * to 1514 assuming the standard 14 byte L2 header.
1639 + *
1640 + * @port:   Management port
1641 + * @size_without_crc:
1642 + *               Size in bytes without FCS
1643 + */
1644 +extern void cvmx_mgmt_port_set_max_packet_size(int port, int size_without_fcs);
1645 +
1646 +#endif /* __CVMX_MGMT_PORT_H__ */
1647 diff --git a/drivers/net/octeon/octeon-mgmt-port.c b/drivers/net/octeon/octeon-mgmt-port.c
1648 new file mode 100644
1649 index 0000000..9cffbb5
1650 --- /dev/null
1651 +++ b/drivers/net/octeon/octeon-mgmt-port.c
1652 @@ -0,0 +1,389 @@
1653 +/*
1654 + *   Octeon Management Port Ethernet Driver
1655 + *
1656 + * This file is subject to the terms and conditions of the GNU General Public
1657 + * License.  See the file "COPYING" in the main directory of this archive
1658 + * for more details.
1659 + *
1660 + * Copyright (C) 2007, 2008 Cavium Networks
1661 + */
1662 +#include <linux/module.h>
1663 +#include <linux/kernel.h>
1664 +#include <linux/netdevice.h>
1665 +#include <linux/etherdevice.h>
1666 +#include <linux/ip.h>
1667 +#include <linux/string.h>
1668 +#include <linux/delay.h>
1669 +
1670 +#include <asm/octeon/octeon.h>
1671 +#include <asm/octeon/cvmx-mixx-defs.h>
1672 +#include <asm/octeon/cvmx-agl-defs.h>
1673 +
1674 +#include "cvmx-mgmt-port.h"
1675 +
1676 +static struct net_device *global_dev[2] = { NULL, NULL };
1677 +
1678 +#define DEBUGPRINT(format, ...) do {if (printk_ratelimit())            \
1679 +                                       printk(format, ##__VA_ARGS__);  \
1680 +                               } while (0)
1681 +
1682 +/**
1683 + * This is the definition of the Ethernet driver's private
1684 + * driver state stored in dev->priv.
1685 + */
1686 +struct device_private {
1687 +       int port;
1688 +       struct net_device_stats stats;  /* Device statistics */
1689 +};
1690 +
1691 +
1692 +/**
1693 + * Packet transmit
1694 + *
1695 + * @param skb    Packet to send
1696 + * @param dev    Device info structure
1697 + * @return Always returns zero
1698 + */
1699 +static int packet_transmit(struct sk_buff *skb, struct net_device *dev)
1700 +{
1701 +       uint64_t flags;
1702 +       struct device_private *priv = netdev_priv(dev);
1703 +       enum cvmx_mgmt_port_result result;
1704 +       local_irq_save(flags);
1705 +       result = cvmx_mgmt_port_send(priv->port, skb->len, skb->data);
1706 +       local_irq_restore(flags);
1707 +       if (result == CVMX_MGMT_PORT_SUCCESS) {
1708 +               priv->stats.tx_packets++;
1709 +               priv->stats.tx_bytes += skb->len;
1710 +       } else {
1711 +               /* DEBUGPRINT("ERROR: cvmx_mgmt_port_send() failed with %d\n",
1712 +                               result);
1713 +               */
1714 +               priv->stats.tx_dropped++;
1715 +       }
1716 +       dev_kfree_skb(skb);
1717 +       return 0;
1718 +}
1719 +
1720 +
1721 +/**
1722 + * Interrupt handler. The interrupt occurs whenever the POW
1723 + * transitions from 0->1 packets in our group.
1724 + *
1725 + * @param cpl
1726 + * @param dev_id
1727 + * @param regs
1728 + * @return
1729 + */
1730 +static irqreturn_t do_interrupt(int cpl, void *dev_id)
1731 +{
1732 +       uint64_t flags;
1733 +       struct sk_buff *skb;
1734 +       int result;
1735 +       char packet[2048];
1736 +       struct net_device *dev = (struct net_device *) dev_id;
1737 +       struct device_private *priv = netdev_priv(dev);
1738 +
1739 +       do {
1740 +               local_irq_save(flags);
1741 +               result = cvmx_mgmt_port_receive(priv->port, sizeof(packet),
1742 +                                               packet);
1743 +               local_irq_restore(flags);
1744 +
1745 +               /* Silently drop packets if we aren't up */
1746 +               if ((dev->flags & IFF_UP) == 0)
1747 +                       continue;
1748 +
1749 +               if (result > 0) {
1750 +                       skb = dev_alloc_skb(result);
1751 +                       if (skb) {
1752 +                               memcpy(skb_put(skb, result), packet, result);
1753 +                               skb->protocol = eth_type_trans(skb, dev);
1754 +                               skb->dev = dev;
1755 +                               skb->ip_summed = CHECKSUM_NONE;
1756 +                               priv->stats.rx_bytes += skb->len;
1757 +                               priv->stats.rx_packets++;
1758 +                               netif_rx(skb);
1759 +                       } else {
1760 +                               DEBUGPRINT("%s: Failed to allocate skbuff, "
1761 +                                          "packet dropped\n",
1762 +                                          dev->name);
1763 +                               priv->stats.rx_dropped++;
1764 +                       }
1765 +               } else if (result < 0) {
1766 +                       DEBUGPRINT("%s: Receive error code %d, packet "
1767 +                                  "dropped\n",
1768 +                                  dev->name, result);
1769 +                       priv->stats.rx_errors++;
1770 +               }
1771 +       } while (result != 0);
1772 +
1773 +       /* Clear any pending interrupts */
1774 +       cvmx_write_csr(CVMX_MIXX_ISR(priv->port),
1775 +                      cvmx_read_csr(CVMX_MIXX_ISR(priv->port)));
1776 +       cvmx_read_csr(CVMX_MIXX_ISR(priv->port));
1777 +
1778 +       return IRQ_HANDLED;
1779 +}
1780 +
1781 +
1782 +#ifdef CONFIG_NET_POLL_CONTROLLER
1783 +/**
1784 + * This is called when the kernel needs to manually poll the
1785 + * device. For Octeon, this is simply calling the interrupt
1786 + * handler. We actually poll all the devices, not just the
1787 + * one supplied.
1788 + *
1789 + * @param dev    Device to poll. Unused
1790 + */
1791 +static void device_poll_controller(struct net_device *dev)
1792 +{
1793 +       do_interrupt(0, dev);
1794 +}
1795 +#endif
1796 +
1797 +
1798 +/**
1799 + * Open a device for use. Device should be able to send and
1800 + * receive packets after this is called.
1801 + *
1802 + * @param dev    Device to bring up
1803 + * @return Zero on success
1804 + */
1805 +static int device_open(struct net_device *dev)
1806 +{
1807 +       /* Clear the statistics whenever the interface is brought up */
1808 +       struct device_private *priv = netdev_priv(dev);
1809 +       memset(&priv->stats, 0, sizeof(priv->stats));
1810 +       cvmx_mgmt_port_enable(priv->port);
1811 +       return 0;
1812 +}
1813 +
1814 +
1815 +/**
1816 + * Stop an ethernet device. No more packets should be
1817 + * received from this device.
1818 + *
1819 + * @param dev    Device to bring down
1820 + * @return Zero on success
1821 + */
1822 +static int device_close(struct net_device *dev)
1823 +{
1824 +       struct device_private *priv = netdev_priv(dev);
1825 +       cvmx_mgmt_port_disable(priv->port);
1826 +       return 0;
1827 +}
1828 +
1829 +
1830 +/**
1831 + * Get the low level ethernet statistics
1832 + *
1833 + * @param dev    Device to get the statistics from
1834 + * @return Pointer to the statistics
1835 + */
1836 +static struct net_device_stats *device_get_stats(struct net_device *dev)
1837 +{
1838 +       struct device_private *priv = netdev_priv(dev);
1839 +       return &priv->stats;
1840 +}
1841 +
1842 +/**
1843 + * Set the multicast list. Currently unimplemented.
1844 + *
1845 + * @param dev    Device to work on
1846 + */
1847 +static void ethernet_mgmt_port_set_multicast_list(struct net_device *dev)
1848 +{
1849 +       struct device_private *priv = netdev_priv(dev);
1850 +       int port = priv->port;
1851 +       int num_ports;
1852 +       if (OCTEON_IS_MODEL(OCTEON_CN52XX))
1853 +               num_ports = 2;
1854 +       else
1855 +               num_ports = 1;
1856 +       if (port < num_ports)
1857 +               cvmx_mgmt_port_set_multicast_list(port, dev->flags);
1858 +}
1859 +
1860 +/**
1861 + * Set the hardware MAC address for a management port device
1862 + *
1863 + * @param dev    Device to change the MAC address for
1864 + * @param addr   Address structure to change it too. MAC address is addr + 2.
1865 + * @return Zero on success
1866 + */
1867 +static int ethernet_mgmt_port_set_mac_address(struct net_device *dev,
1868 +                                             void *addr)
1869 +{
1870 +       struct device_private *priv = netdev_priv(dev);
1871 +       union cvmx_agl_gmx_prtx_cfg agl_gmx_cfg;
1872 +       int port = priv->port;
1873 +       int num_ports;
1874 +
1875 +       if (OCTEON_IS_MODEL(OCTEON_CN52XX))
1876 +               num_ports = 2;
1877 +       else
1878 +               num_ports = 1;
1879 +
1880 +       memcpy(dev->dev_addr, addr + 2, 6);
1881 +
1882 +       if (port < num_ports) {
1883 +               int i;
1884 +               uint8_t *ptr = addr;
1885 +               uint64_t mac = 0;
1886 +               for (i = 0; i < 6; i++)
1887 +                       mac = (mac<<8) | (uint64_t)(ptr[i+2]);
1888 +
1889 +               agl_gmx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
1890 +               cvmx_mgmt_port_set_mac(port, mac);
1891 +               ethernet_mgmt_port_set_multicast_list(dev);
1892 +               cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_cfg.u64);
1893 +       }
1894 +       return 0;
1895 +}
1896 +
1897 +/**
1898 + * Per network device initialization
1899 + *
1900 + * @param dev    Device to initialize
1901 + * @return Zero on success
1902 + */
1903 +static int device_init(struct net_device *dev)
1904 +{
1905 +       struct device_private *priv = netdev_priv(dev);
1906 +       uint64_t mac = cvmx_mgmt_port_get_mac(priv->port);
1907 +
1908 +       dev->hard_start_xmit = packet_transmit;
1909 +       dev->get_stats = device_get_stats;
1910 +       dev->open = device_open;
1911 +       dev->stop = device_close;
1912 +#ifdef CONFIG_NET_POLL_CONTROLLER
1913 +       dev->poll_controller = device_poll_controller;
1914 +#endif
1915 +       dev->dev_addr[0] = (mac >> 40) & 0xff;
1916 +       dev->dev_addr[1] = (mac >> 32) & 0xff;
1917 +       dev->dev_addr[2] = (mac >> 24) & 0xff;
1918 +       dev->dev_addr[3] = (mac >> 16) & 0xff;
1919 +       dev->dev_addr[4] = (mac >> 8) & 0xff;
1920 +       dev->dev_addr[5] = (mac >> 0) & 0xff;
1921 +       return 0;
1922 +}
1923 +
1924 +
1925 +/**
1926 + * Module/ driver initialization. Creates the linux network
1927 + * devices.
1928 + *
1929 + * @return Zero on success
1930 + */
1931 +static int __init ethernet_mgmt_port_init(void)
1932 +{
1933 +       struct net_device *dev;
1934 +       struct device_private *priv;
1935 +       union cvmx_mixx_irhwm mix_irhwm;
1936 +       union cvmx_mixx_intena mix_intena;
1937 +       int num_ports;
1938 +       int port;
1939 +
1940 +       if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
1941 +               return 0;
1942 +
1943 +       if (OCTEON_IS_MODEL(OCTEON_CN52XX))
1944 +               num_ports = 2;
1945 +       else
1946 +               num_ports = 1;
1947 +
1948 +       printk("Octeon management port ethernet driver\n");
1949 +
1950 +       for (port = 0; port < num_ports; port++) {
1951 +               if (cvmx_mgmt_port_initialize(port) != CVMX_MGMT_PORT_SUCCESS) {
1952 +                       pr_err("ERROR: cvmx_mgmt_port_initialize(%d) "
1953 +                              "failed\n", port);
1954 +                       return -1;
1955 +               }
1956 +
1957 +               /* Setup is complete, create the virtual ethernet devices */
1958 +               dev = alloc_etherdev(sizeof(struct device_private));
1959 +               if (dev == NULL) {
1960 +                       pr_err("ERROR: Failed to allocate ethernet device\n");
1961 +                       return -1;
1962 +               }
1963 +
1964 +               dev->init = device_init;
1965 +               strcpy(dev->name, "mgmt%d");
1966 +
1967 +               /* Initialize the device private structure. */
1968 +               priv = netdev_priv(dev);
1969 +               memset(priv, 0, sizeof(struct device_private));
1970 +               priv->port = port;
1971 +
1972 +               if (register_netdev(dev) < 0) {
1973 +                       pr_err("ERROR: Failed to register ethernet device\n");
1974 +                       kfree(dev);
1975 +                       return -1;
1976 +               }
1977 +
1978 +               /* Clear any pending interrupts */
1979 +               cvmx_write_csr(CVMX_MIXX_ISR(priv->port),
1980 +                              cvmx_read_csr(CVMX_MIXX_ISR(priv->port)));
1981 +
1982 +               /* Register an IRQ hander for to receive interrupts */
1983 +               dev->irq =
1984 +                       (priv->port == 0) ? OCTEON_IRQ_MII0 : OCTEON_IRQ_MII1;
1985 +               if (request_irq(dev->irq, do_interrupt, IRQF_SHARED, dev->name,
1986 +                           dev))
1987 +                       pr_err("ethernet-mgmt: Failed to assign "
1988 +                              "interrupt %d\n", dev->irq);
1989 +
1990 +               /* Interrupt every single RX packet */
1991 +               mix_irhwm.u64 = 0;
1992 +               mix_irhwm.s.irhwm = 0;
1993 +               cvmx_write_csr(CVMX_MIXX_IRHWM(priv->port), mix_irhwm.u64);
1994 +
1995 +               /* Enable receive interrupts */
1996 +               mix_intena.u64 = 0;
1997 +               mix_intena.s.ithena = 1;
1998 +               cvmx_write_csr(CVMX_MIXX_INTENA(priv->port), mix_intena.u64);
1999 +
2000 +               global_dev[priv->port] = dev;
2001 +
2002 +               dev->set_mac_address = ethernet_mgmt_port_set_mac_address;
2003 +               dev->set_multicast_list = ethernet_mgmt_port_set_multicast_list;
2004 +       }
2005 +       return 0;
2006 +}
2007 +
2008 +
2009 +/**
2010 + * Module / driver shutdown
2011 + *
2012 + * @return Zero on success
2013 + */
2014 +static void __exit ethernet_mgmt_port_cleanup(void)
2015 +{
2016 +       int port;
2017 +       for (port = 0; port < 2; port++) {
2018 +               if (global_dev[port]) {
2019 +                       struct device_private *priv =
2020 +                               netdev_priv(global_dev[port]);
2021 +                       /* Disable interrupt */
2022 +                       cvmx_write_csr(CVMX_MIXX_IRHWM(priv->port), 0);
2023 +                       cvmx_write_csr(CVMX_MIXX_INTENA(priv->port), 0);
2024 +                       cvmx_mgmt_port_shutdown(priv->port);
2025 +
2026 +                       /* Free the interrupt handler */
2027 +                       free_irq(global_dev[port]->irq, global_dev[port]);
2028 +
2029 +                       /* Free the ethernet devices */
2030 +                       unregister_netdev(global_dev[port]);
2031 +                       kfree(global_dev[port]);
2032 +                       global_dev[port] = NULL;
2033 +               }
2034 +       }
2035 +}
2036 +
2037 +MODULE_LICENSE("GPL");
2038 +MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
2039 +MODULE_DESCRIPTION("Cavium Networks Octeon management port ethernet driver.");
2040 +module_init(ethernet_mgmt_port_init);
2041 +module_exit(ethernet_mgmt_port_cleanup);
2042 -- 
2043 1.5.6.5
2044
2045 --
2046 To unsubscribe from this list: send the line "unsubscribe netdev" in
2047 the body of a message to majordomo@vger.kernel.org
2048 More majordomo info at  http://vger.kernel.org/majordomo-info.html