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

Cache object: d10377fa8881cb5855d4f3ea1b1ff42b


[ 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.