1 Signed-off-by: David Daney <ddaney@caviumnetworks.com>
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
17 diff --git a/arch/mips/include/asm/octeon/cvmx-mdio.h b/arch/mips/include/asm/octeon/cvmx-mdio.h
19 index 0000000..89b0cc8
21 +++ b/arch/mips/include/asm/octeon/cvmx-mdio.h
23 +/***********************license start***************
24 + * Author: Cavium Networks
26 + * Contact: support@caviumnetworks.com
27 + * This file is part of the OCTEON SDK
29 + * Copyright (c) 2003-2008 Cavium Networks
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.
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
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/.
46 + * This file may also be available under a different license from Cavium.
47 + * Contact Cavium Networks for more information
48 + ***********************license end**************************************/
52 + * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3
53 + * clause 22 and clause 45 operations.
57 +#ifndef __CVMX_MIO_H__
58 +#define __CVMX_MIO_H__
60 +#include "cvmx-smix-defs.h"
63 + * PHY register 0 from the 802.3 spec
65 +#define CVMX_MDIO_PHY_REG_CONTROL 0
66 +union cvmx_mdio_phy_reg_control {
70 + uint16_t loopback:1;
71 + uint16_t speed_lsb:1;
72 + uint16_t autoneg_enable:1;
73 + uint16_t power_down:1;
75 + uint16_t restart_autoneg: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;
85 + * PHY register 1 from the 802.3 spec
87 +#define CVMX_MDIO_PHY_REG_STATUS 1
88 +union cvmx_mdio_phy_reg_status {
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;
112 + * PHY register 2 from the 802.3 spec
114 +#define CVMX_MDIO_PHY_REG_ID1 2
115 +union cvmx_mdio_phy_reg_id1 {
118 + uint16_t oui_bits_3_18;
123 + * PHY register 3 from the 802.3 spec
125 +#define CVMX_MDIO_PHY_REG_ID2 3
126 +union cvmx_mdio_phy_reg_id2 {
129 + uint16_t oui_bits_19_24:6;
131 + uint16_t revision:4;
136 + * PHY register 4 from the 802.3 spec
138 +#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4
139 +union cvmx_mdio_phy_reg_autoneg_adver {
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;
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;
158 + * PHY register 5 from the 802.3 spec
160 +#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5
161 +union cvmx_mdio_phy_reg_link_partner_ability {
164 + uint16_t next_page:1;
166 + uint16_t remote_fault:1;
167 + uint16_t reserved_12:1;
168 + uint16_t asymmetric_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;
180 + * PHY register 6 from the 802.3 spec
182 +#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6
183 +union cvmx_mdio_phy_reg_autoneg_expansion {
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;
197 + * PHY register 9 from the 802.3 spec
199 +#define CVMX_MDIO_PHY_REG_CONTROL_1000 9
200 +union cvmx_mdio_phy_reg_control_1000 {
203 + uint16_t test_mode:3;
204 + uint16_t manual_master_slave: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;
214 + * PHY register 10 from the 802.3 spec
216 +#define CVMX_MDIO_PHY_REG_STATUS_1000 10
217 +union cvmx_mdio_phy_reg_status_1000 {
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;
232 + * PHY register 15 from the 802.3 spec
234 +#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15
235 +union cvmx_mdio_phy_reg_extended_status {
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;
247 + * PHY register 13 from the 802.3 spec
249 +#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13
250 +union cvmx_mdio_phy_reg_mmd_control {
253 + uint16_t function:2;
254 + uint16_t reserved_5_13:9;
260 + * PHY register 14 from the 802.3 spec
262 +#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14
263 +union cvmx_mdio_phy_reg_mmd_address_data {
266 + uint16_t address_data:16;
270 +/* Operating request encodings. */
271 +#define MDIO_CLAUSE_22_WRITE 0
272 +#define MDIO_CLAUSE_22_READ 1
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
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
291 + * Perform an MII read. This function is used to read PHY
292 + * registers controlling auto negotiation.
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
299 + * Returns Result from the read or -1 on failure
301 +static inline int cvmx_mdio_read(int bus_id, int phy_id, int location)
303 + union cvmx_smix_cmd smi_cmd;
304 + union cvmx_smix_rd_dat smi_rd;
305 + int timeout = 1000;
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);
315 + smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id));
316 + } while (smi_rd.s.pending && timeout--);
319 + return smi_rd.s.dat;
325 + * Perform an MII write. This function is used to write PHY
326 + * registers controlling auto negotiation.
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
334 + * Returns -1 on error
337 +static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val)
339 + union cvmx_smix_cmd smi_cmd;
340 + union cvmx_smix_wr_dat smi_wr;
341 + int timeout = 1000;
344 + smi_wr.s.dat = val;
345 + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
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);
355 + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
356 + } while (smi_wr.s.pending && --timeout);
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.
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
373 + * Returns Result from the read or -1 on failure
376 +static inline int cvmx_mdio_45_via_22_read(int bus_id, int phy_id, int device,
379 + union cvmx_mdio_phy_reg_mmd_control mmd_control;
382 + * a) To Register 13, write the Function field to 00 (address)
383 + * and DEVAD field to the device address value for the
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,
393 + * b) To Register 14, write the desired address value to the
394 + * MMD's address register;
396 + cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA,
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;
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,
411 + * d) From Register 14, read the content of the MMD's selected
414 + return cvmx_mdio_read(bus_id, phy_id,
415 + CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA);
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.
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
430 + * Returns -1 on error
433 +static inline int cvmx_mdio_45_via_22_write(int bus_id, int phy_id, int device,
434 + int location, int val)
436 + union cvmx_mdio_phy_reg_mmd_control mmd_control;
439 + * a) To Register 13, write the Function field to 00 (address)
440 + * and DEVAD field to the device address value for the
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,
450 + * b) To Register 14, write the desired address value to the
451 + * MMD's address register;
453 + cvmx_mdio_write(bus_id, phy_id, CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA,
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;
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,
468 + * d) To Register 14, write the content of the MMD's selected
471 + return cvmx_mdio_write(bus_id, phy_id,
472 + CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA, val);
478 + * Perform an IEEE 802.3 clause 45 MII read. This function is used to read PHY
479 + * registers controlling auto negotiation.
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
487 + * Returns Result from the read or -1 on failure
490 +static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device,
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;
499 + smi_wr.s.dat = location;
500 + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
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);
510 + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
511 + } while (smi_wr.s.pending && --timeout);
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);
523 + smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id));
524 + } while (smi_rd.s.pending && 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);
532 + return smi_rd.s.dat;
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);
542 + * Perform an IEEE 802.3 clause 45 MII write. This function is used to
543 + * write PHY registers controlling auto negotiation.
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
552 + * Returns -1 on error
555 +static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device,
556 + int location, int val)
558 + union cvmx_smix_cmd smi_cmd;
559 + union cvmx_smix_wr_dat smi_wr;
560 + int timeout = 1000;
563 + smi_wr.s.dat = location;
564 + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
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);
574 + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
575 + } while (smi_wr.s.pending && --timeout);
580 + smi_wr.s.dat = val;
581 + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64);
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);
591 + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id));
592 + } while (smi_wr.s.pending && --timeout);
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
609 + tristate "OCTEON Management port ethernet driver (CN5XXX)"
610 + depends on CPU_CAVIUM_OCTEON
613 + This option enables the ethernet driver for the management port on
614 + CN52XX, CN57XX, CN56XX, CN55XX, and CN54XX chips.
616 source "drivers/net/fs_enet/Kconfig"
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
624 obj-$(CONFIG_MLX4_CORE) += mlx4/
625 obj-$(CONFIG_ENC28J60) += enc28j60.o
626 obj-$(CONFIG_ETHOC) += ethoc.o
627 +obj-$(CONFIG_OCTEON_MGMT) += octeon/
629 obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
631 diff --git a/drivers/net/octeon/Makefile b/drivers/net/octeon/Makefile
633 index 0000000..f32f394
635 +++ b/drivers/net/octeon/Makefile
637 +# Makefile for the Cavium OCTEON Ethernet drivers.
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
643 +# Copyright (C) 2008 Cavium Networks
645 +obj-$(CONFIG_OCTEON_MGMT) += octeon_mgmt.o
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
651 index 0000000..f60255a
653 +++ b/drivers/net/octeon/cvmx-mgmt-port.c
655 +/***********************license start***************
656 + * Author: Cavium Networks
658 + * Contact: support@caviumnetworks.com
659 + * This file is part of the OCTEON SDK
661 + * Copyright (c) 2003-2008 Cavium Networks
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.
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
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/.
678 + * This file may also be available under a different license from Cavium.
679 + * Contact Cavium Networks for more information
680 + ***********************license end**************************************/
684 + * Support functions for managing the MII management port
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>
693 +#include <asm/octeon/cvmx-mixx-defs.h>
694 +#include <asm/octeon/cvmx-agl-defs.h>
696 +#include "cvmx-mgmt-port.h"
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
704 +#define CVMX_MGMT_PORT_TX_BUFFER_SIZE 12288
705 +#define CVMX_MGMT_PORT_RX_BUFFER_SIZE 1536
708 + * Format of the TX/RX ring buffer entries
710 +union cvmx_mgmt_port_ring_entry {
713 + uint64_t reserved_62_63:2;
714 + /* Length of the buffer/packet in bytes */
716 + /* The RX error code */
718 + /* Physical address of the buffer */
724 + * Per port state required for each mgmt port
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 */
733 + /* The SMI/MDIO PHY address */
735 + /* Our MAC address */
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];
746 + * Pointers to each mgmt port's state
748 +struct cvmx_mgmt_port_state *cvmx_mgmt_port_state_ptr;
751 + * Return the number of management ports supported by this chip
753 + * Returns Number of ports
755 +int __cvmx_mgmt_port_num_ports(void)
757 + if (OCTEON_IS_MODEL(OCTEON_CN56XX))
759 + else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
766 + * Called to initialize a management port for use. Multiple calls
767 + * to this function accross applications is safe.
769 + * @port: Port to initialize
771 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
773 +enum cvmx_mgmt_port_result cvmx_mgmt_port_initialize(int port)
775 + char *alloc_name = "cvmx_mgmt_port";
776 + union cvmx_mixx_oring1 oring1;
777 + union cvmx_mixx_ctl mix_ctl;
779 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
780 + return CVMX_MGMT_PORT_INVALID_PARAM;
782 + cvmx_mgmt_port_state_ptr =
783 + cvmx_bootmem_alloc_named(CVMX_MGMT_PORT_NUM_PORTS *
784 + sizeof(struct cvmx_mgmt_port_state), 128,
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));
791 + struct cvmx_bootmem_named_block_desc *block_desc =
792 + cvmx_bootmem_find_named_block(alloc_name);
794 + cvmx_mgmt_port_state_ptr =
795 + cvmx_phys_to_ptr(block_desc->base_addr);
797 + cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: "
798 + "Unable to get named block %s.\n",
800 + return CVMX_MGMT_PORT_NO_MEMORY;
805 + * Reset the MIX block if the previous user had a different TX
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));
814 + cvmx_write_csr(CVMX_MIXX_CTL(port), 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));
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;
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;
837 + /* Make sure BIST passed */
838 + mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(port));
840 + cvmx_dprintf("WARNING: cvmx_mgmt_port_initialize: "
841 + "Managment port MIX failed BIST "
843 + (unsigned long long)mix_bist.u64);
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 "
850 + (unsigned long long)agl_gmx_bist.u64);
852 + /* Clear all state information */
853 + memset(state, 0, sizeof(*state));
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);
860 + /* Set the PHY address */
861 + if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
862 + state->phy_id = -1;
864 + /* Will need to be change to match the board */
865 + state->phy_id = port;
867 + /* Create a default MAC address */
868 + state->mac = 0x000000dead000000ull;
869 + state->mac += 0xffffff & CAST64(state);
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]);
878 + /* Tell the HW where the TX ring is */
880 + oring1.s.obase = cvmx_ptr_to_phys(state->tx_ring) >> 3;
881 + oring1.s.osize = CVMX_MGMT_PORT_NUM_TX_BUFFERS;
883 + cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64);
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]);
894 + /* Tell the HW where the RX ring is */
896 + iring1.s.ibase = cvmx_ptr_to_phys(state->rx_ring) >> 3;
897 + iring1.s.isize = CVMX_MGMT_PORT_NUM_RX_BUFFERS;
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);
903 + /* Disable the external input/output */
904 + cvmx_mgmt_port_disable(port);
906 + /* Set the MAC address filtering up */
907 + cvmx_mgmt_port_set_mac(port, state->mac);
910 + * Set the default max size to an MTU of 1500 with L2
913 + cvmx_mgmt_port_set_max_packet_size(port, 1518);
916 + * Enable the port HW. Packets are not allowed until
917 + * cvmx_mgmt_port_enable() is called.
920 + /* Strip the ending CRC */
921 + mix_ctl.s.crc_strip = 1;
922 + /* Enable the port */
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);
930 + if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
931 + || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
933 + * Force compensation values, as they are not
934 + * determined properly by HW.
936 + union cvmx_agl_gmx_drv_ctl drv_ctl;
938 + drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL);
940 + drv_ctl.s.byp_en1 = 1;
941 + drv_ctl.s.nctl1 = 6;
942 + drv_ctl.s.pctl1 = 6;
944 + drv_ctl.s.byp_en = 1;
945 + drv_ctl.s.nctl = 6;
946 + drv_ctl.s.pctl = 6;
948 + cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64);
951 + return CVMX_MGMT_PORT_SUCCESS;
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.
959 + * @port: Management port
961 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
963 +enum cvmx_mgmt_port_result cvmx_mgmt_port_shutdown(int port)
965 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
966 + return CVMX_MGMT_PORT_INVALID_PARAM;
968 + /* Stop packets from comming in */
969 + cvmx_mgmt_port_disable(port);
972 + * We don't free any memory so the next intialize can reuse
975 + return CVMX_MGMT_PORT_SUCCESS;
979 + * Enable packet IO on a management port
981 + * @port: Management port
983 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
985 +enum cvmx_mgmt_port_result cvmx_mgmt_port_enable(int port)
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;
992 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
993 + return CVMX_MGMT_PORT_INVALID_PARAM;
995 + state = cvmx_mgmt_port_state_ptr + port;
997 + cvmx_spinlock_lock(&state->lock);
999 + rxx_frm_ctl.u64 = 0;
1000 + rxx_frm_ctl.s.pre_align = 1;
1002 + * When set, disables the length check for non-min sized pkts
1003 + * with padding in the client data.
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;
1021 + * This port is configured to send PREAMBLE+SFD to begin every
1022 + * frame. GMX checks that the PREAMBLE is sent correctly.
1024 + rxx_frm_ctl.s.pre_chk = 1;
1025 + cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64);
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);
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;
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);
1043 + cvmx_spinlock_unlock(&state->lock);
1044 + return CVMX_MGMT_PORT_SUCCESS;
1048 + * Disable packet IO on a management port
1050 + * @port: Management port
1052 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1054 +enum cvmx_mgmt_port_result cvmx_mgmt_port_disable(int port)
1056 + struct cvmx_mgmt_port_state *state;
1057 + union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
1059 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1060 + return CVMX_MGMT_PORT_INVALID_PARAM;
1062 + state = cvmx_mgmt_port_state_ptr + port;
1064 + cvmx_spinlock_lock(&state->lock);
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);
1070 + cvmx_spinlock_unlock(&state->lock);
1071 + return CVMX_MGMT_PORT_SUCCESS;
1075 + * Send a packet out the management port. The packet is copied so
1076 + * the input buffer isn't used after this call.
1078 + * @port: Management port
1079 + * @packet_len: Length of the packet to send. It does not include the final CRC
1080 + * @buffer: Packet data
1082 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1084 +enum cvmx_mgmt_port_result cvmx_mgmt_port_send(int port, int packet_len,
1087 + struct cvmx_mgmt_port_state *state;
1088 + union cvmx_mixx_oring2 mix_oring2;
1090 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1091 + return CVMX_MGMT_PORT_INVALID_PARAM;
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;
1097 + if (buffer == NULL)
1098 + return CVMX_MGMT_PORT_INVALID_PARAM;
1100 + state = cvmx_mgmt_port_state_ptr + port;
1102 + cvmx_spinlock_lock(&state->lock);
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;
1110 + /* Copy the packet into the output buffer */
1111 + memcpy(state->tx_buffers[state->tx_write_index], buffer,
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 */
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)));
1128 + cvmx_spinlock_unlock(&state->lock);
1129 + return CVMX_MGMT_PORT_SUCCESS;
1134 + * Receive a packet from the management port.
1136 + * @port: Management port
1137 + * @buffer_len: Size of the buffer to receive the packet into
1138 + * @buffer: Buffer to receive the packet into
1140 + * Returns The size of the packet, or a negative erorr code on failure. Zero
1141 + * means that no packets were available.
1143 +int cvmx_mgmt_port_receive(int port, int buffer_len, void *buffer)
1145 + union cvmx_mixx_ircnt mix_ircnt;
1146 + struct cvmx_mgmt_port_state *state;
1149 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1150 + return CVMX_MGMT_PORT_INVALID_PARAM;
1152 + /* Max sure the buffer size is valid */
1153 + if (buffer_len < 1)
1154 + return CVMX_MGMT_PORT_INVALID_PARAM;
1156 + if (buffer == NULL)
1157 + return CVMX_MGMT_PORT_INVALID_PARAM;
1159 + state = cvmx_mgmt_port_state_ptr + port;
1161 + cvmx_spinlock_lock(&state->lock);
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;
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.
1174 + if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
1175 + && (*zero_check == 0))
1177 + /* Start off with zero bytes received */
1180 + * While the completion code signals more data, copy
1181 + * the buffers into the user's data.
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);
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
1196 + buffer_len -= length;
1199 + * Update this buffer for reuse in future
1200 + * receives. This size is -8 due to an errata
1201 + * for CN56XX pass 1.
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;
1210 + * Zero the beginning of the buffer for use by
1211 + * the errata check.
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;
1221 + /* Check for the final good completion code */
1222 + if (state->rx_ring[state->rx_read_index].s.code == 15) {
1224 + state->rx_ring[state->rx_read_index].s.len) {
1226 + state->rx_ring[state->rx_read_index].s.len;
1227 + memcpy(buffer, source, length);
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,
1236 + result = CVMX_MGMT_PORT_NO_MEMORY;
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 +
1245 + result = -state->rx_ring[state->rx_read_index].s.code;
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;
1253 + agl_gmx_prtx.s.duplex = 1;
1254 + cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port),
1255 + agl_gmx_prtx.u64);
1259 + * Clean out the ring buffer entry. This size is -8
1260 + * due to an errata for CN56XX pass 1.
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;
1268 + * Zero the beginning of the buffer for use by the
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);
1278 + /* No packets available */
1281 + cvmx_spinlock_unlock(&state->lock);
1286 + * Get the management port link status:
1287 + * 100 = 100Mbps, full duplex
1288 + * 10 = 10Mbps, full duplex
1290 + * -10 = 10Mpbs, half duplex
1291 + * -100 = 100Mbps, half duplex
1293 + * @port: Management port
1297 +int cvmx_mgmt_port_get_link(int port)
1299 + struct cvmx_mgmt_port_state *state;
1303 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1304 + return CVMX_MGMT_PORT_INVALID_PARAM;
1306 + state = cvmx_mgmt_port_state_ptr + port;
1308 + /* Assume 100Mbps if we don't know the PHY address */
1309 + if (state->phy_id == -1)
1312 + /* Read the PHY state */
1314 + cvmx_mdio_read(state->phy_id >> 8, state->phy_id & 0xff, 17);
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)))
1321 + /* Create multiple factor to represent duplex */
1322 + if ((phy_status >> 13) & 1)
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;
1339 + * Set the MAC address for a management port
1341 + * @port: Management port
1342 + * @mac: New MAC address. The lower 6 bytes are used.
1344 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1346 +enum cvmx_mgmt_port_result cvmx_mgmt_port_set_mac(int port, uint64_t mac)
1348 + struct cvmx_mgmt_port_state *state;
1349 + union cvmx_agl_gmx_rxx_adr_ctl agl_gmx_rxx_adr_ctl;
1351 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1352 + return CVMX_MGMT_PORT_INVALID_PARAM;
1354 + state = cvmx_mgmt_port_state_ptr + port;
1356 + cvmx_spinlock_lock(&state->lock);
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);
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);
1377 + cvmx_spinlock_unlock(&state->lock);
1378 + return CVMX_MGMT_PORT_SUCCESS;
1382 + * Get the MAC address for a management port
1384 + * @port: Management port
1386 + * Returns MAC address
1388 +uint64_t cvmx_mgmt_port_get_mac(int port)
1390 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1391 + return CVMX_MGMT_PORT_INVALID_PARAM;
1393 + return cvmx_mgmt_port_state_ptr[port].mac;
1397 + * Set the multicast list.
1399 + * @port: Management port
1400 + * @flags: Interface flags
1404 +void cvmx_mgmt_port_set_multicast_list(int port, int flags)
1406 + struct cvmx_mgmt_port_state *state;
1407 + union cvmx_agl_gmx_rxx_adr_ctl agl_gmx_rxx_adr_ctl;
1409 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1412 + state = cvmx_mgmt_port_state_ptr + port;
1414 + cvmx_spinlock_lock(&state->lock);
1416 + agl_gmx_rxx_adr_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port));
1418 + /* Allow broadcast MAC addresses */
1419 + if (!agl_gmx_rxx_adr_ctl.s.bcst)
1420 + agl_gmx_rxx_adr_ctl.s.bcst = 1;
1422 + if ((flags & CVMX_IFF_ALLMULTI) || (flags & CVMX_IFF_PROMISC))
1423 + /* Force accept multicast packets */
1424 + agl_gmx_rxx_adr_ctl.s.mcst = 2;
1426 + /* Force reject multicast packets */
1427 + agl_gmx_rxx_adr_ctl.s.mcst = 1;
1429 + if (flags & CVMX_IFF_PROMISC)
1431 + * Reject matches if promisc. Since CAM is shut off,
1432 + * should accept everything.
1434 + agl_gmx_rxx_adr_ctl.s.cam_mode = 0;
1436 + /* Filter packets based on the CAM */
1437 + agl_gmx_rxx_adr_ctl.s.cam_mode = 1;
1439 + cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), agl_gmx_rxx_adr_ctl.u64);
1441 + if (flags & CVMX_IFF_PROMISC)
1442 + cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 0);
1444 + cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 1);
1446 + cvmx_spinlock_unlock(&state->lock);
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.
1454 + * @port: Management port
1455 + * @size_without_fcs:
1456 + * Size in bytes without FCS
1458 +void cvmx_mgmt_port_set_max_packet_size(int port, int size_without_fcs)
1460 + struct cvmx_mgmt_port_state *state;
1462 + if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports()))
1465 + state = cvmx_mgmt_port_state_ptr + port;
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);
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
1477 +++ b/drivers/net/octeon/cvmx-mgmt-port.h
1479 +/***********************license start***************
1480 + * Author: Cavium Networks
1482 + * Contact: support@caviumnetworks.com
1483 + * This file is part of the OCTEON SDK
1485 + * Copyright (c) 2003-2008 Cavium Networks
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.
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
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/.
1502 + * This file may also be available under a different license from Cavium.
1503 + * Contact Cavium Networks for more information
1504 + ***********************license end**************************************/
1508 + * Support functions for managing the MII management port
1512 +#ifndef __CVMX_MGMT_PORT_H__
1513 +#define __CVMX_MGMT_PORT_H__
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,
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 */
1528 + * Called to initialize a management port for use. Multiple calls
1529 + * to this function accross applications is safe.
1531 + * @port: Port to initialize
1533 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1535 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_initialize(int port);
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.
1542 + * @port: Management port
1544 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1546 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_shutdown(int port);
1549 + * Enable packet IO on a management port
1551 + * @port: Management port
1553 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1555 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_enable(int port);
1558 + * Disable packet IO on a management port
1560 + * @port: Management port
1562 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1564 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_disable(int port);
1567 + * Send a packet out the management port. The packet is copied so
1568 + * the input buffer isn't used after this call.
1570 + * @port: Management port
1571 + * @packet_len: Length of the packet to send. It does not include the final CRC
1572 + * @buffer: Packet data
1574 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1576 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_send(int port, int packet_len,
1580 + * Receive a packet from the management port.
1582 + * @port: Management port
1583 + * @buffer_len: Size of the buffer to receive the packet into
1584 + * @buffer: Buffer to receive the packet into
1586 + * Returns The size of the packet, or a negative erorr code on failure. Zero
1587 + * means that no packets were available.
1589 +extern int cvmx_mgmt_port_receive(int port, int buffer_len, void *buffer);
1592 + * Get the management port link status:
1593 + * 100 = 100Mbps, full duplex
1594 + * 10 = 10Mbps, full duplex
1596 + * -10 = 10Mpbs, half duplex
1597 + * -100 = 100Mbps, half duplex
1599 + * @port: Management port
1603 +extern int cvmx_mgmt_port_get_link(int port);
1606 + * Set the MAC address for a management port
1608 + * @port: Management port
1609 + * @mac: New MAC address. The lower 6 bytes are used.
1611 + * Returns CVMX_MGMT_PORT_SUCCESS or an error code
1613 +extern enum cvmx_mgmt_port_result cvmx_mgmt_port_set_mac(int port,
1617 + * Get the MAC address for a management port
1619 + * @port: Management port
1621 + * Returns MAC address
1623 +extern uint64_t cvmx_mgmt_port_get_mac(int port);
1626 + * Set the multicast list.
1628 + * @port: Management port
1629 + * @flags: Interface flags
1633 +extern void cvmx_mgmt_port_set_multicast_list(int port, int flags);
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.
1640 + * @port: Management port
1641 + * @size_without_crc:
1642 + * Size in bytes without FCS
1644 +extern void cvmx_mgmt_port_set_max_packet_size(int port, int size_without_fcs);
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
1651 +++ b/drivers/net/octeon/octeon-mgmt-port.c
1654 + * Octeon Management Port Ethernet Driver
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.
1660 + * Copyright (C) 2007, 2008 Cavium Networks
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>
1670 +#include <asm/octeon/octeon.h>
1671 +#include <asm/octeon/cvmx-mixx-defs.h>
1672 +#include <asm/octeon/cvmx-agl-defs.h>
1674 +#include "cvmx-mgmt-port.h"
1676 +static struct net_device *global_dev[2] = { NULL, NULL };
1678 +#define DEBUGPRINT(format, ...) do {if (printk_ratelimit()) \
1679 + printk(format, ##__VA_ARGS__); \
1683 + * This is the definition of the Ethernet driver's private
1684 + * driver state stored in dev->priv.
1686 +struct device_private {
1688 + struct net_device_stats stats; /* Device statistics */
1695 + * @param skb Packet to send
1696 + * @param dev Device info structure
1697 + * @return Always returns zero
1699 +static int packet_transmit(struct sk_buff *skb, struct net_device *dev)
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;
1711 + /* DEBUGPRINT("ERROR: cvmx_mgmt_port_send() failed with %d\n",
1714 + priv->stats.tx_dropped++;
1716 + dev_kfree_skb(skb);
1722 + * Interrupt handler. The interrupt occurs whenever the POW
1723 + * transitions from 0->1 packets in our group.
1730 +static irqreturn_t do_interrupt(int cpl, void *dev_id)
1733 + struct sk_buff *skb;
1735 + char packet[2048];
1736 + struct net_device *dev = (struct net_device *) dev_id;
1737 + struct device_private *priv = netdev_priv(dev);
1740 + local_irq_save(flags);
1741 + result = cvmx_mgmt_port_receive(priv->port, sizeof(packet),
1743 + local_irq_restore(flags);
1745 + /* Silently drop packets if we aren't up */
1746 + if ((dev->flags & IFF_UP) == 0)
1750 + skb = dev_alloc_skb(result);
1752 + memcpy(skb_put(skb, result), packet, result);
1753 + skb->protocol = eth_type_trans(skb, dev);
1755 + skb->ip_summed = CHECKSUM_NONE;
1756 + priv->stats.rx_bytes += skb->len;
1757 + priv->stats.rx_packets++;
1760 + DEBUGPRINT("%s: Failed to allocate skbuff, "
1761 + "packet dropped\n",
1763 + priv->stats.rx_dropped++;
1765 + } else if (result < 0) {
1766 + DEBUGPRINT("%s: Receive error code %d, packet "
1768 + dev->name, result);
1769 + priv->stats.rx_errors++;
1771 + } while (result != 0);
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));
1778 + return IRQ_HANDLED;
1782 +#ifdef CONFIG_NET_POLL_CONTROLLER
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
1789 + * @param dev Device to poll. Unused
1791 +static void device_poll_controller(struct net_device *dev)
1793 + do_interrupt(0, dev);
1799 + * Open a device for use. Device should be able to send and
1800 + * receive packets after this is called.
1802 + * @param dev Device to bring up
1803 + * @return Zero on success
1805 +static int device_open(struct net_device *dev)
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);
1816 + * Stop an ethernet device. No more packets should be
1817 + * received from this device.
1819 + * @param dev Device to bring down
1820 + * @return Zero on success
1822 +static int device_close(struct net_device *dev)
1824 + struct device_private *priv = netdev_priv(dev);
1825 + cvmx_mgmt_port_disable(priv->port);
1831 + * Get the low level ethernet statistics
1833 + * @param dev Device to get the statistics from
1834 + * @return Pointer to the statistics
1836 +static struct net_device_stats *device_get_stats(struct net_device *dev)
1838 + struct device_private *priv = netdev_priv(dev);
1839 + return &priv->stats;
1843 + * Set the multicast list. Currently unimplemented.
1845 + * @param dev Device to work on
1847 +static void ethernet_mgmt_port_set_multicast_list(struct net_device *dev)
1849 + struct device_private *priv = netdev_priv(dev);
1850 + int port = priv->port;
1852 + if (OCTEON_IS_MODEL(OCTEON_CN52XX))
1856 + if (port < num_ports)
1857 + cvmx_mgmt_port_set_multicast_list(port, dev->flags);
1861 + * Set the hardware MAC address for a management port device
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
1867 +static int ethernet_mgmt_port_set_mac_address(struct net_device *dev,
1870 + struct device_private *priv = netdev_priv(dev);
1871 + union cvmx_agl_gmx_prtx_cfg agl_gmx_cfg;
1872 + int port = priv->port;
1875 + if (OCTEON_IS_MODEL(OCTEON_CN52XX))
1880 + memcpy(dev->dev_addr, addr + 2, 6);
1882 + if (port < num_ports) {
1884 + uint8_t *ptr = addr;
1886 + for (i = 0; i < 6; i++)
1887 + mac = (mac<<8) | (uint64_t)(ptr[i+2]);
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);
1898 + * Per network device initialization
1900 + * @param dev Device to initialize
1901 + * @return Zero on success
1903 +static int device_init(struct net_device *dev)
1905 + struct device_private *priv = netdev_priv(dev);
1906 + uint64_t mac = cvmx_mgmt_port_get_mac(priv->port);
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;
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;
1926 + * Module/ driver initialization. Creates the linux network
1929 + * @return Zero on success
1931 +static int __init ethernet_mgmt_port_init(void)
1933 + struct net_device *dev;
1934 + struct device_private *priv;
1935 + union cvmx_mixx_irhwm mix_irhwm;
1936 + union cvmx_mixx_intena mix_intena;
1940 + if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
1943 + if (OCTEON_IS_MODEL(OCTEON_CN52XX))
1948 + printk("Octeon management port ethernet driver\n");
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);
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");
1964 + dev->init = device_init;
1965 + strcpy(dev->name, "mgmt%d");
1967 + /* Initialize the device private structure. */
1968 + priv = netdev_priv(dev);
1969 + memset(priv, 0, sizeof(struct device_private));
1970 + priv->port = port;
1972 + if (register_netdev(dev) < 0) {
1973 + pr_err("ERROR: Failed to register ethernet device\n");
1978 + /* Clear any pending interrupts */
1979 + cvmx_write_csr(CVMX_MIXX_ISR(priv->port),
1980 + cvmx_read_csr(CVMX_MIXX_ISR(priv->port)));
1982 + /* Register an IRQ hander for to receive interrupts */
1984 + (priv->port == 0) ? OCTEON_IRQ_MII0 : OCTEON_IRQ_MII1;
1985 + if (request_irq(dev->irq, do_interrupt, IRQF_SHARED, dev->name,
1987 + pr_err("ethernet-mgmt: Failed to assign "
1988 + "interrupt %d\n", dev->irq);
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);
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);
2000 + global_dev[priv->port] = dev;
2002 + dev->set_mac_address = ethernet_mgmt_port_set_mac_address;
2003 + dev->set_multicast_list = ethernet_mgmt_port_set_multicast_list;
2010 + * Module / driver shutdown
2012 + * @return Zero on success
2014 +static void __exit ethernet_mgmt_port_cleanup(void)
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);
2026 + /* Free the interrupt handler */
2027 + free_irq(global_dev[port]->irq, global_dev[port]);
2029 + /* Free the ethernet devices */
2030 + unregister_netdev(global_dev[port]);
2031 + kfree(global_dev[port]);
2032 + global_dev[port] = NULL;
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);
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