1 /*-
2 * Copyright (c) 2011-2012 Semihalf.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/bus.h>
32 #include <sys/lock.h>
33 #include <sys/module.h>
34 #include <sys/mutex.h>
35 #include <sys/proc.h>
36 #include <sys/pcpu.h>
37 #include <sys/rman.h>
38 #include <sys/sched.h>
39
40 #include <machine/tlb.h>
41
42 #include "bman.h"
43
44 static struct bman_softc *bman_sc;
45
46 extern t_Handle bman_portal_setup(struct bman_softc *bsc);
47
48 static void
bman_exception(t_Handle h_App,e_BmExceptions exception)49 bman_exception(t_Handle h_App, e_BmExceptions exception)
50 {
51 struct bman_softc *sc;
52 const char *message;
53
54 sc = h_App;
55
56 switch (exception) {
57 case e_BM_EX_INVALID_COMMAND:
58 message = "Invalid Command Verb";
59 break;
60 case e_BM_EX_FBPR_THRESHOLD:
61 message = "FBPR pool exhaused. Consider increasing "
62 "BMAN_MAX_BUFFERS";
63 break;
64 case e_BM_EX_SINGLE_ECC:
65 message = "Single bit ECC error";
66 break;
67 case e_BM_EX_MULTI_ECC:
68 message = "Multi bit ECC error";
69 break;
70 default:
71 message = "Unknown error";
72 }
73
74 device_printf(sc->sc_dev, "BMAN Exception: %s.\n", message);
75 }
76
77 int
bman_attach(device_t dev)78 bman_attach(device_t dev)
79 {
80 struct bman_softc *sc;
81 t_BmRevisionInfo rev;
82 t_Error error;
83 t_BmParam bp;
84
85 sc = device_get_softc(dev);
86 sc->sc_dev = dev;
87 bman_sc = sc;
88
89 /* Check if MallocSmart allocator is ready */
90 if (XX_MallocSmartInit() != E_OK)
91 return (ENXIO);
92
93 /* Allocate resources */
94 sc->sc_rrid = 0;
95 sc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY,
96 &sc->sc_rrid, BMAN_CCSR_SIZE, RF_ACTIVE);
97 if (sc->sc_rres == NULL)
98 return (ENXIO);
99
100 sc->sc_irid = 0;
101 sc->sc_ires = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ,
102 &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE);
103 if (sc->sc_ires == NULL)
104 goto err;
105
106 /* Initialize BMAN */
107 memset(&bp, 0, sizeof(bp));
108 bp.guestId = NCSW_MASTER_ID;
109 bp.baseAddress = rman_get_bushandle(sc->sc_rres);
110 bp.totalNumOfBuffers = BMAN_MAX_BUFFERS;
111 bp.f_Exception = bman_exception;
112 bp.h_App = sc;
113 bp.errIrq = (uintptr_t)sc->sc_ires;
114 bp.partBpidBase = 0;
115 bp.partNumOfPools = BM_MAX_NUM_OF_POOLS;
116
117 sc->sc_bh = BM_Config(&bp);
118 if (sc->sc_bh == NULL)
119 goto err;
120
121 /* Warn if there is less than 5% free FPBR's in pool */
122 error = BM_ConfigFbprThreshold(sc->sc_bh, (BMAN_MAX_BUFFERS / 8) / 20);
123 if (error != E_OK)
124 goto err;
125
126 error = BM_Init(sc->sc_bh);
127 if (error != E_OK)
128 goto err;
129
130 error = BM_GetRevision(sc->sc_bh, &rev);
131 if (error != E_OK)
132 goto err;
133
134 device_printf(dev, "Hardware version: %d.%d.\n",
135 rev.majorRev, rev.minorRev);
136
137 return (0);
138
139 err:
140 bman_detach(dev);
141 return (ENXIO);
142 }
143
144 int
bman_detach(device_t dev)145 bman_detach(device_t dev)
146 {
147 struct bman_softc *sc;
148
149 sc = device_get_softc(dev);
150
151 if (sc->sc_bh != NULL)
152 BM_Free(sc->sc_bh);
153
154 if (sc->sc_ires != NULL)
155 bus_release_resource(dev, SYS_RES_IRQ,
156 sc->sc_irid, sc->sc_ires);
157
158 if (sc->sc_rres != NULL)
159 bus_release_resource(dev, SYS_RES_MEMORY,
160 sc->sc_rrid, sc->sc_rres);
161
162 return (0);
163 }
164
165 int
bman_suspend(device_t dev)166 bman_suspend(device_t dev)
167 {
168
169 return (0);
170 }
171
172 int
bman_resume(device_t dev)173 bman_resume(device_t dev)
174 {
175
176 return (0);
177 }
178
179 int
bman_shutdown(device_t dev)180 bman_shutdown(device_t dev)
181 {
182
183 return (0);
184 }
185
186 /*
187 * BMAN API
188 */
189
190 t_Handle
bman_pool_create(uint8_t * bpid,uint16_t bufferSize,uint16_t maxBuffers,uint16_t minBuffers,uint16_t allocBuffers,t_GetBufFunction * f_GetBuf,t_PutBufFunction * f_PutBuf,uint32_t dep_sw_entry,uint32_t dep_sw_exit,uint32_t dep_hw_entry,uint32_t dep_hw_exit,t_BmDepletionCallback * f_Depletion,t_Handle h_BufferPool,t_PhysToVirt * f_PhysToVirt,t_VirtToPhys * f_VirtToPhys)191 bman_pool_create(uint8_t *bpid, uint16_t bufferSize, uint16_t maxBuffers,
192 uint16_t minBuffers, uint16_t allocBuffers, t_GetBufFunction *f_GetBuf,
193 t_PutBufFunction *f_PutBuf, uint32_t dep_sw_entry, uint32_t dep_sw_exit,
194 uint32_t dep_hw_entry, uint32_t dep_hw_exit,
195 t_BmDepletionCallback *f_Depletion, t_Handle h_BufferPool,
196 t_PhysToVirt *f_PhysToVirt, t_VirtToPhys *f_VirtToPhys)
197 {
198 uint32_t thresholds[MAX_DEPLETION_THRESHOLDS];
199 struct bman_softc *sc;
200 t_Handle pool, portal;
201 t_BmPoolParam bpp;
202 int error;
203
204 sc = bman_sc;
205 pool = NULL;
206
207 sched_pin();
208
209 portal = bman_portal_setup(sc);
210 if (portal == NULL)
211 goto err;
212
213 memset(&bpp, 0, sizeof(bpp));
214 bpp.h_Bm = sc->sc_bh;
215 bpp.h_BmPortal = portal;
216 bpp.h_App = h_BufferPool;
217 bpp.numOfBuffers = allocBuffers;
218
219 bpp.bufferPoolInfo.h_BufferPool = h_BufferPool;
220 bpp.bufferPoolInfo.f_GetBuf = f_GetBuf;
221 bpp.bufferPoolInfo.f_PutBuf = f_PutBuf;
222 bpp.bufferPoolInfo.f_PhysToVirt = f_PhysToVirt;
223 bpp.bufferPoolInfo.f_VirtToPhys = f_VirtToPhys;
224 bpp.bufferPoolInfo.bufferSize = bufferSize;
225
226 pool = BM_POOL_Config(&bpp);
227 if (pool == NULL)
228 goto err;
229
230 /*
231 * Buffer context must be disabled on FreeBSD
232 * as it could cause memory corruption.
233 */
234 BM_POOL_ConfigBuffContextMode(pool, 0);
235
236 if (minBuffers != 0 || maxBuffers != 0) {
237 error = BM_POOL_ConfigStockpile(pool, maxBuffers, minBuffers);
238 if (error != E_OK)
239 goto err;
240 }
241
242 if (f_Depletion != NULL) {
243 thresholds[BM_POOL_DEP_THRESH_SW_ENTRY] = dep_sw_entry;
244 thresholds[BM_POOL_DEP_THRESH_SW_EXIT] = dep_sw_exit;
245 thresholds[BM_POOL_DEP_THRESH_HW_ENTRY] = dep_hw_entry;
246 thresholds[BM_POOL_DEP_THRESH_HW_EXIT] = dep_hw_exit;
247 error = BM_POOL_ConfigDepletion(pool, f_Depletion, thresholds);
248 if (error != E_OK)
249 goto err;
250 }
251
252 error = BM_POOL_Init(pool);
253 if (error != E_OK)
254 goto err;
255
256 *bpid = BM_POOL_GetId(pool);
257 sc->sc_bpool_cpu[*bpid] = PCPU_GET(cpuid);
258
259 sched_unpin();
260
261 return (pool);
262
263 err:
264 if (pool != NULL)
265 BM_POOL_Free(pool);
266
267 sched_unpin();
268
269 return (NULL);
270 }
271
272 int
bman_pool_destroy(t_Handle pool)273 bman_pool_destroy(t_Handle pool)
274 {
275 struct bman_softc *sc;
276
277 sc = bman_sc;
278 thread_lock(curthread);
279 sched_bind(curthread, sc->sc_bpool_cpu[BM_POOL_GetId(pool)]);
280 thread_unlock(curthread);
281
282 BM_POOL_Free(pool);
283
284 thread_lock(curthread);
285 sched_unbind(curthread);
286 thread_unlock(curthread);
287
288 return (0);
289 }
290
291 int
bman_pool_fill(t_Handle pool,uint16_t nbufs)292 bman_pool_fill(t_Handle pool, uint16_t nbufs)
293 {
294 struct bman_softc *sc;
295 t_Handle portal;
296 int error;
297
298 sc = bman_sc;
299 sched_pin();
300
301 portal = bman_portal_setup(sc);
302 if (portal == NULL) {
303 sched_unpin();
304 return (EIO);
305 }
306
307 error = BM_POOL_FillBufs(pool, portal, nbufs);
308
309 sched_unpin();
310
311 return ((error == E_OK) ? 0 : EIO);
312 }
313
314 void *
bman_get_buffer(t_Handle pool)315 bman_get_buffer(t_Handle pool)
316 {
317 struct bman_softc *sc;
318 t_Handle portal;
319 void *buffer;
320
321 sc = bman_sc;
322 sched_pin();
323
324 portal = bman_portal_setup(sc);
325 if (portal == NULL) {
326 sched_unpin();
327 return (NULL);
328 }
329
330 buffer = BM_POOL_GetBuf(pool, portal);
331
332 sched_unpin();
333
334 return (buffer);
335 }
336
337 int
bman_put_buffer(t_Handle pool,void * buffer)338 bman_put_buffer(t_Handle pool, void *buffer)
339 {
340 struct bman_softc *sc;
341 t_Handle portal;
342 int error;
343
344 sc = bman_sc;
345 sched_pin();
346
347 portal = bman_portal_setup(sc);
348 if (portal == NULL) {
349 sched_unpin();
350 return (EIO);
351 }
352
353 error = BM_POOL_PutBuf(pool, portal, buffer);
354
355 sched_unpin();
356
357 return ((error == E_OK) ? 0 : EIO);
358 }
359
360 uint32_t
bman_count(t_Handle pool)361 bman_count(t_Handle pool)
362 {
363
364 return (BM_POOL_GetCounter(pool, e_BM_POOL_COUNTERS_CONTENT));
365 }
366