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