ethernet.c revision 210311
1210311Sjmallett/************************************************************************* 2210311SjmallettCopyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights 3210311Sjmallettreserved. 4210311Sjmallett 5210311Sjmallett 6210311SjmallettRedistribution and use in source and binary forms, with or without 7210311Sjmallettmodification, are permitted provided that the following conditions are 8210311Sjmallettmet: 9210311Sjmallett 10210311Sjmallett * Redistributions of source code must retain the above copyright 11210311Sjmallett notice, this list of conditions and the following disclaimer. 12210311Sjmallett 13210311Sjmallett * Redistributions in binary form must reproduce the above 14210311Sjmallett copyright notice, this list of conditions and the following 15210311Sjmallett disclaimer in the documentation and/or other materials provided 16210311Sjmallett with the distribution. 17210311Sjmallett 18210311Sjmallett * Neither the name of Cavium Networks nor the names of 19210311Sjmallett its contributors may be used to endorse or promote products 20210311Sjmallett derived from this software without specific prior written 21210311Sjmallett permission. 22210311Sjmallett 23210311SjmallettThis 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. 24210311Sjmallett 25210311SjmallettTO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 26210311SjmallettAND 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. 27210311Sjmallett*************************************************************************/ 28210311Sjmallett 29210311Sjmallett#include <sys/cdefs.h> 30210311Sjmallett__FBSDID("$FreeBSD: head/sys/mips/cavium/octe/ethernet.c 210311 2010-07-20 19:25:11Z jmallett $"); 31210311Sjmallett 32210311Sjmallett#include <sys/param.h> 33210311Sjmallett#include <sys/systm.h> 34210311Sjmallett#include <sys/bus.h> 35210311Sjmallett#include <sys/conf.h> 36210311Sjmallett#include <sys/endian.h> 37210311Sjmallett#include <sys/kernel.h> 38210311Sjmallett#include <sys/rman.h> 39210311Sjmallett#include <sys/mbuf.h> 40210311Sjmallett#include <sys/socket.h> 41210311Sjmallett#include <sys/module.h> 42210311Sjmallett#include <sys/smp.h> 43210311Sjmallett 44210311Sjmallett#include <net/ethernet.h> 45210311Sjmallett#include <net/if.h> 46210311Sjmallett#include <net/if_types.h> 47210311Sjmallett 48210311Sjmallett#include "wrapper-cvmx-includes.h" 49210311Sjmallett#include "ethernet-headers.h" 50210311Sjmallett 51210311Sjmallett#include "octebusvar.h" 52210311Sjmallett 53210311Sjmallett/* 54210311Sjmallett * XXX/juli 55210311Sjmallett * Convert 0444 to tunables, 0644 to sysctls. 56210311Sjmallett */ 57210311Sjmallett#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS 58210311Sjmallettint num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS; 59210311Sjmallett#else 60210311Sjmallettint num_packet_buffers = 1024; 61210311Sjmallett#endif 62210311SjmallettTUNABLE_INT("hw.octe.num_packet_buffers", &num_packet_buffers); 63210311Sjmallett/* 64210311Sjmallett "\t\tNumber of packet buffers to allocate and store in the\n" 65210311Sjmallett "\t\tFPA. By default, 1024 packet buffers are used unless\n" 66210311Sjmallett "\t\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined." */ 67210311Sjmallett 68210311Sjmallettint pow_receive_group = 15; 69210311SjmallettTUNABLE_INT("hw.octe.pow_receive_group", &pow_receive_group); 70210311Sjmallett/* 71210311Sjmallett "\t\tPOW group to receive packets from. All ethernet hardware\n" 72210311Sjmallett "\t\twill be configured to send incomming packets to this POW\n" 73210311Sjmallett "\t\tgroup. Also any other software can submit packets to this\n" 74210311Sjmallett "\t\tgroup for the kernel to process." */ 75210311Sjmallett 76210311Sjmallettint pow_send_group = -1; /* XXX Should be a sysctl. */ 77210311SjmallettTUNABLE_INT("hw.octe.pow_send_group", &pow_send_group); 78210311Sjmallett/* 79210311Sjmallett "\t\tPOW group to send packets to other software on. This\n" 80210311Sjmallett "\t\tcontrols the creation of the virtual device pow0.\n" 81210311Sjmallett "\t\talways_use_pow also depends on this value." */ 82210311Sjmallett 83210311Sjmallettint always_use_pow; 84210311SjmallettTUNABLE_INT("hw.octe.always_use_pow", &always_use_pow); 85210311Sjmallett/* 86210311Sjmallett "\t\tWhen set, always send to the pow group. This will cause\n" 87210311Sjmallett "\t\tpackets sent to real ethernet devices to be sent to the\n" 88210311Sjmallett "\t\tPOW group instead of the hardware. Unless some other\n" 89210311Sjmallett "\t\tapplication changes the config, packets will still be\n" 90210311Sjmallett "\t\treceived from the low level hardware. Use this option\n" 91210311Sjmallett "\t\tto allow a CVMX app to intercept all packets from the\n" 92210311Sjmallett "\t\tlinux kernel. You must specify pow_send_group along with\n" 93210311Sjmallett "\t\tthis option." */ 94210311Sjmallett 95210311Sjmallettchar pow_send_list[128] = ""; 96210311SjmallettTUNABLE_STR("hw.octe.pow_send_list", pow_send_list, sizeof pow_send_list); 97210311Sjmallett/* 98210311Sjmallett "\t\tComma separated list of ethernet devices that should use the\n" 99210311Sjmallett "\t\tPOW for transmit instead of the actual ethernet hardware. This\n" 100210311Sjmallett "\t\tis a per port version of always_use_pow. always_use_pow takes\n" 101210311Sjmallett "\t\tprecedence over this list. For example, setting this to\n" 102210311Sjmallett "\t\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n" 103210311Sjmallett "\t\tusing the pow_send_group." */ 104210311Sjmallett 105210311Sjmallett 106210311Sjmallettstatic int disable_core_queueing = 1; 107210311SjmallettTUNABLE_INT("hw.octe.disable_core_queueing", &disable_core_queueing); 108210311Sjmallett/* 109210311Sjmallett "\t\tWhen set the networking core's tx_queue_len is set to zero. This\n" 110210311Sjmallett "\t\tallows packets to be sent without lock contention in the packet scheduler\n" 111210311Sjmallett "\t\tresulting in some cases in improved throughput.\n" */ 112210311Sjmallett 113210311Sjmallettextern int octeon_is_simulation(void); 114210311Sjmallett 115210311Sjmallett/** 116210311Sjmallett * Exported from the kernel so we can determine board information. It is 117210311Sjmallett * passed by the bootloader to the kernel. 118210311Sjmallett */ 119210311Sjmallettextern cvmx_bootinfo_t *octeon_bootinfo; 120210311Sjmallett 121210311Sjmallett/** 122210311Sjmallett * Periodic timer to check auto negotiation 123210311Sjmallett */ 124210311Sjmallettstatic struct callout cvm_oct_poll_timer; 125210311Sjmallett 126210311Sjmallett/** 127210311Sjmallett * Array of every ethernet device owned by this driver indexed by 128210311Sjmallett * the ipd input port number. 129210311Sjmallett */ 130210311Sjmallettstruct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS]; 131210311Sjmallett 132210311Sjmallett 133210311Sjmallett/** 134210311Sjmallett * Periodic timer tick for slow management operations 135210311Sjmallett * 136210311Sjmallett * @param arg Device to check 137210311Sjmallett */ 138210311Sjmallettstatic void cvm_do_timer(void *arg) 139210311Sjmallett{ 140210311Sjmallett static int port; 141210311Sjmallett if (port < CVMX_PIP_NUM_INPUT_PORTS) { 142210311Sjmallett if (cvm_oct_device[port]) { 143210311Sjmallett int queues_per_port; 144210311Sjmallett int qos; 145210311Sjmallett cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc; 146210311Sjmallett if (priv->poll) 147210311Sjmallett { 148210311Sjmallett /* skip polling if we don't get the lock */ 149210311Sjmallett if (MDIO_TRYLOCK()) { 150210311Sjmallett priv->poll(cvm_oct_device[port]); 151210311Sjmallett MDIO_UNLOCK(); 152210311Sjmallett } 153210311Sjmallett } 154210311Sjmallett 155210311Sjmallett queues_per_port = cvmx_pko_get_num_queues(port); 156210311Sjmallett /* Drain any pending packets in the free list */ 157210311Sjmallett for (qos = 0; qos < queues_per_port; qos++) { 158210311Sjmallett if (_IF_QLEN(&priv->tx_free_queue[qos]) > 0) { 159210311Sjmallett IF_LOCK(&priv->tx_free_queue[qos]); 160210311Sjmallett while (_IF_QLEN(&priv->tx_free_queue[qos]) > cvmx_fau_fetch_and_add32(priv->fau+qos*4, 0)) { 161210311Sjmallett struct mbuf *m; 162210311Sjmallett 163210311Sjmallett _IF_DEQUEUE(&priv->tx_free_queue[qos], m); 164210311Sjmallett m_freem(m); 165210311Sjmallett } 166210311Sjmallett IF_UNLOCK(&priv->tx_free_queue[qos]); 167210311Sjmallett 168210311Sjmallett /* 169210311Sjmallett * XXX locking! 170210311Sjmallett */ 171210311Sjmallett priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 172210311Sjmallett } 173210311Sjmallett } 174210311Sjmallett#if 0 175210311Sjmallett cvm_oct_device[port]->get_stats(cvm_oct_device[port]); 176210311Sjmallett#endif 177210311Sjmallett } 178210311Sjmallett port++; 179210311Sjmallett /* Poll the next port in a 50th of a second. 180210311Sjmallett This spreads the polling of ports out a little bit */ 181210311Sjmallett callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL); 182210311Sjmallett } else { 183210311Sjmallett port = 0; 184210311Sjmallett /* All ports have been polled. Start the next iteration through 185210311Sjmallett the ports in one second */ 186210311Sjmallett callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); 187210311Sjmallett } 188210311Sjmallett} 189210311Sjmallett 190210311Sjmallett 191210311Sjmallett/** 192210311Sjmallett * Configure common hardware for all interfaces 193210311Sjmallett */ 194210311Sjmallettstatic void cvm_oct_configure_common_hw(device_t bus) 195210311Sjmallett{ 196210311Sjmallett struct octebus_softc *sc; 197210311Sjmallett int error; 198210311Sjmallett int rid; 199210311Sjmallett 200210311Sjmallett sc = device_get_softc(bus); 201210311Sjmallett 202210311Sjmallett /* Setup the FPA */ 203210311Sjmallett cvmx_fpa_enable(); 204210311Sjmallett cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers); 205210311Sjmallett cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers); 206210311Sjmallett if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) 207210311Sjmallett cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); 208210311Sjmallett 209210311Sjmallett if (USE_RED) 210210311Sjmallett cvmx_helper_setup_red(num_packet_buffers/4, num_packet_buffers/8); 211210311Sjmallett 212210311Sjmallett /* Enable the MII interface */ 213210311Sjmallett if (!octeon_is_simulation()) 214210311Sjmallett cvmx_write_csr(CVMX_SMI_EN, 1); 215210311Sjmallett 216210311Sjmallett /* Register an IRQ hander for to receive POW interrupts */ 217210311Sjmallett rid = 0; 218210311Sjmallett sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid, 219210311Sjmallett CVMX_IRQ_WORKQ0 + pow_receive_group, 220210311Sjmallett CVMX_IRQ_WORKQ0 + pow_receive_group, 221210311Sjmallett 1, RF_ACTIVE); 222210311Sjmallett if (sc->sc_rx_irq == NULL) { 223210311Sjmallett device_printf(bus, "could not allocate workq irq"); 224210311Sjmallett return; 225210311Sjmallett } 226210311Sjmallett 227210311Sjmallett error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE, 228210311Sjmallett cvm_oct_do_interrupt, NULL, cvm_oct_device, 229210311Sjmallett NULL); 230210311Sjmallett if (error != 0) { 231210311Sjmallett device_printf(bus, "could not setup workq irq"); 232210311Sjmallett return; 233210311Sjmallett } 234210311Sjmallett 235210311Sjmallett 236210311Sjmallett#ifdef SMP 237210311Sjmallett if (USE_MULTICORE_RECEIVE) { 238210311Sjmallett critical_enter(); 239210311Sjmallett { 240210311Sjmallett int cpu; 241210311Sjmallett for (cpu = 0; cpu < mp_maxid; cpu++) { 242210311Sjmallett if (!CPU_ABSENT(cpu) && 243210311Sjmallett (cpu != PCPU_GET(cpuid))) { 244210311Sjmallett cvmx_ciu_intx0_t en; 245210311Sjmallett en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(cpu*2)); 246210311Sjmallett en.s.workq |= (1<<pow_receive_group); 247210311Sjmallett cvmx_write_csr(CVMX_CIU_INTX_EN0(cpu*2), en.u64); 248210311Sjmallett } 249210311Sjmallett } 250210311Sjmallett } 251210311Sjmallett critical_exit(); 252210311Sjmallett } 253210311Sjmallett#endif 254210311Sjmallett} 255210311Sjmallett 256210311Sjmallett 257210311Sjmallett/** 258210311Sjmallett * Free a work queue entry received in a intercept callback. 259210311Sjmallett * 260210311Sjmallett * @param work_queue_entry 261210311Sjmallett * Work queue entry to free 262210311Sjmallett * @return Zero on success, Negative on failure. 263210311Sjmallett */ 264210311Sjmallettint cvm_oct_free_work(void *work_queue_entry) 265210311Sjmallett{ 266210311Sjmallett cvmx_wqe_t *work = work_queue_entry; 267210311Sjmallett 268210311Sjmallett int segments = work->word2.s.bufs; 269210311Sjmallett cvmx_buf_ptr_t segment_ptr = work->packet_ptr; 270210311Sjmallett 271210311Sjmallett while (segments--) { 272210311Sjmallett cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8); 273210311Sjmallett if (__predict_false(!segment_ptr.s.i)) 274210311Sjmallett cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128)); 275210311Sjmallett segment_ptr = next_ptr; 276210311Sjmallett } 277210311Sjmallett cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); 278210311Sjmallett 279210311Sjmallett return 0; 280210311Sjmallett} 281210311Sjmallett 282210311Sjmallett 283210311Sjmallett/** 284210311Sjmallett * Module/ driver initialization. Creates the linux network 285210311Sjmallett * devices. 286210311Sjmallett * 287210311Sjmallett * @return Zero on success 288210311Sjmallett */ 289210311Sjmallettint cvm_oct_init_module(device_t bus) 290210311Sjmallett{ 291210311Sjmallett device_t dev; 292210311Sjmallett int ifnum; 293210311Sjmallett int num_interfaces; 294210311Sjmallett int interface; 295210311Sjmallett int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; 296210311Sjmallett int qos; 297210311Sjmallett 298210311Sjmallett printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING); 299210311Sjmallett 300210311Sjmallett#if 0 301210311Sjmallett cvm_oct_proc_initialize(); 302210311Sjmallett#endif 303210311Sjmallett cvm_oct_rx_initialize(); 304210311Sjmallett cvm_oct_configure_common_hw(bus); 305210311Sjmallett 306210311Sjmallett cvmx_helper_initialize_packet_io_global(); 307210311Sjmallett 308210311Sjmallett /* Change the input group for all ports before input is enabled */ 309210311Sjmallett num_interfaces = cvmx_helper_get_number_of_interfaces(); 310210311Sjmallett for (interface = 0; interface < num_interfaces; interface++) { 311210311Sjmallett int num_ports = cvmx_helper_ports_on_interface(interface); 312210311Sjmallett int port; 313210311Sjmallett 314210311Sjmallett for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) { 315210311Sjmallett cvmx_pip_prt_tagx_t pip_prt_tagx; 316210311Sjmallett pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(port)); 317210311Sjmallett pip_prt_tagx.s.grp = pow_receive_group; 318210311Sjmallett cvmx_write_csr(CVMX_PIP_PRT_TAGX(port), pip_prt_tagx.u64); 319210311Sjmallett } 320210311Sjmallett } 321210311Sjmallett 322210311Sjmallett cvmx_helper_ipd_and_packet_input_enable(); 323210311Sjmallett 324210311Sjmallett memset(cvm_oct_device, 0, sizeof(cvm_oct_device)); 325210311Sjmallett 326210311Sjmallett /* Initialize the FAU used for counting packet buffers that need to be freed */ 327210311Sjmallett cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); 328210311Sjmallett 329210311Sjmallett if ((pow_send_group != -1)) { 330210311Sjmallett struct ifnet *ifp; 331210311Sjmallett 332210311Sjmallett printf("\tConfiguring device for POW only access\n"); 333210311Sjmallett dev = BUS_ADD_CHILD(bus, 0, "pow", 0); 334210311Sjmallett if (dev != NULL) 335210311Sjmallett ifp = if_alloc(IFT_ETHER); 336210311Sjmallett if (dev != NULL && ifp != NULL) { 337210311Sjmallett /* Initialize the device private structure. */ 338210311Sjmallett cvm_oct_private_t *priv; 339210311Sjmallett 340210311Sjmallett device_probe(dev); 341210311Sjmallett priv = device_get_softc(dev); 342210311Sjmallett priv->dev = dev; 343210311Sjmallett priv->ifp = ifp; 344210311Sjmallett priv->init = cvm_oct_common_init; 345210311Sjmallett priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED; 346210311Sjmallett priv->port = CVMX_PIP_NUM_INPUT_PORTS; 347210311Sjmallett priv->queue = -1; 348210311Sjmallett 349210311Sjmallett device_set_desc(dev, "Cavium Octeon POW Ethernet\n"); 350210311Sjmallett 351210311Sjmallett ifp->if_softc = priv; 352210311Sjmallett 353210311Sjmallett if (priv->init(ifp) < 0) { 354210311Sjmallett printf("\t\tFailed to register ethernet device for POW\n"); 355210311Sjmallett panic("%s: need to free ifp.", __func__); 356210311Sjmallett } else { 357210311Sjmallett cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = ifp; 358210311Sjmallett printf("\t\t%s: POW send group %d, receive group %d\n", 359210311Sjmallett if_name(ifp), pow_send_group, pow_receive_group); 360210311Sjmallett } 361210311Sjmallett } else { 362210311Sjmallett printf("\t\tFailed to allocate ethernet device for POW\n"); 363210311Sjmallett } 364210311Sjmallett } 365210311Sjmallett 366210311Sjmallett ifnum = 0; 367210311Sjmallett num_interfaces = cvmx_helper_get_number_of_interfaces(); 368210311Sjmallett for (interface = 0; interface < num_interfaces; interface++) { 369210311Sjmallett cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface); 370210311Sjmallett int num_ports = cvmx_helper_ports_on_interface(interface); 371210311Sjmallett int port; 372210311Sjmallett 373210311Sjmallett for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) { 374210311Sjmallett cvm_oct_private_t *priv; 375210311Sjmallett struct ifnet *ifp; 376210311Sjmallett 377210311Sjmallett dev = BUS_ADD_CHILD(bus, 0, "octe", ifnum++); 378210311Sjmallett if (dev != NULL) 379210311Sjmallett ifp = if_alloc(IFT_ETHER); 380210311Sjmallett if (dev == NULL || ifp == NULL) { 381210311Sjmallett printf("\t\tFailed to allocate ethernet device for port %d\n", port); 382210311Sjmallett continue; 383210311Sjmallett } 384210311Sjmallett /* XXX/juli set max send q len. */ 385210311Sjmallett#if 0 386210311Sjmallett if (disable_core_queueing) 387210311Sjmallett ifp->tx_queue_len = 0; 388210311Sjmallett#endif 389210311Sjmallett 390210311Sjmallett /* Initialize the device private structure. */ 391210311Sjmallett device_probe(dev); 392210311Sjmallett priv = device_get_softc(dev); 393210311Sjmallett priv->dev = dev; 394210311Sjmallett priv->ifp = ifp; 395210311Sjmallett priv->imode = imode; 396210311Sjmallett priv->port = port; 397210311Sjmallett priv->queue = cvmx_pko_get_base_queue(priv->port); 398210311Sjmallett priv->fau = fau - cvmx_pko_get_num_queues(port) * 4; 399210311Sjmallett for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++) 400210311Sjmallett cvmx_fau_atomic_write32(priv->fau+qos*4, 0); 401210311Sjmallett 402210311Sjmallett switch (priv->imode) { 403210311Sjmallett 404210311Sjmallett /* These types don't support ports to IPD/PKO */ 405210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_DISABLED: 406210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_PCIE: 407210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_PICMG: 408210311Sjmallett break; 409210311Sjmallett 410210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_NPI: 411210311Sjmallett priv->init = cvm_oct_common_init; 412210311Sjmallett priv->uninit = cvm_oct_common_uninit; 413210311Sjmallett device_set_desc(dev, "Cavium Octeon NPI Ethernet"); 414210311Sjmallett break; 415210311Sjmallett 416210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_XAUI: 417210311Sjmallett priv->init = cvm_oct_xaui_init; 418210311Sjmallett priv->uninit = cvm_oct_xaui_uninit; 419210311Sjmallett device_set_desc(dev, "Cavium Octeon XAUI Ethernet"); 420210311Sjmallett break; 421210311Sjmallett 422210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_LOOP: 423210311Sjmallett priv->init = cvm_oct_common_init; 424210311Sjmallett priv->uninit = cvm_oct_common_uninit; 425210311Sjmallett device_set_desc(dev, "Cavium Octeon LOOP Ethernet"); 426210311Sjmallett break; 427210311Sjmallett 428210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_SGMII: 429210311Sjmallett priv->init = cvm_oct_sgmii_init; 430210311Sjmallett priv->uninit = cvm_oct_sgmii_uninit; 431210311Sjmallett device_set_desc(dev, "Cavium Octeon SGMII Ethernet"); 432210311Sjmallett break; 433210311Sjmallett 434210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_SPI: 435210311Sjmallett priv->init = cvm_oct_spi_init; 436210311Sjmallett priv->uninit = cvm_oct_spi_uninit; 437210311Sjmallett device_set_desc(dev, "Cavium Octeon SPI Ethernet"); 438210311Sjmallett break; 439210311Sjmallett 440210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_RGMII: 441210311Sjmallett priv->init = cvm_oct_rgmii_init; 442210311Sjmallett priv->uninit = cvm_oct_rgmii_uninit; 443210311Sjmallett device_set_desc(dev, "Cavium Octeon RGMII Ethernet"); 444210311Sjmallett break; 445210311Sjmallett 446210311Sjmallett case CVMX_HELPER_INTERFACE_MODE_GMII: 447210311Sjmallett priv->init = cvm_oct_rgmii_init; 448210311Sjmallett priv->uninit = cvm_oct_rgmii_uninit; 449210311Sjmallett device_set_desc(dev, "Cavium Octeon GMII Ethernet"); 450210311Sjmallett break; 451210311Sjmallett } 452210311Sjmallett 453210311Sjmallett ifp->if_softc = priv; 454210311Sjmallett 455210311Sjmallett if (!priv->init) { 456210311Sjmallett panic("%s: unsupported device type, need to free ifp.", __func__); 457210311Sjmallett } else 458210311Sjmallett if (priv->init(ifp) < 0) { 459210311Sjmallett printf("\t\tFailed to register ethernet device for interface %d, port %d\n", 460210311Sjmallett interface, priv->port); 461210311Sjmallett panic("%s: init failed, need to free ifp.", __func__); 462210311Sjmallett } else { 463210311Sjmallett cvm_oct_device[priv->port] = ifp; 464210311Sjmallett fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t); 465210311Sjmallett } 466210311Sjmallett } 467210311Sjmallett } 468210311Sjmallett 469210311Sjmallett if (INTERRUPT_LIMIT) { 470210311Sjmallett /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */ 471210311Sjmallett cvmx_write_csr(CVMX_POW_WQ_INT_PC, octeon_bootinfo->eclock_hz/(INTERRUPT_LIMIT*16*256)<<8); 472210311Sjmallett 473210311Sjmallett /* Enable POW timer interrupt. It will count when there are packets available */ 474210311Sjmallett cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24); 475210311Sjmallett } else { 476210311Sjmallett /* Enable POW interrupt when our port has at least one packet */ 477210311Sjmallett cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001); 478210311Sjmallett } 479210311Sjmallett 480210311Sjmallett callout_init(&cvm_oct_poll_timer, CALLOUT_MPSAFE); 481210311Sjmallett callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); 482210311Sjmallett 483210311Sjmallett return 0; 484210311Sjmallett} 485210311Sjmallett 486210311Sjmallett 487210311Sjmallett/** 488210311Sjmallett * Module / driver shutdown 489210311Sjmallett * 490210311Sjmallett * @return Zero on success 491210311Sjmallett */ 492210311Sjmallettvoid cvm_oct_cleanup_module(void) 493210311Sjmallett{ 494210311Sjmallett int port; 495210311Sjmallett 496210311Sjmallett /* Disable POW interrupt */ 497210311Sjmallett cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); 498210311Sjmallett 499210311Sjmallett cvmx_ipd_disable(); 500210311Sjmallett 501210311Sjmallett#if 0 502210311Sjmallett /* Free the interrupt handler */ 503210311Sjmallett free_irq(8 + pow_receive_group, cvm_oct_device); 504210311Sjmallett#endif 505210311Sjmallett 506210311Sjmallett callout_stop(&cvm_oct_poll_timer); 507210311Sjmallett cvm_oct_rx_shutdown(); 508210311Sjmallett cvmx_pko_disable(); 509210311Sjmallett 510210311Sjmallett /* Free the ethernet devices */ 511210311Sjmallett for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) { 512210311Sjmallett if (cvm_oct_device[port]) { 513210311Sjmallett cvm_oct_tx_shutdown(cvm_oct_device[port]); 514210311Sjmallett#if 0 515210311Sjmallett unregister_netdev(cvm_oct_device[port]); 516210311Sjmallett kfree(cvm_oct_device[port]); 517210311Sjmallett#else 518210311Sjmallett panic("%s: need to detach and free interface.", __func__); 519210311Sjmallett#endif 520210311Sjmallett cvm_oct_device[port] = NULL; 521210311Sjmallett } 522210311Sjmallett } 523210311Sjmallett 524210311Sjmallett cvmx_pko_shutdown(); 525210311Sjmallett#if 0 526210311Sjmallett cvm_oct_proc_shutdown(); 527210311Sjmallett#endif 528210311Sjmallett 529210311Sjmallett cvmx_ipd_free_ptr(); 530210311Sjmallett 531210311Sjmallett /* Free the HW pools */ 532210311Sjmallett cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers); 533210311Sjmallett cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers); 534210311Sjmallett if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) 535210311Sjmallett cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); 536210311Sjmallett} 537