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 int 36 cxgb_printf(dev_info_t *dip, int level, char *f, ...) 37 { 38 va_list list; 39 char fmt[128]; 40 int rv; 41 42 rv = snprintf(fmt, sizeof (fmt), "%s%d: %s", ddi_driver_name(dip), 43 ddi_get_instance(dip), f); 44 va_start(list, f); 45 vcmn_err(level, fmt, list); 46 va_end(list); 47 return (rv); 48 } 49 50 kmem_cache_t * 51 rxbuf_cache_create(struct rxbuf_cache_params *p) 52 { 53 char name[32]; 54 55 (void) snprintf(name, sizeof (name), "%s%d_rxbuf_cache", 56 ddi_driver_name(p->dip), ddi_get_instance(p->dip)); 57 58 return kmem_cache_create(name, sizeof (struct rxbuf), CACHE_LINE, 59 rxbuf_ctor, rxbuf_dtor, NULL, p, NULL, 0); 60 } 61 62 void 63 rxbuf_cache_destroy(kmem_cache_t *cache) 64 { 65 kmem_cache_destroy(cache); 66 } 67 68 /* 69 * If ref_cnt is more than 1 then those many calls to rxbuf_free will 70 * have to be made before the rxb is released back to the kmem_cache. 71 */ 72 struct rxbuf * 73 rxbuf_alloc(kmem_cache_t *cache, int kmflags, uint_t ref_cnt) 74 { 75 struct rxbuf *rxb; 76 77 ASSERT(ref_cnt > 0); 78 79 rxb = kmem_cache_alloc(cache, kmflags); 80 if (rxb != NULL) { 81 rxb->ref_cnt = ref_cnt; 82 rxb->cache = cache; 83 } 84 85 return (rxb); 86 } 87 88 /* 89 * This is normally called via the rxb's freefunc, when an mblk referencing the 90 * rxb is freed. 91 */ 92 void 93 rxbuf_free(struct rxbuf *rxb) 94 { 95 if (atomic_dec_uint_nv(&rxb->ref_cnt) == 0) 96 kmem_cache_free(rxb->cache, rxb); 97 } 98 99 static int 100 rxbuf_ctor(void *arg1, void *arg2, int kmflag) 101 { 102 struct rxbuf *rxb = arg1; 103 struct rxbuf_cache_params *p = arg2; 104 size_t real_len; 105 ddi_dma_cookie_t cookie; 106 uint_t ccount = 0; 107 int (*callback)(caddr_t); 108 int rc = ENOMEM; 109 110 if ((kmflag & KM_NOSLEEP) != 0) 111 callback = DDI_DMA_DONTWAIT; 112 else 113 callback = DDI_DMA_SLEEP; 114 115 rc = ddi_dma_alloc_handle(p->dip, &p->dma_attr_rx, callback, 0, 116 &rxb->dhdl); 117 if (rc != DDI_SUCCESS) 118 return (rc == DDI_DMA_BADATTR ? EINVAL : ENOMEM); 119 120 rc = ddi_dma_mem_alloc(rxb->dhdl, p->buf_size, &p->acc_attr_rx, 121 DDI_DMA_STREAMING, callback, 0, &rxb->va, &real_len, &rxb->ahdl); 122 if (rc != DDI_SUCCESS) { 123 rc = ENOMEM; 124 goto fail1; 125 } 126 127 rc = ddi_dma_addr_bind_handle(rxb->dhdl, NULL, rxb->va, p->buf_size, 128 DDI_DMA_READ | DDI_DMA_STREAMING, NULL, NULL, &cookie, &ccount); 129 if (rc != DDI_DMA_MAPPED) { 130 if (rc == DDI_DMA_INUSE) 131 rc = EBUSY; 132 else if (rc == DDI_DMA_TOOBIG) 133 rc = E2BIG; 134 else 135 rc = ENOMEM; 136 goto fail2; 137 } 138 139 if (ccount != 1) { 140 rc = E2BIG; 141 goto fail3; 142 } 143 144 rxb->ref_cnt = 0; 145 rxb->buf_size = p->buf_size; 146 rxb->freefunc.free_arg = (caddr_t)rxb; 147 rxb->freefunc.free_func = rxbuf_free; 148 rxb->ba = cookie.dmac_laddress; 149 150 return (0); 151 152 fail3: (void) ddi_dma_unbind_handle(rxb->dhdl); 153 fail2: ddi_dma_mem_free(&rxb->ahdl); 154 fail1: ddi_dma_free_handle(&rxb->dhdl); 155 return (rc); 156 } 157 158 /* ARGSUSED */ 159 static void 160 rxbuf_dtor(void *arg1, void *arg2) 161 { 162 struct rxbuf *rxb = arg1; 163 164 (void) ddi_dma_unbind_handle(rxb->dhdl); 165 ddi_dma_mem_free(&rxb->ahdl); 166 ddi_dma_free_handle(&rxb->dhdl); 167 } 168