ethernet-common.c revision 232289
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: head/sys/mips/cavium/octe/ethernet-common.c 232289 2012-02-29 05:48:29Z gonzo $"); 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 47extern int octeon_is_simulation(void); 48 49static uint64_t cvm_oct_mac_addr = 0; 50static uint32_t cvm_oct_mac_addr_offset = 0; 51 52/** 53 * Set the multicast list. Currently unimplemented. 54 * 55 * @param dev Device to work on 56 */ 57void cvm_oct_common_set_multicast_list(struct ifnet *ifp) 58{ 59 cvmx_gmxx_prtx_cfg_t gmx_cfg; 60 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 61 int interface = INTERFACE(priv->port); 62 int index = INDEX(priv->port); 63 64 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { 65 cvmx_gmxx_rxx_adr_ctl_t control; 66 control.u64 = 0; 67 control.s.bcst = 1; /* Allow broadcast MAC addresses */ 68 69 if (/*ifp->mc_list || */(ifp->if_flags&IFF_ALLMULTI) || 70 (ifp->if_flags & IFF_PROMISC)) 71 control.s.mcst = 2; /* Force accept multicast packets */ 72 else 73 control.s.mcst = 1; /* Force reject multicat packets */ 74 75 if (ifp->if_flags & IFF_PROMISC) 76 control.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */ 77 else 78 control.s.cam_mode = 1; /* Filter packets based on the CAM */ 79 80 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 81 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull); 82 83 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), control.u64); 84 if (ifp->if_flags&IFF_PROMISC) 85 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0); 86 else 87 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1); 88 89 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 90 } 91} 92 93 94/** 95 * Assign a MAC addres from the pool of available MAC addresses 96 * Can return as either a 64-bit value and/or 6 octets. 97 * 98 * @param macp Filled in with the assigned address if non-NULL 99 * @param octets Filled in with the assigned address if non-NULL 100 * @return Zero on success 101 */ 102int cvm_assign_mac_address(uint64_t *macp, uint8_t *octets) 103{ 104 /* Initialize from global MAC address base; fail if not set */ 105 if (cvm_oct_mac_addr == 0) { 106 memcpy((uint8_t *)&cvm_oct_mac_addr + 2, 107 cvmx_sysinfo_get()->mac_addr_base, 6); 108 109 if (cvm_oct_mac_addr == 0) 110 return ENXIO; 111 112 /* 113 * The offset from mac_addr_base that should be used for the next port 114 * that is configured. By convention, if any mgmt ports exist on the 115 * chip, they get the first mac addresses. The ports controlled by 116 * driver that use this function are numbered sequencially following 117 * any mgmt addresses that may exist. 118 * 119 * XXX Would be nice if __cvmx_mgmt_port_num_ports() were 120 * not static to cvmx-mgmt-port.c. 121 */ 122 if (OCTEON_IS_MODEL(OCTEON_CN56XX)) 123 cvm_oct_mac_addr_offset = 1; 124 else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) 125 cvm_oct_mac_addr_offset = 2; 126 else 127 cvm_oct_mac_addr_offset = 0; 128 cvm_oct_mac_addr += cvm_oct_mac_addr_offset; 129 } 130 131 if (cvm_oct_mac_addr_offset >= cvmx_sysinfo_get()->mac_addr_count) 132 return ENXIO; /* Out of addresses to assign */ 133 134 if (macp) 135 *macp = cvm_oct_mac_addr; 136 if (octets) 137 memcpy(octets, (u_int8_t *)&cvm_oct_mac_addr + 2, 6); 138 139 cvm_oct_mac_addr++; 140 cvm_oct_mac_addr_offset++; 141 142 return 0; 143} 144 145/** 146 * Set the hardware MAC address for a device 147 * 148 * @param dev Device to change the MAC address for 149 * @param addr Address structure to change it too. 150 */ 151void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr) 152{ 153 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 154 cvmx_gmxx_prtx_cfg_t gmx_cfg; 155 int interface = INTERFACE(priv->port); 156 int index = INDEX(priv->port); 157 158 memcpy(priv->mac, addr, 6); 159 160 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { 161 int i; 162 const uint8_t *ptr = addr; 163 uint64_t mac = 0; 164 for (i = 0; i < 6; i++) 165 mac = (mac<<8) | (uint64_t)(ptr[i]); 166 167 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 168 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull); 169 170 cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac); 171 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]); 172 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]); 173 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]); 174 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]); 175 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]); 176 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]); 177 cvm_oct_common_set_multicast_list(ifp); 178 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 179 } 180} 181 182 183/** 184 * Change the link MTU. Unimplemented 185 * 186 * @param dev Device to change 187 * @param new_mtu The new MTU 188 * @return Zero on success 189 */ 190int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu) 191{ 192 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 193 int interface = INTERFACE(priv->port); 194 int index = INDEX(priv->port); 195 int vlan_bytes = 4; 196 197 /* Limit the MTU to make sure the ethernet packets are between 64 bytes 198 and 65535 bytes */ 199 if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) { 200 printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes); 201 return -EINVAL; 202 } 203 ifp->if_mtu = new_mtu; 204 205 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) { 206 int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */ 207 208 if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) { 209 /* Signal errors on packets larger than the MTU */ 210 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet); 211 } else { 212 /* Set the hardware to truncate packets larger than the MTU and 213 smaller the 64 bytes */ 214 cvmx_pip_frm_len_chkx_t frm_len_chk; 215 frm_len_chk.u64 = 0; 216 frm_len_chk.s.minlen = 64; 217 frm_len_chk.s.maxlen = max_packet; 218 cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64); 219 } 220 /* Set the hardware to truncate packets larger than the MTU. The 221 jabber register must be set to a multiple of 8 bytes, so round up */ 222 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u); 223 } 224 return 0; 225} 226 227 228/** 229 * Enable port. 230 */ 231int cvm_oct_common_open(struct ifnet *ifp) 232{ 233 cvmx_gmxx_prtx_cfg_t gmx_cfg; 234 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 235 int interface = INTERFACE(priv->port); 236 int index = INDEX(priv->port); 237 cvmx_helper_link_info_t link_info; 238 239 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 240 gmx_cfg.s.en = 1; 241 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 242 243 /* 244 * Set the link state unless we are using MII. 245 */ 246 if (!octeon_is_simulation() && priv->miibus == NULL) { 247 link_info = cvmx_helper_link_get(priv->port); 248 if (!link_info.s.link_up) 249 if_link_state_change(ifp, LINK_STATE_DOWN); 250 else 251 if_link_state_change(ifp, LINK_STATE_UP); 252 } 253 254 return 0; 255} 256 257 258/** 259 * Disable port. 260 */ 261int cvm_oct_common_stop(struct ifnet *ifp) 262{ 263 cvmx_gmxx_prtx_cfg_t gmx_cfg; 264 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 265 int interface = INTERFACE(priv->port); 266 int index = INDEX(priv->port); 267 268 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 269 gmx_cfg.s.en = 0; 270 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 271 return 0; 272} 273 274/** 275 * Poll for link status change. 276 */ 277void cvm_oct_common_poll(struct ifnet *ifp) 278{ 279 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 280 cvmx_helper_link_info_t link_info; 281 282 /* 283 * If this is a simulation, do nothing. 284 */ 285 if (octeon_is_simulation()) 286 return; 287 288 /* 289 * If there is a device-specific poll method, use it. 290 */ 291 if (priv->poll != NULL) { 292 priv->poll(ifp); 293 return; 294 } 295 296 /* 297 * If an MII bus is attached, don't use the Simple Executive's link 298 * state routines. 299 */ 300 if (priv->miibus != NULL) 301 return; 302 303 /* 304 * Use the Simple Executive's link state routines. 305 */ 306 link_info = cvmx_helper_link_get(priv->port); 307 if (link_info.u64 == priv->link_info) 308 return; 309 310 link_info = cvmx_helper_link_autoconf(priv->port); 311 priv->link_info = link_info.u64; 312 priv->need_link_update = 1; 313} 314 315 316/** 317 * Per network device initialization 318 * 319 * @param dev Device to initialize 320 * @return Zero on success 321 */ 322int cvm_oct_common_init(struct ifnet *ifp) 323{ 324 uint8_t mac[6]; 325 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; 326 327 if (cvm_assign_mac_address(NULL, mac) != 0) 328 return ENXIO; 329 330 ifp->if_mtu = ETHERMTU; 331 332 cvm_oct_mdio_setup_device(ifp); 333 334 cvm_oct_common_set_mac_address(ifp, mac); 335 cvm_oct_common_change_mtu(ifp, ifp->if_mtu); 336 337 /* 338 * Do any last-minute board-specific initialization. 339 */ 340 switch (cvmx_sysinfo_get()->board_type) { 341#if defined(OCTEON_VENDOR_LANNER) 342 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 343 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: 344 if (priv->phy_id == 16) 345 cvm_oct_mv88e61xx_setup_device(ifp); 346 break; 347#endif 348 default: 349 break; 350 } 351 352 device_attach(priv->dev); 353 354 return 0; 355} 356 357void cvm_oct_common_uninit(struct ifnet *ifp) 358{ 359 /* Currently nothing to do */ 360} 361 362