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