icap_ebus.c revision 1.3 1 1.3 chs /* $NetBSD: icap_ebus.c,v 1.3 2012/10/27 17:17:45 chs Exp $ */
2 1.1 pooka
3 1.1 pooka /*-
4 1.1 pooka * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 1.1 pooka * All rights reserved.
6 1.1 pooka *
7 1.1 pooka * This code was written by Alessandro Forin and Neil Pittman
8 1.1 pooka * at Microsoft Research and contributed to The NetBSD Foundation
9 1.1 pooka * by Microsoft Corporation.
10 1.1 pooka *
11 1.1 pooka * Redistribution and use in source and binary forms, with or without
12 1.1 pooka * modification, are permitted provided that the following conditions
13 1.1 pooka * are met:
14 1.1 pooka * 1. Redistributions of source code must retain the above copyright
15 1.1 pooka * notice, this list of conditions and the following disclaimer.
16 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 pooka * notice, this list of conditions and the following disclaimer in the
18 1.1 pooka * documentation and/or other materials provided with the distribution.
19 1.1 pooka *
20 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.1 pooka * POSSIBILITY OF SUCH DAMAGE.
31 1.1 pooka */
32 1.1 pooka
33 1.1 pooka #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
34 1.3 chs __KERNEL_RCSID(0, "$NetBSD: icap_ebus.c,v 1.3 2012/10/27 17:17:45 chs Exp $");
35 1.1 pooka
36 1.1 pooka #include <sys/param.h>
37 1.1 pooka #include <sys/systm.h>
38 1.1 pooka #include <sys/buf.h>
39 1.1 pooka #include <sys/bufq.h>
40 1.1 pooka #include <sys/proc.h>
41 1.1 pooka #include <sys/errno.h>
42 1.1 pooka #include <sys/ioctl.h>
43 1.1 pooka #include <sys/device.h>
44 1.1 pooka #include <sys/conf.h>
45 1.1 pooka #include <uvm/uvm_param.h>
46 1.1 pooka
47 1.1 pooka #include <emips/ebus/ebusvar.h>
48 1.1 pooka #include <emips/emips/machdep.h>
49 1.1 pooka #include <machine/emipsreg.h>
50 1.1 pooka
51 1.1 pooka #define DEBUG_INTR 0x01
52 1.1 pooka #define DEBUG_XFERS 0x02
53 1.1 pooka #define DEBUG_STATUS 0x04
54 1.1 pooka #define DEBUG_FUNCS 0x08
55 1.1 pooka #define DEBUG_PROBE 0x10
56 1.1 pooka #define DEBUG_WRITES 0x20
57 1.1 pooka #define DEBUG_READS 0x40
58 1.1 pooka #define DEBUG_ERRORS 0x80
59 1.1 pooka #ifdef DEBUG
60 1.1 pooka int icap_debug = DEBUG_ERRORS;
61 1.1 pooka #define ICAP_DEBUG(x) (icap_debug & (x))
62 1.1 pooka #define DBGME(_lev_,_x_) if ((_lev_) & icap_debug) _x_
63 1.1 pooka #else
64 1.1 pooka #define ICAP_DEBUG(x) (0)
65 1.1 pooka #define DBGME(_lev_,_x_)
66 1.1 pooka #endif
67 1.1 pooka #define DEBUG_PRINT(_args_,_lev_) DBGME(_lev_,printf _args_)
68 1.1 pooka
69 1.1 pooka /*
70 1.1 pooka * Device softc
71 1.1 pooka */
72 1.1 pooka struct icap_softc {
73 1.1 pooka device_t sc_dev;
74 1.1 pooka struct _Icap *sc_dp;
75 1.1 pooka struct bufq_state *sc_buflist;
76 1.1 pooka struct buf *sc_bp;
77 1.1 pooka char *sc_data;
78 1.1 pooka int sc_count;
79 1.1 pooka };
80 1.1 pooka
81 1.1 pooka /* Required funcs
82 1.1 pooka */
83 1.3 chs static int icap_ebus_match (device_t, cfdata_t, void *);
84 1.3 chs static void icap_ebus_attach (device_t, device_t, void *);
85 1.1 pooka
86 1.1 pooka static dev_type_open(icapopen);
87 1.1 pooka static dev_type_close(icapclose);
88 1.1 pooka static dev_type_read(icapread);
89 1.1 pooka static dev_type_write(icapwrite);
90 1.1 pooka static dev_type_ioctl(icapioctl);
91 1.1 pooka static dev_type_strategy(icapstrategy);
92 1.1 pooka
93 1.1 pooka /* Other functions
94 1.1 pooka */
95 1.1 pooka extern paddr_t kvtophys(vaddr_t);
96 1.1 pooka static void icapstart(struct icap_softc *sc);
97 1.1 pooka static int icap_ebus_intr(void *cookie, void *f);
98 1.1 pooka static void icap_reset(struct icap_softc *sc);
99 1.1 pooka
100 1.1 pooka /* Config stuff
101 1.1 pooka */
102 1.1 pooka extern struct cfdriver icap_cd;
103 1.1 pooka
104 1.1 pooka CFATTACH_DECL_NEW(icap_ebus, sizeof (struct icap_softc),
105 1.1 pooka icap_ebus_match, icap_ebus_attach, NULL, NULL);
106 1.1 pooka
107 1.1 pooka static int
108 1.3 chs icap_ebus_match(device_t parent, cfdata_t match, void *aux)
109 1.1 pooka {
110 1.1 pooka struct ebus_attach_args *ia = aux;
111 1.1 pooka struct _Icap *f = (struct _Icap *)ia->ia_vaddr;
112 1.1 pooka
113 1.1 pooka DEBUG_PRINT(("icap_match %x\n", (f) ? f->Tag : 0), DEBUG_PROBE);
114 1.1 pooka if (strcmp("icap", ia->ia_name) != 0)
115 1.1 pooka return (0);
116 1.1 pooka if ((f == NULL) ||
117 1.1 pooka (! (f->Tag == PMTTAG_ICAP)))
118 1.1 pooka return (0);
119 1.1 pooka
120 1.1 pooka return (1);
121 1.1 pooka }
122 1.1 pooka
123 1.1 pooka static void
124 1.3 chs icap_ebus_attach(device_t parent, device_t self, void *aux)
125 1.1 pooka {
126 1.1 pooka struct icap_softc *sc = device_private(self);
127 1.1 pooka struct ebus_attach_args *ia =aux;
128 1.1 pooka
129 1.1 pooka DEBUG_PRINT(("icap_attach %p\n", sc), DEBUG_PROBE);
130 1.1 pooka
131 1.1 pooka sc->sc_dev = self;
132 1.1 pooka sc->sc_dp = (struct _Icap*)ia->ia_vaddr;
133 1.1 pooka bufq_alloc(&sc->sc_buflist, "fcfs", 0);
134 1.1 pooka sc->sc_bp = NULL;
135 1.1 pooka sc->sc_data = NULL;
136 1.1 pooka sc->sc_count = 0;
137 1.1 pooka
138 1.1 pooka #if DEBUG
139 1.1 pooka printf(" virt=%p", (void*)sc->sc_dp);
140 1.1 pooka #endif
141 1.1 pooka printf(": %s\n", "Internal Configuration Access Port");
142 1.1 pooka
143 1.1 pooka ebus_intr_establish(parent, (void*)ia->ia_cookie, IPL_BIO,
144 1.1 pooka icap_ebus_intr, sc);
145 1.1 pooka
146 1.1 pooka icap_reset(sc);
147 1.1 pooka }
148 1.1 pooka
149 1.1 pooka /* The character device handlers
150 1.1 pooka */
151 1.1 pooka const struct cdevsw icap_cdevsw = {
152 1.1 pooka icapopen,
153 1.1 pooka icapclose,
154 1.1 pooka icapread,
155 1.1 pooka icapwrite,
156 1.1 pooka icapioctl,
157 1.1 pooka nostop,
158 1.1 pooka notty,
159 1.1 pooka nopoll,
160 1.1 pooka nommap,
161 1.1 pooka nokqfilter,
162 1.1 pooka };
163 1.1 pooka
164 1.1 pooka /*
165 1.1 pooka * Handle an open request on the device.
166 1.1 pooka */
167 1.1 pooka static int
168 1.1 pooka icapopen(dev_t device, int flags, int fmt, struct lwp *process)
169 1.1 pooka {
170 1.1 pooka struct icap_softc *sc;
171 1.1 pooka
172 1.1 pooka DEBUG_PRINT(("icapopen\n"), DEBUG_FUNCS);
173 1.1 pooka sc = device_lookup_private(&icap_cd, minor(device));
174 1.1 pooka if (sc == NULL)
175 1.1 pooka return (ENXIO);
176 1.1 pooka
177 1.1 pooka return 0;
178 1.1 pooka }
179 1.1 pooka
180 1.1 pooka /*
181 1.1 pooka * Handle the close request for the device.
182 1.1 pooka */
183 1.1 pooka static int
184 1.1 pooka icapclose(dev_t device, int flags, int fmt, struct lwp *process)
185 1.1 pooka {
186 1.1 pooka DEBUG_PRINT(("icapclose\n"), DEBUG_FUNCS);
187 1.1 pooka return 0; /* this always succeeds */
188 1.1 pooka }
189 1.1 pooka
190 1.1 pooka /*
191 1.1 pooka * Handle the read request for the device.
192 1.1 pooka */
193 1.1 pooka static int
194 1.1 pooka icapread(dev_t dev, struct uio *uio, int flags)
195 1.1 pooka {
196 1.1 pooka DEBUG_PRINT(("icapread\n"), DEBUG_READS);
197 1.1 pooka return (physio(icapstrategy, NULL, dev, B_READ, minphys, uio));
198 1.1 pooka }
199 1.1 pooka
200 1.1 pooka /*
201 1.1 pooka * Handle the write request for the device.
202 1.1 pooka */
203 1.1 pooka static int
204 1.1 pooka icapwrite(dev_t dev, struct uio *uio, int flags)
205 1.1 pooka {
206 1.1 pooka DEBUG_PRINT(("icapwrite\n"), DEBUG_WRITES);
207 1.1 pooka return (physio(icapstrategy, NULL, dev, B_WRITE, minphys, uio));
208 1.1 pooka }
209 1.1 pooka
210 1.1 pooka /*
211 1.1 pooka * Handle the ioctl request for the device.
212 1.1 pooka */
213 1.1 pooka static int
214 1.1 pooka icapioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l)
215 1.1 pooka {
216 1.1 pooka
217 1.1 pooka return ENOTTY;
218 1.1 pooka }
219 1.1 pooka
220 1.1 pooka /*
221 1.1 pooka * Strategy function for the device.
222 1.1 pooka */
223 1.1 pooka static void
224 1.1 pooka icapstrategy(struct buf *bp)
225 1.1 pooka {
226 1.1 pooka struct icap_softc *sc;
227 1.1 pooka int s;
228 1.1 pooka
229 1.1 pooka DEBUG_PRINT(("icapstrategy\n"), DEBUG_FUNCS);
230 1.1 pooka
231 1.1 pooka /* We did nothing lest we did */
232 1.1 pooka bp->b_resid = bp->b_bcount;
233 1.1 pooka
234 1.1 pooka /* Do we know you. */
235 1.1 pooka sc = device_lookup_private(&icap_cd, minor(bp->b_dev));
236 1.1 pooka if (sc == NULL) {
237 1.2 tsutsui DEBUG_PRINT(("icapstrategy: nodev %" PRIx64 "\n",bp->b_dev),
238 1.1 pooka DEBUG_ERRORS);
239 1.1 pooka bp->b_error = ENXIO;
240 1.1 pooka biodone(bp);
241 1.1 pooka return;
242 1.1 pooka }
243 1.1 pooka
244 1.1 pooka /* Add to Q. If Q was empty get it started */
245 1.1 pooka s = splbio();
246 1.1 pooka bufq_put(sc->sc_buflist, bp);
247 1.1 pooka if (bufq_peek(sc->sc_buflist) == bp) {
248 1.1 pooka icapstart(sc);
249 1.1 pooka }
250 1.1 pooka splx(s);
251 1.1 pooka }
252 1.1 pooka
253 1.1 pooka /*
254 1.1 pooka * Get the next I/O request started
255 1.1 pooka */
256 1.1 pooka static void
257 1.1 pooka icapstart(struct icap_softc *sc)
258 1.1 pooka {
259 1.1 pooka paddr_t phys, phys2;
260 1.1 pooka vaddr_t virt;
261 1.1 pooka size_t count;
262 1.1 pooka uint32_t fl;
263 1.1 pooka struct buf *bp = sc->sc_bp;
264 1.1 pooka
265 1.1 pooka DEBUG_PRINT(("icapstart %p %p\n",sc,bp), DEBUG_FUNCS);
266 1.1 pooka
267 1.1 pooka /* Were we idle?
268 1.1 pooka */
269 1.1 pooka recheck:
270 1.1 pooka if (bp == NULL) {
271 1.1 pooka
272 1.1 pooka /* Yes, get the next request if any
273 1.1 pooka */
274 1.1 pooka bp = bufq_get(sc->sc_buflist);
275 1.1 pooka DEBUG_PRINT(("icapnext: %p\n",bp), DEBUG_XFERS);
276 1.1 pooka if (bp == NULL)
277 1.1 pooka return;
278 1.1 pooka }
279 1.1 pooka
280 1.1 pooka /* Done with this request?
281 1.1 pooka */
282 1.1 pooka if ((bp->b_resid == 0) || bp->b_error) {
283 1.1 pooka
284 1.1 pooka /* Yes, complete and move to next, if any
285 1.1 pooka */
286 1.1 pooka sc->sc_bp = NULL;
287 1.1 pooka biodone(bp);
288 1.1 pooka DEBUG_PRINT(("icapdone %p\n",bp), DEBUG_XFERS);
289 1.1 pooka bp = NULL;
290 1.1 pooka goto recheck;
291 1.1 pooka }
292 1.1 pooka
293 1.1 pooka /* If new request init the xfer info
294 1.1 pooka */
295 1.1 pooka if (sc->sc_bp == NULL) {
296 1.1 pooka sc->sc_bp = bp;
297 1.1 pooka sc->sc_data = bp->b_data;
298 1.1 pooka sc->sc_count = bp->b_resid;
299 1.1 pooka }
300 1.1 pooka
301 1.1 pooka /* Loop filling as many buffers as will fit in the FIFO
302 1.1 pooka */
303 1.1 pooka fl = (bp->b_flags & B_READ) ? ICAPS_F_RECV : ICAPS_F_XMIT;
304 1.1 pooka for (;;) {
305 1.1 pooka
306 1.1 pooka /* Make sure there's still room in the FIFO, no errors.
307 1.1 pooka */
308 1.1 pooka if (sc->sc_dp->Control & (ICAPC_IF_FULL|ICAPC_ERROR))
309 1.1 pooka break;
310 1.1 pooka
311 1.1 pooka /* How much data do we xfer and where
312 1.1 pooka */
313 1.1 pooka virt = (vaddr_t)sc->sc_data;
314 1.1 pooka phys = kvtophys(virt);
315 1.1 pooka count = round_page(virt) - virt;
316 1.1 pooka if (count == 0) count = PAGE_SIZE;/* could(will) be aligned */
317 1.1 pooka
318 1.1 pooka /* How much of it is contiguous
319 1.1 pooka */
320 1.1 pooka while (count < sc->sc_count) {
321 1.1 pooka phys2 = kvtophys(virt + count);
322 1.1 pooka if (phys2 != (phys + count)) {
323 1.1 pooka
324 1.1 pooka /* No longer contig, ship it
325 1.1 pooka */
326 1.1 pooka break;
327 1.1 pooka }
328 1.1 pooka count += PAGE_SIZE;
329 1.1 pooka }
330 1.1 pooka
331 1.1 pooka /* Trim if we went too far
332 1.1 pooka */
333 1.1 pooka if (count > sc->sc_count)
334 1.1 pooka count = sc->sc_count;
335 1.1 pooka
336 1.1 pooka /* Ship it
337 1.1 pooka */
338 1.2 tsutsui DEBUG_PRINT(("icapship %" PRIxPADDR " %d\n",phys,count), DEBUG_XFERS);
339 1.1 pooka sc->sc_dp->SizeAndFlags = fl | count;
340 1.1 pooka sc->sc_dp->BufferAddressHi32 = 0; /* BUGBUG 64bit */
341 1.1 pooka sc->sc_dp->BufferAddressLo32 = phys; /* this pushes the fifo */
342 1.1 pooka
343 1.1 pooka /* Adjust pointers and continue
344 1.1 pooka */
345 1.1 pooka sc->sc_data += count;
346 1.1 pooka sc->sc_count -= count;
347 1.1 pooka
348 1.1 pooka if (sc->sc_count <= 0)
349 1.1 pooka break;
350 1.1 pooka }
351 1.1 pooka }
352 1.1 pooka
353 1.1 pooka /*
354 1.1 pooka * Interrupt handler
355 1.1 pooka */
356 1.1 pooka static int
357 1.1 pooka icap_ebus_intr(void *cookie, void *f)
358 1.1 pooka {
359 1.1 pooka struct icap_softc *sc = cookie;
360 1.1 pooka struct buf *bp = sc->sc_bp;
361 1.1 pooka u_int32_t isr, saf = 0, hi, lo;
362 1.1 pooka
363 1.1 pooka isr = sc->sc_dp->Control;
364 1.1 pooka
365 1.1 pooka DEBUG_PRINT(("i %x\n",isr), DEBUG_INTR);
366 1.1 pooka
367 1.1 pooka /* Make sure there is an interrupt and that we should take it
368 1.1 pooka */
369 1.1 pooka if ((isr & (ICAPC_INTEN|ICAPC_DONE)) != (ICAPC_INTEN|ICAPC_DONE))
370 1.1 pooka return (0);
371 1.1 pooka
372 1.1 pooka /* Pull out all completed buffers
373 1.1 pooka */
374 1.1 pooka while ((isr & ICAPC_OF_EMPTY) == 0) {
375 1.1 pooka
376 1.1 pooka if (isr & ICAPC_ERROR) {
377 1.1 pooka printf("%s: internal error (%x)\n", device_xname(sc->sc_dev),isr);
378 1.1 pooka icap_reset(sc);
379 1.1 pooka if (bp) {
380 1.1 pooka bp->b_error = EIO;
381 1.1 pooka icapstart(sc);
382 1.1 pooka }
383 1.1 pooka return (1);
384 1.1 pooka }
385 1.1 pooka
386 1.1 pooka /* Beware, order matters */
387 1.1 pooka saf = sc->sc_dp->SizeAndFlags;
388 1.1 pooka hi = sc->sc_dp->BufferAddressHi32; /* BUGBUG 64bit */
389 1.1 pooka lo = sc->sc_dp->BufferAddressLo32; /* this pops the fifo */
390 1.1 pooka
391 1.1 pooka /* Say its done that much (and sanity)
392 1.1 pooka */
393 1.1 pooka if (bp) {
394 1.1 pooka size_t count = saf & ICAPS_S_MASK;
395 1.1 pooka /* more sanity */
396 1.1 pooka if (count > bp->b_resid)
397 1.1 pooka count = bp->b_resid;
398 1.1 pooka bp->b_resid -= count;
399 1.1 pooka }
400 1.1 pooka
401 1.1 pooka /* More? */
402 1.1 pooka isr = sc->sc_dp->Control;
403 1.1 pooka }
404 1.1 pooka
405 1.1 pooka /* Did we pop at least one */
406 1.1 pooka if (saf)
407 1.1 pooka icapstart(sc);
408 1.1 pooka
409 1.1 pooka return (1);
410 1.1 pooka }
411 1.1 pooka
412 1.1 pooka /*
413 1.1 pooka * HW (re)Initialization
414 1.1 pooka */
415 1.1 pooka static void
416 1.1 pooka icap_reset(struct icap_softc *sc)
417 1.1 pooka {
418 1.1 pooka DEBUG_PRINT(("icap_reset %x\n",sc->sc_dp->Control), DEBUG_STATUS);
419 1.1 pooka sc->sc_dp->Control = ICAPC_RESET;
420 1.1 pooka DELAY(2);
421 1.1 pooka sc->sc_dp->Control = ICAPC_INTEN;
422 1.1 pooka }
423