cvmx-mgmt-port.c revision 232812
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" 59215990Sjmallett#include "cvmx-error.h" 60210284Sjmallett 61210284Sjmallett/** 62215990Sjmallett * Enum of MIX interface modes 63215990Sjmallett */ 64215990Sjmalletttypedef enum 65215990Sjmallett{ 66215990Sjmallett CVMX_MGMT_PORT_NONE = 0, 67215990Sjmallett CVMX_MGMT_PORT_MII_MODE, 68215990Sjmallett CVMX_MGMT_PORT_RGMII_MODE, 69215990Sjmallett} cvmx_mgmt_port_mode_t; 70215990Sjmallett 71215990Sjmallett/** 72210284Sjmallett * Format of the TX/RX ring buffer entries 73210284Sjmallett */ 74210284Sjmalletttypedef union 75210284Sjmallett{ 76210284Sjmallett uint64_t u64; 77210284Sjmallett struct 78210284Sjmallett { 79210284Sjmallett uint64_t reserved_62_63 : 2; 80210284Sjmallett uint64_t len : 14; /* Length of the buffer/packet in bytes */ 81215990Sjmallett uint64_t tstamp : 1; /* For TX, signals that the packet should be timestamped */ 82215990Sjmallett uint64_t code : 7; /* The RX error code */ 83210284Sjmallett uint64_t addr : 40; /* Physical address of the buffer */ 84210284Sjmallett } s; 85210284Sjmallett} cvmx_mgmt_port_ring_entry_t; 86210284Sjmallett 87210284Sjmallett/** 88210284Sjmallett * Per port state required for each mgmt port 89210284Sjmallett */ 90210284Sjmalletttypedef struct 91210284Sjmallett{ 92210284Sjmallett cvmx_spinlock_t lock; /* Used for exclusive access to this structure */ 93210284Sjmallett int tx_write_index; /* Where the next TX will write in the tx_ring and tx_buffers */ 94210284Sjmallett int rx_read_index; /* Where the next RX will be in the rx_ring and rx_buffers */ 95215990Sjmallett int port; /* Port to use. (This is the 'fake' IPD port number */ 96210284Sjmallett uint64_t mac; /* Our MAC address */ 97210284Sjmallett cvmx_mgmt_port_ring_entry_t tx_ring[CVMX_MGMT_PORT_NUM_TX_BUFFERS]; 98210284Sjmallett cvmx_mgmt_port_ring_entry_t rx_ring[CVMX_MGMT_PORT_NUM_RX_BUFFERS]; 99210284Sjmallett char tx_buffers[CVMX_MGMT_PORT_NUM_TX_BUFFERS][CVMX_MGMT_PORT_TX_BUFFER_SIZE]; 100210284Sjmallett char rx_buffers[CVMX_MGMT_PORT_NUM_RX_BUFFERS][CVMX_MGMT_PORT_RX_BUFFER_SIZE]; 101215990Sjmallett cvmx_mgmt_port_mode_t mode; /* Mode of the interface */ 102210284Sjmallett} cvmx_mgmt_port_state_t; 103210284Sjmallett 104210284Sjmallett/** 105210284Sjmallett * Pointers to each mgmt port's state 106210284Sjmallett */ 107210284SjmallettCVMX_SHARED cvmx_mgmt_port_state_t *cvmx_mgmt_port_state_ptr = NULL; 108210284Sjmallett 109210284Sjmallett 110210284Sjmallett/** 111210284Sjmallett * Return the number of management ports supported by this chip 112210284Sjmallett * 113210284Sjmallett * @return Number of ports 114210284Sjmallett */ 115217214Sjmallettstatic int __cvmx_mgmt_port_num_ports(void) 116210284Sjmallett{ 117232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) 118210284Sjmallett return 1; 119232812Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN6XXX)) 120210284Sjmallett return 2; 121210284Sjmallett else 122210284Sjmallett return 0; 123210284Sjmallett} 124210284Sjmallett 125210284Sjmallett 126210284Sjmallett/** 127210284Sjmallett * Called to initialize a management port for use. Multiple calls 128215990Sjmallett * to this function across applications is safe. 129210284Sjmallett * 130210284Sjmallett * @param port Port to initialize 131210284Sjmallett * 132210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 133210284Sjmallett */ 134210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_initialize(int port) 135210284Sjmallett{ 136210284Sjmallett char *alloc_name = "cvmx_mgmt_port"; 137210284Sjmallett cvmx_mixx_oring1_t oring1; 138210284Sjmallett cvmx_mixx_ctl_t mix_ctl; 139210284Sjmallett 140210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 141210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 142210284Sjmallett 143232812Sjmallett 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); 144210284Sjmallett if (cvmx_mgmt_port_state_ptr) 145210284Sjmallett { 146210284Sjmallett memset(cvmx_mgmt_port_state_ptr, 0, CVMX_MGMT_PORT_NUM_PORTS * sizeof(cvmx_mgmt_port_state_t)); 147210284Sjmallett } 148210284Sjmallett else 149210284Sjmallett { 150215990Sjmallett const cvmx_bootmem_named_block_desc_t *block_desc = cvmx_bootmem_find_named_block(alloc_name); 151210284Sjmallett if (block_desc) 152210284Sjmallett cvmx_mgmt_port_state_ptr = cvmx_phys_to_ptr(block_desc->base_addr); 153210284Sjmallett else 154210284Sjmallett { 155215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Unable to get named block %s on MIX%d.\n", alloc_name, port); 156210284Sjmallett return CVMX_MGMT_PORT_NO_MEMORY; 157210284Sjmallett } 158210284Sjmallett } 159210284Sjmallett 160210284Sjmallett /* Reset the MIX block if the previous user had a different TX ring size, or if 161210284Sjmallett ** we allocated a new (and blank) state structure. */ 162210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 163210284Sjmallett if (!mix_ctl.s.reset) 164210284Sjmallett { 165210284Sjmallett oring1.u64 = cvmx_read_csr(CVMX_MIXX_ORING1(port)); 166210284Sjmallett if (oring1.s.osize != CVMX_MGMT_PORT_NUM_TX_BUFFERS || cvmx_mgmt_port_state_ptr[port].tx_ring[0].u64 == 0) 167210284Sjmallett { 168210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 169210284Sjmallett mix_ctl.s.en = 0; 170210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 171210284Sjmallett do 172210284Sjmallett { 173210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 174210284Sjmallett } while (mix_ctl.s.busy); 175210284Sjmallett mix_ctl.s.reset = 1; 176210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 177210284Sjmallett cvmx_read_csr(CVMX_MIXX_CTL(port)); 178210284Sjmallett memset(cvmx_mgmt_port_state_ptr + port, 0, sizeof(cvmx_mgmt_port_state_t)); 179210284Sjmallett } 180210284Sjmallett } 181210284Sjmallett 182210284Sjmallett if (cvmx_mgmt_port_state_ptr[port].tx_ring[0].u64 == 0) 183210284Sjmallett { 184210284Sjmallett cvmx_mgmt_port_state_t *state = cvmx_mgmt_port_state_ptr + port; 185210284Sjmallett int i; 186210284Sjmallett cvmx_mixx_bist_t mix_bist; 187210284Sjmallett cvmx_agl_gmx_bist_t agl_gmx_bist; 188210284Sjmallett cvmx_mixx_oring1_t oring1; 189210284Sjmallett cvmx_mixx_iring1_t iring1; 190210284Sjmallett cvmx_mixx_ctl_t mix_ctl; 191215990Sjmallett cvmx_agl_prtx_ctl_t agl_prtx_ctl; 192210284Sjmallett 193210284Sjmallett /* Make sure BIST passed */ 194210284Sjmallett mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(port)); 195210284Sjmallett if (mix_bist.u64) 196215990Sjmallett cvmx_dprintf("WARNING: cvmx_mgmt_port_initialize: Managment port MIX failed BIST (0x%016llx) on MIX%d\n", CAST64(mix_bist.u64), port); 197210284Sjmallett 198210284Sjmallett agl_gmx_bist.u64 = cvmx_read_csr(CVMX_AGL_GMX_BIST); 199210284Sjmallett if (agl_gmx_bist.u64) 200215990Sjmallett cvmx_dprintf("WARNING: cvmx_mgmt_port_initialize: Managment port AGL failed BIST (0x%016llx) on MIX%d\n", CAST64(agl_gmx_bist.u64), port); 201210284Sjmallett 202210284Sjmallett /* Clear all state information */ 203210284Sjmallett memset(state, 0, sizeof(*state)); 204210284Sjmallett 205210284Sjmallett /* Take the control logic out of reset */ 206210284Sjmallett mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port)); 207210284Sjmallett mix_ctl.s.reset = 0; 208210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 209210284Sjmallett 210215990Sjmallett /* Read until reset == 0. Timeout should never happen... */ 211215990Sjmallett if (CVMX_WAIT_FOR_FIELD64(CVMX_MIXX_CTL(port), cvmx_mixx_ctl_t, reset, ==, 0, 300000000)) 212215990Sjmallett { 213215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Timeout waiting for MIX(%d) reset.\n", port); 214215990Sjmallett return CVMX_MGMT_PORT_INIT_ERROR; 215215990Sjmallett } 216215990Sjmallett 217215990Sjmallett /* Set the PHY address and mode of the interface (RGMII/MII mode). */ 218210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 219215990Sjmallett { 220215990Sjmallett state->port = -1; 221215990Sjmallett state->mode = CVMX_MGMT_PORT_MII_MODE; 222215990Sjmallett } 223210284Sjmallett else 224215990Sjmallett { 225215990Sjmallett int port_num = CVMX_HELPER_BOARD_MGMT_IPD_PORT + port; 226215990Sjmallett int phy_addr = cvmx_helper_board_get_mii_address(port_num); 227215990Sjmallett if (phy_addr != -1) 228215990Sjmallett { 229215990Sjmallett cvmx_mdio_phy_reg_status_t phy_status; 230215990Sjmallett /* Read PHY status register to find the mode of the interface. */ 231215990Sjmallett phy_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS); 232215990Sjmallett if (phy_status.s.capable_extended_status == 0) // MII mode 233215990Sjmallett state->mode = CVMX_MGMT_PORT_MII_MODE; 234215990Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN6XXX) 235215990Sjmallett && phy_status.s.capable_extended_status) // RGMII mode 236215990Sjmallett state->mode = CVMX_MGMT_PORT_RGMII_MODE; 237215990Sjmallett else 238215990Sjmallett state->mode = CVMX_MGMT_PORT_NONE; 239215990Sjmallett } 240215990Sjmallett else 241215990Sjmallett { 242215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Not able to read the PHY on MIX%d\n", port); 243215990Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 244215990Sjmallett } 245215990Sjmallett state->port = port_num; 246215990Sjmallett } 247210284Sjmallett 248215990Sjmallett /* All interfaces should be configured in same mode */ 249215990Sjmallett for (i = 0; i < __cvmx_mgmt_port_num_ports(); i++) 250215990Sjmallett { 251215990Sjmallett if (i != port 252215990Sjmallett && cvmx_mgmt_port_state_ptr[i].mode != CVMX_MGMT_PORT_NONE 253215990Sjmallett && cvmx_mgmt_port_state_ptr[i].mode != state->mode) 254215990Sjmallett { 255215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: All ports in MIX interface are not configured in same mode.\n \ 256215990Sjmallett Port %d is configured as %d\n \ 257215990Sjmallett And Port %d is configured as %d\n", port, state->mode, i, cvmx_mgmt_port_state_ptr[i].mode); 258215990Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 259215990Sjmallett } 260215990Sjmallett } 261215990Sjmallett 262210284Sjmallett /* Create a default MAC address */ 263210284Sjmallett state->mac = 0x000000dead000000ull; 264210284Sjmallett state->mac += 0xffffff & CAST64(state); 265210284Sjmallett 266210284Sjmallett /* Setup the TX ring */ 267210284Sjmallett for (i=0; i<CVMX_MGMT_PORT_NUM_TX_BUFFERS; i++) 268210284Sjmallett { 269210284Sjmallett state->tx_ring[i].s.len = CVMX_MGMT_PORT_TX_BUFFER_SIZE; 270210284Sjmallett state->tx_ring[i].s.addr = cvmx_ptr_to_phys(state->tx_buffers[i]); 271210284Sjmallett } 272210284Sjmallett 273210284Sjmallett /* Tell the HW where the TX ring is */ 274210284Sjmallett oring1.u64 = 0; 275210284Sjmallett oring1.s.obase = cvmx_ptr_to_phys(state->tx_ring)>>3; 276210284Sjmallett oring1.s.osize = CVMX_MGMT_PORT_NUM_TX_BUFFERS; 277210284Sjmallett CVMX_SYNCWS; 278210284Sjmallett cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64); 279210284Sjmallett 280210284Sjmallett /* Setup the RX ring */ 281210284Sjmallett for (i=0; i<CVMX_MGMT_PORT_NUM_RX_BUFFERS; i++) 282210284Sjmallett { 283210284Sjmallett /* This size is -8 due to an errata for CN56XX pass 1 */ 284210284Sjmallett state->rx_ring[i].s.len = CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8; 285210284Sjmallett state->rx_ring[i].s.addr = cvmx_ptr_to_phys(state->rx_buffers[i]); 286210284Sjmallett } 287210284Sjmallett 288210284Sjmallett /* Tell the HW where the RX ring is */ 289210284Sjmallett iring1.u64 = 0; 290210284Sjmallett iring1.s.ibase = cvmx_ptr_to_phys(state->rx_ring)>>3; 291210284Sjmallett iring1.s.isize = CVMX_MGMT_PORT_NUM_RX_BUFFERS; 292210284Sjmallett CVMX_SYNCWS; 293210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64); 294210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING2(port), CVMX_MGMT_PORT_NUM_RX_BUFFERS); 295210284Sjmallett 296210284Sjmallett /* Disable the external input/output */ 297210284Sjmallett cvmx_mgmt_port_disable(port); 298210284Sjmallett 299210284Sjmallett /* Set the MAC address filtering up */ 300210284Sjmallett cvmx_mgmt_port_set_mac(port, state->mac); 301210284Sjmallett 302210284Sjmallett /* Set the default max size to an MTU of 1500 with L2 and VLAN */ 303210284Sjmallett cvmx_mgmt_port_set_max_packet_size(port, 1518); 304210284Sjmallett 305210284Sjmallett /* Enable the port HW. Packets are not allowed until cvmx_mgmt_port_enable() is called */ 306210284Sjmallett mix_ctl.u64 = 0; 307210284Sjmallett mix_ctl.s.crc_strip = 1; /* Strip the ending CRC */ 308210284Sjmallett mix_ctl.s.en = 1; /* Enable the port */ 309210284Sjmallett mix_ctl.s.nbtarb = 0; /* Arbitration mode */ 310210284Sjmallett mix_ctl.s.mrq_hwm = 1; /* MII CB-request FIFO programmable high watermark */ 311210284Sjmallett cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64); 312210284Sjmallett 313215990Sjmallett /* Select the mode of operation for the interface. */ 314215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 315210284Sjmallett { 316215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 317215990Sjmallett 318215990Sjmallett if (state->mode == CVMX_MGMT_PORT_RGMII_MODE) 319215990Sjmallett agl_prtx_ctl.s.mode = 0; 320215990Sjmallett else if (state->mode == CVMX_MGMT_PORT_MII_MODE) 321215990Sjmallett agl_prtx_ctl.s.mode = 1; 322215990Sjmallett else 323215990Sjmallett { 324215990Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_initialize: Invalid mode for MIX(%d)\n", port); 325215990Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 326215990Sjmallett } 327215990Sjmallett 328215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 329215990Sjmallett } 330215990Sjmallett 331215990Sjmallett /* Initialize the physical layer. */ 332215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 333215990Sjmallett { 334215990Sjmallett /* MII clocks counts are based on the 125Mhz reference, so our 335215990Sjmallett delays need to be scaled to match the core clock rate. The 336215990Sjmallett "+1" is to make sure rounding always waits a little too 337215990Sjmallett long. */ 338215990Sjmallett uint64_t clock_scale = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 125000000 + 1; 339215990Sjmallett 340215990Sjmallett /* Take the DLL and clock tree out of reset */ 341215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 342215990Sjmallett agl_prtx_ctl.s.clkrst = 0; 343215990Sjmallett if (state->mode == CVMX_MGMT_PORT_RGMII_MODE) // RGMII Initialization 344215990Sjmallett { 345215990Sjmallett agl_prtx_ctl.s.dllrst = 0; 346215990Sjmallett agl_prtx_ctl.s.clktx_byp = 0; 347215990Sjmallett } 348215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 349215990Sjmallett cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); /* Force write out before wait */ 350215990Sjmallett 351215990Sjmallett /* Wait for the DLL to lock. External 125 MHz reference clock must be stable at this point. */ 352215990Sjmallett cvmx_wait(256 * clock_scale); 353215990Sjmallett 354215990Sjmallett /* The rest of the config is common between RGMII/MII */ 355215990Sjmallett 356215990Sjmallett /* Enable the interface */ 357215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 358215990Sjmallett agl_prtx_ctl.s.enable = 1; 359215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 360215990Sjmallett 361215990Sjmallett /* Read the value back to force the previous write */ 362215990Sjmallett agl_prtx_ctl.u64 = cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); 363215990Sjmallett 364215990Sjmallett /* Enable the componsation controller */ 365215990Sjmallett agl_prtx_ctl.s.comp = 1; 366232812Sjmallett agl_prtx_ctl.s.drv_byp = 0; 367215990Sjmallett cvmx_write_csr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64); 368215990Sjmallett cvmx_read_csr(CVMX_AGL_PRTX_CTL(port)); /* Force write out before wait */ 369215990Sjmallett cvmx_wait(1024 * clock_scale); // for componsation state to lock. 370215990Sjmallett } 371215990Sjmallett else if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) 372215990Sjmallett { 373210284Sjmallett /* Force compensation values, as they are not determined properly by HW */ 374210284Sjmallett cvmx_agl_gmx_drv_ctl_t drv_ctl; 375210284Sjmallett 376210284Sjmallett drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL); 377210284Sjmallett if (port) 378210284Sjmallett { 379210284Sjmallett drv_ctl.s.byp_en1 = 1; 380210284Sjmallett drv_ctl.s.nctl1 = 6; 381210284Sjmallett drv_ctl.s.pctl1 = 6; 382210284Sjmallett } 383210284Sjmallett else 384210284Sjmallett { 385210284Sjmallett drv_ctl.s.byp_en = 1; 386210284Sjmallett drv_ctl.s.nctl = 6; 387210284Sjmallett drv_ctl.s.pctl = 6; 388210284Sjmallett } 389210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64); 390210284Sjmallett } 391210284Sjmallett } 392215990Sjmallett cvmx_error_enable_group(CVMX_ERROR_GROUP_MGMT_PORT, port); 393210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 394210284Sjmallett} 395210284Sjmallett 396210284Sjmallett 397210284Sjmallett/** 398210284Sjmallett * Shutdown a management port. This currently disables packet IO 399210284Sjmallett * but leaves all hardware and buffers. Another application can then 400210284Sjmallett * call initialize() without redoing the hardware setup. 401210284Sjmallett * 402210284Sjmallett * @param port Management port 403210284Sjmallett * 404210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 405210284Sjmallett */ 406210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_shutdown(int port) 407210284Sjmallett{ 408210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 409210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 410210284Sjmallett 411215990Sjmallett cvmx_error_disable_group(CVMX_ERROR_GROUP_MGMT_PORT, port); 412215990Sjmallett 413210284Sjmallett /* Stop packets from comming in */ 414210284Sjmallett cvmx_mgmt_port_disable(port); 415210284Sjmallett 416210284Sjmallett /* We don't free any memory so the next intialize can reuse the HW setup */ 417210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 418210284Sjmallett} 419210284Sjmallett 420210284Sjmallett 421210284Sjmallett/** 422210284Sjmallett * Enable packet IO on a management port 423210284Sjmallett * 424210284Sjmallett * @param port Management port 425210284Sjmallett * 426210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 427210284Sjmallett */ 428210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_enable(int port) 429210284Sjmallett{ 430210284Sjmallett cvmx_mgmt_port_state_t *state; 431210284Sjmallett cvmx_agl_gmx_inf_mode_t agl_gmx_inf_mode; 432210284Sjmallett cvmx_agl_gmx_rxx_frm_ctl_t rxx_frm_ctl; 433210284Sjmallett 434210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 435210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 436210284Sjmallett 437210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 438210284Sjmallett 439210284Sjmallett cvmx_spinlock_lock(&state->lock); 440210284Sjmallett 441210284Sjmallett rxx_frm_ctl.u64 = 0; 442210284Sjmallett rxx_frm_ctl.s.pre_align = 1; 443210284Sjmallett rxx_frm_ctl.s.pad_len = 1; /* When set, disables the length check for non-min sized pkts with padding in the client data */ 444210284Sjmallett rxx_frm_ctl.s.vlan_len = 1; /* When set, disables the length check for VLAN pkts */ 445210284Sjmallett rxx_frm_ctl.s.pre_free = 1; /* When set, PREAMBLE checking is less strict */ 446210284Sjmallett rxx_frm_ctl.s.ctl_smac = 0; /* Control Pause Frames can match station SMAC */ 447210284Sjmallett rxx_frm_ctl.s.ctl_mcst = 1; /* Control Pause Frames can match globally assign Multicast address */ 448210284Sjmallett rxx_frm_ctl.s.ctl_bck = 1; /* Forward pause information to TX block */ 449210284Sjmallett rxx_frm_ctl.s.ctl_drp = 1; /* Drop Control Pause Frames */ 450210284Sjmallett rxx_frm_ctl.s.pre_strp = 1; /* Strip off the preamble */ 451210284Sjmallett 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 */ 452210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64); 453210284Sjmallett 454210284Sjmallett /* Enable the AGL block */ 455215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) 456215990Sjmallett { 457215990Sjmallett agl_gmx_inf_mode.u64 = 0; 458215990Sjmallett agl_gmx_inf_mode.s.en = 1; 459215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64); 460215990Sjmallett } 461210284Sjmallett 462210284Sjmallett /* Configure the port duplex and enables */ 463215990Sjmallett cvmx_mgmt_port_link_set(port, cvmx_mgmt_port_link_get(port)); 464210284Sjmallett 465210284Sjmallett cvmx_spinlock_unlock(&state->lock); 466210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 467210284Sjmallett} 468210284Sjmallett 469210284Sjmallett 470210284Sjmallett/** 471210284Sjmallett * Disable packet IO on a management port 472210284Sjmallett * 473210284Sjmallett * @param port Management port 474210284Sjmallett * 475210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 476210284Sjmallett */ 477210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_disable(int port) 478210284Sjmallett{ 479210284Sjmallett cvmx_mgmt_port_state_t *state; 480210284Sjmallett cvmx_agl_gmx_prtx_cfg_t agl_gmx_prtx; 481210284Sjmallett 482210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 483210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 484210284Sjmallett 485210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 486210284Sjmallett 487210284Sjmallett cvmx_spinlock_lock(&state->lock); 488210284Sjmallett 489210284Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 490210284Sjmallett agl_gmx_prtx.s.en = 0; 491210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 492210284Sjmallett 493210284Sjmallett cvmx_spinlock_unlock(&state->lock); 494210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 495210284Sjmallett} 496210284Sjmallett 497210284Sjmallett 498210284Sjmallett/** 499210284Sjmallett * Send a packet out the management port. The packet is copied so 500210284Sjmallett * the input buffer isn't used after this call. 501210284Sjmallett * 502210284Sjmallett * @param port Management port 503210284Sjmallett * @param packet_len Length of the packet to send. It does not include the final CRC 504210284Sjmallett * @param buffer Packet data 505210284Sjmallett * 506210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 507210284Sjmallett */ 508210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_send(int port, int packet_len, void *buffer) 509210284Sjmallett{ 510210284Sjmallett cvmx_mgmt_port_state_t *state; 511210284Sjmallett cvmx_mixx_oring2_t mix_oring2; 512210284Sjmallett 513210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 514210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 515210284Sjmallett 516210284Sjmallett /* Max sure the packet size is valid */ 517210284Sjmallett if ((packet_len < 1) || (packet_len > CVMX_MGMT_PORT_TX_BUFFER_SIZE)) 518210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 519210284Sjmallett 520210284Sjmallett if (buffer == NULL) 521210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 522210284Sjmallett 523210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 524210284Sjmallett 525210284Sjmallett cvmx_spinlock_lock(&state->lock); 526210284Sjmallett 527210284Sjmallett mix_oring2.u64 = cvmx_read_csr(CVMX_MIXX_ORING2(port)); 528210284Sjmallett if (mix_oring2.s.odbell >= CVMX_MGMT_PORT_NUM_TX_BUFFERS - 1) 529210284Sjmallett { 530210284Sjmallett /* No room for another packet */ 531210284Sjmallett cvmx_spinlock_unlock(&state->lock); 532210284Sjmallett return CVMX_MGMT_PORT_NO_MEMORY; 533210284Sjmallett } 534210284Sjmallett else 535210284Sjmallett { 536210284Sjmallett /* Copy the packet into the output buffer */ 537210284Sjmallett memcpy(state->tx_buffers[state->tx_write_index], buffer, packet_len); 538210284Sjmallett /* Insert the source MAC */ 539210284Sjmallett memcpy(state->tx_buffers[state->tx_write_index] + 6, ((char*)&state->mac) + 2, 6); 540210284Sjmallett /* Update the TX ring buffer entry size */ 541210284Sjmallett state->tx_ring[state->tx_write_index].s.len = packet_len; 542215990Sjmallett /* This code doesn't support TX timestamps */ 543215990Sjmallett state->tx_ring[state->tx_write_index].s.tstamp = 0; 544210284Sjmallett /* Increment our TX index */ 545210284Sjmallett state->tx_write_index = (state->tx_write_index + 1) % CVMX_MGMT_PORT_NUM_TX_BUFFERS; 546215990Sjmallett /* Ring the doorbell, sending the packet */ 547210284Sjmallett CVMX_SYNCWS; 548210284Sjmallett cvmx_write_csr(CVMX_MIXX_ORING2(port), 1); 549210284Sjmallett if (cvmx_read_csr(CVMX_MIXX_ORCNT(port))) 550210284Sjmallett cvmx_write_csr(CVMX_MIXX_ORCNT(port), cvmx_read_csr(CVMX_MIXX_ORCNT(port))); 551210284Sjmallett 552210284Sjmallett cvmx_spinlock_unlock(&state->lock); 553210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 554210284Sjmallett } 555210284Sjmallett} 556210284Sjmallett 557210284Sjmallett 558217214Sjmallett#if defined(__FreeBSD__) 559210284Sjmallett/** 560217214Sjmallett * Send a packet out the management port. The packet is copied so 561217214Sjmallett * the input mbuf isn't used after this call. 562217214Sjmallett * 563217214Sjmallett * @param port Management port 564217214Sjmallett * @param m Packet mbuf (with pkthdr) 565217214Sjmallett * 566217214Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 567217214Sjmallett */ 568217214Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_sendm(int port, const struct mbuf *m) 569217214Sjmallett{ 570217214Sjmallett cvmx_mgmt_port_state_t *state; 571217214Sjmallett cvmx_mixx_oring2_t mix_oring2; 572217214Sjmallett 573217214Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 574217214Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 575217214Sjmallett 576217214Sjmallett /* Max sure the packet size is valid */ 577217214Sjmallett if ((m->m_pkthdr.len < 1) || (m->m_pkthdr.len > CVMX_MGMT_PORT_TX_BUFFER_SIZE)) 578217214Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 579217214Sjmallett 580217214Sjmallett state = cvmx_mgmt_port_state_ptr + port; 581217214Sjmallett 582217214Sjmallett cvmx_spinlock_lock(&state->lock); 583217214Sjmallett 584217214Sjmallett mix_oring2.u64 = cvmx_read_csr(CVMX_MIXX_ORING2(port)); 585217214Sjmallett if (mix_oring2.s.odbell >= CVMX_MGMT_PORT_NUM_TX_BUFFERS - 1) 586217214Sjmallett { 587217214Sjmallett /* No room for another packet */ 588217214Sjmallett cvmx_spinlock_unlock(&state->lock); 589217214Sjmallett return CVMX_MGMT_PORT_NO_MEMORY; 590217214Sjmallett } 591217214Sjmallett else 592217214Sjmallett { 593217214Sjmallett /* Copy the packet into the output buffer */ 594217214Sjmallett m_copydata(m, 0, m->m_pkthdr.len, state->tx_buffers[state->tx_write_index]); 595217214Sjmallett /* Update the TX ring buffer entry size */ 596217214Sjmallett state->tx_ring[state->tx_write_index].s.len = m->m_pkthdr.len; 597217214Sjmallett /* This code doesn't support TX timestamps */ 598217214Sjmallett state->tx_ring[state->tx_write_index].s.tstamp = 0; 599217214Sjmallett /* Increment our TX index */ 600217214Sjmallett state->tx_write_index = (state->tx_write_index + 1) % CVMX_MGMT_PORT_NUM_TX_BUFFERS; 601217214Sjmallett /* Ring the doorbell, sending the packet */ 602217214Sjmallett CVMX_SYNCWS; 603217214Sjmallett cvmx_write_csr(CVMX_MIXX_ORING2(port), 1); 604217214Sjmallett if (cvmx_read_csr(CVMX_MIXX_ORCNT(port))) 605217214Sjmallett cvmx_write_csr(CVMX_MIXX_ORCNT(port), cvmx_read_csr(CVMX_MIXX_ORCNT(port))); 606217214Sjmallett 607217214Sjmallett cvmx_spinlock_unlock(&state->lock); 608217214Sjmallett return CVMX_MGMT_PORT_SUCCESS; 609217214Sjmallett } 610217214Sjmallett} 611217214Sjmallett#endif 612217214Sjmallett 613217214Sjmallett 614217214Sjmallett/** 615210284Sjmallett * Receive a packet from the management port. 616210284Sjmallett * 617210284Sjmallett * @param port Management port 618210284Sjmallett * @param buffer_len Size of the buffer to receive the packet into 619210284Sjmallett * @param buffer Buffer to receive the packet into 620210284Sjmallett * 621210284Sjmallett * @return The size of the packet, or a negative erorr code on failure. Zero 622210284Sjmallett * means that no packets were available. 623210284Sjmallett */ 624217214Sjmallettint cvmx_mgmt_port_receive(int port, int buffer_len, uint8_t *buffer) 625210284Sjmallett{ 626210284Sjmallett cvmx_mixx_ircnt_t mix_ircnt; 627210284Sjmallett cvmx_mgmt_port_state_t *state; 628210284Sjmallett int result; 629210284Sjmallett 630210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 631210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 632210284Sjmallett 633210284Sjmallett /* Max sure the buffer size is valid */ 634210284Sjmallett if (buffer_len < 1) 635210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 636210284Sjmallett 637210284Sjmallett if (buffer == NULL) 638210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 639210284Sjmallett 640210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 641210284Sjmallett 642210284Sjmallett cvmx_spinlock_lock(&state->lock); 643210284Sjmallett 644210284Sjmallett /* Find out how many RX packets are pending */ 645210284Sjmallett mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port)); 646210284Sjmallett if (mix_ircnt.s.ircnt) 647210284Sjmallett { 648217214Sjmallett uint64_t *source = (void *)state->rx_buffers[state->rx_read_index]; 649217214Sjmallett uint64_t *zero_check = source; 650210284Sjmallett /* CN56XX pass 1 has an errata where packets might start 8 bytes 651210284Sjmallett into the buffer instead of at their correct lcoation. If the 652210284Sjmallett first 8 bytes is zero we assume this has happened */ 653210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && (*zero_check == 0)) 654217214Sjmallett source++; 655210284Sjmallett /* Start off with zero bytes received */ 656210284Sjmallett result = 0; 657210284Sjmallett /* While the completion code signals more data, copy the buffers 658210284Sjmallett into the user's data */ 659210284Sjmallett while (state->rx_ring[state->rx_read_index].s.code == 16) 660210284Sjmallett { 661210284Sjmallett /* Only copy what will fit in the user's buffer */ 662210284Sjmallett int length = state->rx_ring[state->rx_read_index].s.len; 663210284Sjmallett if (length > buffer_len) 664210284Sjmallett length = buffer_len; 665210284Sjmallett memcpy(buffer, source, length); 666210284Sjmallett /* Reduce the size of the buffer to the remaining space. If we run 667210284Sjmallett out we will signal an error when the code 15 buffer doesn't fit */ 668210284Sjmallett buffer += length; 669210284Sjmallett buffer_len -= length; 670210284Sjmallett result += length; 671210284Sjmallett /* Update this buffer for reuse in future receives. This size is 672210284Sjmallett -8 due to an errata for CN56XX pass 1 */ 673210284Sjmallett state->rx_ring[state->rx_read_index].s.code = 0; 674210284Sjmallett state->rx_ring[state->rx_read_index].s.len = CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8; 675210284Sjmallett state->rx_read_index = (state->rx_read_index + 1) % CVMX_MGMT_PORT_NUM_RX_BUFFERS; 676210284Sjmallett /* Zero the beginning of the buffer for use by the errata check */ 677210284Sjmallett *zero_check = 0; 678210284Sjmallett CVMX_SYNCWS; 679210284Sjmallett /* Increment the number of RX buffers */ 680210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING2(port), 1); 681217214Sjmallett source = (void *)state->rx_buffers[state->rx_read_index]; 682210284Sjmallett zero_check = source; 683210284Sjmallett } 684210284Sjmallett 685210284Sjmallett /* Check for the final good completion code */ 686210284Sjmallett if (state->rx_ring[state->rx_read_index].s.code == 15) 687210284Sjmallett { 688210284Sjmallett if (buffer_len >= state->rx_ring[state->rx_read_index].s.len) 689210284Sjmallett { 690210284Sjmallett int length = state->rx_ring[state->rx_read_index].s.len; 691210284Sjmallett memcpy(buffer, source, length); 692210284Sjmallett result += length; 693210284Sjmallett } 694210284Sjmallett else 695210284Sjmallett { 696210284Sjmallett /* Not enough room for the packet */ 697210284Sjmallett 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); 698210284Sjmallett result = CVMX_MGMT_PORT_NO_MEMORY; 699210284Sjmallett } 700210284Sjmallett } 701210284Sjmallett else 702210284Sjmallett { 703210284Sjmallett cvmx_dprintf("ERROR: cvmx_mgmt_port_receive: Receive error code %d. Packet dropped(Len %d), \n", 704210284Sjmallett state->rx_ring[state->rx_read_index].s.code, state->rx_ring[state->rx_read_index].s.len + result); 705210284Sjmallett result = -state->rx_ring[state->rx_read_index].s.code; 706210284Sjmallett 707210284Sjmallett 708210284Sjmallett /* Check to see if we need to change the duplex. */ 709215990Sjmallett cvmx_mgmt_port_link_set(port, cvmx_mgmt_port_link_get(port)); 710210284Sjmallett } 711210284Sjmallett 712210284Sjmallett /* Clean out the ring buffer entry. This size is -8 due to an errata 713210284Sjmallett for CN56XX pass 1 */ 714210284Sjmallett state->rx_ring[state->rx_read_index].s.code = 0; 715210284Sjmallett state->rx_ring[state->rx_read_index].s.len = CVMX_MGMT_PORT_RX_BUFFER_SIZE - 8; 716210284Sjmallett state->rx_read_index = (state->rx_read_index + 1) % CVMX_MGMT_PORT_NUM_RX_BUFFERS; 717210284Sjmallett /* Zero the beginning of the buffer for use by the errata check */ 718210284Sjmallett *zero_check = 0; 719210284Sjmallett CVMX_SYNCWS; 720210284Sjmallett /* Increment the number of RX buffers */ 721210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRING2(port), 1); 722210284Sjmallett /* Decrement the pending RX count */ 723210284Sjmallett cvmx_write_csr(CVMX_MIXX_IRCNT(port), 1); 724210284Sjmallett } 725210284Sjmallett else 726210284Sjmallett { 727210284Sjmallett /* No packets available */ 728210284Sjmallett result = 0; 729210284Sjmallett } 730210284Sjmallett cvmx_spinlock_unlock(&state->lock); 731210284Sjmallett return result; 732210284Sjmallett} 733210284Sjmallett 734210284Sjmallett/** 735210284Sjmallett * Set the MAC address for a management port 736210284Sjmallett * 737210284Sjmallett * @param port Management port 738210284Sjmallett * @param mac New MAC address. The lower 6 bytes are used. 739210284Sjmallett * 740210284Sjmallett * @return CVMX_MGMT_PORT_SUCCESS or an error code 741210284Sjmallett */ 742210284Sjmallettcvmx_mgmt_port_result_t cvmx_mgmt_port_set_mac(int port, uint64_t mac) 743210284Sjmallett{ 744210284Sjmallett cvmx_mgmt_port_state_t *state; 745210284Sjmallett cvmx_agl_gmx_rxx_adr_ctl_t agl_gmx_rxx_adr_ctl; 746210284Sjmallett 747210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 748210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 749210284Sjmallett 750210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 751210284Sjmallett 752210284Sjmallett cvmx_spinlock_lock(&state->lock); 753210284Sjmallett 754210284Sjmallett agl_gmx_rxx_adr_ctl.u64 = 0; 755210284Sjmallett agl_gmx_rxx_adr_ctl.s.cam_mode = 1; /* Only accept matching MAC addresses */ 756210284Sjmallett agl_gmx_rxx_adr_ctl.s.mcst = 0; /* Drop multicast */ 757210284Sjmallett agl_gmx_rxx_adr_ctl.s.bcst = 1; /* Allow broadcast */ 758210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), agl_gmx_rxx_adr_ctl.u64); 759210284Sjmallett 760210284Sjmallett /* Only using one of the CAMs */ 761210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), (mac >> 40) & 0xff); 762210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), (mac >> 32) & 0xff); 763210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), (mac >> 24) & 0xff); 764210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), (mac >> 16) & 0xff); 765210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), (mac >> 8) & 0xff); 766210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), (mac >> 0) & 0xff); 767210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 1); 768210284Sjmallett state->mac = mac; 769210284Sjmallett 770210284Sjmallett cvmx_spinlock_unlock(&state->lock); 771210284Sjmallett return CVMX_MGMT_PORT_SUCCESS; 772210284Sjmallett} 773210284Sjmallett 774210284Sjmallett 775210284Sjmallett/** 776210284Sjmallett * Get the MAC address for a management port 777210284Sjmallett * 778210284Sjmallett * @param port Management port 779210284Sjmallett * 780210284Sjmallett * @return MAC address 781210284Sjmallett */ 782210284Sjmallettuint64_t cvmx_mgmt_port_get_mac(int port) 783210284Sjmallett{ 784210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 785210284Sjmallett return CVMX_MGMT_PORT_INVALID_PARAM; 786210284Sjmallett 787210284Sjmallett return cvmx_mgmt_port_state_ptr[port].mac; 788210284Sjmallett} 789210284Sjmallett 790210284Sjmallett/** 791210284Sjmallett * Set the multicast list. 792210284Sjmallett * 793210284Sjmallett * @param port Management port 794210284Sjmallett * @param flags Interface flags 795210284Sjmallett * 796210284Sjmallett * @return 797210284Sjmallett */ 798210284Sjmallettvoid cvmx_mgmt_port_set_multicast_list(int port, int flags) 799210284Sjmallett{ 800210284Sjmallett cvmx_mgmt_port_state_t *state; 801210284Sjmallett cvmx_agl_gmx_rxx_adr_ctl_t agl_gmx_rxx_adr_ctl; 802210284Sjmallett 803210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 804210284Sjmallett return; 805210284Sjmallett 806210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 807210284Sjmallett 808210284Sjmallett cvmx_spinlock_lock(&state->lock); 809210284Sjmallett 810210284Sjmallett agl_gmx_rxx_adr_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port)); 811215990Sjmallett 812210284Sjmallett /* Allow broadcast MAC addresses */ 813210284Sjmallett if (!agl_gmx_rxx_adr_ctl.s.bcst) 814210284Sjmallett agl_gmx_rxx_adr_ctl.s.bcst = 1; 815210284Sjmallett 816210284Sjmallett if ((flags & CVMX_IFF_ALLMULTI) || (flags & CVMX_IFF_PROMISC)) 817210284Sjmallett agl_gmx_rxx_adr_ctl.s.mcst = 2; /* Force accept multicast packets */ 818210284Sjmallett else 819210284Sjmallett agl_gmx_rxx_adr_ctl.s.mcst = 1; /* Force reject multicast packets */ 820210284Sjmallett 821210284Sjmallett if (flags & CVMX_IFF_PROMISC) 822210284Sjmallett agl_gmx_rxx_adr_ctl.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */ 823210284Sjmallett else 824210284Sjmallett agl_gmx_rxx_adr_ctl.s.cam_mode = 1; /* Filter packets based on the CAM */ 825210284Sjmallett 826210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), agl_gmx_rxx_adr_ctl.u64); 827210284Sjmallett 828210284Sjmallett if (flags & CVMX_IFF_PROMISC) 829210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 0); 830210284Sjmallett else 831210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), 1); 832215990Sjmallett 833210284Sjmallett cvmx_spinlock_unlock(&state->lock); 834210284Sjmallett} 835210284Sjmallett 836210284Sjmallett 837210284Sjmallett/** 838210284Sjmallett * Set the maximum packet allowed in. Size is specified 839210284Sjmallett * including L2 but without FCS. A normal MTU would corespond 840210284Sjmallett * to 1514 assuming the standard 14 byte L2 header. 841210284Sjmallett * 842210284Sjmallett * @param port Management port 843210284Sjmallett * @param size_without_fcs 844210284Sjmallett * Size in bytes without FCS 845210284Sjmallett */ 846210284Sjmallettvoid cvmx_mgmt_port_set_max_packet_size(int port, int size_without_fcs) 847210284Sjmallett{ 848210284Sjmallett cvmx_mgmt_port_state_t *state; 849210284Sjmallett 850210284Sjmallett if ((port < 0) || (port >= __cvmx_mgmt_port_num_ports())) 851210284Sjmallett return; 852210284Sjmallett 853210284Sjmallett state = cvmx_mgmt_port_state_ptr + port; 854210284Sjmallett 855210284Sjmallett cvmx_spinlock_lock(&state->lock); 856210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs); 857210284Sjmallett cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port), (size_without_fcs+7) & 0xfff8); 858210284Sjmallett cvmx_spinlock_unlock(&state->lock); 859210284Sjmallett} 860210284Sjmallett 861215990Sjmallett/** 862215990Sjmallett * Return the link state of an RGMII/MII port as returned by 863215990Sjmallett * auto negotiation. The result of this function may not match 864215990Sjmallett * Octeon's link config if auto negotiation has changed since 865215990Sjmallett * the last call to cvmx_mgmt_port_link_set(). 866215990Sjmallett * 867215990Sjmallett * @param port The RGMII/MII interface port to query 868215990Sjmallett * 869215990Sjmallett * @return Link state 870215990Sjmallett */ 871215990Sjmallettcvmx_helper_link_info_t cvmx_mgmt_port_link_get(int port) 872215990Sjmallett{ 873215990Sjmallett cvmx_mgmt_port_state_t *state; 874215990Sjmallett cvmx_helper_link_info_t result; 875215990Sjmallett 876215990Sjmallett state = cvmx_mgmt_port_state_ptr + port; 877215990Sjmallett result.u64 = 0; 878215990Sjmallett 879215990Sjmallett if (port > __cvmx_mgmt_port_num_ports()) 880215990Sjmallett { 881215990Sjmallett cvmx_dprintf("WARNING: Invalid port %d\n", port); 882215990Sjmallett return result; 883215990Sjmallett } 884215990Sjmallett 885215990Sjmallett if (state->port != -1) 886215990Sjmallett return __cvmx_helper_board_link_get(state->port); 887215990Sjmallett else // Simulator does not have PHY, use some defaults. 888215990Sjmallett { 889215990Sjmallett result.s.full_duplex = 1; 890215990Sjmallett result.s.link_up = 1; 891215990Sjmallett result.s.speed = 100; 892215990Sjmallett return result; 893215990Sjmallett } 894215990Sjmallett return result; 895215990Sjmallett} 896215990Sjmallett 897215990Sjmallett/** 898215990Sjmallett * Configure RGMII/MII port for the specified link state. This 899215990Sjmallett * function does not influence auto negotiation at the PHY level. 900215990Sjmallett * 901215990Sjmallett * @param port RGMII/MII interface port 902215990Sjmallett * @param link_info The new link state 903215990Sjmallett * 904215990Sjmallett * @return Zero on success, negative on failure 905215990Sjmallett */ 906215990Sjmallettint cvmx_mgmt_port_link_set(int port, cvmx_helper_link_info_t link_info) 907215990Sjmallett{ 908215990Sjmallett cvmx_agl_gmx_prtx_cfg_t agl_gmx_prtx; 909215990Sjmallett 910215990Sjmallett /* Disable GMX before we make any changes. */ 911215990Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 912215990Sjmallett agl_gmx_prtx.s.en = 0; 913215990Sjmallett agl_gmx_prtx.s.tx_en = 0; 914215990Sjmallett agl_gmx_prtx.s.rx_en = 0; 915215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 916215990Sjmallett 917215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 918215990Sjmallett { 919215990Sjmallett uint64_t one_second = cvmx_clock_get_rate(CVMX_CLOCK_CORE); 920215990Sjmallett /* Wait for GMX to be idle */ 921215990Sjmallett if (CVMX_WAIT_FOR_FIELD64(CVMX_AGL_GMX_PRTX_CFG(port), cvmx_agl_gmx_prtx_cfg_t, rx_idle, ==, 1, one_second) 922215990Sjmallett || CVMX_WAIT_FOR_FIELD64(CVMX_AGL_GMX_PRTX_CFG(port), cvmx_agl_gmx_prtx_cfg_t, tx_idle, ==, 1, one_second)) 923215990Sjmallett { 924215990Sjmallett cvmx_dprintf("MIX%d: Timeout waiting for GMX to be idle\n", port); 925215990Sjmallett return -1; 926215990Sjmallett } 927215990Sjmallett } 928215990Sjmallett 929215990Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 930215990Sjmallett 931215990Sjmallett /* Set duplex mode */ 932215990Sjmallett if (!link_info.s.link_up) 933215990Sjmallett agl_gmx_prtx.s.duplex = 1; /* Force full duplex on down links */ 934215990Sjmallett else 935215990Sjmallett agl_gmx_prtx.s.duplex = link_info.s.full_duplex; 936215990Sjmallett 937215990Sjmallett switch(link_info.s.speed) 938215990Sjmallett { 939215990Sjmallett case 10: 940215990Sjmallett agl_gmx_prtx.s.speed = 0; 941215990Sjmallett agl_gmx_prtx.s.slottime = 0; 942215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 943215990Sjmallett { 944215990Sjmallett agl_gmx_prtx.s.speed_msb = 1; 945215990Sjmallett agl_gmx_prtx.s.burst = 1; 946215990Sjmallett } 947215990Sjmallett break; 948215990Sjmallett 949215990Sjmallett case 100: 950215990Sjmallett agl_gmx_prtx.s.speed = 0; 951215990Sjmallett agl_gmx_prtx.s.slottime = 0; 952215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 953215990Sjmallett { 954215990Sjmallett agl_gmx_prtx.s.speed_msb = 0; 955215990Sjmallett agl_gmx_prtx.s.burst = 1; 956215990Sjmallett } 957215990Sjmallett break; 958215990Sjmallett 959215990Sjmallett case 1000: 960215990Sjmallett /* 1000 MBits is only supported on 6XXX chips */ 961215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 962215990Sjmallett { 963215990Sjmallett agl_gmx_prtx.s.speed_msb = 0; 964215990Sjmallett agl_gmx_prtx.s.speed = 1; 965215990Sjmallett agl_gmx_prtx.s.slottime = 1; /* Only matters for half-duplex */ 966215990Sjmallett agl_gmx_prtx.s.burst = agl_gmx_prtx.s.duplex; 967215990Sjmallett } 968215990Sjmallett break; 969215990Sjmallett 970215990Sjmallett /* No link */ 971215990Sjmallett case 0: 972215990Sjmallett default: 973215990Sjmallett break; 974215990Sjmallett } 975215990Sjmallett 976215990Sjmallett /* Write the new GMX setting with the port still disabled. */ 977215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 978215990Sjmallett 979215990Sjmallett /* Read GMX CFG again to make sure the config is completed. */ 980215990Sjmallett agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port)); 981215990Sjmallett 982215990Sjmallett 983215990Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 984215990Sjmallett { 985215990Sjmallett cvmx_mgmt_port_state_t *state = cvmx_mgmt_port_state_ptr + port; 986215990Sjmallett cvmx_agl_gmx_txx_clk_t agl_clk; 987215990Sjmallett agl_clk.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_CLK(port)); 988215990Sjmallett agl_clk.s.clk_cnt = 1; /* MII (both speeds) and RGMII 1000 setting */ 989215990Sjmallett if (state->mode == CVMX_MGMT_PORT_RGMII_MODE) 990215990Sjmallett { 991215990Sjmallett if (link_info.s.speed == 10) 992215990Sjmallett agl_clk.s.clk_cnt = 50; 993215990Sjmallett else if (link_info.s.speed == 100) 994215990Sjmallett agl_clk.s.clk_cnt = 5; 995215990Sjmallett } 996215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_TXX_CLK(port), agl_clk.u64); 997215990Sjmallett } 998215990Sjmallett 999215990Sjmallett /* Enable transmit and receive ports */ 1000215990Sjmallett agl_gmx_prtx.s.tx_en = 1; 1001215990Sjmallett agl_gmx_prtx.s.rx_en = 1; 1002215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 1003215990Sjmallett 1004215990Sjmallett /* Enable the link. */ 1005215990Sjmallett agl_gmx_prtx.s.en = 1; 1006215990Sjmallett cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64); 1007215990Sjmallett return 0; 1008215990Sjmallett} 1009