1 1.7 mrg /* $NetBSD: icap_ebus.c,v 1.7 2018/03/04 21:41:48 mrg 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.7 mrg __KERNEL_RCSID(0, "$NetBSD: icap_ebus.c,v 1.7 2018/03/04 21:41:48 mrg 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.5 dholland .d_open = icapopen, 153 1.5 dholland .d_close = icapclose, 154 1.5 dholland .d_read = icapread, 155 1.5 dholland .d_write = icapwrite, 156 1.5 dholland .d_ioctl = icapioctl, 157 1.5 dholland .d_stop = nostop, 158 1.5 dholland .d_tty = notty, 159 1.5 dholland .d_poll = nopoll, 160 1.5 dholland .d_mmap = nommap, 161 1.5 dholland .d_kqfilter = nokqfilter, 162 1.6 dholland .d_discard = nodiscard, 163 1.5 dholland .d_flag = 0 164 1.1 pooka }; 165 1.1 pooka 166 1.1 pooka /* 167 1.1 pooka * Handle an open request on the device. 168 1.1 pooka */ 169 1.1 pooka static int 170 1.1 pooka icapopen(dev_t device, int flags, int fmt, struct lwp *process) 171 1.1 pooka { 172 1.1 pooka struct icap_softc *sc; 173 1.1 pooka 174 1.1 pooka DEBUG_PRINT(("icapopen\n"), DEBUG_FUNCS); 175 1.1 pooka sc = device_lookup_private(&icap_cd, minor(device)); 176 1.1 pooka if (sc == NULL) 177 1.1 pooka return (ENXIO); 178 1.1 pooka 179 1.1 pooka return 0; 180 1.1 pooka } 181 1.1 pooka 182 1.1 pooka /* 183 1.1 pooka * Handle the close request for the device. 184 1.1 pooka */ 185 1.1 pooka static int 186 1.1 pooka icapclose(dev_t device, int flags, int fmt, struct lwp *process) 187 1.1 pooka { 188 1.1 pooka DEBUG_PRINT(("icapclose\n"), DEBUG_FUNCS); 189 1.1 pooka return 0; /* this always succeeds */ 190 1.1 pooka } 191 1.1 pooka 192 1.1 pooka /* 193 1.1 pooka * Handle the read request for the device. 194 1.1 pooka */ 195 1.1 pooka static int 196 1.1 pooka icapread(dev_t dev, struct uio *uio, int flags) 197 1.1 pooka { 198 1.1 pooka DEBUG_PRINT(("icapread\n"), DEBUG_READS); 199 1.1 pooka return (physio(icapstrategy, NULL, dev, B_READ, minphys, uio)); 200 1.1 pooka } 201 1.1 pooka 202 1.1 pooka /* 203 1.1 pooka * Handle the write request for the device. 204 1.1 pooka */ 205 1.1 pooka static int 206 1.1 pooka icapwrite(dev_t dev, struct uio *uio, int flags) 207 1.1 pooka { 208 1.1 pooka DEBUG_PRINT(("icapwrite\n"), DEBUG_WRITES); 209 1.1 pooka return (physio(icapstrategy, NULL, dev, B_WRITE, minphys, uio)); 210 1.1 pooka } 211 1.1 pooka 212 1.1 pooka /* 213 1.1 pooka * Handle the ioctl request for the device. 214 1.1 pooka */ 215 1.1 pooka static int 216 1.1 pooka icapioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l) 217 1.1 pooka { 218 1.1 pooka 219 1.1 pooka return ENOTTY; 220 1.1 pooka } 221 1.1 pooka 222 1.1 pooka /* 223 1.1 pooka * Strategy function for the device. 224 1.1 pooka */ 225 1.1 pooka static void 226 1.1 pooka icapstrategy(struct buf *bp) 227 1.1 pooka { 228 1.1 pooka struct icap_softc *sc; 229 1.1 pooka int s; 230 1.1 pooka 231 1.1 pooka DEBUG_PRINT(("icapstrategy\n"), DEBUG_FUNCS); 232 1.1 pooka 233 1.1 pooka /* We did nothing lest we did */ 234 1.1 pooka bp->b_resid = bp->b_bcount; 235 1.1 pooka 236 1.1 pooka /* Do we know you. */ 237 1.1 pooka sc = device_lookup_private(&icap_cd, minor(bp->b_dev)); 238 1.1 pooka if (sc == NULL) { 239 1.2 tsutsui DEBUG_PRINT(("icapstrategy: nodev %" PRIx64 "\n",bp->b_dev), 240 1.1 pooka DEBUG_ERRORS); 241 1.1 pooka bp->b_error = ENXIO; 242 1.1 pooka biodone(bp); 243 1.1 pooka return; 244 1.1 pooka } 245 1.1 pooka 246 1.1 pooka /* Add to Q. If Q was empty get it started */ 247 1.1 pooka s = splbio(); 248 1.1 pooka bufq_put(sc->sc_buflist, bp); 249 1.1 pooka if (bufq_peek(sc->sc_buflist) == bp) { 250 1.1 pooka icapstart(sc); 251 1.1 pooka } 252 1.1 pooka splx(s); 253 1.1 pooka } 254 1.1 pooka 255 1.1 pooka /* 256 1.1 pooka * Get the next I/O request started 257 1.1 pooka */ 258 1.1 pooka static void 259 1.1 pooka icapstart(struct icap_softc *sc) 260 1.1 pooka { 261 1.1 pooka paddr_t phys, phys2; 262 1.1 pooka vaddr_t virt; 263 1.1 pooka size_t count; 264 1.1 pooka uint32_t fl; 265 1.1 pooka struct buf *bp = sc->sc_bp; 266 1.1 pooka 267 1.1 pooka DEBUG_PRINT(("icapstart %p %p\n",sc,bp), DEBUG_FUNCS); 268 1.1 pooka 269 1.1 pooka /* Were we idle? 270 1.1 pooka */ 271 1.1 pooka recheck: 272 1.1 pooka if (bp == NULL) { 273 1.1 pooka 274 1.1 pooka /* Yes, get the next request if any 275 1.1 pooka */ 276 1.1 pooka bp = bufq_get(sc->sc_buflist); 277 1.1 pooka DEBUG_PRINT(("icapnext: %p\n",bp), DEBUG_XFERS); 278 1.1 pooka if (bp == NULL) 279 1.1 pooka return; 280 1.1 pooka } 281 1.1 pooka 282 1.1 pooka /* Done with this request? 283 1.1 pooka */ 284 1.1 pooka if ((bp->b_resid == 0) || bp->b_error) { 285 1.1 pooka 286 1.1 pooka /* Yes, complete and move to next, if any 287 1.1 pooka */ 288 1.1 pooka sc->sc_bp = NULL; 289 1.1 pooka biodone(bp); 290 1.1 pooka DEBUG_PRINT(("icapdone %p\n",bp), DEBUG_XFERS); 291 1.1 pooka bp = NULL; 292 1.1 pooka goto recheck; 293 1.1 pooka } 294 1.1 pooka 295 1.1 pooka /* If new request init the xfer info 296 1.1 pooka */ 297 1.1 pooka if (sc->sc_bp == NULL) { 298 1.1 pooka sc->sc_bp = bp; 299 1.1 pooka sc->sc_data = bp->b_data; 300 1.1 pooka sc->sc_count = bp->b_resid; 301 1.1 pooka } 302 1.1 pooka 303 1.1 pooka /* Loop filling as many buffers as will fit in the FIFO 304 1.1 pooka */ 305 1.1 pooka fl = (bp->b_flags & B_READ) ? ICAPS_F_RECV : ICAPS_F_XMIT; 306 1.1 pooka for (;;) { 307 1.1 pooka 308 1.1 pooka /* Make sure there's still room in the FIFO, no errors. 309 1.1 pooka */ 310 1.1 pooka if (sc->sc_dp->Control & (ICAPC_IF_FULL|ICAPC_ERROR)) 311 1.1 pooka break; 312 1.1 pooka 313 1.1 pooka /* How much data do we xfer and where 314 1.1 pooka */ 315 1.1 pooka virt = (vaddr_t)sc->sc_data; 316 1.1 pooka phys = kvtophys(virt); 317 1.1 pooka count = round_page(virt) - virt; 318 1.1 pooka if (count == 0) count = PAGE_SIZE;/* could(will) be aligned */ 319 1.1 pooka 320 1.1 pooka /* How much of it is contiguous 321 1.1 pooka */ 322 1.1 pooka while (count < sc->sc_count) { 323 1.1 pooka phys2 = kvtophys(virt + count); 324 1.1 pooka if (phys2 != (phys + count)) { 325 1.1 pooka 326 1.1 pooka /* No longer contig, ship it 327 1.1 pooka */ 328 1.1 pooka break; 329 1.1 pooka } 330 1.1 pooka count += PAGE_SIZE; 331 1.1 pooka } 332 1.1 pooka 333 1.1 pooka /* Trim if we went too far 334 1.1 pooka */ 335 1.1 pooka if (count > sc->sc_count) 336 1.1 pooka count = sc->sc_count; 337 1.1 pooka 338 1.1 pooka /* Ship it 339 1.1 pooka */ 340 1.2 tsutsui DEBUG_PRINT(("icapship %" PRIxPADDR " %d\n",phys,count), DEBUG_XFERS); 341 1.1 pooka sc->sc_dp->SizeAndFlags = fl | count; 342 1.1 pooka sc->sc_dp->BufferAddressHi32 = 0; /* BUGBUG 64bit */ 343 1.1 pooka sc->sc_dp->BufferAddressLo32 = phys; /* this pushes the fifo */ 344 1.1 pooka 345 1.1 pooka /* Adjust pointers and continue 346 1.1 pooka */ 347 1.1 pooka sc->sc_data += count; 348 1.1 pooka sc->sc_count -= count; 349 1.1 pooka 350 1.1 pooka if (sc->sc_count <= 0) 351 1.1 pooka break; 352 1.1 pooka } 353 1.1 pooka } 354 1.1 pooka 355 1.1 pooka /* 356 1.1 pooka * Interrupt handler 357 1.1 pooka */ 358 1.1 pooka static int 359 1.1 pooka icap_ebus_intr(void *cookie, void *f) 360 1.1 pooka { 361 1.1 pooka struct icap_softc *sc = cookie; 362 1.1 pooka struct buf *bp = sc->sc_bp; 363 1.1 pooka u_int32_t isr, saf = 0, hi, lo; 364 1.1 pooka 365 1.1 pooka isr = sc->sc_dp->Control; 366 1.1 pooka 367 1.1 pooka DEBUG_PRINT(("i %x\n",isr), DEBUG_INTR); 368 1.1 pooka 369 1.1 pooka /* Make sure there is an interrupt and that we should take it 370 1.1 pooka */ 371 1.1 pooka if ((isr & (ICAPC_INTEN|ICAPC_DONE)) != (ICAPC_INTEN|ICAPC_DONE)) 372 1.1 pooka return (0); 373 1.1 pooka 374 1.1 pooka /* Pull out all completed buffers 375 1.1 pooka */ 376 1.1 pooka while ((isr & ICAPC_OF_EMPTY) == 0) { 377 1.1 pooka 378 1.1 pooka if (isr & ICAPC_ERROR) { 379 1.1 pooka printf("%s: internal error (%x)\n", device_xname(sc->sc_dev),isr); 380 1.1 pooka icap_reset(sc); 381 1.1 pooka if (bp) { 382 1.1 pooka bp->b_error = EIO; 383 1.1 pooka icapstart(sc); 384 1.1 pooka } 385 1.1 pooka return (1); 386 1.1 pooka } 387 1.1 pooka 388 1.1 pooka /* Beware, order matters */ 389 1.1 pooka saf = sc->sc_dp->SizeAndFlags; 390 1.1 pooka hi = sc->sc_dp->BufferAddressHi32; /* BUGBUG 64bit */ 391 1.1 pooka lo = sc->sc_dp->BufferAddressLo32; /* this pops the fifo */ 392 1.4 christos __USE(hi); 393 1.4 christos __USE(lo); 394 1.1 pooka 395 1.1 pooka /* Say its done that much (and sanity) 396 1.1 pooka */ 397 1.1 pooka if (bp) { 398 1.1 pooka size_t count = saf & ICAPS_S_MASK; 399 1.1 pooka /* more sanity */ 400 1.1 pooka if (count > bp->b_resid) 401 1.1 pooka count = bp->b_resid; 402 1.1 pooka bp->b_resid -= count; 403 1.1 pooka } 404 1.1 pooka 405 1.1 pooka /* More? */ 406 1.1 pooka isr = sc->sc_dp->Control; 407 1.1 pooka } 408 1.1 pooka 409 1.1 pooka /* Did we pop at least one */ 410 1.1 pooka if (saf) 411 1.1 pooka icapstart(sc); 412 1.1 pooka 413 1.7 mrg return (1); 414 1.1 pooka } 415 1.1 pooka 416 1.1 pooka /* 417 1.1 pooka * HW (re)Initialization 418 1.1 pooka */ 419 1.1 pooka static void 420 1.1 pooka icap_reset(struct icap_softc *sc) 421 1.1 pooka { 422 1.1 pooka DEBUG_PRINT(("icap_reset %x\n",sc->sc_dp->Control), DEBUG_STATUS); 423 1.1 pooka sc->sc_dp->Control = ICAPC_RESET; 424 1.1 pooka DELAY(2); 425 1.1 pooka sc->sc_dp->Control = ICAPC_INTEN; 426 1.1 pooka } 427