1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * This file is part of the Chelsio T4 support code. 14 * 15 * Copyright (C) 2011-2013 Chelsio Communications. All rights reserved. 16 * 17 * This program is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this 20 * release for licensing terms and conditions. 21 */ 22 23 #include <sys/ddi.h> 24 #include <sys/sunddi.h> 25 #include <sys/atomic.h> 26 #include <sys/types.h> 27 #include <sys/kmem.h> 28 29 #include "osdep.h" 30 #include "shared.h" 31 32 static int rxbuf_ctor(void *, void *, int); 33 static void rxbuf_dtor(void *, void *); 34 35 void 36 cxgb_printf(dev_info_t *dip, int level, char *f, ...) 37 { 38 va_list list; 39 char fmt[128]; 40 41 (void) snprintf(fmt, sizeof (fmt), "%s%d: %s", ddi_driver_name(dip), 42 ddi_get_instance(dip), f); 43 va_start(list, f); 44 vcmn_err(level, fmt, list); 45 va_end(list); 46 } 47 48 kmem_cache_t * 49 rxbuf_cache_create(struct rxbuf_cache_params *p) 50 { 51 char name[32]; 52 53 (void) snprintf(name, sizeof (name), "%s%d_rxbuf_cache", 54 ddi_driver_name(p->dip), ddi_get_instance(p->dip)); 55 56 return kmem_cache_create(name, sizeof (struct rxbuf), CACHE_LINE, 57 rxbuf_ctor, rxbuf_dtor, NULL, p, NULL, 0); 58 } 59 60 void 61 rxbuf_cache_destroy(kmem_cache_t *cache) 62 { 63 kmem_cache_destroy(cache); 64 } 65 66 /* 67 * If ref_cnt is more than 1 then those many calls to rxbuf_free will 68 * have to be made before the rxb is released back to the kmem_cache. 69 */ 70 struct rxbuf * 71 rxbuf_alloc(kmem_cache_t *cache, int kmflags, uint_t ref_cnt) 72 { 73 struct rxbuf *rxb; 74 75 ASSERT(ref_cnt > 0); 76 77 rxb = kmem_cache_alloc(cache, kmflags); 78 if (rxb != NULL) { 79 rxb->ref_cnt = ref_cnt; 80 rxb->cache = cache; 81 } 82 83 return (rxb); 84 } 85 86 /* 87 * This is normally called via the rxb's freefunc, when an mblk referencing the 88 * rxb is freed. 89 */ 90 void 91 rxbuf_free(struct rxbuf *rxb) 92 { 93 if (atomic_dec_uint_nv(&rxb->ref_cnt) == 0) 94 kmem_cache_free(rxb->cache, rxb); 95 } 96 97 static int 98 rxbuf_ctor(void *arg1, void *arg2, int kmflag) 99 { 100 struct rxbuf *rxb = arg1; 101 struct rxbuf_cache_params *p = arg2; 102 size_t real_len; 103 ddi_dma_cookie_t cookie; 104 uint_t ccount = 0; 105 int (*callback)(caddr_t); 106 int rc = ENOMEM; 107 108 if (kmflag & KM_SLEEP) 109 callback = DDI_DMA_SLEEP; 110 else 111 callback = DDI_DMA_DONTWAIT; 112 113 rc = ddi_dma_alloc_handle(p->dip, &p->dma_attr_rx, callback, 0, 114 &rxb->dhdl); 115 if (rc != DDI_SUCCESS) 116 return (rc == DDI_DMA_BADATTR ? EINVAL : ENOMEM); 117 118 rc = ddi_dma_mem_alloc(rxb->dhdl, p->buf_size, &p->acc_attr_rx, 119 DDI_DMA_STREAMING, callback, 0, &rxb->va, &real_len, &rxb->ahdl); 120 if (rc != DDI_SUCCESS) { 121 rc = ENOMEM; 122 goto fail1; 123 } 124 125 rc = ddi_dma_addr_bind_handle(rxb->dhdl, NULL, rxb->va, p->buf_size, 126 DDI_DMA_READ | DDI_DMA_STREAMING, NULL, NULL, &cookie, &ccount); 127 if (rc != DDI_DMA_MAPPED) { 128 if (rc == DDI_DMA_INUSE) 129 rc = EBUSY; 130 else if (rc == DDI_DMA_TOOBIG) 131 rc = E2BIG; 132 else 133 rc = ENOMEM; 134 goto fail2; 135 } 136 137 if (ccount != 1) { 138 rc = E2BIG; 139 goto fail3; 140 } 141 142 rxb->ref_cnt = 0; 143 rxb->buf_size = p->buf_size; 144 rxb->freefunc.free_arg = (caddr_t)rxb; 145 rxb->freefunc.free_func = rxbuf_free; 146 rxb->ba = cookie.dmac_laddress; 147 148 return (0); 149 150 fail3: (void) ddi_dma_unbind_handle(rxb->dhdl); 151 fail2: ddi_dma_mem_free(&rxb->ahdl); 152 fail1: ddi_dma_free_handle(&rxb->dhdl); 153 return (rc); 154 } 155 156 /* ARGSUSED */ 157 static void 158 rxbuf_dtor(void *arg1, void *arg2) 159 { 160 struct rxbuf *rxb = arg1; 161 162 (void) ddi_dma_unbind_handle(rxb->dhdl); 163 ddi_dma_mem_free(&rxb->ahdl); 164 ddi_dma_free_handle(&rxb->dhdl); 165 } 166