156b2bdd1SGireesh Nagabhushana /*
256b2bdd1SGireesh Nagabhushana  * This file and its contents are supplied under the terms of the
356b2bdd1SGireesh Nagabhushana  * Common Development and Distribution License ("CDDL"), version 1.0.
456b2bdd1SGireesh Nagabhushana  * You may only use this file in accordance with the terms of version
556b2bdd1SGireesh Nagabhushana  * 1.0 of the CDDL.
656b2bdd1SGireesh Nagabhushana  *
756b2bdd1SGireesh Nagabhushana  * A full copy of the text of the CDDL should have accompanied this
856b2bdd1SGireesh Nagabhushana  * source. A copy of the CDDL is also available via the Internet at
956b2bdd1SGireesh Nagabhushana  * http://www.illumos.org/license/CDDL.
1056b2bdd1SGireesh Nagabhushana  */
1156b2bdd1SGireesh Nagabhushana 
1256b2bdd1SGireesh Nagabhushana /*
1356b2bdd1SGireesh Nagabhushana  * This file is part of the Chelsio T4 support code.
1456b2bdd1SGireesh Nagabhushana  *
1556b2bdd1SGireesh Nagabhushana  * Copyright (C) 2011-2013 Chelsio Communications.  All rights reserved.
1656b2bdd1SGireesh Nagabhushana  *
1756b2bdd1SGireesh Nagabhushana  * This program is distributed in the hope that it will be useful, but WITHOUT
1856b2bdd1SGireesh Nagabhushana  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1956b2bdd1SGireesh Nagabhushana  * FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
2056b2bdd1SGireesh Nagabhushana  * release for licensing terms and conditions.
2156b2bdd1SGireesh Nagabhushana  */
2256b2bdd1SGireesh Nagabhushana 
2356b2bdd1SGireesh Nagabhushana #include <sys/ddi.h>
2456b2bdd1SGireesh Nagabhushana #include <sys/sunddi.h>
2556b2bdd1SGireesh Nagabhushana #include <sys/atomic.h>
2656b2bdd1SGireesh Nagabhushana #include <sys/types.h>
2756b2bdd1SGireesh Nagabhushana #include <sys/kmem.h>
2856b2bdd1SGireesh Nagabhushana 
2956b2bdd1SGireesh Nagabhushana #include "osdep.h"
3056b2bdd1SGireesh Nagabhushana #include "shared.h"
3156b2bdd1SGireesh Nagabhushana 
3256b2bdd1SGireesh Nagabhushana static int rxbuf_ctor(void *, void *, int);
3356b2bdd1SGireesh Nagabhushana static void rxbuf_dtor(void *, void *);
3456b2bdd1SGireesh Nagabhushana 
3541378e79SToomas Soome int
cxgb_printf(dev_info_t * dip,int level,char * f,...)3656b2bdd1SGireesh Nagabhushana cxgb_printf(dev_info_t *dip, int level, char *f, ...)
3756b2bdd1SGireesh Nagabhushana {
3856b2bdd1SGireesh Nagabhushana 	va_list list;
3956b2bdd1SGireesh Nagabhushana 	char fmt[128];
4041378e79SToomas Soome 	int rv;
4156b2bdd1SGireesh Nagabhushana 
4241378e79SToomas Soome 	rv = snprintf(fmt, sizeof (fmt), "%s%d: %s", ddi_driver_name(dip),
4356b2bdd1SGireesh Nagabhushana 	    ddi_get_instance(dip), f);
4456b2bdd1SGireesh Nagabhushana 	va_start(list, f);
4556b2bdd1SGireesh Nagabhushana 	vcmn_err(level, fmt, list);
4656b2bdd1SGireesh Nagabhushana 	va_end(list);
4741378e79SToomas Soome 	return (rv);
4856b2bdd1SGireesh Nagabhushana }
4956b2bdd1SGireesh Nagabhushana 
5056b2bdd1SGireesh Nagabhushana kmem_cache_t *
rxbuf_cache_create(struct rxbuf_cache_params * p)5156b2bdd1SGireesh Nagabhushana rxbuf_cache_create(struct rxbuf_cache_params *p)
5256b2bdd1SGireesh Nagabhushana {
5356b2bdd1SGireesh Nagabhushana 	char name[32];
5456b2bdd1SGireesh Nagabhushana 
5556b2bdd1SGireesh Nagabhushana 	(void) snprintf(name, sizeof (name), "%s%d_rxbuf_cache",
5656b2bdd1SGireesh Nagabhushana 	    ddi_driver_name(p->dip), ddi_get_instance(p->dip));
5756b2bdd1SGireesh Nagabhushana 
5856b2bdd1SGireesh Nagabhushana 	return kmem_cache_create(name, sizeof (struct rxbuf), CACHE_LINE,
5956b2bdd1SGireesh Nagabhushana 	    rxbuf_ctor, rxbuf_dtor, NULL, p, NULL, 0);
6056b2bdd1SGireesh Nagabhushana }
6156b2bdd1SGireesh Nagabhushana 
6256b2bdd1SGireesh Nagabhushana void
rxbuf_cache_destroy(kmem_cache_t * cache)6356b2bdd1SGireesh Nagabhushana rxbuf_cache_destroy(kmem_cache_t *cache)
6456b2bdd1SGireesh Nagabhushana {
6556b2bdd1SGireesh Nagabhushana 	kmem_cache_destroy(cache);
6656b2bdd1SGireesh Nagabhushana }
6756b2bdd1SGireesh Nagabhushana 
6856b2bdd1SGireesh Nagabhushana /*
6956b2bdd1SGireesh Nagabhushana  * If ref_cnt is more than 1 then those many calls to rxbuf_free will
7056b2bdd1SGireesh Nagabhushana  * have to be made before the rxb is released back to the kmem_cache.
7156b2bdd1SGireesh Nagabhushana  */
7256b2bdd1SGireesh Nagabhushana struct rxbuf *
rxbuf_alloc(kmem_cache_t * cache,int kmflags,uint_t ref_cnt)7356b2bdd1SGireesh Nagabhushana rxbuf_alloc(kmem_cache_t *cache, int kmflags, uint_t ref_cnt)
7456b2bdd1SGireesh Nagabhushana {
7556b2bdd1SGireesh Nagabhushana 	struct rxbuf *rxb;
7656b2bdd1SGireesh Nagabhushana 
7756b2bdd1SGireesh Nagabhushana 	ASSERT(ref_cnt > 0);
7856b2bdd1SGireesh Nagabhushana 
7956b2bdd1SGireesh Nagabhushana 	rxb = kmem_cache_alloc(cache, kmflags);
8056b2bdd1SGireesh Nagabhushana 	if (rxb != NULL) {
8156b2bdd1SGireesh Nagabhushana 		rxb->ref_cnt = ref_cnt;
8256b2bdd1SGireesh Nagabhushana 		rxb->cache = cache;
8356b2bdd1SGireesh Nagabhushana 	}
8456b2bdd1SGireesh Nagabhushana 
8556b2bdd1SGireesh Nagabhushana 	return (rxb);
8656b2bdd1SGireesh Nagabhushana }
8756b2bdd1SGireesh Nagabhushana 
8856b2bdd1SGireesh Nagabhushana /*
8956b2bdd1SGireesh Nagabhushana  * This is normally called via the rxb's freefunc, when an mblk referencing the
9056b2bdd1SGireesh Nagabhushana  * rxb is freed.
9156b2bdd1SGireesh Nagabhushana  */
9256b2bdd1SGireesh Nagabhushana void
rxbuf_free(struct rxbuf * rxb)9356b2bdd1SGireesh Nagabhushana rxbuf_free(struct rxbuf *rxb)
9456b2bdd1SGireesh Nagabhushana {
9556b2bdd1SGireesh Nagabhushana 	if (atomic_dec_uint_nv(&rxb->ref_cnt) == 0)
9656b2bdd1SGireesh Nagabhushana 		kmem_cache_free(rxb->cache, rxb);
9756b2bdd1SGireesh Nagabhushana }
9856b2bdd1SGireesh Nagabhushana 
9956b2bdd1SGireesh Nagabhushana static int
rxbuf_ctor(void * arg1,void * arg2,int kmflag)10056b2bdd1SGireesh Nagabhushana rxbuf_ctor(void *arg1, void *arg2, int kmflag)
10156b2bdd1SGireesh Nagabhushana {
10256b2bdd1SGireesh Nagabhushana 	struct rxbuf *rxb = arg1;
10356b2bdd1SGireesh Nagabhushana 	struct rxbuf_cache_params *p = arg2;
10456b2bdd1SGireesh Nagabhushana 	size_t real_len;
10556b2bdd1SGireesh Nagabhushana 	ddi_dma_cookie_t cookie;
10656b2bdd1SGireesh Nagabhushana 	uint_t ccount = 0;
10756b2bdd1SGireesh Nagabhushana 	int (*callback)(caddr_t);
10856b2bdd1SGireesh Nagabhushana 	int rc = ENOMEM;
10956b2bdd1SGireesh Nagabhushana 
110*89f249c9SRobert Mustacchi 	if ((kmflag & KM_NOSLEEP) != 0)
11156b2bdd1SGireesh Nagabhushana 		callback = DDI_DMA_DONTWAIT;
112*89f249c9SRobert Mustacchi 	else
113*89f249c9SRobert Mustacchi 		callback = DDI_DMA_SLEEP;
11456b2bdd1SGireesh Nagabhushana 
11556b2bdd1SGireesh Nagabhushana 	rc = ddi_dma_alloc_handle(p->dip, &p->dma_attr_rx, callback, 0,
11656b2bdd1SGireesh Nagabhushana 	    &rxb->dhdl);
11756b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS)
11856b2bdd1SGireesh Nagabhushana 		return (rc == DDI_DMA_BADATTR ? EINVAL : ENOMEM);
11956b2bdd1SGireesh Nagabhushana 
12056b2bdd1SGireesh Nagabhushana 	rc = ddi_dma_mem_alloc(rxb->dhdl, p->buf_size, &p->acc_attr_rx,
12156b2bdd1SGireesh Nagabhushana 	    DDI_DMA_STREAMING, callback, 0, &rxb->va, &real_len, &rxb->ahdl);
12256b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
12356b2bdd1SGireesh Nagabhushana 		rc = ENOMEM;
12456b2bdd1SGireesh Nagabhushana 		goto fail1;
12556b2bdd1SGireesh Nagabhushana 	}
12656b2bdd1SGireesh Nagabhushana 
12756b2bdd1SGireesh Nagabhushana 	rc = ddi_dma_addr_bind_handle(rxb->dhdl, NULL, rxb->va, p->buf_size,
12856b2bdd1SGireesh Nagabhushana 	    DDI_DMA_READ | DDI_DMA_STREAMING, NULL, NULL, &cookie, &ccount);
12956b2bdd1SGireesh Nagabhushana 	if (rc != DDI_DMA_MAPPED) {
13056b2bdd1SGireesh Nagabhushana 		if (rc == DDI_DMA_INUSE)
13156b2bdd1SGireesh Nagabhushana 			rc = EBUSY;
13256b2bdd1SGireesh Nagabhushana 		else if (rc == DDI_DMA_TOOBIG)
13356b2bdd1SGireesh Nagabhushana 			rc = E2BIG;
13456b2bdd1SGireesh Nagabhushana 		else
13556b2bdd1SGireesh Nagabhushana 			rc = ENOMEM;
13656b2bdd1SGireesh Nagabhushana 		goto fail2;
13756b2bdd1SGireesh Nagabhushana 	}
13856b2bdd1SGireesh Nagabhushana 
13956b2bdd1SGireesh Nagabhushana 	if (ccount != 1) {
14056b2bdd1SGireesh Nagabhushana 		rc = E2BIG;
14156b2bdd1SGireesh Nagabhushana 		goto fail3;
14256b2bdd1SGireesh Nagabhushana 	}
14356b2bdd1SGireesh Nagabhushana 
14456b2bdd1SGireesh Nagabhushana 	rxb->ref_cnt = 0;
14556b2bdd1SGireesh Nagabhushana 	rxb->buf_size = p->buf_size;
14656b2bdd1SGireesh Nagabhushana 	rxb->freefunc.free_arg = (caddr_t)rxb;
14756b2bdd1SGireesh Nagabhushana 	rxb->freefunc.free_func = rxbuf_free;
14856b2bdd1SGireesh Nagabhushana 	rxb->ba = cookie.dmac_laddress;
14956b2bdd1SGireesh Nagabhushana 
15056b2bdd1SGireesh Nagabhushana 	return (0);
15156b2bdd1SGireesh Nagabhushana 
15256b2bdd1SGireesh Nagabhushana fail3:	(void) ddi_dma_unbind_handle(rxb->dhdl);
15356b2bdd1SGireesh Nagabhushana fail2:	ddi_dma_mem_free(&rxb->ahdl);
15456b2bdd1SGireesh Nagabhushana fail1:	ddi_dma_free_handle(&rxb->dhdl);
15556b2bdd1SGireesh Nagabhushana 	return (rc);
15656b2bdd1SGireesh Nagabhushana }
15756b2bdd1SGireesh Nagabhushana 
15856b2bdd1SGireesh Nagabhushana /* ARGSUSED */
15956b2bdd1SGireesh Nagabhushana static void
rxbuf_dtor(void * arg1,void * arg2)16056b2bdd1SGireesh Nagabhushana rxbuf_dtor(void *arg1, void *arg2)
16156b2bdd1SGireesh Nagabhushana {
16256b2bdd1SGireesh Nagabhushana 	struct rxbuf *rxb = arg1;
16356b2bdd1SGireesh Nagabhushana 
16456b2bdd1SGireesh Nagabhushana 	(void) ddi_dma_unbind_handle(rxb->dhdl);
16556b2bdd1SGireesh Nagabhushana 	ddi_dma_mem_free(&rxb->ahdl);
16656b2bdd1SGireesh Nagabhushana 	ddi_dma_free_handle(&rxb->dhdl);
16756b2bdd1SGireesh Nagabhushana }
168