ethernet.c revision 231987
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#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: head/sys/mips/cavium/octe/ethernet.c 231987 2012-02-22 01:30:25Z gonzo $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/conf.h> 36#include <sys/endian.h> 37#include <sys/kernel.h> 38#include <sys/rman.h> 39#include <sys/mbuf.h> 40#include <sys/socket.h> 41#include <sys/module.h> 42#include <sys/smp.h> 43#include <sys/taskqueue.h> 44 45#include <net/ethernet.h> 46#include <net/if.h> 47#include <net/if_types.h> 48 49#include "wrapper-cvmx-includes.h" 50#include "ethernet-headers.h" 51 52#include "octebusvar.h" 53 54/* 55 * XXX/juli 56 * Convert 0444 to tunables, 0644 to sysctls. 57 */ 58#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS 59int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS; 60#else 61int num_packet_buffers = 1024; 62#endif 63TUNABLE_INT("hw.octe.num_packet_buffers", &num_packet_buffers); 64/* 65 "\t\tNumber of packet buffers to allocate and store in the\n" 66 "\t\tFPA. By default, 1024 packet buffers are used unless\n" 67 "\t\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined." */ 68 69int pow_receive_group = 15; 70TUNABLE_INT("hw.octe.pow_receive_group", &pow_receive_group); 71/* 72 "\t\tPOW group to receive packets from. All ethernet hardware\n" 73 "\t\twill be configured to send incomming packets to this POW\n" 74 "\t\tgroup. Also any other software can submit packets to this\n" 75 "\t\tgroup for the kernel to process." */ 76 77extern int octeon_is_simulation(void); 78 79/** 80 * Periodic timer to check auto negotiation 81 */ 82static struct callout cvm_oct_poll_timer; 83 84/** 85 * Array of every ethernet device owned by this driver indexed by 86 * the ipd input port number. 87 */ 88struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS]; 89 90/** 91 * Task to handle link status changes. 92 */ 93static struct taskqueue *cvm_oct_link_taskq; 94 95/* 96 * Number of buffers in output buffer pool. 97 */ 98static int cvm_oct_num_output_buffers; 99 100/** 101 * Function to update link status. 102 */ 103static void cvm_oct_update_link(void *context, int pending) 104{ 105 cvm_oct_private_t *priv = (cvm_oct_private_t *)context; 106 struct ifnet *ifp = priv->ifp; 107 cvmx_helper_link_info_t link_info; 108 109 link_info.u64 = priv->link_info; 110 111 if (link_info.s.link_up) { 112 if_link_state_change(ifp, LINK_STATE_UP); 113 DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n", 114 if_name(ifp), link_info.s.speed, 115 (link_info.s.full_duplex) ? "Full" : "Half", 116 priv->port, priv->queue); 117 } else { 118 if_link_state_change(ifp, LINK_STATE_DOWN); 119 DEBUGPRINT("%s: Link down\n", if_name(ifp)); 120 } 121 priv->need_link_update = 0; 122} 123 124/** 125 * Periodic timer tick for slow management operations 126 * 127 * @param arg Device to check 128 */ 129static void cvm_do_timer(void *arg) 130{ 131 static int port; 132 static int updated; 133 if (port < CVMX_PIP_NUM_INPUT_PORTS) { 134 if (cvm_oct_device[port]) { 135 int queues_per_port; 136 int qos; 137 cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc; 138 139 cvm_oct_common_poll(priv->ifp); 140 if (priv->need_link_update) { 141 updated++; 142 taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task); 143 } 144 145 queues_per_port = cvmx_pko_get_num_queues(port); 146 /* Drain any pending packets in the free list */ 147 for (qos = 0; qos < queues_per_port; qos++) { 148 if (_IF_QLEN(&priv->tx_free_queue[qos]) > 0) { 149 IF_LOCK(&priv->tx_free_queue[qos]); 150 while (_IF_QLEN(&priv->tx_free_queue[qos]) > cvmx_fau_fetch_and_add32(priv->fau+qos*4, 0)) { 151 struct mbuf *m; 152 153 _IF_DEQUEUE(&priv->tx_free_queue[qos], m); 154 m_freem(m); 155 } 156 IF_UNLOCK(&priv->tx_free_queue[qos]); 157 158 /* 159 * XXX locking! 160 */ 161 priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 162 } 163 } 164 } 165 port++; 166 /* Poll the next port in a 50th of a second. 167 This spreads the polling of ports out a little bit */ 168 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL); 169 } else { 170 port = 0; 171 /* If any updates were made in this run, continue iterating at 172 * 1/50th of a second, so that if a link has merely gone down 173 * temporarily (e.g. because of interface reinitialization) it 174 * will not be forced to stay down for an entire second. 175 */ 176 if (updated > 0) { 177 updated = 0; 178 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL); 179 } else { 180 /* All ports have been polled. Start the next iteration through 181 the ports in one second */ 182 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); 183 } 184 } 185} 186 187/** 188 * Configure common hardware for all interfaces 189 */ 190static void cvm_oct_configure_common_hw(device_t bus) 191{ 192 struct octebus_softc *sc; 193 int pko_queues; 194 int error; 195 int rid; 196 197 sc = device_get_softc(bus); 198 199 /* Setup the FPA */ 200 cvmx_fpa_enable(); 201 cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, 202 num_packet_buffers); 203 cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, 204 num_packet_buffers); 205 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) { 206 /* 207 * If the FPA uses different pools for output buffers and 208 * packets, size the output buffer pool based on the number 209 * of PKO queues. 210 */ 211 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 212 pko_queues = 128; 213 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) 214 pko_queues = 32; 215 else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 216 pko_queues = 32; 217 else 218 pko_queues = 256; 219 220 cvm_oct_num_output_buffers = 4 * pko_queues; 221 cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, 222 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 223 cvm_oct_num_output_buffers); 224 } 225 226 if (USE_RED) 227 cvmx_helper_setup_red(num_packet_buffers/4, 228 num_packet_buffers/8); 229 230 /* Enable the MII interface */ 231 if (!octeon_is_simulation()) 232 cvmx_write_csr(CVMX_SMI_EN, 1); 233 234 /* Register an IRQ hander for to receive POW interrupts */ 235 rid = 0; 236 sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid, 237 CVMX_IRQ_WORKQ0 + pow_receive_group, 238 CVMX_IRQ_WORKQ0 + pow_receive_group, 239 1, RF_ACTIVE); 240 if (sc->sc_rx_irq == NULL) { 241 device_printf(bus, "could not allocate workq irq"); 242 return; 243 } 244 245 error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE, 246 cvm_oct_do_interrupt, NULL, cvm_oct_device, 247 &sc->sc_rx_intr_cookie); 248 if (error != 0) { 249 device_printf(bus, "could not setup workq irq"); 250 return; 251 } 252 253 254#ifdef SMP 255 { 256 cvmx_ciu_intx0_t en; 257 int core; 258 259 CPU_FOREACH(core) { 260 if (core == PCPU_GET(cpuid)) 261 continue; 262 263 en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(core*2)); 264 en.s.workq |= (1<<pow_receive_group); 265 cvmx_write_csr(CVMX_CIU_INTX_EN0(core*2), en.u64); 266 } 267 } 268#endif 269} 270 271 272/** 273 * Free a work queue entry received in a intercept callback. 274 * 275 * @param work_queue_entry 276 * Work queue entry to free 277 * @return Zero on success, Negative on failure. 278 */ 279int cvm_oct_free_work(void *work_queue_entry) 280{ 281 cvmx_wqe_t *work = work_queue_entry; 282 283 int segments = work->word2.s.bufs; 284 cvmx_buf_ptr_t segment_ptr = work->packet_ptr; 285 286 while (segments--) { 287 cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8); 288 if (__predict_false(!segment_ptr.s.i)) 289 cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128)); 290 segment_ptr = next_ptr; 291 } 292 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); 293 294 return 0; 295} 296 297 298/** 299 * Module/ driver initialization. Creates the linux network 300 * devices. 301 * 302 * @return Zero on success 303 */ 304int cvm_oct_init_module(device_t bus) 305{ 306 device_t dev; 307 int ifnum; 308 int num_interfaces; 309 int interface; 310 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; 311 int qos; 312 313 printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING); 314 315 cvm_oct_rx_initialize(); 316 cvm_oct_configure_common_hw(bus); 317 318 cvmx_helper_initialize_packet_io_global(); 319 320 /* Change the input group for all ports before input is enabled */ 321 num_interfaces = cvmx_helper_get_number_of_interfaces(); 322 for (interface = 0; interface < num_interfaces; interface++) { 323 int num_ports = cvmx_helper_ports_on_interface(interface); 324 int port; 325 326 for (port = 0; port < num_ports; port++) { 327 cvmx_pip_prt_tagx_t pip_prt_tagx; 328 int pkind = cvmx_helper_get_ipd_port(interface, port); 329 330 pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(pkind)); 331 pip_prt_tagx.s.grp = pow_receive_group; 332 cvmx_write_csr(CVMX_PIP_PRT_TAGX(pkind), pip_prt_tagx.u64); 333 } 334 } 335 336 cvmx_helper_ipd_and_packet_input_enable(); 337 338 memset(cvm_oct_device, 0, sizeof(cvm_oct_device)); 339 340 cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT, 341 taskqueue_thread_enqueue, &cvm_oct_link_taskq); 342 taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET, 343 "octe link taskq"); 344 345 /* Initialize the FAU used for counting packet buffers that need to be freed */ 346 cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); 347 348 ifnum = 0; 349 num_interfaces = cvmx_helper_get_number_of_interfaces(); 350 for (interface = 0; interface < num_interfaces; interface++) { 351 cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface); 352 int num_ports = cvmx_helper_ports_on_interface(interface); 353 int port; 354 355 for (port = cvmx_helper_get_ipd_port(interface, 0); 356 port < cvmx_helper_get_ipd_port(interface, num_ports); 357 ifnum++, port++) { 358 cvm_oct_private_t *priv; 359 struct ifnet *ifp; 360 361 dev = BUS_ADD_CHILD(bus, 0, "octe", ifnum); 362 if (dev != NULL) 363 ifp = if_alloc(IFT_ETHER); 364 if (dev == NULL || ifp == NULL) { 365 printf("Failed to allocate ethernet device for interface %d port %d\n", interface, port); 366 continue; 367 } 368 369 /* Initialize the device private structure. */ 370 device_probe(dev); 371 priv = device_get_softc(dev); 372 priv->dev = dev; 373 priv->ifp = ifp; 374 priv->imode = imode; 375 priv->port = port; 376 priv->queue = cvmx_pko_get_base_queue(priv->port); 377 priv->fau = fau - cvmx_pko_get_num_queues(port) * 4; 378 for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++) 379 cvmx_fau_atomic_write32(priv->fau+qos*4, 0); 380 TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv); 381 382 switch (priv->imode) { 383 384 /* These types don't support ports to IPD/PKO */ 385 case CVMX_HELPER_INTERFACE_MODE_DISABLED: 386 case CVMX_HELPER_INTERFACE_MODE_PCIE: 387 case CVMX_HELPER_INTERFACE_MODE_PICMG: 388 break; 389 390 case CVMX_HELPER_INTERFACE_MODE_NPI: 391 priv->init = cvm_oct_common_init; 392 priv->uninit = cvm_oct_common_uninit; 393 device_set_desc(dev, "Cavium Octeon NPI Ethernet"); 394 break; 395 396 case CVMX_HELPER_INTERFACE_MODE_XAUI: 397 priv->init = cvm_oct_xaui_init; 398 priv->uninit = cvm_oct_common_uninit; 399 device_set_desc(dev, "Cavium Octeon XAUI Ethernet"); 400 break; 401 402 case CVMX_HELPER_INTERFACE_MODE_LOOP: 403 priv->init = cvm_oct_common_init; 404 priv->uninit = cvm_oct_common_uninit; 405 device_set_desc(dev, "Cavium Octeon LOOP Ethernet"); 406 break; 407 408 case CVMX_HELPER_INTERFACE_MODE_SGMII: 409 priv->init = cvm_oct_sgmii_init; 410 priv->uninit = cvm_oct_common_uninit; 411 device_set_desc(dev, "Cavium Octeon SGMII Ethernet"); 412 break; 413 414 case CVMX_HELPER_INTERFACE_MODE_SPI: 415 priv->init = cvm_oct_spi_init; 416 priv->uninit = cvm_oct_spi_uninit; 417 device_set_desc(dev, "Cavium Octeon SPI Ethernet"); 418 break; 419 420 case CVMX_HELPER_INTERFACE_MODE_RGMII: 421 priv->init = cvm_oct_rgmii_init; 422 priv->uninit = cvm_oct_rgmii_uninit; 423 device_set_desc(dev, "Cavium Octeon RGMII Ethernet"); 424 break; 425 426 case CVMX_HELPER_INTERFACE_MODE_GMII: 427 priv->init = cvm_oct_rgmii_init; 428 priv->uninit = cvm_oct_rgmii_uninit; 429 device_set_desc(dev, "Cavium Octeon GMII Ethernet"); 430 break; 431 } 432 433 ifp->if_softc = priv; 434 435 if (!priv->init) { 436 printf("octe%d: unsupported device type interface %d, port %d\n", 437 ifnum, interface, priv->port); 438 if_free(ifp); 439 } else if (priv->init(ifp) != 0) { 440 printf("octe%d: failed to register device for interface %d, port %d\n", 441 ifnum, interface, priv->port); 442 if_free(ifp); 443 } else { 444 cvm_oct_device[priv->port] = ifp; 445 fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t); 446 } 447 } 448 } 449 450 if (INTERRUPT_LIMIT) { 451 /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */ 452 cvmx_write_csr(CVMX_POW_WQ_INT_PC, cvmx_clock_get_rate(CVMX_CLOCK_CORE)/(INTERRUPT_LIMIT*16*256)<<8); 453 454 /* Enable POW timer interrupt. It will count when there are packets available */ 455 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24); 456 } else { 457 /* Enable POW interrupt when our port has at least one packet */ 458 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001); 459 } 460 461 callout_init(&cvm_oct_poll_timer, CALLOUT_MPSAFE); 462 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); 463 464 return 0; 465} 466 467 468/** 469 * Module / driver shutdown 470 * 471 * @return Zero on success 472 */ 473void cvm_oct_cleanup_module(device_t bus) 474{ 475 int port; 476 struct octebus_softc *sc = device_get_softc(bus); 477 478 /* Disable POW interrupt */ 479 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); 480 481 /* Free the interrupt handler */ 482 bus_teardown_intr(bus, sc->sc_rx_irq, sc->sc_rx_intr_cookie); 483 484 callout_stop(&cvm_oct_poll_timer); 485 cvm_oct_rx_shutdown(); 486 487 cvmx_helper_shutdown_packet_io_global(); 488 489 /* Free the ethernet devices */ 490 for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) { 491 if (cvm_oct_device[port]) { 492 cvm_oct_tx_shutdown(cvm_oct_device[port]); 493#if 0 494 unregister_netdev(cvm_oct_device[port]); 495 kfree(cvm_oct_device[port]); 496#else 497 panic("%s: need to detach and free interface.", __func__); 498#endif 499 cvm_oct_device[port] = NULL; 500 } 501 } 502 /* Free the HW pools */ 503 cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers); 504 cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers); 505 506 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) 507 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, cvm_oct_num_output_buffers); 508 509 /* Disable FPA, all buffers are free, not done by helper shutdown. */ 510 cvmx_fpa_disable(); 511} 512