xref: /freebsd/sys/dev/dpaa/bman.c (revision d5b0e70f7e04d971691517ce1304d86a1e367e2e)
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 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/lock.h>
35 #include <sys/module.h>
36 #include <sys/mutex.h>
37 #include <sys/proc.h>
38 #include <sys/pcpu.h>
39 #include <sys/rman.h>
40 #include <sys/sched.h>
41 
42 #include <machine/tlb.h>
43 
44 #include "bman.h"
45 
46 static struct bman_softc *bman_sc;
47 
48 extern t_Handle bman_portal_setup(struct bman_softc *bsc);
49 
50 static void
51 bman_exception(t_Handle h_App, e_BmExceptions exception)
52 {
53 	struct bman_softc *sc;
54 	const char *message;
55 
56 	sc = h_App;
57 
58 	switch (exception) {
59     	case e_BM_EX_INVALID_COMMAND:
60 		message = "Invalid Command Verb";
61 		break;
62 	case e_BM_EX_FBPR_THRESHOLD:
63 		message = "FBPR pool exhaused. Consider increasing "
64 		    "BMAN_MAX_BUFFERS";
65 		break;
66 	case e_BM_EX_SINGLE_ECC:
67 		message = "Single bit ECC error";
68 		break;
69 	case e_BM_EX_MULTI_ECC:
70 		message = "Multi bit ECC error";
71 		break;
72 	default:
73 		message = "Unknown error";
74 	}
75 
76 	device_printf(sc->sc_dev, "BMAN Exception: %s.\n", message);
77 }
78 
79 int
80 bman_attach(device_t dev)
81 {
82 	struct bman_softc *sc;
83 	t_BmRevisionInfo rev;
84 	t_Error error;
85 	t_BmParam bp;
86 
87 	sc = device_get_softc(dev);
88 	sc->sc_dev = dev;
89 	bman_sc = sc;
90 
91 	/* Check if MallocSmart allocator is ready */
92 	if (XX_MallocSmartInit() != E_OK)
93 		return (ENXIO);
94 
95 	/* Allocate resources */
96 	sc->sc_rrid = 0;
97 	sc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY,
98 	    &sc->sc_rrid, BMAN_CCSR_SIZE, RF_ACTIVE);
99 	if (sc->sc_rres == NULL)
100 		return (ENXIO);
101 
102 	sc->sc_irid = 0;
103 	sc->sc_ires = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ,
104 	    &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE);
105 	if (sc->sc_ires == NULL)
106 		goto err;
107 
108 	/* Initialize BMAN */
109 	memset(&bp, 0, sizeof(bp));
110 	bp.guestId = NCSW_MASTER_ID;
111 	bp.baseAddress = rman_get_bushandle(sc->sc_rres);
112 	bp.totalNumOfBuffers = BMAN_MAX_BUFFERS;
113 	bp.f_Exception = bman_exception;
114 	bp.h_App = sc;
115 	bp.errIrq = (uintptr_t)sc->sc_ires;
116 	bp.partBpidBase = 0;
117 	bp.partNumOfPools = BM_MAX_NUM_OF_POOLS;
118 
119 	sc->sc_bh = BM_Config(&bp);
120 	if (sc->sc_bh == NULL)
121 		goto err;
122 
123 	/* Warn if there is less than 5% free FPBR's in pool */
124 	error = BM_ConfigFbprThreshold(sc->sc_bh, (BMAN_MAX_BUFFERS / 8) / 20);
125 	if (error != E_OK)
126 		goto err;
127 
128 	error = BM_Init(sc->sc_bh);
129 	if (error != E_OK)
130 		goto err;
131 
132 	error = BM_GetRevision(sc->sc_bh, &rev);
133 	if (error != E_OK)
134 		goto err;
135 
136 	device_printf(dev, "Hardware version: %d.%d.\n",
137 	    rev.majorRev, rev.minorRev);
138 
139 	return (0);
140 
141 err:
142 	bman_detach(dev);
143 	return (ENXIO);
144 }
145 
146 int
147 bman_detach(device_t dev)
148 {
149 	struct bman_softc *sc;
150 
151 	sc = device_get_softc(dev);
152 
153 	if (sc->sc_bh != NULL)
154 		BM_Free(sc->sc_bh);
155 
156 	if (sc->sc_ires != NULL)
157 		bus_release_resource(dev, SYS_RES_IRQ,
158 		    sc->sc_irid, sc->sc_ires);
159 
160 	if (sc->sc_rres != NULL)
161 		bus_release_resource(dev, SYS_RES_MEMORY,
162 		    sc->sc_rrid, sc->sc_rres);
163 
164 	return (0);
165 }
166 
167 int
168 bman_suspend(device_t dev)
169 {
170 
171 	return (0);
172 }
173 
174 int
175 bman_resume(device_t dev)
176 {
177 
178 	return (0);
179 }
180 
181 int
182 bman_shutdown(device_t dev)
183 {
184 
185 	return (0);
186 }
187 
188 /*
189  * BMAN API
190  */
191 
192 t_Handle
193 bman_pool_create(uint8_t *bpid, uint16_t bufferSize, uint16_t maxBuffers,
194     uint16_t minBuffers, uint16_t allocBuffers, t_GetBufFunction *f_GetBuf,
195     t_PutBufFunction *f_PutBuf, uint32_t dep_sw_entry, uint32_t dep_sw_exit,
196     uint32_t dep_hw_entry, uint32_t dep_hw_exit,
197     t_BmDepletionCallback *f_Depletion, t_Handle h_BufferPool,
198     t_PhysToVirt *f_PhysToVirt, t_VirtToPhys *f_VirtToPhys)
199 {
200 	uint32_t thresholds[MAX_DEPLETION_THRESHOLDS];
201 	struct bman_softc *sc;
202 	t_Handle pool, portal;
203 	t_BmPoolParam bpp;
204 	int error;
205 
206 	sc = bman_sc;
207 	pool = NULL;
208 
209 	sched_pin();
210 
211 	portal = bman_portal_setup(sc);
212 	if (portal == NULL)
213 		goto err;
214 
215 	memset(&bpp, 0, sizeof(bpp));
216 	bpp.h_Bm = sc->sc_bh;
217 	bpp.h_BmPortal = portal;
218 	bpp.h_App = h_BufferPool;
219 	bpp.numOfBuffers = allocBuffers;
220 
221 	bpp.bufferPoolInfo.h_BufferPool = h_BufferPool;
222 	bpp.bufferPoolInfo.f_GetBuf = f_GetBuf;
223 	bpp.bufferPoolInfo.f_PutBuf = f_PutBuf;
224 	bpp.bufferPoolInfo.f_PhysToVirt = f_PhysToVirt;
225 	bpp.bufferPoolInfo.f_VirtToPhys = f_VirtToPhys;
226 	bpp.bufferPoolInfo.bufferSize = bufferSize;
227 
228 	pool = BM_POOL_Config(&bpp);
229 	if (pool == NULL)
230 		goto err;
231 
232 	/*
233 	 * Buffer context must be disabled on FreeBSD
234 	 * as it could cause memory corruption.
235 	 */
236 	BM_POOL_ConfigBuffContextMode(pool, 0);
237 
238 	if (minBuffers != 0 || maxBuffers != 0) {
239 		error = BM_POOL_ConfigStockpile(pool, maxBuffers, minBuffers);
240 		if (error != E_OK)
241 			goto err;
242 	}
243 
244 	if (f_Depletion != NULL) {
245 		thresholds[BM_POOL_DEP_THRESH_SW_ENTRY] = dep_sw_entry;
246 		thresholds[BM_POOL_DEP_THRESH_SW_EXIT] = dep_sw_exit;
247 		thresholds[BM_POOL_DEP_THRESH_HW_ENTRY] = dep_hw_entry;
248 		thresholds[BM_POOL_DEP_THRESH_HW_EXIT] = dep_hw_exit;
249 		error = BM_POOL_ConfigDepletion(pool, f_Depletion, thresholds);
250 		if (error != E_OK)
251 			goto err;
252 	}
253 
254 	error = BM_POOL_Init(pool);
255 	if (error != E_OK)
256 		goto err;
257 
258 	*bpid = BM_POOL_GetId(pool);
259 	sc->sc_bpool_cpu[*bpid] = PCPU_GET(cpuid);
260 
261 	sched_unpin();
262 
263 	return (pool);
264 
265 err:
266 	if (pool != NULL)
267 		BM_POOL_Free(pool);
268 
269 	sched_unpin();
270 
271 	return (NULL);
272 }
273 
274 int
275 bman_pool_destroy(t_Handle pool)
276 {
277 	struct bman_softc *sc;
278 
279 	sc = bman_sc;
280 	thread_lock(curthread);
281 	sched_bind(curthread, sc->sc_bpool_cpu[BM_POOL_GetId(pool)]);
282 	thread_unlock(curthread);
283 
284 	BM_POOL_Free(pool);
285 
286 	thread_lock(curthread);
287 	sched_unbind(curthread);
288 	thread_unlock(curthread);
289 
290 	return (0);
291 }
292 
293 int
294 bman_pool_fill(t_Handle pool, uint16_t nbufs)
295 {
296 	struct bman_softc *sc;
297 	t_Handle portal;
298 	int error;
299 
300 	sc = bman_sc;
301 	sched_pin();
302 
303 	portal = bman_portal_setup(sc);
304 	if (portal == NULL) {
305 		sched_unpin();
306 		return (EIO);
307 	}
308 
309 	error = BM_POOL_FillBufs(pool, portal, nbufs);
310 
311 	sched_unpin();
312 
313 	return ((error == E_OK) ? 0 : EIO);
314 }
315 
316 void *
317 bman_get_buffer(t_Handle pool)
318 {
319 	struct bman_softc *sc;
320 	t_Handle portal;
321 	void *buffer;
322 
323 	sc = bman_sc;
324 	sched_pin();
325 
326 	portal = bman_portal_setup(sc);
327 	if (portal == NULL) {
328 		sched_unpin();
329 		return (NULL);
330 	}
331 
332 	buffer = BM_POOL_GetBuf(pool, portal);
333 
334 	sched_unpin();
335 
336 	return (buffer);
337 }
338 
339 int
340 bman_put_buffer(t_Handle pool, void *buffer)
341 {
342 	struct bman_softc *sc;
343 	t_Handle portal;
344 	int error;
345 
346 	sc = bman_sc;
347 	sched_pin();
348 
349 	portal = bman_portal_setup(sc);
350 	if (portal == NULL) {
351 		sched_unpin();
352 		return (EIO);
353 	}
354 
355 	error = BM_POOL_PutBuf(pool, portal, buffer);
356 
357 	sched_unpin();
358 
359 	return ((error == E_OK) ? 0 : EIO);
360 }
361 
362 uint32_t
363 bman_count(t_Handle pool)
364 {
365 
366 	return (BM_POOL_GetCounter(pool, e_BM_POOL_COUNTERS_CONTENT));
367 }
368