ethernet-common.c revision 256281
1/************************************************************************* 2Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights 3reserved. 4 5 6Redistribution and use in source and binary forms, with or without 7modification, are permitted provided that the following conditions are 8met: 9 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 13 * Redistributions in binary form must reproduce the above 14 copyright notice, this list of conditions and the following 15 disclaimer in the documentation and/or other materials provided 16 with the distribution. 17 18 * Neither the name of Cavium Networks nor the names of 19 its contributors may be used to endorse or promote products 20 derived from this software without specific prior written 21 permission. 22 23This Software, including technical data, may be subject to U.S. export control laws, including the U.S. Export Administration Act and its associated regulations, and may be subject to export or import regulations in other countries. 24 25TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 26AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 27 28*************************************************************************/ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: stable/10/sys/mips/cavium/octe/ethernet-common.c 250192 2013-05-02 19:47:36Z imp $"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36#include <sys/endian.h> 37#include <sys/kernel.h> 38#include <sys/mbuf.h> 39#include <sys/socket.h> 40 41#include <net/ethernet.h> 42#include <net/if.h> 43 44#include "wrapper-cvmx-includes.h" 45#include "ethernet-headers.h" 46 47static uint64_t cvm_oct_mac_addr = 0; 48static uint32_t cvm_oct_mac_addr_offset = 0; 49 50/** 51 * Set the multicast list. Currently unimplemented. 52 * 53 * @param dev Device to work on 54 */ 55void cvm_oct_common_set_multicast_list(struct ifnet *ifp) 56{ 57 cvmx_gmxx_prtx_cfg_t gmx_cfg; 58 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 59 int interface = INTERFACE(priv->port); 60 int index = INDEX(priv->port); 61 62 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { 63 cvmx_gmxx_rxx_adr_ctl_t control; 64 control.u64 = 0; 65 control.s.bcst = 1; /* Allow broadcast MAC addresses */ 66 67 if (/*ifp->mc_list || */(ifp->if_flags&IFF_ALLMULTI) || 68 (ifp->if_flags & IFF_PROMISC)) 69 control.s.mcst = 2; /* Force accept multicast packets */ 70 else 71 control.s.mcst = 1; /* Force reject multicat packets */ 72 73 if (ifp->if_flags & IFF_PROMISC) 74 control.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */ 75 else 76 control.s.cam_mode = 1; /* Filter packets based on the CAM */ 77 78 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 79 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull); 80 81 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), control.u64); 82 if (ifp->if_flags&IFF_PROMISC) 83 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0); 84 else 85 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1); 86 87 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 88 } 89} 90 91 92/** 93 * Assign a MAC addres from the pool of available MAC addresses 94 * Can return as either a 64-bit value and/or 6 octets. 95 * 96 * @param macp Filled in with the assigned address if non-NULL 97 * @param octets Filled in with the assigned address if non-NULL 98 * @return Zero on success 99 */ 100int cvm_assign_mac_address(uint64_t *macp, uint8_t *octets) 101{ 102 /* Initialize from global MAC address base; fail if not set */ 103 if (cvm_oct_mac_addr == 0) { 104 memcpy((uint8_t *)&cvm_oct_mac_addr + 2, 105 cvmx_sysinfo_get()->mac_addr_base, 6); 106 107 if (cvm_oct_mac_addr == 0) 108 return ENXIO; 109 110 cvm_oct_mac_addr_offset = cvmx_mgmt_port_num_ports(); 111 cvm_oct_mac_addr += cvm_oct_mac_addr_offset; 112 } 113 114 if (cvm_oct_mac_addr_offset >= cvmx_sysinfo_get()->mac_addr_count) 115 return ENXIO; /* Out of addresses to assign */ 116 117 if (macp) 118 *macp = cvm_oct_mac_addr; 119 if (octets) 120 memcpy(octets, (u_int8_t *)&cvm_oct_mac_addr + 2, 6); 121 122 cvm_oct_mac_addr++; 123 cvm_oct_mac_addr_offset++; 124 125 return 0; 126} 127 128/** 129 * Set the hardware MAC address for a device 130 * 131 * @param dev Device to change the MAC address for 132 * @param addr Address structure to change it too. 133 */ 134void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr) 135{ 136 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 137 cvmx_gmxx_prtx_cfg_t gmx_cfg; 138 int interface = INTERFACE(priv->port); 139 int index = INDEX(priv->port); 140 141 memcpy(priv->mac, addr, 6); 142 143 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { 144 int i; 145 const uint8_t *ptr = addr; 146 uint64_t mac = 0; 147 for (i = 0; i < 6; i++) 148 mac = (mac<<8) | (uint64_t)(ptr[i]); 149 150 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 151 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull); 152 153 cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac); 154 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]); 155 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]); 156 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]); 157 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]); 158 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]); 159 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]); 160 cvm_oct_common_set_multicast_list(ifp); 161 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 162 } 163} 164 165 166/** 167 * Change the link MTU. Unimplemented 168 * 169 * @param dev Device to change 170 * @param new_mtu The new MTU 171 * @return Zero on success 172 */ 173int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu) 174{ 175 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 176 int interface = INTERFACE(priv->port); 177 int index = INDEX(priv->port); 178 int vlan_bytes = 4; 179 180 /* Limit the MTU to make sure the ethernet packets are between 64 bytes 181 and 65535 bytes */ 182 if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) { 183 printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes); 184 return -EINVAL; 185 } 186 ifp->if_mtu = new_mtu; 187 188 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { 189 int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */ 190 191 if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) { 192 /* Signal errors on packets larger than the MTU */ 193 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet); 194 } else { 195 /* Set the hardware to truncate packets larger than the MTU and 196 smaller the 64 bytes */ 197 cvmx_pip_frm_len_chkx_t frm_len_chk; 198 frm_len_chk.u64 = 0; 199 frm_len_chk.s.minlen = 64; 200 frm_len_chk.s.maxlen = max_packet; 201 cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64); 202 } 203 /* Set the hardware to truncate packets larger than the MTU. The 204 jabber register must be set to a multiple of 8 bytes, so round up */ 205 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u); 206 } 207 return 0; 208} 209 210 211/** 212 * Enable port. 213 */ 214int cvm_oct_common_open(struct ifnet *ifp) 215{ 216 cvmx_gmxx_prtx_cfg_t gmx_cfg; 217 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 218 int interface = INTERFACE(priv->port); 219 int index = INDEX(priv->port); 220 cvmx_helper_link_info_t link_info; 221 222 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 223 gmx_cfg.s.en = 1; 224 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 225 226 /* 227 * Set the link state unless we are using MII. 228 */ 229 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM && priv->miibus == NULL) { 230 link_info = cvmx_helper_link_get(priv->port); 231 if (!link_info.s.link_up) 232 if_link_state_change(ifp, LINK_STATE_DOWN); 233 else 234 if_link_state_change(ifp, LINK_STATE_UP); 235 } 236 237 return 0; 238} 239 240 241/** 242 * Disable port. 243 */ 244int cvm_oct_common_stop(struct ifnet *ifp) 245{ 246 cvmx_gmxx_prtx_cfg_t gmx_cfg; 247 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 248 int interface = INTERFACE(priv->port); 249 int index = INDEX(priv->port); 250 251 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 252 gmx_cfg.s.en = 0; 253 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 254 return 0; 255} 256 257/** 258 * Poll for link status change. 259 */ 260void cvm_oct_common_poll(struct ifnet *ifp) 261{ 262 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 263 cvmx_helper_link_info_t link_info; 264 265 /* 266 * If this is a simulation, do nothing. 267 */ 268 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 269 return; 270 271 /* 272 * If there is a device-specific poll method, use it. 273 */ 274 if (priv->poll != NULL) { 275 priv->poll(ifp); 276 return; 277 } 278 279 /* 280 * If an MII bus is attached, don't use the Simple Executive's link 281 * state routines. 282 */ 283 if (priv->miibus != NULL) 284 return; 285 286 /* 287 * Use the Simple Executive's link state routines. 288 */ 289 link_info = cvmx_helper_link_get(priv->port); 290 if (link_info.u64 == priv->link_info) 291 return; 292 293 link_info = cvmx_helper_link_autoconf(priv->port); 294 priv->link_info = link_info.u64; 295 priv->need_link_update = 1; 296} 297 298 299/** 300 * Per network device initialization 301 * 302 * @param dev Device to initialize 303 * @return Zero on success 304 */ 305int cvm_oct_common_init(struct ifnet *ifp) 306{ 307 uint8_t mac[6]; 308 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 309 310 if (cvm_assign_mac_address(NULL, mac) != 0) 311 return ENXIO; 312 313 ifp->if_mtu = ETHERMTU; 314 315 cvm_oct_mdio_setup_device(ifp); 316 317 cvm_oct_common_set_mac_address(ifp, mac); 318 cvm_oct_common_change_mtu(ifp, ifp->if_mtu); 319 320 /* 321 * Do any last-minute board-specific initialization. 322 */ 323 switch (cvmx_sysinfo_get()->board_type) { 324#if defined(OCTEON_VENDOR_LANNER) 325 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 326 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 327 if (priv->phy_id == 16) 328 cvm_oct_mv88e61xx_setup_device(ifp); 329 break; 330#endif 331 default: 332 break; 333 } 334 335 device_attach(priv->dev); 336 337 return 0; 338} 339 340void cvm_oct_common_uninit(struct ifnet *ifp) 341{ 342 /* Currently nothing to do */ 343} 344 345