cvmx-mgmt-port.c revision 232816
1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett 41210284Sjmallett 42210284Sjmallett 43210284Sjmallett 44210284Sjmallett 45215990Sjmallett 46210284Sjmallett/** 47210284Sjmallett * @file 48210284Sjmallett * 49210284Sjmallett * Support functions for managing the MII management port 50210284Sjmallett * 51232812Sjmallett * <hr>$Revision: 70030 $<hr> 52210284Sjmallett */ 53210284Sjmallett#include "cvmx.h" 54210284Sjmallett#include "cvmx-bootmem.h" 55210284Sjmallett#include "cvmx-spinlock.h" 56210284Sjmallett#include "cvmx-mdio.h" 57210284Sjmallett#include "cvmx-mgmt-port.h" 58210284Sjmallett#include "cvmx-sysinfo.h" 59232816Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL) 60215990Sjmallett#include "cvmx-error.h" 61232816Sjmallett#endif 62210284Sjmallett 63210284Sjmallett/** 64215990Sjmallett * Enum of MIX interface modes 65215990Sjmallett */ 66215990Sjmalletttypedef enum 67215990Sjmallett{ 68215990Sjmallett CVMX_MGMT_PORT_NONE = 0, 69215990Sjmallett CVMX_MGMT_PORT_MII_MODE, 70215990Sjmallett CVMX_MGMT_PORT_RGMII_MODE, 71215990Sjmallett} cvmx_mgmt_port_mode_t; 72215990Sjmallett 73215990Sjmallett/** 74210284Sjmallett * Format of the TX/RX ring buffer entries 75210284Sjmallett */ 76210284Sjmalletttypedef union 77210284Sjmallett{ 78210284Sjmallett uint64_t u64; 79210284Sjmallett struct 80210284Sjmallett { 81210284Sjmallett uint64_t reserved_62_63 : 2; 82210284Sjmallett uint64_t len : 14; /* Length of the buffer/packet in bytes */ 83215990Sjmallett uint64_t tstamp : 1; /* For TX, signals that the packet should be timestamped */ 84215990Sjmallett uint64_t code : 7; /* The RX error code */ 85210284Sjmallett uint64_t addr : 40; /* Physical address of the buffer */ 86210284Sjmallett } s; 87210284Sjmallett} cvmx_mgmt_port_ring_entry_t; 88210284Sjmallett 89210284Sjmallett/** 90210284Sjmallett * Per port state required for each mgmt port 91210284Sjmallett */ 92210284Sjmalletttypedef struct 93210284Sjmallett{ 94210284Sjmallett cvmx_spinlock_t lock; /* Used for exclusive access to this structure */ 95210284Sjmallett int tx_write_index; /* Where the next TX will write in the tx_ring and tx_buffers */ 96210284Sjmallett int rx_read_index; /* Where the next RX will be in the rx_ring and rx_buffers */ 97215990Sjmallett int port; /* Port to use. (This is the 'fake' IPD port number */ 98210284Sjmallett uint64_t mac; /* Our MAC address */ 99210284Sjmallett cvmx_mgmt_port_ring_entry_t tx_ring[CVMX_MGMT_PORT_NUM_TX_BUFFERS]; 100210284Sjmallett cvmx_mgmt_port_ring_entry_t rx_ring[CVMX_MGMT_PORT_NUM_RX_BUFFERS]; 101210284Sjmallett char tx_buffers[CVMX_MGMT_PORT_NUM_TX_BUFFERS][CVMX_MGMT_PORT_TX_BUFFER_SIZE]; 102210284Sjmallett char rx_buffers[CVMX_MGMT_PORT_NUM_RX_BUFFERS][CVMX_MGMT_PORT_RX_BUFFER_SIZE]; 103215990Sjmallett cvmx_mgmt_port_mode_t mode; /* Mode of the interface */ 104210284Sjmallett} cvmx_mgmt_port_state_t; 105210284Sjmallett 106210284Sjmallett/** 107210284Sjmallett * Pointers to each mgmt port's state 108210284Sjmallett */ 109210284SjmallettCVMX_SHARED cvmx_mgmt_port_state_t *cvmx_mgmt_port_state_ptr = NULL; 110210284Sjmallett 111210284Sjmallett 112210284Sjmallett/** 113210284Sjmallett * Return the number of management ports supported by this chip 114210284Sjmallett * 115210284Sjmallett * @return Number of ports 116210284Sjmallett */ 117217214Sjmallettstatic int __cvmx_mgmt_port_num_ports(void) 118210284Sjmallett{ 119232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) 120210284Sjmallett return 1; 121232812Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN6XXX)) 122210284Sjmallett return 2; 123210284Sjmallett else 124210284Sjmallett return 0; 125210284Sjmallett} 126210284Sjmallett 127210284Sjmallett 128210284Sjmallett/** 129210284Sjmallett * Called to initialize a management port for use. Multiple calls 130215990Sjmallett * to this function across applications is safe. 131210284Sjmallett * 132210284Sjmallett * @param port Port to initialize 133210284Sjmallett * 134210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 135210284Sjmallett */ 136210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_initialize(int port) 137210284Sjmallett{ 138210284Sjmallett char *alloc_name = "cvmx_mgmt_port"; 139210284Sjmallett cvmx_mixx_oring1_t oring1; 140210284Sjmallett cvmx_mixx_ctl_t mix_ctl; 141210284Sjmallett 142210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 143210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 144210284Sjmallett 145232812Sjmallett cvmx_mgmt_port_state_ptr = cvmx_bootmem_alloc_named_flags(CVMX_MGMT_PORT_NUM_PORTS * sizeof(cvmx_mgmt_port_state_t), 128, alloc_name, CVMX_BOOTMEM_FLAG_END_ALLOC); 146210284Sjmallett if (cvmx_mgmt_port_state_ptr) 147210284Sjmallett { 148210284Sjmallett memset(cvmx_mgmt_port_state_ptr, 0, CVMX_MGMT_PORT_NUM_PORTS * sizeof(cvmx_mgmt_port_state_t)); 149210284Sjmallett } 150210284Sjmallett else 151210284Sjmallett { 152215990Sjmallett const cvmx_bootmem_named_block_desc_t *block_desc = cvmx_bootmem_find_named_block(alloc_name); 153210284Sjmallett if (block_desc) 154210284Sjmallett cvmx_mgmt_port_state_ptr = cvmx_phys_to_ptr(block_desc->base_addr); 155210284Sjmallett else 156210284Sjmallett { 157215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Unable to get named block %s on MIX%d.\n", alloc_name, port); 158210284Sjmallett return CVMX_MGMT_PORT_NO_MEMORY; 159210284Sjmallett } 160210284Sjmallett } 161210284Sjmallett 162210284Sjmallett /* Reset the MIX block if the previous user had a different TX ring size, or if 163210284Sjmallett ** we allocated a new (and blank) state structure. */ 164210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 165210284Sjmallett if (!mix_ctl.s.reset) 166210284Sjmallett { 167210284Sjmallett oring1.u64 = cvmx_read_csr(CVMX_MIXX_ORING1(port)); 168210284Sjmallett if (oring1.s.osize != CVMX_MGMT_PORT_NUM_TX_BUFFERS || cvmx_mgmt_port_state_ptr[port].tx_ring[0].u64 == 0) 169210284Sjmallett { 170210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 171210284Sjmallett mix_ctl.s.en = 0; 172210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 173210284Sjmallett do 174210284Sjmallett { 175210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 176210284Sjmallett } while (mix_ctl.s.busy); 177210284Sjmallett mix_ctl.s.reset = 1; 178210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 179210284Sjmallett cvmx_read_csr(CVMX_MIXX_CTL(port)); 180210284Sjmallett memset(cvmx_mgmt_port_state_ptr + port, 0, sizeof(cvmx_mgmt_port_state_t)); 181210284Sjmallett } 182210284Sjmallett } 183210284Sjmallett 184210284Sjmallett if (cvmx_mgmt_port_state_ptr[port].tx_ring[0].u64 == 0) 185210284Sjmallett { 186210284Sjmallett cvmx_mgmt_port_state_t *state = cvmx_mgmt_port_state_ptr + port; 187210284Sjmallett int i; 188210284Sjmallett cvmx_mixx_bist_t mix_bist; 189210284Sjmallett cvmx_agl_gmx_bist_t agl_gmx_bist; 190210284Sjmallett cvmx_mixx_oring1_t oring1; 191210284Sjmallett cvmx_mixx_iring1_t iring1; 192210284Sjmallett cvmx_mixx_ctl_t mix_ctl; 193215990Sjmallett cvmx_agl_prtx_ctl_t agl_prtx_ctl; 194210284Sjmallett 195210284Sjmallett /* Make sure BIST passed */ 196210284Sjmallett mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(port)); 197210284Sjmallett if (mix_bist.u64) 198215990Sjmallett cvmx_dprintf("WARNING: cvmx_mgmt_port_initialize: Managment port MIX failed BIST (0x%016llx) on MIX%d\n", CAST64(mix_bist.u64), port); 199210284Sjmallett 200210284Sjmallett agl_gmx_bist.u64 = cvmx_read_csr(CVMX_AGL_GMX_BIST); 201210284Sjmallett if (agl_gmx_bist.u64) 202215990Sjmallett cvmx_dprintf("WARNING: cvmx_mgmt_port_initialize: Managment port AGL failed BIST (0x%016llx) on MIX%d\n", CAST64(agl_gmx_bist.u64), port); 203210284Sjmallett 204210284Sjmallett /* Clear all state information */ 205210284Sjmallett memset(state, 0, sizeof(*state)); 206210284Sjmallett 207210284Sjmallett /* Take the control logic out of reset */ 208210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 209210284Sjmallett mix_ctl.s.reset = 0; 210210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 211210284Sjmallett 212215990Sjmallett /* Read until reset == 0. Timeout should never happen... */ 213215990Sjmallett if (CVMX_WAIT_FOR_FIELD64(CVMX_MIXX_CTL(port), cvmx_mixx_ctl_t, reset, ==, 0, 300000000)) 214215990Sjmallett { 215215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Timeout waiting for MIX(%d) reset.\n", port); 216215990Sjmallett return CVMX_MGMT_PORT_INIT_ERROR; 217215990Sjmallett } 218215990Sjmallett 219215990Sjmallett /* Set the PHY address and mode of the interface (RGMII/MII mode). */ 220210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 221215990Sjmallett { 222215990Sjmallett state->port = -1; 223215990Sjmallett state->mode = CVMX_MGMT_PORT_MII_MODE; 224215990Sjmallett } 225210284Sjmallett else 226215990Sjmallett { 227215990Sjmallett int port_num = CVMX_HELPER_BOARD_MGMT_IPD_PORT + port; 228215990Sjmallett int phy_addr = cvmx_helper_board_get_mii_address(port_num); 229215990Sjmallett if (phy_addr != -1) 230215990Sjmallett { 231215990Sjmallett cvmx_mdio_phy_reg_status_t phy_status; 232215990Sjmallett /* Read PHY status register to find the mode of the interface. */ 233215990Sjmallett phy_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 234215990Sjmallett if (phy_status.s.capable_extended_status == 0) // MII mode 235215990Sjmallett state->mode = CVMX_MGMT_PORT_MII_MODE; 236215990Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN6XXX) 237215990Sjmallett && phy_status.s.capable_extended_status) // RGMII mode 238215990Sjmallett state->mode = CVMX_MGMT_PORT_RGMII_MODE; 239215990Sjmallett else 240215990Sjmallett state->mode = CVMX_MGMT_PORT_NONE; 241215990Sjmallett } 242215990Sjmallett else 243215990Sjmallett { 244215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Not able to read the PHY on MIX%d\n", port); 245215990Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 246215990Sjmallett } 247215990Sjmallett state->port = port_num; 248215990Sjmallett } 249210284Sjmallett 250215990Sjmallett /* All interfaces should be configured in same mode */ 251215990Sjmallett for (i = 0; i < __cvmx_mgmt_port_num_ports(); i++) 252215990Sjmallett { 253215990Sjmallett if (i != port 254215990Sjmallett && cvmx_mgmt_port_state_ptr[i].mode != CVMX_MGMT_PORT_NONE 255215990Sjmallett && cvmx_mgmt_port_state_ptr[i].mode != state->mode) 256215990Sjmallett { 257215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: All ports in MIX interface are not configured in same mode.\n \ 258215990Sjmallett Port %d is configured as %d\n \ 259215990Sjmallett And Port %d is configured as %d\n", port, state->mode, i, cvmx_mgmt_port_state_ptr[i].mode); 260215990Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 261215990Sjmallett } 262215990Sjmallett } 263215990Sjmallett 264210284Sjmallett /* Create a default MAC address */ 265210284Sjmallett state->mac = 0x000000dead000000ull; 266210284Sjmallett state->mac += 0xffffff & CAST64(state); 267210284Sjmallett 268210284Sjmallett /* Setup the TX ring */ 269210284Sjmallett for (i=0; i<CVMX_MGMT_PORT_NUM_TX_BUFFERS; i++) 270210284Sjmallett { 271210284Sjmallett state->tx_ring[i].s.len = CVMX_MGMT_PORT_TX_BUFFER_SIZE; 272210284Sjmallett state->tx_ring[i].s.addr = cvmx_ptr_to_phys(state->tx_buffers[i]); 273210284Sjmallett } 274210284Sjmallett 275210284Sjmallett /* Tell the HW where the TX ring is */ 276210284Sjmallett oring1.u64 = 0; 277210284Sjmallett oring1.s.obase = cvmx_ptr_to_phys(state->tx_ring)>>3; 278210284Sjmallett oring1.s.osize = CVMX_MGMT_PORT_NUM_TX_BUFFERS; 279210284Sjmallett CVMX_SYNCWS; 280210284Sjmallett cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64); 281210284Sjmallett 282210284Sjmallett /* Setup the RX ring */ 283210284Sjmallett for (i=0; i<CVMX_MGMT_PORT_NUM_RX_BUFFERS; i++) 284210284Sjmallett { 285210284Sjmallett /* This size is -8 due to an errata for CN56XX pass 1 */ 286210284Sjmallett state->rx_ring[i].s.len = CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8; 287210284Sjmallett state->rx_ring[i].s.addr = cvmx_ptr_to_phys(state->rx_buffers[i]); 288210284Sjmallett } 289210284Sjmallett 290210284Sjmallett /* Tell the HW where the RX ring is */ 291210284Sjmallett iring1.u64 = 0; 292210284Sjmallett iring1.s.ibase = cvmx_ptr_to_phys(state->rx_ring)>>3; 293210284Sjmallett iring1.s.isize = CVMX_MGMT_PORT_NUM_RX_BUFFERS; 294210284Sjmallett CVMX_SYNCWS; 295210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64); 296210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING2(port), CVMX_MGMT_PORT_NUM_RX_BUFFERS); 297210284Sjmallett 298210284Sjmallett /* Disable the external input/output */ 299210284Sjmallett cvmx_mgmt_port_disable(port); 300210284Sjmallett 301210284Sjmallett /* Set the MAC address filtering up */ 302210284Sjmallett cvmx_mgmt_port_set_mac(port, state->mac); 303210284Sjmallett 304210284Sjmallett /* Set the default max size to an MTU of 1500 with L2 and VLAN */ 305210284Sjmallett cvmx_mgmt_port_set_max_packet_size(port, 1518); 306210284Sjmallett 307210284Sjmallett /* Enable the port HW. Packets are not allowed until cvmx_mgmt_port_enable() is called */ 308210284Sjmallett mix_ctl.u64 = 0; 309210284Sjmallett mix_ctl.s.crc_strip = 1; /* Strip the ending CRC */ 310210284Sjmallett mix_ctl.s.en = 1; /* Enable the port */ 311210284Sjmallett mix_ctl.s.nbtarb = 0; /* Arbitration mode */ 312210284Sjmallett mix_ctl.s.mrq_hwm = 1; /* MII CB-request FIFO programmable high watermark */ 313210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 314210284Sjmallett 315215990Sjmallett /* Select the mode of operation for the interface. */ 316215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 317210284Sjmallett { 318215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 319215990Sjmallett 320215990Sjmallett if (state->mode == CVMX_MGMT_PORT_RGMII_MODE) 321215990Sjmallett agl_prtx_ctl.s.mode = 0; 322215990Sjmallett else if (state->mode == CVMX_MGMT_PORT_MII_MODE) 323215990Sjmallett agl_prtx_ctl.s.mode = 1; 324215990Sjmallett else 325215990Sjmallett { 326215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Invalid mode for MIX(%d)\n", port); 327215990Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 328215990Sjmallett } 329215990Sjmallett 330215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 331215990Sjmallett } 332215990Sjmallett 333215990Sjmallett /* Initialize the physical layer. */ 334215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 335215990Sjmallett { 336215990Sjmallett /* MII clocks counts are based on the 125Mhz reference, so our 337215990Sjmallett delays need to be scaled to match the core clock rate. The 338215990Sjmallett "+1" is to make sure rounding always waits a little too 339215990Sjmallett long. */ 340215990Sjmallett uint64_t clock_scale = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 125000000 + 1; 341215990Sjmallett 342215990Sjmallett /* Take the DLL and clock tree out of reset */ 343215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 344215990Sjmallett agl_prtx_ctl.s.clkrst = 0; 345215990Sjmallett if (state->mode == CVMX_MGMT_PORT_RGMII_MODE) // RGMII Initialization 346215990Sjmallett { 347215990Sjmallett agl_prtx_ctl.s.dllrst = 0; 348215990Sjmallett agl_prtx_ctl.s.clktx_byp = 0; 349215990Sjmallett } 350215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 351215990Sjmallett cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); /* Force write out before wait */ 352215990Sjmallett 353215990Sjmallett /* Wait for the DLL to lock. External 125 MHz reference clock must be stable at this point. */ 354215990Sjmallett cvmx_wait(256 * clock_scale); 355215990Sjmallett 356215990Sjmallett /* The rest of the config is common between RGMII/MII */ 357215990Sjmallett 358215990Sjmallett /* Enable the interface */ 359215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 360215990Sjmallett agl_prtx_ctl.s.enable = 1; 361215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 362215990Sjmallett 363215990Sjmallett /* Read the value back to force the previous write */ 364215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 365215990Sjmallett 366215990Sjmallett /* Enable the componsation controller */ 367215990Sjmallett agl_prtx_ctl.s.comp = 1; 368232812Sjmallett agl_prtx_ctl.s.drv_byp = 0; 369215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 370215990Sjmallett cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); /* Force write out before wait */ 371215990Sjmallett cvmx_wait(1024 * clock_scale); // for componsation state to lock. 372215990Sjmallett } 373215990Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) 374215990Sjmallett { 375210284Sjmallett /* Force compensation values, as they are not determined properly by HW */ 376210284Sjmallett cvmx_agl_gmx_drv_ctl_t drv_ctl; 377210284Sjmallett 378210284Sjmallett drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL); 379210284Sjmallett if (port) 380210284Sjmallett { 381210284Sjmallett drv_ctl.s.byp_en1 = 1; 382210284Sjmallett drv_ctl.s.nctl1 = 6; 383210284Sjmallett drv_ctl.s.pctl1 = 6; 384210284Sjmallett } 385210284Sjmallett else 386210284Sjmallett { 387210284Sjmallett drv_ctl.s.byp_en = 1; 388210284Sjmallett drv_ctl.s.nctl = 6; 389210284Sjmallett drv_ctl.s.pctl = 6; 390210284Sjmallett } 391210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64); 392210284Sjmallett } 393210284Sjmallett } 394232816Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL) 395215990Sjmallett cvmx_error_enable_group(CVMX_ERROR_GROUP_MGMT_PORT, port); 396232816Sjmallett#endif 397210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 398210284Sjmallett} 399210284Sjmallett 400210284Sjmallett 401210284Sjmallett/** 402210284Sjmallett * Shutdown a management port. This currently disables packet IO 403210284Sjmallett * but leaves all hardware and buffers. Another application can then 404210284Sjmallett * call initialize() without redoing the hardware setup. 405210284Sjmallett * 406210284Sjmallett * @param port Management port 407210284Sjmallett * 408210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 409210284Sjmallett */ 410210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_shutdown(int port) 411210284Sjmallett{ 412210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 413210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 414210284Sjmallett 415232816Sjmallett#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL) 416215990Sjmallett cvmx_error_disable_group(CVMX_ERROR_GROUP_MGMT_PORT, port); 417232816Sjmallett#endif 418215990Sjmallett 419210284Sjmallett /* Stop packets from comming in */ 420210284Sjmallett cvmx_mgmt_port_disable(port); 421210284Sjmallett 422210284Sjmallett /* We don't free any memory so the next intialize can reuse the HW setup */ 423210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 424210284Sjmallett} 425210284Sjmallett 426210284Sjmallett 427210284Sjmallett/** 428210284Sjmallett * Enable packet IO on a management port 429210284Sjmallett * 430210284Sjmallett * @param port Management port 431210284Sjmallett * 432210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 433210284Sjmallett */ 434210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_enable(int port) 435210284Sjmallett{ 436210284Sjmallett cvmx_mgmt_port_state_t *state; 437210284Sjmallett cvmx_agl_gmx_inf_mode_t agl_gmx_inf_mode; 438210284Sjmallett cvmx_agl_gmx_rxx_frm_ctl_t rxx_frm_ctl; 439210284Sjmallett 440210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 441210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 442210284Sjmallett 443210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 444210284Sjmallett 445210284Sjmallett cvmx_spinlock_lock(&state->lock); 446210284Sjmallett 447210284Sjmallett rxx_frm_ctl.u64 = 0; 448210284Sjmallett rxx_frm_ctl.s.pre_align = 1; 449210284Sjmallett rxx_frm_ctl.s.pad_len = 1; /* When set, disables the length check for non-min sized pkts with padding in the client data */ 450210284Sjmallett rxx_frm_ctl.s.vlan_len = 1; /* When set, disables the length check for VLAN pkts */ 451210284Sjmallett rxx_frm_ctl.s.pre_free = 1; /* When set, PREAMBLE checking is less strict */ 452210284Sjmallett rxx_frm_ctl.s.ctl_smac = 0; /* Control Pause Frames can match station SMAC */ 453210284Sjmallett rxx_frm_ctl.s.ctl_mcst = 1; /* Control Pause Frames can match globally assign Multicast address */ 454210284Sjmallett rxx_frm_ctl.s.ctl_bck = 1; /* Forward pause information to TX block */ 455210284Sjmallett rxx_frm_ctl.s.ctl_drp = 1; /* Drop Control Pause Frames */ 456210284Sjmallett rxx_frm_ctl.s.pre_strp = 1; /* Strip off the preamble */ 457210284Sjmallett rxx_frm_ctl.s.pre_chk = 1; /* This port is configured to send PREAMBLE+SFD to begin every frame. GMX checks that the PREAMBLE is sent correctly */ 458210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64); 459210284Sjmallett 460210284Sjmallett /* Enable the AGL block */ 461215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) 462215990Sjmallett { 463215990Sjmallett agl_gmx_inf_mode.u64 = 0; 464215990Sjmallett agl_gmx_inf_mode.s.en = 1; 465215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64); 466215990Sjmallett } 467210284Sjmallett 468210284Sjmallett /* Configure the port duplex and enables */ 469215990Sjmallett cvmx_mgmt_port_link_set(port, cvmx_mgmt_port_link_get(port)); 470210284Sjmallett 471210284Sjmallett cvmx_spinlock_unlock(&state->lock); 472210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 473210284Sjmallett} 474210284Sjmallett 475210284Sjmallett 476210284Sjmallett/** 477210284Sjmallett * Disable packet IO on a management port 478210284Sjmallett * 479210284Sjmallett * @param port Management port 480210284Sjmallett * 481210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 482210284Sjmallett */ 483210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_disable(int port) 484210284Sjmallett{ 485210284Sjmallett cvmx_mgmt_port_state_t *state; 486210284Sjmallett cvmx_agl_gmx_prtx_cfg_t agl_gmx_prtx; 487210284Sjmallett 488210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 489210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 490210284Sjmallett 491210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 492210284Sjmallett 493210284Sjmallett cvmx_spinlock_lock(&state->lock); 494210284Sjmallett 495210284Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 496210284Sjmallett agl_gmx_prtx.s.en = 0; 497210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 498210284Sjmallett 499210284Sjmallett cvmx_spinlock_unlock(&state->lock); 500210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 501210284Sjmallett} 502210284Sjmallett 503210284Sjmallett 504210284Sjmallett/** 505210284Sjmallett * Send a packet out the management port. The packet is copied so 506210284Sjmallett * the input buffer isn't used after this call. 507210284Sjmallett * 508210284Sjmallett * @param port Management port 509210284Sjmallett * @param packet_len Length of the packet to send. It does not include the final CRC 510210284Sjmallett * @param buffer Packet data 511210284Sjmallett * 512210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 513210284Sjmallett */ 514210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_send(int port, int packet_len, void *buffer) 515210284Sjmallett{ 516210284Sjmallett cvmx_mgmt_port_state_t *state; 517210284Sjmallett cvmx_mixx_oring2_t mix_oring2; 518210284Sjmallett 519210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 520210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 521210284Sjmallett 522210284Sjmallett /* Max sure the packet size is valid */ 523210284Sjmallett if ((packet_len < 1) || (packet_len > CVMX_MGMT_PORT_TX_BUFFER_SIZE)) 524210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 525210284Sjmallett 526210284Sjmallett if (buffer == NULL) 527210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 528210284Sjmallett 529210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 530210284Sjmallett 531210284Sjmallett cvmx_spinlock_lock(&state->lock); 532210284Sjmallett 533210284Sjmallett mix_oring2.u64 = cvmx_read_csr(CVMX_MIXX_ORING2(port)); 534210284Sjmallett if (mix_oring2.s.odbell >= CVMX_MGMT_PORT_NUM_TX_BUFFERS - 1) 535210284Sjmallett { 536210284Sjmallett /* No room for another packet */ 537210284Sjmallett cvmx_spinlock_unlock(&state->lock); 538210284Sjmallett return CVMX_MGMT_PORT_NO_MEMORY; 539210284Sjmallett } 540210284Sjmallett else 541210284Sjmallett { 542210284Sjmallett /* Copy the packet into the output buffer */ 543210284Sjmallett memcpy(state->tx_buffers[state->tx_write_index], buffer, packet_len); 544210284Sjmallett /* Insert the source MAC */ 545210284Sjmallett memcpy(state->tx_buffers[state->tx_write_index] + 6, ((char*)&state->mac) + 2, 6); 546210284Sjmallett /* Update the TX ring buffer entry size */ 547210284Sjmallett state->tx_ring[state->tx_write_index].s.len = packet_len; 548215990Sjmallett /* This code doesn't support TX timestamps */ 549215990Sjmallett state->tx_ring[state->tx_write_index].s.tstamp = 0; 550210284Sjmallett /* Increment our TX index */ 551210284Sjmallett state->tx_write_index = (state->tx_write_index + 1) % CVMX_MGMT_PORT_NUM_TX_BUFFERS; 552215990Sjmallett /* Ring the doorbell, sending the packet */ 553210284Sjmallett CVMX_SYNCWS; 554210284Sjmallett cvmx_write_csr(CVMX_MIXX_ORING2(port), 1); 555210284Sjmallett if (cvmx_read_csr(CVMX_MIXX_ORCNT(port))) 556210284Sjmallett cvmx_write_csr(CVMX_MIXX_ORCNT(port), cvmx_read_csr(CVMX_MIXX_ORCNT(port))); 557210284Sjmallett 558210284Sjmallett cvmx_spinlock_unlock(&state->lock); 559210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 560210284Sjmallett } 561210284Sjmallett} 562210284Sjmallett 563210284Sjmallett 564217214Sjmallett#if defined(__FreeBSD__) 565210284Sjmallett/** 566217214Sjmallett * Send a packet out the management port. The packet is copied so 567217214Sjmallett * the input mbuf isn't used after this call. 568217214Sjmallett * 569217214Sjmallett * @param port Management port 570217214Sjmallett * @param m Packet mbuf (with pkthdr) 571217214Sjmallett * 572217214Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 573217214Sjmallett */ 574217214Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_sendm(int port, const struct mbuf *m) 575217214Sjmallett{ 576217214Sjmallett cvmx_mgmt_port_state_t *state; 577217214Sjmallett cvmx_mixx_oring2_t mix_oring2; 578217214Sjmallett 579217214Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 580217214Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 581217214Sjmallett 582217214Sjmallett /* Max sure the packet size is valid */ 583217214Sjmallett if ((m->m_pkthdr.len < 1) || (m->m_pkthdr.len > CVMX_MGMT_PORT_TX_BUFFER_SIZE)) 584217214Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 585217214Sjmallett 586217214Sjmallett state = cvmx_mgmt_port_state_ptr + port; 587217214Sjmallett 588217214Sjmallett cvmx_spinlock_lock(&state->lock); 589217214Sjmallett 590217214Sjmallett mix_oring2.u64 = cvmx_read_csr(CVMX_MIXX_ORING2(port)); 591217214Sjmallett if (mix_oring2.s.odbell >= CVMX_MGMT_PORT_NUM_TX_BUFFERS - 1) 592217214Sjmallett { 593217214Sjmallett /* No room for another packet */ 594217214Sjmallett cvmx_spinlock_unlock(&state->lock); 595217214Sjmallett return CVMX_MGMT_PORT_NO_MEMORY; 596217214Sjmallett } 597217214Sjmallett else 598217214Sjmallett { 599217214Sjmallett /* Copy the packet into the output buffer */ 600217214Sjmallett m_copydata(m, 0, m->m_pkthdr.len, state->tx_buffers[state->tx_write_index]); 601217214Sjmallett /* Update the TX ring buffer entry size */ 602217214Sjmallett state->tx_ring[state->tx_write_index].s.len = m->m_pkthdr.len; 603217214Sjmallett /* This code doesn't support TX timestamps */ 604217214Sjmallett state->tx_ring[state->tx_write_index].s.tstamp = 0; 605217214Sjmallett /* Increment our TX index */ 606217214Sjmallett state->tx_write_index = (state->tx_write_index + 1) % CVMX_MGMT_PORT_NUM_TX_BUFFERS; 607217214Sjmallett /* Ring the doorbell, sending the packet */ 608217214Sjmallett CVMX_SYNCWS; 609217214Sjmallett cvmx_write_csr(CVMX_MIXX_ORING2(port), 1); 610217214Sjmallett if (cvmx_read_csr(CVMX_MIXX_ORCNT(port))) 611217214Sjmallett cvmx_write_csr(CVMX_MIXX_ORCNT(port), cvmx_read_csr(CVMX_MIXX_ORCNT(port))); 612217214Sjmallett 613217214Sjmallett cvmx_spinlock_unlock(&state->lock); 614217214Sjmallett return CVMX_MGMT_PORT_SUCCESS; 615217214Sjmallett } 616217214Sjmallett} 617217214Sjmallett#endif 618217214Sjmallett 619217214Sjmallett 620217214Sjmallett/** 621210284Sjmallett * Receive a packet from the management port. 622210284Sjmallett * 623210284Sjmallett * @param port Management port 624210284Sjmallett * @param buffer_len Size of the buffer to receive the packet into 625210284Sjmallett * @param buffer Buffer to receive the packet into 626210284Sjmallett * 627210284Sjmallett * @return The size of the packet, or a negative erorr code on failure. Zero 628210284Sjmallett * means that no packets were available. 629210284Sjmallett */ 630217214Sjmallettint cvmx_mgmt_port_receive(int port, int buffer_len, uint8_t *buffer) 631210284Sjmallett{ 632210284Sjmallett cvmx_mixx_ircnt_t mix_ircnt; 633210284Sjmallett cvmx_mgmt_port_state_t *state; 634210284Sjmallett int result; 635210284Sjmallett 636210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 637210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 638210284Sjmallett 639210284Sjmallett /* Max sure the buffer size is valid */ 640210284Sjmallett if (buffer_len < 1) 641210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 642210284Sjmallett 643210284Sjmallett if (buffer == NULL) 644210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 645210284Sjmallett 646210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 647210284Sjmallett 648210284Sjmallett cvmx_spinlock_lock(&state->lock); 649210284Sjmallett 650210284Sjmallett /* Find out how many RX packets are pending */ 651210284Sjmallett mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port)); 652210284Sjmallett if (mix_ircnt.s.ircnt) 653210284Sjmallett { 654217214Sjmallett uint64_t *source = (void *)state->rx_buffers[state->rx_read_index]; 655217214Sjmallett uint64_t *zero_check = source; 656210284Sjmallett /* CN56XX pass 1 has an errata where packets might start 8 bytes 657210284Sjmallett into the buffer instead of at their correct lcoation. If the 658210284Sjmallett first 8 bytes is zero we assume this has happened */ 659210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && (*zero_check == 0)) 660217214Sjmallett source++; 661210284Sjmallett /* Start off with zero bytes received */ 662210284Sjmallett result = 0; 663210284Sjmallett /* While the completion code signals more data, copy the buffers 664210284Sjmallett into the user's data */ 665210284Sjmallett while (state->rx_ring[state->rx_read_index].s.code == 16) 666210284Sjmallett { 667210284Sjmallett /* Only copy what will fit in the user's buffer */ 668210284Sjmallett int length = state->rx_ring[state->rx_read_index].s.len; 669210284Sjmallett if (length > buffer_len) 670210284Sjmallett length = buffer_len; 671210284Sjmallett memcpy(buffer, source, length); 672210284Sjmallett /* Reduce the size of the buffer to the remaining space. If we run 673210284Sjmallett out we will signal an error when the code 15 buffer doesn't fit */ 674210284Sjmallett buffer += length; 675210284Sjmallett buffer_len -= length; 676210284Sjmallett result += length; 677210284Sjmallett /* Update this buffer for reuse in future receives. This size is 678210284Sjmallett -8 due to an errata for CN56XX pass 1 */ 679210284Sjmallett state->rx_ring[state->rx_read_index].s.code = 0; 680210284Sjmallett state->rx_ring[state->rx_read_index].s.len = CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8; 681210284Sjmallett state->rx_read_index = (state->rx_read_index + 1) % CVMX_MGMT_PORT_NUM_RX_BUFFERS; 682210284Sjmallett /* Zero the beginning of the buffer for use by the errata check */ 683210284Sjmallett *zero_check = 0; 684210284Sjmallett CVMX_SYNCWS; 685210284Sjmallett /* Increment the number of RX buffers */ 686210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING2(port), 1); 687217214Sjmallett source = (void *)state->rx_buffers[state->rx_read_index]; 688210284Sjmallett zero_check = source; 689210284Sjmallett } 690210284Sjmallett 691210284Sjmallett /* Check for the final good completion code */ 692210284Sjmallett if (state->rx_ring[state->rx_read_index].s.code == 15) 693210284Sjmallett { 694210284Sjmallett if (buffer_len >= state->rx_ring[state->rx_read_index].s.len) 695210284Sjmallett { 696210284Sjmallett int length = state->rx_ring[state->rx_read_index].s.len; 697210284Sjmallett memcpy(buffer, source, length); 698210284Sjmallett result += length; 699210284Sjmallett } 700210284Sjmallett else 701210284Sjmallett { 702210284Sjmallett /* Not enough room for the packet */ 703210284Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_receive: Packet (%d) larger than supplied buffer (%d)\n", state->rx_ring[state->rx_read_index].s.len, buffer_len); 704210284Sjmallett result = CVMX_MGMT_PORT_NO_MEMORY; 705210284Sjmallett } 706210284Sjmallett } 707210284Sjmallett else 708210284Sjmallett { 709210284Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_receive: Receive error code %d. Packet dropped(Len %d), \n", 710210284Sjmallett state->rx_ring[state->rx_read_index].s.code, state->rx_ring[state->rx_read_index].s.len + result); 711210284Sjmallett result = -state->rx_ring[state->rx_read_index].s.code; 712210284Sjmallett 713210284Sjmallett 714210284Sjmallett /* Check to see if we need to change the duplex. */ 715215990Sjmallett cvmx_mgmt_port_link_set(port, cvmx_mgmt_port_link_get(port)); 716210284Sjmallett } 717210284Sjmallett 718210284Sjmallett /* Clean out the ring buffer entry. This size is -8 due to an errata 719210284Sjmallett for CN56XX pass 1 */ 720210284Sjmallett state->rx_ring[state->rx_read_index].s.code = 0; 721210284Sjmallett state->rx_ring[state->rx_read_index].s.len = CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8; 722210284Sjmallett state->rx_read_index = (state->rx_read_index + 1) % CVMX_MGMT_PORT_NUM_RX_BUFFERS; 723210284Sjmallett /* Zero the beginning of the buffer for use by the errata check */ 724210284Sjmallett *zero_check = 0; 725210284Sjmallett CVMX_SYNCWS; 726210284Sjmallett /* Increment the number of RX buffers */ 727210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING2(port), 1); 728210284Sjmallett /* Decrement the pending RX count */ 729210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRCNT(port), 1); 730210284Sjmallett } 731210284Sjmallett else 732210284Sjmallett { 733210284Sjmallett /* No packets available */ 734210284Sjmallett result = 0; 735210284Sjmallett } 736210284Sjmallett cvmx_spinlock_unlock(&state->lock); 737210284Sjmallett return result; 738210284Sjmallett} 739210284Sjmallett 740210284Sjmallett/** 741210284Sjmallett * Set the MAC address for a management port 742210284Sjmallett * 743210284Sjmallett * @param port Management port 744210284Sjmallett * @param mac New MAC address. The lower 6 bytes are used. 745210284Sjmallett * 746210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 747210284Sjmallett */ 748210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_set_mac(int port, uint64_t mac) 749210284Sjmallett{ 750210284Sjmallett cvmx_mgmt_port_state_t *state; 751210284Sjmallett cvmx_agl_gmx_rxx_adr_ctl_t agl_gmx_rxx_adr_ctl; 752210284Sjmallett 753210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 754210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 755210284Sjmallett 756210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 757210284Sjmallett 758210284Sjmallett cvmx_spinlock_lock(&state->lock); 759210284Sjmallett 760210284Sjmallett agl_gmx_rxx_adr_ctl.u64 = 0; 761210284Sjmallett agl_gmx_rxx_adr_ctl.s.cam_mode = 1; /* Only accept matching MAC addresses */ 762210284Sjmallett agl_gmx_rxx_adr_ctl.s.mcst = 0; /* Drop multicast */ 763210284Sjmallett agl_gmx_rxx_adr_ctl.s.bcst = 1; /* Allow broadcast */ 764210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), agl_gmx_rxx_adr_ctl.u64); 765210284Sjmallett 766210284Sjmallett /* Only using one of the CAMs */ 767210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), (mac >> 40) & 0xff); 768210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), (mac >> 32) & 0xff); 769210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), (mac >> 24) & 0xff); 770210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), (mac >> 16) & 0xff); 771210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), (mac >> 8) & 0xff); 772210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), (mac >> 0) & 0xff); 773210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 1); 774210284Sjmallett state->mac = mac; 775210284Sjmallett 776210284Sjmallett cvmx_spinlock_unlock(&state->lock); 777210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 778210284Sjmallett} 779210284Sjmallett 780210284Sjmallett 781210284Sjmallett/** 782210284Sjmallett * Get the MAC address for a management port 783210284Sjmallett * 784210284Sjmallett * @param port Management port 785210284Sjmallett * 786210284Sjmallett * @return MAC address 787210284Sjmallett */ 788210284Sjmallettuint64_t cvmx_mgmt_port_get_mac(int port) 789210284Sjmallett{ 790210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 791210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 792210284Sjmallett 793210284Sjmallett return cvmx_mgmt_port_state_ptr[port].mac; 794210284Sjmallett} 795210284Sjmallett 796210284Sjmallett/** 797210284Sjmallett * Set the multicast list. 798210284Sjmallett * 799210284Sjmallett * @param port Management port 800210284Sjmallett * @param flags Interface flags 801210284Sjmallett * 802210284Sjmallett * @return 803210284Sjmallett */ 804210284Sjmallettvoid cvmx_mgmt_port_set_multicast_list(int port, int flags) 805210284Sjmallett{ 806210284Sjmallett cvmx_mgmt_port_state_t *state; 807210284Sjmallett cvmx_agl_gmx_rxx_adr_ctl_t agl_gmx_rxx_adr_ctl; 808210284Sjmallett 809210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 810210284Sjmallett return; 811210284Sjmallett 812210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 813210284Sjmallett 814210284Sjmallett cvmx_spinlock_lock(&state->lock); 815210284Sjmallett 816210284Sjmallett agl_gmx_rxx_adr_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port)); 817215990Sjmallett 818210284Sjmallett /* Allow broadcast MAC addresses */ 819210284Sjmallett if (!agl_gmx_rxx_adr_ctl.s.bcst) 820210284Sjmallett agl_gmx_rxx_adr_ctl.s.bcst = 1; 821210284Sjmallett 822210284Sjmallett if ((flags & CVMX_IFF_ALLMULTI) || (flags & CVMX_IFF_PROMISC)) 823210284Sjmallett agl_gmx_rxx_adr_ctl.s.mcst = 2; /* Force accept multicast packets */ 824210284Sjmallett else 825210284Sjmallett agl_gmx_rxx_adr_ctl.s.mcst = 1; /* Force reject multicast packets */ 826210284Sjmallett 827210284Sjmallett if (flags & CVMX_IFF_PROMISC) 828210284Sjmallett agl_gmx_rxx_adr_ctl.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */ 829210284Sjmallett else 830210284Sjmallett agl_gmx_rxx_adr_ctl.s.cam_mode = 1; /* Filter packets based on the CAM */ 831210284Sjmallett 832210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), agl_gmx_rxx_adr_ctl.u64); 833210284Sjmallett 834210284Sjmallett if (flags & CVMX_IFF_PROMISC) 835210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 0); 836210284Sjmallett else 837210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 1); 838215990Sjmallett 839210284Sjmallett cvmx_spinlock_unlock(&state->lock); 840210284Sjmallett} 841210284Sjmallett 842210284Sjmallett 843210284Sjmallett/** 844210284Sjmallett * Set the maximum packet allowed in. Size is specified 845210284Sjmallett * including L2 but without FCS. A normal MTU would corespond 846210284Sjmallett * to 1514 assuming the standard 14 byte L2 header. 847210284Sjmallett * 848210284Sjmallett * @param port Management port 849210284Sjmallett * @param size_without_fcs 850210284Sjmallett * Size in bytes without FCS 851210284Sjmallett */ 852210284Sjmallettvoid cvmx_mgmt_port_set_max_packet_size(int port, int size_without_fcs) 853210284Sjmallett{ 854210284Sjmallett cvmx_mgmt_port_state_t *state; 855210284Sjmallett 856210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 857210284Sjmallett return; 858210284Sjmallett 859210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 860210284Sjmallett 861210284Sjmallett cvmx_spinlock_lock(&state->lock); 862210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs); 863210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port), (size_without_fcs+7) & 0xfff8); 864210284Sjmallett cvmx_spinlock_unlock(&state->lock); 865210284Sjmallett} 866210284Sjmallett 867215990Sjmallett/** 868215990Sjmallett * Return the link state of an RGMII/MII port as returned by 869215990Sjmallett * auto negotiation. The result of this function may not match 870215990Sjmallett * Octeon's link config if auto negotiation has changed since 871215990Sjmallett * the last call to cvmx_mgmt_port_link_set(). 872215990Sjmallett * 873215990Sjmallett * @param port The RGMII/MII interface port to query 874215990Sjmallett * 875215990Sjmallett * @return Link state 876215990Sjmallett */ 877215990Sjmallettcvmx_helper_link_info_t cvmx_mgmt_port_link_get(int port) 878215990Sjmallett{ 879215990Sjmallett cvmx_mgmt_port_state_t *state; 880215990Sjmallett cvmx_helper_link_info_t result; 881215990Sjmallett 882215990Sjmallett state = cvmx_mgmt_port_state_ptr + port; 883215990Sjmallett result.u64 = 0; 884215990Sjmallett 885215990Sjmallett if (port > __cvmx_mgmt_port_num_ports()) 886215990Sjmallett { 887215990Sjmallett cvmx_dprintf("WARNING: Invalid port %d\n", port); 888215990Sjmallett return result; 889215990Sjmallett } 890215990Sjmallett 891215990Sjmallett if (state->port != -1) 892215990Sjmallett return __cvmx_helper_board_link_get(state->port); 893215990Sjmallett else // Simulator does not have PHY, use some defaults. 894215990Sjmallett { 895215990Sjmallett result.s.full_duplex = 1; 896215990Sjmallett result.s.link_up = 1; 897215990Sjmallett result.s.speed = 100; 898215990Sjmallett return result; 899215990Sjmallett } 900215990Sjmallett return result; 901215990Sjmallett} 902215990Sjmallett 903215990Sjmallett/** 904215990Sjmallett * Configure RGMII/MII port for the specified link state. This 905215990Sjmallett * function does not influence auto negotiation at the PHY level. 906215990Sjmallett * 907215990Sjmallett * @param port RGMII/MII interface port 908215990Sjmallett * @param link_info The new link state 909215990Sjmallett * 910215990Sjmallett * @return Zero on success, negative on failure 911215990Sjmallett */ 912215990Sjmallettint cvmx_mgmt_port_link_set(int port, cvmx_helper_link_info_t link_info) 913215990Sjmallett{ 914215990Sjmallett cvmx_agl_gmx_prtx_cfg_t agl_gmx_prtx; 915215990Sjmallett 916215990Sjmallett /* Disable GMX before we make any changes. */ 917215990Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 918215990Sjmallett agl_gmx_prtx.s.en = 0; 919215990Sjmallett agl_gmx_prtx.s.tx_en = 0; 920215990Sjmallett agl_gmx_prtx.s.rx_en = 0; 921215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 922215990Sjmallett 923215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 924215990Sjmallett { 925215990Sjmallett uint64_t one_second = cvmx_clock_get_rate(CVMX_CLOCK_CORE); 926215990Sjmallett /* Wait for GMX to be idle */ 927215990Sjmallett if (CVMX_WAIT_FOR_FIELD64(CVMX_AGL_GMX_PRTX_CFG(port), cvmx_agl_gmx_prtx_cfg_t, rx_idle, ==, 1, one_second) 928215990Sjmallett || CVMX_WAIT_FOR_FIELD64(CVMX_AGL_GMX_PRTX_CFG(port), cvmx_agl_gmx_prtx_cfg_t, tx_idle, ==, 1, one_second)) 929215990Sjmallett { 930215990Sjmallett cvmx_dprintf("MIX%d: Timeout waiting for GMX to be idle\n", port); 931215990Sjmallett return -1; 932215990Sjmallett } 933215990Sjmallett } 934215990Sjmallett 935215990Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 936215990Sjmallett 937215990Sjmallett /* Set duplex mode */ 938215990Sjmallett if (!link_info.s.link_up) 939215990Sjmallett agl_gmx_prtx.s.duplex = 1; /* Force full duplex on down links */ 940215990Sjmallett else 941215990Sjmallett agl_gmx_prtx.s.duplex = link_info.s.full_duplex; 942215990Sjmallett 943215990Sjmallett switch(link_info.s.speed) 944215990Sjmallett { 945215990Sjmallett case 10: 946215990Sjmallett agl_gmx_prtx.s.speed = 0; 947215990Sjmallett agl_gmx_prtx.s.slottime = 0; 948215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 949215990Sjmallett { 950215990Sjmallett agl_gmx_prtx.s.speed_msb = 1; 951215990Sjmallett agl_gmx_prtx.s.burst = 1; 952215990Sjmallett } 953215990Sjmallett break; 954215990Sjmallett 955215990Sjmallett case 100: 956215990Sjmallett agl_gmx_prtx.s.speed = 0; 957215990Sjmallett agl_gmx_prtx.s.slottime = 0; 958215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 959215990Sjmallett { 960215990Sjmallett agl_gmx_prtx.s.speed_msb = 0; 961215990Sjmallett agl_gmx_prtx.s.burst = 1; 962215990Sjmallett } 963215990Sjmallett break; 964215990Sjmallett 965215990Sjmallett case 1000: 966215990Sjmallett /* 1000 MBits is only supported on 6XXX chips */ 967215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 968215990Sjmallett { 969215990Sjmallett agl_gmx_prtx.s.speed_msb = 0; 970215990Sjmallett agl_gmx_prtx.s.speed = 1; 971215990Sjmallett agl_gmx_prtx.s.slottime = 1; /* Only matters for half-duplex */ 972215990Sjmallett agl_gmx_prtx.s.burst = agl_gmx_prtx.s.duplex; 973215990Sjmallett } 974215990Sjmallett break; 975215990Sjmallett 976215990Sjmallett /* No link */ 977215990Sjmallett case 0: 978215990Sjmallett default: 979215990Sjmallett break; 980215990Sjmallett } 981215990Sjmallett 982215990Sjmallett /* Write the new GMX setting with the port still disabled. */ 983215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 984215990Sjmallett 985215990Sjmallett /* Read GMX CFG again to make sure the config is completed. */ 986215990Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 987215990Sjmallett 988215990Sjmallett 989215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 990215990Sjmallett { 991215990Sjmallett cvmx_mgmt_port_state_t *state = cvmx_mgmt_port_state_ptr + port; 992215990Sjmallett cvmx_agl_gmx_txx_clk_t agl_clk; 993215990Sjmallett agl_clk.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_CLK(port)); 994215990Sjmallett agl_clk.s.clk_cnt = 1; /* MII (both speeds) and RGMII 1000 setting */ 995215990Sjmallett if (state->mode == CVMX_MGMT_PORT_RGMII_MODE) 996215990Sjmallett { 997215990Sjmallett if (link_info.s.speed == 10) 998215990Sjmallett agl_clk.s.clk_cnt = 50; 999215990Sjmallett else if (link_info.s.speed == 100) 1000215990Sjmallett agl_clk.s.clk_cnt = 5; 1001215990Sjmallett } 1002215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_TXX_CLK(port), agl_clk.u64); 1003215990Sjmallett } 1004215990Sjmallett 1005215990Sjmallett /* Enable transmit and receive ports */ 1006215990Sjmallett agl_gmx_prtx.s.tx_en = 1; 1007215990Sjmallett agl_gmx_prtx.s.rx_en = 1; 1008215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 1009215990Sjmallett 1010215990Sjmallett /* Enable the link. */ 1011215990Sjmallett agl_gmx_prtx.s.en = 1; 1012215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 1013215990Sjmallett return 0; 1014215990Sjmallett} 1015