ethernet.c revision 213150
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 213150 2010-09-25 01:18:01Z jmallett $"); 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 77int pow_send_group = -1; /* XXX Should be a sysctl. */ 78TUNABLE_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 84int always_use_pow; 85TUNABLE_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 96char pow_send_list[128] = ""; 97TUNABLE_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 107static int disable_core_queueing = 1; 108TUNABLE_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 114extern 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 */ 120extern cvmx_bootinfo_t *octeon_bootinfo; 121 122/** 123 * Periodic timer to check auto negotiation 124 */ 125static 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 */ 131struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS]; 132 133/** 134 * Task to handle link status changes. 135 */ 136static struct taskqueue *cvm_oct_link_taskq; 137 138/** 139 * Function to update link status. 140 */ 141static 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 */ 173static void cvm_do_timer(void *arg) 174{ 175 static int port; 176 if (port < CVMX_PIP_NUM_INPUT_PORTS) { 177 if (cvm_oct_device[port]) { 178 int queues_per_port; 179 int qos; 180 cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc; 181 if (priv->poll) 182 { 183 /* skip polling if we don't get the lock */ 184 if (MDIO_TRYLOCK()) { 185 priv->poll(cvm_oct_device[port]); 186 MDIO_UNLOCK(); 187 188 if (priv->need_link_update) { 189 taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task); 190 } 191 } 192 } 193 194 queues_per_port = cvmx_pko_get_num_queues(port); 195 /* Drain any pending packets in the free list */ 196 for (qos = 0; qos < queues_per_port; qos++) { 197 if (_IF_QLEN(&priv->tx_free_queue[qos]) > 0) { 198 IF_LOCK(&priv->tx_free_queue[qos]); 199 while (_IF_QLEN(&priv->tx_free_queue[qos]) > cvmx_fau_fetch_and_add32(priv->fau+qos*4, 0)) { 200 struct mbuf *m; 201 202 _IF_DEQUEUE(&priv->tx_free_queue[qos], m); 203 m_freem(m); 204 } 205 IF_UNLOCK(&priv->tx_free_queue[qos]); 206 207 /* 208 * XXX locking! 209 */ 210 priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 211 } 212 } 213#if 0 214 cvm_oct_device[port]->get_stats(cvm_oct_device[port]); 215#endif 216 } 217 port++; 218 /* Poll the next port in a 50th of a second. 219 This spreads the polling of ports out a little bit */ 220 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL); 221 } else { 222 port = 0; 223 /* All ports have been polled. Start the next iteration through 224 the ports in one second */ 225 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); 226 } 227} 228 229 230/** 231 * Configure common hardware for all interfaces 232 */ 233static void cvm_oct_configure_common_hw(device_t bus) 234{ 235 struct octebus_softc *sc; 236 int error; 237 int rid; 238 239 sc = device_get_softc(bus); 240 241 /* Setup the FPA */ 242 cvmx_fpa_enable(); 243 cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers); 244 cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers); 245 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) 246 cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); 247 248 if (USE_RED) 249 cvmx_helper_setup_red(num_packet_buffers/4, num_packet_buffers/8); 250 251 /* Enable the MII interface */ 252 if (!octeon_is_simulation()) 253 cvmx_write_csr(CVMX_SMI_EN, 1); 254 255 /* Register an IRQ hander for to receive POW interrupts */ 256 rid = 0; 257 sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid, 258 CVMX_IRQ_WORKQ0 + pow_receive_group, 259 CVMX_IRQ_WORKQ0 + pow_receive_group, 260 1, RF_ACTIVE); 261 if (sc->sc_rx_irq == NULL) { 262 device_printf(bus, "could not allocate workq irq"); 263 return; 264 } 265 266 error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE, 267 cvm_oct_do_interrupt, NULL, cvm_oct_device, 268 NULL); 269 if (error != 0) { 270 device_printf(bus, "could not setup workq irq"); 271 return; 272 } 273 274 275#ifdef SMP 276 if (USE_MULTICORE_RECEIVE) { 277 critical_enter(); 278 { 279 int cpu; 280 for (cpu = 0; cpu < mp_maxid; cpu++) { 281 if (!CPU_ABSENT(cpu) && 282 (cpu != PCPU_GET(cpuid))) { 283 cvmx_ciu_intx0_t en; 284 en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(cpu*2)); 285 en.s.workq |= (1<<pow_receive_group); 286 cvmx_write_csr(CVMX_CIU_INTX_EN0(cpu*2), en.u64); 287 } 288 } 289 } 290 critical_exit(); 291 } 292#endif 293} 294 295 296/** 297 * Free a work queue entry received in a intercept callback. 298 * 299 * @param work_queue_entry 300 * Work queue entry to free 301 * @return Zero on success, Negative on failure. 302 */ 303int cvm_oct_free_work(void *work_queue_entry) 304{ 305 cvmx_wqe_t *work = work_queue_entry; 306 307 int segments = work->word2.s.bufs; 308 cvmx_buf_ptr_t segment_ptr = work->packet_ptr; 309 310 while (segments--) { 311 cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8); 312 if (__predict_false(!segment_ptr.s.i)) 313 cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128)); 314 segment_ptr = next_ptr; 315 } 316 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); 317 318 return 0; 319} 320 321 322/** 323 * Module/ driver initialization. Creates the linux network 324 * devices. 325 * 326 * @return Zero on success 327 */ 328int cvm_oct_init_module(device_t bus) 329{ 330 device_t dev; 331 int ifnum; 332 int num_interfaces; 333 int interface; 334 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; 335 int qos; 336 337 printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING); 338 339#if 0 340 cvm_oct_proc_initialize(); 341#endif 342 cvm_oct_rx_initialize(); 343 cvm_oct_configure_common_hw(bus); 344 345 cvmx_helper_initialize_packet_io_global(); 346 347 /* Change the input group for all ports before input is enabled */ 348 num_interfaces = cvmx_helper_get_number_of_interfaces(); 349 for (interface = 0; interface < num_interfaces; interface++) { 350 int num_ports = cvmx_helper_ports_on_interface(interface); 351 int port; 352 353 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) { 354 cvmx_pip_prt_tagx_t pip_prt_tagx; 355 pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(port)); 356 pip_prt_tagx.s.grp = pow_receive_group; 357 cvmx_write_csr(CVMX_PIP_PRT_TAGX(port), pip_prt_tagx.u64); 358 } 359 } 360 361 cvmx_helper_ipd_and_packet_input_enable(); 362 363 memset(cvm_oct_device, 0, sizeof(cvm_oct_device)); 364 365 cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT, 366 taskqueue_thread_enqueue, &cvm_oct_link_taskq); 367 taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET, 368 "octe link taskq"); 369 370 /* Initialize the FAU used for counting packet buffers that need to be freed */ 371 cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); 372 373 if ((pow_send_group != -1)) { 374 struct ifnet *ifp; 375 376 printf("\tConfiguring device for POW only access\n"); 377 dev = BUS_ADD_CHILD(bus, 0, "pow", 0); 378 if (dev != NULL) 379 ifp = if_alloc(IFT_ETHER); 380 if (dev != NULL && ifp != NULL) { 381 /* Initialize the device private structure. */ 382 cvm_oct_private_t *priv; 383 384 device_probe(dev); 385 priv = device_get_softc(dev); 386 priv->dev = dev; 387 priv->ifp = ifp; 388 priv->init = cvm_oct_common_init; 389 priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED; 390 priv->port = CVMX_PIP_NUM_INPUT_PORTS; 391 priv->queue = -1; 392 TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv); 393 394 device_set_desc(dev, "Cavium Octeon POW Ethernet\n"); 395 396 ifp->if_softc = priv; 397 398 if (priv->init(ifp) < 0) { 399 printf("\t\tFailed to register ethernet device for POW\n"); 400 panic("%s: need to free ifp.", __func__); 401 } else { 402 cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = ifp; 403 printf("\t\t%s: POW send group %d, receive group %d\n", 404 if_name(ifp), pow_send_group, pow_receive_group); 405 } 406 } else { 407 printf("\t\tFailed to allocate ethernet device for POW\n"); 408 } 409 } 410 411 ifnum = 0; 412 num_interfaces = cvmx_helper_get_number_of_interfaces(); 413 for (interface = 0; interface < num_interfaces; interface++) { 414 cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface); 415 int num_ports = cvmx_helper_ports_on_interface(interface); 416 int port; 417 418 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) { 419 cvm_oct_private_t *priv; 420 struct ifnet *ifp; 421 422 dev = BUS_ADD_CHILD(bus, 0, "octe", ifnum++); 423 if (dev != NULL) 424 ifp = if_alloc(IFT_ETHER); 425 if (dev == NULL || ifp == NULL) { 426 printf("\t\tFailed to allocate ethernet device for port %d\n", port); 427 continue; 428 } 429 /* XXX/juli set max send q len. */ 430#if 0 431 if (disable_core_queueing) 432 ifp->tx_queue_len = 0; 433#endif 434 435 /* Initialize the device private structure. */ 436 device_probe(dev); 437 priv = device_get_softc(dev); 438 priv->dev = dev; 439 priv->ifp = ifp; 440 priv->imode = imode; 441 priv->port = port; 442 priv->queue = cvmx_pko_get_base_queue(priv->port); 443 priv->fau = fau - cvmx_pko_get_num_queues(port) * 4; 444 for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++) 445 cvmx_fau_atomic_write32(priv->fau+qos*4, 0); 446 TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv); 447 448 switch (priv->imode) { 449 450 /* These types don't support ports to IPD/PKO */ 451 case CVMX_HELPER_INTERFACE_MODE_DISABLED: 452 case CVMX_HELPER_INTERFACE_MODE_PCIE: 453 case CVMX_HELPER_INTERFACE_MODE_PICMG: 454 break; 455 456 case CVMX_HELPER_INTERFACE_MODE_NPI: 457 priv->init = cvm_oct_common_init; 458 priv->uninit = cvm_oct_common_uninit; 459 device_set_desc(dev, "Cavium Octeon NPI Ethernet"); 460 break; 461 462 case CVMX_HELPER_INTERFACE_MODE_XAUI: 463 priv->init = cvm_oct_xaui_init; 464 priv->uninit = cvm_oct_xaui_uninit; 465 device_set_desc(dev, "Cavium Octeon XAUI Ethernet"); 466 break; 467 468 case CVMX_HELPER_INTERFACE_MODE_LOOP: 469 priv->init = cvm_oct_common_init; 470 priv->uninit = cvm_oct_common_uninit; 471 device_set_desc(dev, "Cavium Octeon LOOP Ethernet"); 472 break; 473 474 case CVMX_HELPER_INTERFACE_MODE_SGMII: 475 priv->init = cvm_oct_sgmii_init; 476 priv->uninit = cvm_oct_sgmii_uninit; 477 device_set_desc(dev, "Cavium Octeon SGMII Ethernet"); 478 break; 479 480 case CVMX_HELPER_INTERFACE_MODE_SPI: 481 priv->init = cvm_oct_spi_init; 482 priv->uninit = cvm_oct_spi_uninit; 483 device_set_desc(dev, "Cavium Octeon SPI Ethernet"); 484 break; 485 486 case CVMX_HELPER_INTERFACE_MODE_RGMII: 487 priv->init = cvm_oct_rgmii_init; 488 priv->uninit = cvm_oct_rgmii_uninit; 489 device_set_desc(dev, "Cavium Octeon RGMII Ethernet"); 490 break; 491 492 case CVMX_HELPER_INTERFACE_MODE_GMII: 493 priv->init = cvm_oct_rgmii_init; 494 priv->uninit = cvm_oct_rgmii_uninit; 495 device_set_desc(dev, "Cavium Octeon GMII Ethernet"); 496 break; 497 } 498 499 ifp->if_softc = priv; 500 501 if (!priv->init) { 502 panic("%s: unsupported device type, need to free ifp.", __func__); 503 } else 504 if (priv->init(ifp) < 0) { 505 printf("\t\tFailed to register ethernet device for interface %d, port %d\n", 506 interface, priv->port); 507 panic("%s: init failed, need to free ifp.", __func__); 508 } else { 509 cvm_oct_device[priv->port] = ifp; 510 fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t); 511 } 512 } 513 } 514 515 if (INTERRUPT_LIMIT) { 516 /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */ 517 cvmx_write_csr(CVMX_POW_WQ_INT_PC, octeon_bootinfo->eclock_hz/(INTERRUPT_LIMIT*16*256)<<8); 518 519 /* Enable POW timer interrupt. It will count when there are packets available */ 520 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24); 521 } else { 522 /* Enable POW interrupt when our port has at least one packet */ 523 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001); 524 } 525 526 callout_init(&cvm_oct_poll_timer, CALLOUT_MPSAFE); 527 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); 528 529 return 0; 530} 531 532 533/** 534 * Module / driver shutdown 535 * 536 * @return Zero on success 537 */ 538void cvm_oct_cleanup_module(void) 539{ 540 int port; 541 542 /* Disable POW interrupt */ 543 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); 544 545 cvmx_ipd_disable(); 546 547#if 0 548 /* Free the interrupt handler */ 549 free_irq(8 + pow_receive_group, cvm_oct_device); 550#endif 551 552 callout_stop(&cvm_oct_poll_timer); 553 cvm_oct_rx_shutdown(); 554 cvmx_pko_disable(); 555 556 /* Free the ethernet devices */ 557 for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) { 558 if (cvm_oct_device[port]) { 559 cvm_oct_tx_shutdown(cvm_oct_device[port]); 560#if 0 561 unregister_netdev(cvm_oct_device[port]); 562 kfree(cvm_oct_device[port]); 563#else 564 panic("%s: need to detach and free interface.", __func__); 565#endif 566 cvm_oct_device[port] = NULL; 567 } 568 } 569 570 cvmx_pko_shutdown(); 571#if 0 572 cvm_oct_proc_shutdown(); 573#endif 574 575 cvmx_ipd_free_ptr(); 576 577 /* Free the HW pools */ 578 cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers); 579 cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers); 580 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) 581 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); 582} 583