The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/cavium/octe/ethernet.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*************************************************************************
    2 Copyright (c) 2003-2007  Cavium Networks (support@cavium.com). All rights
    3 reserved.
    4 
    5 
    6 Redistribution and use in source and binary forms, with or without
    7 modification, are permitted provided that the following conditions are
    8 met:
    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 
   23 This 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 
   25 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
   26 AND 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: releng/8.4/sys/mips/cavium/octe/ethernet.c 215938 2010-11-27 12:26:40Z jchandra $");
   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
   59 int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS;
   60 #else
   61 int num_packet_buffers = 1024;
   62 #endif
   63 TUNABLE_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 
   69 int pow_receive_group = 15;
   70 TUNABLE_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 
   77 int pow_send_group = -1; /* XXX Should be a sysctl.  */
   78 TUNABLE_INT("hw.octe.pow_send_group", &pow_send_group);
   79 /*
   80                  "\t\tPOW group to send packets to other software on. This\n"
   81                  "\t\tcontrols the creation of the virtual device pow0.\n"
   82                  "\t\talways_use_pow also depends on this value." */
   83 
   84 int always_use_pow;
   85 TUNABLE_INT("hw.octe.always_use_pow", &always_use_pow);
   86 /*
   87                  "\t\tWhen set, always send to the pow group. This will cause\n"
   88                  "\t\tpackets sent to real ethernet devices to be sent to the\n"
   89                  "\t\tPOW group instead of the hardware. Unless some other\n"
   90                  "\t\tapplication changes the config, packets will still be\n"
   91                  "\t\treceived from the low level hardware. Use this option\n"
   92                  "\t\tto allow a CVMX app to intercept all packets from the\n"
   93                  "\t\tlinux kernel. You must specify pow_send_group along with\n"
   94                  "\t\tthis option." */
   95 
   96 char pow_send_list[128] = "";
   97 TUNABLE_STR("hw.octe.pow_send_list", pow_send_list, sizeof pow_send_list);
   98 /*
   99                  "\t\tComma separated list of ethernet devices that should use the\n"
  100                  "\t\tPOW for transmit instead of the actual ethernet hardware. This\n"
  101                  "\t\tis a per port version of always_use_pow. always_use_pow takes\n"
  102                  "\t\tprecedence over this list. For example, setting this to\n"
  103                  "\t\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n"
  104                  "\t\tusing the pow_send_group." */
  105 
  106 
  107 static int disable_core_queueing = 1;
  108 TUNABLE_INT("hw.octe.disable_core_queueing", &disable_core_queueing);
  109 /*
  110                 "\t\tWhen set the networking core's tx_queue_len is set to zero.  This\n"
  111                 "\t\tallows packets to be sent without lock contention in the packet scheduler\n"
  112                 "\t\tresulting in some cases in improved throughput.\n" */
  113 
  114 extern int octeon_is_simulation(void);
  115 
  116 /**
  117  * Exported from the kernel so we can determine board information. It is
  118  * passed by the bootloader to the kernel.
  119  */
  120 extern cvmx_bootinfo_t *octeon_bootinfo;
  121 
  122 /**
  123  * Periodic timer to check auto negotiation
  124  */
  125 static struct callout cvm_oct_poll_timer;
  126 
  127 /**
  128  * Array of every ethernet device owned by this driver indexed by
  129  * the ipd input port number.
  130  */
  131 struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
  132 
  133 /**
  134  * Task to handle link status changes.
  135  */
  136 static struct taskqueue *cvm_oct_link_taskq;
  137 
  138 /**
  139  * Function to update link status.
  140  */
  141 static void cvm_oct_update_link(void *context, int pending)
  142 {
  143         cvm_oct_private_t *priv = (cvm_oct_private_t *)context;
  144         struct ifnet *ifp = priv->ifp;
  145         cvmx_helper_link_info_t link_info;
  146 
  147         link_info.u64 = priv->link_info;
  148 
  149         if (link_info.s.link_up) {
  150                 if_link_state_change(ifp, LINK_STATE_UP);
  151                 if (priv->queue != -1)
  152                         DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
  153                                    if_name(ifp), link_info.s.speed,
  154                                    (link_info.s.full_duplex) ? "Full" : "Half",
  155                                    priv->port, priv->queue);
  156                 else
  157                         DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n",
  158                                    if_name(ifp), link_info.s.speed,
  159                                    (link_info.s.full_duplex) ? "Full" : "Half",
  160                                    priv->port);
  161         } else {
  162                 if_link_state_change(ifp, LINK_STATE_DOWN);
  163                 DEBUGPRINT("%s: Link down\n", if_name(ifp));
  164         }
  165         priv->need_link_update = 0;
  166 }
  167 
  168 /**
  169  * Periodic timer tick for slow management operations
  170  *
  171  * @param arg    Device to check
  172  */
  173 static void cvm_do_timer(void *arg)
  174 {
  175         static int port;
  176         static int updated;
  177         if (port < CVMX_PIP_NUM_INPUT_PORTS) {
  178                 if (cvm_oct_device[port]) {
  179                         int queues_per_port;
  180                         int qos;
  181                         cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc;
  182                         if (priv->poll) 
  183                         {
  184                                 /* skip polling if we don't get the lock */
  185                                 if (MDIO_TRYLOCK()) {
  186                                         priv->poll(cvm_oct_device[port]);
  187                                         MDIO_UNLOCK();
  188 
  189                                         if (priv->need_link_update) {
  190                                                 updated++;
  191                                                 taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task);
  192                                         }
  193                                 }
  194                         }
  195 
  196                         queues_per_port = cvmx_pko_get_num_queues(port);
  197                         /* Drain any pending packets in the free list */
  198                         for (qos = 0; qos < queues_per_port; qos++) {
  199                                 if (_IF_QLEN(&priv->tx_free_queue[qos]) > 0) {
  200                                         IF_LOCK(&priv->tx_free_queue[qos]);
  201                                         while (_IF_QLEN(&priv->tx_free_queue[qos]) > cvmx_fau_fetch_and_add32(priv->fau+qos*4, 0)) {
  202                                                 struct mbuf *m;
  203 
  204                                                 _IF_DEQUEUE(&priv->tx_free_queue[qos], m);
  205                                                 m_freem(m);
  206                                         }
  207                                         IF_UNLOCK(&priv->tx_free_queue[qos]);
  208 
  209                                         /*
  210                                          * XXX locking!
  211                                          */
  212                                         priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  213                                 }
  214                         }
  215 #if 0
  216                         cvm_oct_device[port]->get_stats(cvm_oct_device[port]);
  217 #endif
  218                 }
  219                 port++;
  220                 /* Poll the next port in a 50th of a second.
  221                    This spreads the polling of ports out a little bit */
  222                 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
  223         } else {
  224                 port = 0;
  225                 /* If any updates were made in this run, continue iterating at
  226                  * 1/50th of a second, so that if a link has merely gone down
  227                  * temporarily (e.g. because of interface reinitialization) it
  228                  * will not be forced to stay down for an entire second.
  229                  */
  230                 if (updated > 0) {
  231                         updated = 0;
  232                         callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
  233                 } else {
  234                         /* All ports have been polled. Start the next iteration through
  235                            the ports in one second */
  236                         callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
  237                 }
  238         }
  239 }
  240 
  241 
  242 /**
  243  * Configure common hardware for all interfaces
  244  */
  245 static void cvm_oct_configure_common_hw(device_t bus)
  246 {
  247         struct octebus_softc *sc;
  248         int error;
  249         int rid;
  250 
  251         sc = device_get_softc(bus);
  252 
  253         /* Setup the FPA */
  254         cvmx_fpa_enable();
  255         cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
  256         cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
  257         if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
  258                 cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
  259 
  260         if (USE_RED)
  261                 cvmx_helper_setup_red(num_packet_buffers/4, num_packet_buffers/8);
  262 
  263         /* Enable the MII interface */
  264         if (!octeon_is_simulation())
  265                 cvmx_write_csr(CVMX_SMI_EN, 1);
  266 
  267         /* Register an IRQ hander for to receive POW interrupts */
  268         rid = 0;
  269         sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid,
  270                                            CVMX_IRQ_WORKQ0 + pow_receive_group,
  271                                            CVMX_IRQ_WORKQ0 + pow_receive_group,
  272                                            1, RF_ACTIVE);
  273         if (sc->sc_rx_irq == NULL) {
  274                 device_printf(bus, "could not allocate workq irq");
  275                 return;
  276         }
  277 
  278         error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
  279                                cvm_oct_do_interrupt, NULL, cvm_oct_device,
  280                                NULL);
  281         if (error != 0) {
  282                 device_printf(bus, "could not setup workq irq");
  283                 return;
  284         }
  285 
  286 
  287 #ifdef SMP
  288         if (USE_MULTICORE_RECEIVE) {
  289                 critical_enter();
  290                 {
  291                         int cpu;
  292                         for (cpu = 0; cpu < mp_maxid; cpu++) {
  293                                 if (!CPU_ABSENT(cpu) &&
  294                                    (cpu != PCPU_GET(cpuid))) {
  295                                         cvmx_ciu_intx0_t en;
  296                                         en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(cpu*2));
  297                                         en.s.workq |= (1<<pow_receive_group);
  298                                         cvmx_write_csr(CVMX_CIU_INTX_EN0(cpu*2), en.u64);
  299                                 }
  300                         }
  301                 }
  302                 critical_exit();
  303         }
  304 #endif
  305 }
  306 
  307 
  308 /**
  309  * Free a work queue entry received in a intercept callback.
  310  *
  311  * @param work_queue_entry
  312  *               Work queue entry to free
  313  * @return Zero on success, Negative on failure.
  314  */
  315 int cvm_oct_free_work(void *work_queue_entry)
  316 {
  317         cvmx_wqe_t *work = work_queue_entry;
  318 
  319         int segments = work->word2.s.bufs;
  320         cvmx_buf_ptr_t segment_ptr = work->packet_ptr;
  321 
  322         while (segments--) {
  323                 cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8);
  324                 if (__predict_false(!segment_ptr.s.i))
  325                         cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128));
  326                 segment_ptr = next_ptr;
  327         }
  328         cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
  329 
  330         return 0;
  331 }
  332 
  333 
  334 /**
  335  * Module/ driver initialization. Creates the linux network
  336  * devices.
  337  *
  338  * @return Zero on success
  339  */
  340 int cvm_oct_init_module(device_t bus)
  341 {
  342         device_t dev;
  343         int ifnum;
  344         int num_interfaces;
  345         int interface;
  346         int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
  347         int qos;
  348 
  349         printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING);
  350 
  351 #if 0
  352         cvm_oct_proc_initialize();
  353 #endif
  354         cvm_oct_rx_initialize();
  355         cvm_oct_configure_common_hw(bus);
  356 
  357         cvmx_helper_initialize_packet_io_global();
  358 
  359         /* Change the input group for all ports before input is enabled */
  360         num_interfaces = cvmx_helper_get_number_of_interfaces();
  361         for (interface = 0; interface < num_interfaces; interface++) {
  362                 int num_ports = cvmx_helper_ports_on_interface(interface);
  363                 int port;
  364 
  365                 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
  366                         cvmx_pip_prt_tagx_t pip_prt_tagx;
  367                         pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(port));
  368                         pip_prt_tagx.s.grp = pow_receive_group;
  369                         cvmx_write_csr(CVMX_PIP_PRT_TAGX(port), pip_prt_tagx.u64);
  370                 }
  371         }
  372 
  373         cvmx_helper_ipd_and_packet_input_enable();
  374 
  375         memset(cvm_oct_device, 0, sizeof(cvm_oct_device));
  376 
  377         cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT,
  378             taskqueue_thread_enqueue, &cvm_oct_link_taskq);
  379         taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET,
  380             "octe link taskq");
  381 
  382         /* Initialize the FAU used for counting packet buffers that need to be freed */
  383         cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
  384 
  385         if ((pow_send_group != -1)) {
  386                 struct ifnet *ifp;
  387 
  388                 printf("\tConfiguring device for POW only access\n");
  389                 dev = BUS_ADD_CHILD(bus, 0, "pow", 0);
  390                 if (dev != NULL)
  391                         ifp = if_alloc(IFT_ETHER);
  392                 if (dev != NULL && ifp != NULL) {
  393                         /* Initialize the device private structure. */
  394                         cvm_oct_private_t *priv;
  395 
  396                         device_probe(dev);
  397                         priv = device_get_softc(dev);
  398                         priv->dev = dev;
  399                         priv->ifp = ifp;
  400                         priv->init = cvm_oct_common_init;
  401                         priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
  402                         priv->port = CVMX_PIP_NUM_INPUT_PORTS;
  403                         priv->queue = -1;
  404                         TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv);
  405 
  406                         device_set_desc(dev, "Cavium Octeon POW Ethernet\n");
  407 
  408                         ifp->if_softc = priv;
  409 
  410                         if (priv->init(ifp) < 0) {
  411                                 printf("\t\tFailed to register ethernet device for POW\n");
  412                                 panic("%s: need to free ifp.", __func__);
  413                         } else {
  414                                 cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = ifp;
  415                                 printf("\t\t%s: POW send group %d, receive group %d\n",
  416                                 if_name(ifp), pow_send_group, pow_receive_group);
  417                         }
  418                 } else {
  419                         printf("\t\tFailed to allocate ethernet device for POW\n");
  420                 }
  421         }
  422 
  423         ifnum = 0;
  424         num_interfaces = cvmx_helper_get_number_of_interfaces();
  425         for (interface = 0; interface < num_interfaces; interface++) {
  426                 cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface);
  427                 int num_ports = cvmx_helper_ports_on_interface(interface);
  428                 int port;
  429 
  430                 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
  431                         cvm_oct_private_t *priv;
  432                         struct ifnet *ifp;
  433                         
  434                         dev = BUS_ADD_CHILD(bus, 0, "octe", ifnum++);
  435                         if (dev != NULL)
  436                                 ifp = if_alloc(IFT_ETHER);
  437                         if (dev == NULL || ifp == NULL) {
  438                                 printf("\t\tFailed to allocate ethernet device for port %d\n", port);
  439                                 continue;
  440                         }
  441                         /* XXX/juli set max send q len.  */
  442 #if 0
  443                         if (disable_core_queueing)
  444                                 ifp->tx_queue_len = 0;
  445 #endif
  446 
  447                         /* Initialize the device private structure. */
  448                         device_probe(dev);
  449                         priv = device_get_softc(dev);
  450                         priv->dev = dev;
  451                         priv->ifp = ifp;
  452                         priv->imode = imode;
  453                         priv->port = port;
  454                         priv->queue = cvmx_pko_get_base_queue(priv->port);
  455                         priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
  456                         for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++)
  457                                 cvmx_fau_atomic_write32(priv->fau+qos*4, 0);
  458                         TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv);
  459 
  460                         switch (priv->imode) {
  461 
  462                         /* These types don't support ports to IPD/PKO */
  463                         case CVMX_HELPER_INTERFACE_MODE_DISABLED:
  464                         case CVMX_HELPER_INTERFACE_MODE_PCIE:
  465                         case CVMX_HELPER_INTERFACE_MODE_PICMG:
  466                                 break;
  467 
  468                         case CVMX_HELPER_INTERFACE_MODE_NPI:
  469                                 priv->init = cvm_oct_common_init;
  470                                 priv->uninit = cvm_oct_common_uninit;
  471                                 device_set_desc(dev, "Cavium Octeon NPI Ethernet");
  472                                 break;
  473 
  474                         case CVMX_HELPER_INTERFACE_MODE_XAUI:
  475                                 priv->init = cvm_oct_xaui_init;
  476                                 priv->uninit = cvm_oct_xaui_uninit;
  477                                 device_set_desc(dev, "Cavium Octeon XAUI Ethernet");
  478                                 break;
  479 
  480                         case CVMX_HELPER_INTERFACE_MODE_LOOP:
  481                                 priv->init = cvm_oct_common_init;
  482                                 priv->uninit = cvm_oct_common_uninit;
  483                                 device_set_desc(dev, "Cavium Octeon LOOP Ethernet");
  484                                 break;
  485 
  486                         case CVMX_HELPER_INTERFACE_MODE_SGMII:
  487                                 priv->init = cvm_oct_sgmii_init;
  488                                 priv->uninit = cvm_oct_sgmii_uninit;
  489                                 device_set_desc(dev, "Cavium Octeon SGMII Ethernet");
  490                                 break;
  491 
  492                         case CVMX_HELPER_INTERFACE_MODE_SPI:
  493                                 priv->init = cvm_oct_spi_init;
  494                                 priv->uninit = cvm_oct_spi_uninit;
  495                                 device_set_desc(dev, "Cavium Octeon SPI Ethernet");
  496                                 break;
  497 
  498                         case CVMX_HELPER_INTERFACE_MODE_RGMII:
  499                                 priv->init = cvm_oct_rgmii_init;
  500                                 priv->uninit = cvm_oct_rgmii_uninit;
  501                                 device_set_desc(dev, "Cavium Octeon RGMII Ethernet");
  502                                 break;
  503 
  504                         case CVMX_HELPER_INTERFACE_MODE_GMII:
  505                                 priv->init = cvm_oct_rgmii_init;
  506                                 priv->uninit = cvm_oct_rgmii_uninit;
  507                                 device_set_desc(dev, "Cavium Octeon GMII Ethernet");
  508                                 break;
  509                         }
  510 
  511                         ifp->if_softc = priv;
  512 
  513                         if (!priv->init) {
  514                                 panic("%s: unsupported device type, need to free ifp.", __func__);
  515                         } else
  516                         if (priv->init(ifp) < 0) {
  517                                 printf("\t\tFailed to register ethernet device for interface %d, port %d\n",
  518                                 interface, priv->port);
  519                                 panic("%s: init failed, need to free ifp.", __func__);
  520                         } else {
  521                                 cvm_oct_device[priv->port] = ifp;
  522                                 fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t);
  523                         }
  524                 }
  525         }
  526 
  527         if (INTERRUPT_LIMIT) {
  528                 /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */
  529                 cvmx_write_csr(CVMX_POW_WQ_INT_PC, octeon_bootinfo->eclock_hz/(INTERRUPT_LIMIT*16*256)<<8);
  530 
  531                 /* Enable POW timer interrupt. It will count when there are packets available */
  532                 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24);
  533         } else {
  534                 /* Enable POW interrupt when our port has at least one packet */
  535                 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
  536         }
  537 
  538         callout_init(&cvm_oct_poll_timer, CALLOUT_MPSAFE);
  539         callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
  540 
  541         return 0;
  542 }
  543 
  544 
  545 /**
  546  * Module / driver shutdown
  547  *
  548  * @return Zero on success
  549  */
  550 void cvm_oct_cleanup_module(void)
  551 {
  552         int port;
  553 
  554         /* Disable POW interrupt */
  555         cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0);
  556 
  557         cvmx_ipd_disable();
  558 
  559 #if 0
  560         /* Free the interrupt handler */
  561         free_irq(8 + pow_receive_group, cvm_oct_device);
  562 #endif
  563 
  564         callout_stop(&cvm_oct_poll_timer);
  565         cvm_oct_rx_shutdown();
  566         cvmx_pko_disable();
  567 
  568         /* Free the ethernet devices */
  569         for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
  570                 if (cvm_oct_device[port]) {
  571                         cvm_oct_tx_shutdown(cvm_oct_device[port]);
  572 #if 0
  573                         unregister_netdev(cvm_oct_device[port]);
  574                         kfree(cvm_oct_device[port]);
  575 #else
  576                         panic("%s: need to detach and free interface.", __func__);
  577 #endif
  578                         cvm_oct_device[port] = NULL;
  579                 }
  580         }
  581 
  582         cvmx_pko_shutdown();
  583 #if 0
  584         cvm_oct_proc_shutdown();
  585 #endif
  586 
  587         cvmx_ipd_free_ptr();
  588 
  589         /* Free the HW pools */
  590         cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
  591         cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
  592         if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
  593                 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
  594 }

Cache object: f8b7783a58964adea89928694bae9163


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.