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
cxgb_printf(dev_info_t * dip,int level,char * f,...)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 *
rxbuf_cache_create(struct rxbuf_cache_params * p)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
rxbuf_cache_destroy(kmem_cache_t * cache)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 *
rxbuf_alloc(kmem_cache_t * cache,int kmflags,uint_t ref_cnt)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
rxbuf_free(struct rxbuf * rxb)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
rxbuf_ctor(void * arg1,void * arg2,int kmflag)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
rxbuf_dtor(void * arg1,void * arg2)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