diff options
Diffstat (limited to 'usr/src/uts/common/io/ixgbe/ixgbe_buf.c')
-rw-r--r-- | usr/src/uts/common/io/ixgbe/ixgbe_buf.c | 891 |
1 files changed, 891 insertions, 0 deletions
diff --git a/usr/src/uts/common/io/ixgbe/ixgbe_buf.c b/usr/src/uts/common/io/ixgbe/ixgbe_buf.c new file mode 100644 index 0000000000..aa64ad5006 --- /dev/null +++ b/usr/src/uts/common/io/ixgbe/ixgbe_buf.c @@ -0,0 +1,891 @@ +/* + * CDDL HEADER START + * + * Copyright(c) 2007-2008 Intel Corporation. All rights reserved. + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at: + * http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When using or redistributing this file, you may do so under the + * License only. No other modification of this header is permitted. + * + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms of the CDDL. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "ixgbe_sw.h" + +static int ixgbe_alloc_tbd_ring(ixgbe_tx_ring_t *); +static void ixgbe_free_tbd_ring(ixgbe_tx_ring_t *); +static int ixgbe_alloc_rbd_ring(ixgbe_rx_ring_t *); +static void ixgbe_free_rbd_ring(ixgbe_rx_ring_t *); +static int ixgbe_alloc_dma_buffer(ixgbe_t *, dma_buffer_t *, size_t); +static void ixgbe_free_dma_buffer(dma_buffer_t *); +static int ixgbe_alloc_tcb_lists(ixgbe_tx_ring_t *); +static void ixgbe_free_tcb_lists(ixgbe_tx_ring_t *); +static int ixgbe_alloc_rcb_lists(ixgbe_rx_ring_t *); +static void ixgbe_free_rcb_lists(ixgbe_rx_ring_t *); + +#ifdef __sparc +#define IXGBE_DMA_ALIGNMENT 0x0000000000002000ull +#else +#define IXGBE_DMA_ALIGNMENT 0x0000000000001000ull +#endif + +/* + * DMA attributes for tx/rx descriptors. + */ +static ddi_dma_attr_t ixgbe_desc_dma_attr = { + DMA_ATTR_V0, /* version number */ + 0x0000000000000000ull, /* low address */ + 0xFFFFFFFFFFFFFFFFull, /* high address */ + 0x00000000FFFFFFFFull, /* dma counter max */ + IXGBE_DMA_ALIGNMENT, /* alignment */ + 0x00000FFF, /* burst sizes */ + 0x00000001, /* minimum transfer size */ + 0x00000000FFFFFFFFull, /* maximum transfer size */ + 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */ + 1, /* scatter/gather list length */ + 0x00000001, /* granularity */ + DDI_DMA_FLAGERR /* DMA flags */ +}; + +/* + * DMA attributes for tx/rx buffers. + */ +static ddi_dma_attr_t ixgbe_buf_dma_attr = { + DMA_ATTR_V0, /* version number */ + 0x0000000000000000ull, /* low address */ + 0xFFFFFFFFFFFFFFFFull, /* high address */ + 0x00000000FFFFFFFFull, /* dma counter max */ + IXGBE_DMA_ALIGNMENT, /* alignment */ + 0x00000FFF, /* burst sizes */ + 0x00000001, /* minimum transfer size */ + 0x00000000FFFFFFFFull, /* maximum transfer size */ + 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */ + 1, /* scatter/gather list length */ + 0x00000001, /* granularity */ + DDI_DMA_FLAGERR /* DMA flags */ +}; + +/* + * DMA attributes for transmit. + */ +static ddi_dma_attr_t ixgbe_tx_dma_attr = { + DMA_ATTR_V0, /* version number */ + 0x0000000000000000ull, /* low address */ + 0xFFFFFFFFFFFFFFFFull, /* high address */ + 0x00000000FFFFFFFFull, /* dma counter max */ + 1, /* alignment */ + 0x00000FFF, /* burst sizes */ + 0x00000001, /* minimum transfer size */ + 0x00000000FFFFFFFFull, /* maximum transfer size */ + 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */ + MAX_COOKIE, /* scatter/gather list length */ + 0x00000001, /* granularity */ + DDI_DMA_FLAGERR /* DMA flags */ +}; + +/* + * DMA access attributes for descriptors. + */ +static ddi_device_acc_attr_t ixgbe_desc_acc_attr = { + DDI_DEVICE_ATTR_V0, + DDI_STRUCTURE_LE_ACC, + DDI_STRICTORDER_ACC, + DDI_FLAGERR_ACC +}; + +/* + * DMA access attributes for buffers. + */ +static ddi_device_acc_attr_t ixgbe_buf_acc_attr = { + DDI_DEVICE_ATTR_V0, + DDI_NEVERSWAP_ACC, + DDI_STRICTORDER_ACC +}; + +/* + * ixgbe_alloc_dma - Allocate DMA resources for all rx/tx rings. + */ +int +ixgbe_alloc_dma(ixgbe_t *ixgbe) +{ + ixgbe_rx_ring_t *rx_ring; + ixgbe_tx_ring_t *tx_ring; + int i; + + for (i = 0; i < ixgbe->num_rx_rings; i++) { + /* + * Allocate receive desciptor ring and control block lists + */ + rx_ring = &ixgbe->rx_rings[i]; + + if (ixgbe_alloc_rbd_ring(rx_ring) != IXGBE_SUCCESS) + goto alloc_dma_failure; + + if (ixgbe_alloc_rcb_lists(rx_ring) != IXGBE_SUCCESS) + goto alloc_dma_failure; + } + + for (i = 0; i < ixgbe->num_tx_rings; i++) { + /* + * Allocate transmit desciptor ring and control block lists + */ + tx_ring = &ixgbe->tx_rings[i]; + + if (ixgbe_alloc_tbd_ring(tx_ring) != IXGBE_SUCCESS) + goto alloc_dma_failure; + + if (ixgbe_alloc_tcb_lists(tx_ring) != IXGBE_SUCCESS) + goto alloc_dma_failure; + } + + return (IXGBE_SUCCESS); + +alloc_dma_failure: + ixgbe_free_dma(ixgbe); + + return (IXGBE_FAILURE); +} + +/* + * ixgbe_free_dma - Free all the DMA resources of all rx/tx rings. + */ +void +ixgbe_free_dma(ixgbe_t *ixgbe) +{ + ixgbe_rx_ring_t *rx_ring; + ixgbe_tx_ring_t *tx_ring; + int i; + + /* + * Free DMA resources of rx rings + */ + for (i = 0; i < ixgbe->num_rx_rings; i++) { + rx_ring = &ixgbe->rx_rings[i]; + ixgbe_free_rbd_ring(rx_ring); + ixgbe_free_rcb_lists(rx_ring); + } + + /* + * Free DMA resources of tx rings + */ + for (i = 0; i < ixgbe->num_tx_rings; i++) { + tx_ring = &ixgbe->tx_rings[i]; + ixgbe_free_tbd_ring(tx_ring); + ixgbe_free_tcb_lists(tx_ring); + } +} + +/* + * ixgbe_alloc_tbd_ring - Memory allocation for the tx descriptors of one ring. + */ +static int +ixgbe_alloc_tbd_ring(ixgbe_tx_ring_t *tx_ring) +{ + int ret; + size_t size; + size_t len; + uint_t cookie_num; + dev_info_t *devinfo; + ddi_dma_cookie_t cookie; + ixgbe_t *ixgbe = tx_ring->ixgbe; + + devinfo = ixgbe->dip; + size = sizeof (union ixgbe_adv_tx_desc) * tx_ring->ring_size; + + /* + * If tx head write-back is enabled, an extra tbd is allocated + * to save the head write-back value + */ + if (ixgbe->tx_head_wb_enable) { + size += sizeof (union ixgbe_adv_tx_desc); + } + + /* + * Allocate a DMA handle for the transmit descriptor + * memory area. + */ + ret = ddi_dma_alloc_handle(devinfo, &ixgbe_desc_dma_attr, + DDI_DMA_DONTWAIT, NULL, + &tx_ring->tbd_area.dma_handle); + + if (ret != DDI_SUCCESS) { + ixgbe_error(ixgbe, + "Could not allocate tbd dma handle: %x", ret); + tx_ring->tbd_area.dma_handle = NULL; + + return (IXGBE_FAILURE); + } + + /* + * Allocate memory to DMA data to and from the transmit + * descriptors. + */ + ret = ddi_dma_mem_alloc(tx_ring->tbd_area.dma_handle, + size, &ixgbe_desc_acc_attr, DDI_DMA_CONSISTENT, + DDI_DMA_DONTWAIT, NULL, + (caddr_t *)&tx_ring->tbd_area.address, + &len, &tx_ring->tbd_area.acc_handle); + + if (ret != DDI_SUCCESS) { + ixgbe_error(ixgbe, + "Could not allocate tbd dma memory: %x", ret); + tx_ring->tbd_area.acc_handle = NULL; + tx_ring->tbd_area.address = NULL; + if (tx_ring->tbd_area.dma_handle != NULL) { + ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle); + tx_ring->tbd_area.dma_handle = NULL; + } + return (IXGBE_FAILURE); + } + + /* + * Initialize the entire transmit buffer descriptor area to zero + */ + bzero(tx_ring->tbd_area.address, len); + + /* + * Allocates DMA resources for the memory that was allocated by + * the ddi_dma_mem_alloc call. The DMA resources then get bound to the + * the memory address + */ + ret = ddi_dma_addr_bind_handle(tx_ring->tbd_area.dma_handle, + NULL, (caddr_t)tx_ring->tbd_area.address, + len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, + DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num); + + if (ret != DDI_DMA_MAPPED) { + ixgbe_error(ixgbe, + "Could not bind tbd dma resource: %x", ret); + tx_ring->tbd_area.dma_address = NULL; + if (tx_ring->tbd_area.acc_handle != NULL) { + ddi_dma_mem_free(&tx_ring->tbd_area.acc_handle); + tx_ring->tbd_area.acc_handle = NULL; + tx_ring->tbd_area.address = NULL; + } + if (tx_ring->tbd_area.dma_handle != NULL) { + ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle); + tx_ring->tbd_area.dma_handle = NULL; + } + return (IXGBE_FAILURE); + } + + ASSERT(cookie_num == 1); + + tx_ring->tbd_area.dma_address = cookie.dmac_laddress; + tx_ring->tbd_area.size = len; + + tx_ring->tbd_ring = (union ixgbe_adv_tx_desc *)(uintptr_t) + tx_ring->tbd_area.address; + + return (IXGBE_SUCCESS); +} + +/* + * ixgbe_free_tbd_ring - Free the tx descriptors of one ring. + */ +static void +ixgbe_free_tbd_ring(ixgbe_tx_ring_t *tx_ring) +{ + if (tx_ring->tbd_area.dma_handle != NULL) { + (void) ddi_dma_unbind_handle(tx_ring->tbd_area.dma_handle); + } + if (tx_ring->tbd_area.acc_handle != NULL) { + ddi_dma_mem_free(&tx_ring->tbd_area.acc_handle); + tx_ring->tbd_area.acc_handle = NULL; + } + if (tx_ring->tbd_area.dma_handle != NULL) { + ddi_dma_free_handle(&tx_ring->tbd_area.dma_handle); + tx_ring->tbd_area.dma_handle = NULL; + } + tx_ring->tbd_area.address = NULL; + tx_ring->tbd_area.dma_address = NULL; + tx_ring->tbd_area.size = 0; + + tx_ring->tbd_ring = NULL; +} + +/* + * ixgbe_alloc_rbd_ring - Memory allocation for the rx descriptors of one ring. + */ +static int +ixgbe_alloc_rbd_ring(ixgbe_rx_ring_t *rx_ring) +{ + int ret; + size_t size; + size_t len; + uint_t cookie_num; + dev_info_t *devinfo; + ddi_dma_cookie_t cookie; + ixgbe_t *ixgbe = rx_ring->ixgbe; + + devinfo = ixgbe->dip; + size = sizeof (union ixgbe_adv_rx_desc) * rx_ring->ring_size; + + /* + * Allocate a new DMA handle for the receive descriptor + * memory area. + */ + ret = ddi_dma_alloc_handle(devinfo, &ixgbe_desc_dma_attr, + DDI_DMA_DONTWAIT, NULL, + &rx_ring->rbd_area.dma_handle); + + if (ret != DDI_SUCCESS) { + ixgbe_error(ixgbe, + "Could not allocate rbd dma handle: %x", ret); + rx_ring->rbd_area.dma_handle = NULL; + return (IXGBE_FAILURE); + } + + /* + * Allocate memory to DMA data to and from the receive + * descriptors. + */ + ret = ddi_dma_mem_alloc(rx_ring->rbd_area.dma_handle, + size, &ixgbe_desc_acc_attr, DDI_DMA_CONSISTENT, + DDI_DMA_DONTWAIT, NULL, + (caddr_t *)&rx_ring->rbd_area.address, + &len, &rx_ring->rbd_area.acc_handle); + + if (ret != DDI_SUCCESS) { + ixgbe_error(ixgbe, + "Could not allocate rbd dma memory: %x", ret); + rx_ring->rbd_area.acc_handle = NULL; + rx_ring->rbd_area.address = NULL; + if (rx_ring->rbd_area.dma_handle != NULL) { + ddi_dma_free_handle(&rx_ring->rbd_area.dma_handle); + rx_ring->rbd_area.dma_handle = NULL; + } + return (IXGBE_FAILURE); + } + + /* + * Initialize the entire transmit buffer descriptor area to zero + */ + bzero(rx_ring->rbd_area.address, len); + + /* + * Allocates DMA resources for the memory that was allocated by + * the ddi_dma_mem_alloc call. + */ + ret = ddi_dma_addr_bind_handle(rx_ring->rbd_area.dma_handle, + NULL, (caddr_t)rx_ring->rbd_area.address, + len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, + DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num); + + if (ret != DDI_DMA_MAPPED) { + ixgbe_error(ixgbe, + "Could not bind rbd dma resource: %x", ret); + rx_ring->rbd_area.dma_address = NULL; + if (rx_ring->rbd_area.acc_handle != NULL) { + ddi_dma_mem_free(&rx_ring->rbd_area.acc_handle); + rx_ring->rbd_area.acc_handle = NULL; + rx_ring->rbd_area.address = NULL; + } + if (rx_ring->rbd_area.dma_handle != NULL) { + ddi_dma_free_handle(&rx_ring->rbd_area.dma_handle); + rx_ring->rbd_area.dma_handle = NULL; + } + return (IXGBE_FAILURE); + } + + ASSERT(cookie_num == 1); + + rx_ring->rbd_area.dma_address = cookie.dmac_laddress; + rx_ring->rbd_area.size = len; + + rx_ring->rbd_ring = (union ixgbe_adv_rx_desc *)(uintptr_t) + rx_ring->rbd_area.address; + + return (IXGBE_SUCCESS); +} + +/* + * ixgbe_free_rbd_ring - Free the rx descriptors of one ring. + */ +static void +ixgbe_free_rbd_ring(ixgbe_rx_ring_t *rx_ring) +{ + if (rx_ring->rbd_area.dma_handle != NULL) { + (void) ddi_dma_unbind_handle(rx_ring->rbd_area.dma_handle); + } + if (rx_ring->rbd_area.acc_handle != NULL) { + ddi_dma_mem_free(&rx_ring->rbd_area.acc_handle); + rx_ring->rbd_area.acc_handle = NULL; + } + if (rx_ring->rbd_area.dma_handle != NULL) { + ddi_dma_free_handle(&rx_ring->rbd_area.dma_handle); + rx_ring->rbd_area.dma_handle = NULL; + } + rx_ring->rbd_area.address = NULL; + rx_ring->rbd_area.dma_address = NULL; + rx_ring->rbd_area.size = 0; + + rx_ring->rbd_ring = NULL; +} + +/* + * ixgbe_alloc_dma_buffer - Allocate DMA resources for a DMA buffer. + */ +static int +ixgbe_alloc_dma_buffer(ixgbe_t *ixgbe, dma_buffer_t *buf, size_t size) +{ + int ret; + dev_info_t *devinfo = ixgbe->dip; + ddi_dma_cookie_t cookie; + size_t len; + uint_t cookie_num; + + ret = ddi_dma_alloc_handle(devinfo, + &ixgbe_buf_dma_attr, DDI_DMA_DONTWAIT, + NULL, &buf->dma_handle); + + if (ret != DDI_SUCCESS) { + buf->dma_handle = NULL; + ixgbe_error(ixgbe, + "Could not allocate dma buffer handle: %x", ret); + return (IXGBE_FAILURE); + } + + ret = ddi_dma_mem_alloc(buf->dma_handle, + size, &ixgbe_buf_acc_attr, DDI_DMA_STREAMING, + DDI_DMA_DONTWAIT, NULL, &buf->address, + &len, &buf->acc_handle); + + if (ret != DDI_SUCCESS) { + buf->acc_handle = NULL; + buf->address = NULL; + if (buf->dma_handle != NULL) { + ddi_dma_free_handle(&buf->dma_handle); + buf->dma_handle = NULL; + } + ixgbe_error(ixgbe, + "Could not allocate dma buffer memory: %x", ret); + return (IXGBE_FAILURE); + } + + ret = ddi_dma_addr_bind_handle(buf->dma_handle, NULL, + buf->address, + len, DDI_DMA_RDWR | DDI_DMA_STREAMING, + DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_num); + + if (ret != DDI_DMA_MAPPED) { + buf->dma_address = NULL; + if (buf->acc_handle != NULL) { + ddi_dma_mem_free(&buf->acc_handle); + buf->acc_handle = NULL; + buf->address = NULL; + } + if (buf->dma_handle != NULL) { + ddi_dma_free_handle(&buf->dma_handle); + buf->dma_handle = NULL; + } + ixgbe_error(ixgbe, + "Could not bind dma buffer handle: %x", ret); + return (IXGBE_FAILURE); + } + + ASSERT(cookie_num == 1); + + buf->dma_address = cookie.dmac_laddress; + buf->size = len; + buf->len = 0; + + return (IXGBE_SUCCESS); +} + +/* + * ixgbe_free_dma_buffer - Free one allocated area of dma memory and handle. + */ +static void +ixgbe_free_dma_buffer(dma_buffer_t *buf) +{ + if (buf->dma_handle != NULL) { + (void) ddi_dma_unbind_handle(buf->dma_handle); + buf->dma_address = NULL; + } else { + return; + } + + if (buf->acc_handle != NULL) { + ddi_dma_mem_free(&buf->acc_handle); + buf->acc_handle = NULL; + buf->address = NULL; + } + + if (buf->dma_handle != NULL) { + ddi_dma_free_handle(&buf->dma_handle); + buf->dma_handle = NULL; + } + + buf->size = 0; + buf->len = 0; +} + +/* + * ixgbe_alloc_tcb_lists - Memory allocation for the transmit control bolcks + * of one ring. + */ +static int +ixgbe_alloc_tcb_lists(ixgbe_tx_ring_t *tx_ring) +{ + int i; + int ret; + tx_control_block_t *tcb; + dma_buffer_t *tx_buf; + ixgbe_t *ixgbe = tx_ring->ixgbe; + dev_info_t *devinfo = ixgbe->dip; + + /* + * Allocate memory for the work list. + */ + tx_ring->work_list = kmem_zalloc(sizeof (tx_control_block_t *) * + tx_ring->ring_size, KM_NOSLEEP); + + if (tx_ring->work_list == NULL) { + ixgbe_error(ixgbe, + "Cound not allocate memory for tx work list"); + return (IXGBE_FAILURE); + } + + /* + * Allocate memory for the free list. + */ + tx_ring->free_list = kmem_zalloc(sizeof (tx_control_block_t *) * + tx_ring->free_list_size, KM_NOSLEEP); + + if (tx_ring->free_list == NULL) { + kmem_free(tx_ring->work_list, + sizeof (tx_control_block_t *) * tx_ring->ring_size); + tx_ring->work_list = NULL; + + ixgbe_error(ixgbe, + "Cound not allocate memory for tx free list"); + return (IXGBE_FAILURE); + } + + /* + * Allocate memory for the tx control blocks of free list. + */ + tx_ring->tcb_area = + kmem_zalloc(sizeof (tx_control_block_t) * + tx_ring->free_list_size, KM_NOSLEEP); + + if (tx_ring->tcb_area == NULL) { + kmem_free(tx_ring->work_list, + sizeof (tx_control_block_t *) * tx_ring->ring_size); + tx_ring->work_list = NULL; + + kmem_free(tx_ring->free_list, + sizeof (tx_control_block_t *) * tx_ring->free_list_size); + tx_ring->free_list = NULL; + + ixgbe_error(ixgbe, + "Cound not allocate memory for tx control blocks"); + return (IXGBE_FAILURE); + } + + /* + * Allocate dma memory for the tx control block of free list. + */ + tcb = tx_ring->tcb_area; + for (i = 0; i < tx_ring->free_list_size; i++, tcb++) { + ASSERT(tcb != NULL); + + tx_ring->free_list[i] = tcb; + + /* + * Pre-allocate dma handles for transmit. These dma handles + * will be dynamically bound to the data buffers passed down + * from the upper layers at the time of transmitting. + */ + ret = ddi_dma_alloc_handle(devinfo, + &ixgbe_tx_dma_attr, + DDI_DMA_DONTWAIT, NULL, + &tcb->tx_dma_handle); + if (ret != DDI_SUCCESS) { + tcb->tx_dma_handle = NULL; + ixgbe_error(ixgbe, + "Could not allocate tx dma handle: %x", ret); + goto alloc_tcb_lists_fail; + } + + /* + * Pre-allocate transmit buffers for packets that the + * size is less than bcopy_thresh. + */ + tx_buf = &tcb->tx_buf; + + ret = ixgbe_alloc_dma_buffer(ixgbe, + tx_buf, ixgbe->tx_buf_size); + + if (ret != IXGBE_SUCCESS) { + ASSERT(tcb->tx_dma_handle != NULL); + ddi_dma_free_handle(&tcb->tx_dma_handle); + tcb->tx_dma_handle = NULL; + ixgbe_error(ixgbe, "Allocate tx dma buffer failed"); + goto alloc_tcb_lists_fail; + } + } + + return (IXGBE_SUCCESS); + +alloc_tcb_lists_fail: + ixgbe_free_tcb_lists(tx_ring); + + return (IXGBE_FAILURE); +} + +/* + * ixgbe_free_tcb_lists - Release the memory allocated for + * the transmit control bolcks of one ring. + */ +static void +ixgbe_free_tcb_lists(ixgbe_tx_ring_t *tx_ring) +{ + int i; + tx_control_block_t *tcb; + + tcb = tx_ring->tcb_area; + if (tcb == NULL) + return; + + for (i = 0; i < tx_ring->free_list_size; i++, tcb++) { + ASSERT(tcb != NULL); + + /* Free the tx dma handle for dynamical binding */ + if (tcb->tx_dma_handle != NULL) { + ddi_dma_free_handle(&tcb->tx_dma_handle); + tcb->tx_dma_handle = NULL; + } else { + /* + * If the dma handle is NULL, then we don't + * have to check the remaining. + */ + break; + } + + ixgbe_free_dma_buffer(&tcb->tx_buf); + } + + if (tx_ring->tcb_area != NULL) { + kmem_free(tx_ring->tcb_area, + sizeof (tx_control_block_t) * tx_ring->free_list_size); + tx_ring->tcb_area = NULL; + } + + if (tx_ring->work_list != NULL) { + kmem_free(tx_ring->work_list, + sizeof (tx_control_block_t *) * tx_ring->ring_size); + tx_ring->work_list = NULL; + } + + if (tx_ring->free_list != NULL) { + kmem_free(tx_ring->free_list, + sizeof (tx_control_block_t *) * tx_ring->free_list_size); + tx_ring->free_list = NULL; + } +} + +/* + * ixgbe_alloc_rcb_lists - Memory allocation for the receive control blocks + * of one ring. + */ +static int +ixgbe_alloc_rcb_lists(ixgbe_rx_ring_t *rx_ring) +{ + int i; + int ret; + rx_control_block_t *rcb; + ixgbe_t *ixgbe = rx_ring->ixgbe; + dma_buffer_t *rx_buf; + uint32_t rcb_count; + + /* + * Allocate memory for the work list. + */ + rx_ring->work_list = kmem_zalloc(sizeof (rx_control_block_t *) * + rx_ring->ring_size, KM_NOSLEEP); + + if (rx_ring->work_list == NULL) { + ixgbe_error(ixgbe, + "Could not allocate memory for rx work list"); + return (IXGBE_FAILURE); + } + + /* + * Allocate memory for the free list. + */ + rx_ring->free_list = kmem_zalloc(sizeof (rx_control_block_t *) * + rx_ring->free_list_size, KM_NOSLEEP); + + if (rx_ring->free_list == NULL) { + kmem_free(rx_ring->work_list, + sizeof (rx_control_block_t *) * rx_ring->ring_size); + rx_ring->work_list = NULL; + + ixgbe_error(ixgbe, + "Cound not allocate memory for rx free list"); + return (IXGBE_FAILURE); + } + + /* + * Allocate memory for the rx control blocks for work list and + * free list. + */ + rcb_count = rx_ring->ring_size + rx_ring->free_list_size; + rx_ring->rcb_area = + kmem_zalloc(sizeof (rx_control_block_t) * rcb_count, + KM_NOSLEEP); + + if (rx_ring->rcb_area == NULL) { + kmem_free(rx_ring->work_list, + sizeof (rx_control_block_t *) * rx_ring->ring_size); + rx_ring->work_list = NULL; + + kmem_free(rx_ring->free_list, + sizeof (rx_control_block_t *) * rx_ring->free_list_size); + rx_ring->free_list = NULL; + + ixgbe_error(ixgbe, + "Cound not allocate memory for rx control blocks"); + return (IXGBE_FAILURE); + } + + /* + * Allocate dma memory for the rx control blocks + */ + rcb = rx_ring->rcb_area; + for (i = 0; i < rcb_count; i++, rcb++) { + ASSERT(rcb != NULL); + + if (i < rx_ring->ring_size) { + /* Attach the rx control block to the work list */ + rx_ring->work_list[i] = rcb; + } else { + /* Attach the rx control block to the free list */ + rx_ring->free_list[i - rx_ring->ring_size] = rcb; + } + + rx_buf = &rcb->rx_buf; + ret = ixgbe_alloc_dma_buffer(ixgbe, + rx_buf, ixgbe->rx_buf_size); + + if (ret != IXGBE_SUCCESS) { + ixgbe_error(ixgbe, "Allocate rx dma buffer failed"); + goto alloc_rcb_lists_fail; + } + + rx_buf->size -= IPHDR_ALIGN_ROOM; + rx_buf->address += IPHDR_ALIGN_ROOM; + rx_buf->dma_address += IPHDR_ALIGN_ROOM; + + rcb->state = RCB_FREE; + rcb->rx_ring = (ixgbe_rx_ring_t *)rx_ring; + rcb->free_rtn.free_func = ixgbe_rx_recycle; + rcb->free_rtn.free_arg = (char *)rcb; + + rcb->mp = desballoc((unsigned char *) + rx_buf->address - IPHDR_ALIGN_ROOM, + rx_buf->size + IPHDR_ALIGN_ROOM, + 0, &rcb->free_rtn); + + if (rcb->mp != NULL) { + rcb->mp->b_rptr += IPHDR_ALIGN_ROOM; + rcb->mp->b_wptr += IPHDR_ALIGN_ROOM; + } + } + + return (IXGBE_SUCCESS); + +alloc_rcb_lists_fail: + ixgbe_free_rcb_lists(rx_ring); + + return (IXGBE_FAILURE); +} + +/* + * ixgbe_free_rcb_lists - Free the receive control blocks of one ring. + */ +static void +ixgbe_free_rcb_lists(ixgbe_rx_ring_t *rx_ring) +{ + int i; + rx_control_block_t *rcb; + uint32_t rcb_count; + + rcb = rx_ring->rcb_area; + if (rcb == NULL) + return; + + rcb_count = rx_ring->ring_size + rx_ring->free_list_size; + for (i = 0; i < rcb_count; i++, rcb++) { + ASSERT(rcb != NULL); + ASSERT(rcb->state == RCB_FREE); + + if (rcb->mp != NULL) { + freemsg(rcb->mp); + rcb->mp = NULL; + } + + ixgbe_free_dma_buffer(&rcb->rx_buf); + } + + if (rx_ring->rcb_area != NULL) { + kmem_free(rx_ring->rcb_area, + sizeof (rx_control_block_t) * rcb_count); + rx_ring->rcb_area = NULL; + } + + if (rx_ring->work_list != NULL) { + kmem_free(rx_ring->work_list, + sizeof (rx_control_block_t *) * rx_ring->ring_size); + rx_ring->work_list = NULL; + } + + if (rx_ring->free_list != NULL) { + kmem_free(rx_ring->free_list, + sizeof (rx_control_block_t *) * rx_ring->free_list_size); + rx_ring->free_list = NULL; + } +} + +/* + * ixgbe_set_fma_flags - Set the attribute for fma support. + */ +void +ixgbe_set_fma_flags(int acc_flag, int dma_flag) +{ + if (acc_flag) { + ixgbe_desc_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; + } else { + ixgbe_desc_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; + } + + if (dma_flag) { + ixgbe_tx_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; + ixgbe_buf_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; + ixgbe_desc_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; + } else { + ixgbe_tx_dma_attr.dma_attr_flags = 0; + ixgbe_buf_dma_attr.dma_attr_flags = 0; + ixgbe_desc_dma_attr.dma_attr_flags = 0; + } +} |