1 /*- 2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * SRI-Cambridge BERI soft processor <-> ARM core ring buffer. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/bus.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/malloc.h> 41 #include <sys/rman.h> 42 #include <sys/timeet.h> 43 #include <sys/timetc.h> 44 #include <sys/conf.h> 45 #include <sys/uio.h> 46 #include <sys/stat.h> 47 #include <sys/time.h> 48 #include <sys/event.h> 49 #include <sys/selinfo.h> 50 51 #include <dev/fdt/fdt_common.h> 52 #include <dev/ofw/openfirm.h> 53 #include <dev/ofw/ofw_bus.h> 54 #include <dev/ofw/ofw_bus_subr.h> 55 56 #include <machine/bus.h> 57 #include <machine/fdt.h> 58 #include <machine/cpu.h> 59 #include <machine/intr.h> 60 61 #define READ4(_sc, _reg) \ 62 bus_read_4((_sc)->res[0], _reg) 63 #define WRITE4(_sc, _reg, _val) \ 64 bus_write_4((_sc)->res[0], _reg, _val) 65 66 #define CDES_INT_EN (1 << 15) 67 #define CDES_CAUSE_MASK 0x3 68 #define CDES_CAUSE_SHIFT 13 69 #define DEVNAME_MAXLEN 256 70 71 typedef struct 72 { 73 uint16_t cdes; 74 uint16_t interrupt_level; 75 uint16_t in; 76 uint16_t out; 77 } control_reg_t; 78 79 struct beri_softc { 80 struct resource *res[3]; 81 bus_space_tag_t bst; 82 bus_space_handle_t bsh; 83 struct cdev *cdev; 84 device_t dev; 85 void *read_ih; 86 void *write_ih; 87 struct selinfo beri_rsel; 88 struct mtx beri_mtx; 89 int opened; 90 91 char devname[DEVNAME_MAXLEN]; 92 int control_read; 93 int control_write; 94 int data_read; 95 int data_write; 96 int data_size; 97 }; 98 99 static struct resource_spec beri_spec[] = { 100 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 101 { SYS_RES_IRQ, 0, RF_ACTIVE }, 102 { SYS_RES_IRQ, 1, RF_ACTIVE }, 103 { -1, 0 } 104 }; 105 106 static control_reg_t 107 get_control_reg(struct beri_softc *sc, int dir) 108 { 109 uint32_t offset; 110 uint16_t dst[4]; 111 control_reg_t c; 112 uint16_t *cp; 113 int i; 114 115 cp = (uint16_t *)&c; 116 117 offset = dir ? sc->control_write : sc->control_read; 118 ((uint32_t *)dst)[0] = READ4(sc, offset); 119 ((uint32_t *)dst)[1] = READ4(sc, offset + 4); 120 121 for (i = 0; i < 4; i++) 122 cp[i] = dst[3 - i]; 123 124 return (c); 125 } 126 127 static void 128 set_control_reg(struct beri_softc *sc, int dir, control_reg_t *c) 129 { 130 uint32_t offset; 131 uint16_t src[4]; 132 uint16_t *cp; 133 int i; 134 135 cp = (uint16_t *)c; 136 137 for (i = 0; i < 4; i++) 138 src[3 - i] = cp[i]; 139 140 offset = dir ? sc->control_write : sc->control_read; 141 WRITE4(sc, offset + 0, ((uint32_t *)src)[0]); 142 WRITE4(sc, offset + 4, ((uint32_t *)src)[1]); 143 } 144 145 static int 146 get_stock(struct beri_softc *sc, int dir, control_reg_t *c) 147 { 148 uint32_t fill; 149 150 fill = (c->in - c->out + sc->data_size) % sc->data_size; 151 152 if (dir) 153 return (sc->data_size - fill - 1); 154 else 155 return (fill); 156 } 157 158 static void 159 beri_intr_write(void *arg) 160 { 161 struct beri_softc *sc; 162 control_reg_t c; 163 164 sc = arg; 165 166 c = get_control_reg(sc, 1); 167 if (c.cdes & CDES_INT_EN) { 168 c.cdes &= ~(CDES_INT_EN); 169 set_control_reg(sc, 1, &c); 170 } 171 172 mtx_lock(&sc->beri_mtx); 173 selwakeuppri(&sc->beri_rsel, PZERO + 1); 174 KNOTE_LOCKED(&sc->beri_rsel.si_note, 0); 175 mtx_unlock(&sc->beri_mtx); 176 } 177 178 static void 179 beri_intr_read(void *arg) 180 { 181 struct beri_softc *sc; 182 control_reg_t c; 183 184 sc = arg; 185 186 c = get_control_reg(sc, 0); 187 if (c.cdes & CDES_INT_EN) { 188 c.cdes &= ~(CDES_INT_EN); 189 set_control_reg(sc, 0, &c); 190 } 191 192 mtx_lock(&sc->beri_mtx); 193 selwakeuppri(&sc->beri_rsel, PZERO + 1); 194 KNOTE_LOCKED(&sc->beri_rsel.si_note, 0); 195 mtx_unlock(&sc->beri_mtx); 196 } 197 198 static int 199 beri_open(struct cdev *dev, int flags __unused, 200 int fmt __unused, struct thread *td __unused) 201 { 202 struct beri_softc *sc; 203 control_reg_t c; 204 205 sc = dev->si_drv1; 206 207 if (sc->opened) 208 return (1); 209 210 /* Setup interrupt handlers */ 211 if (bus_setup_intr(sc->dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, 212 NULL, beri_intr_read, sc, &sc->read_ih)) { 213 device_printf(sc->dev, "Unable to setup read intr\n"); 214 return (1); 215 } 216 if (bus_setup_intr(sc->dev, sc->res[2], INTR_TYPE_BIO | INTR_MPSAFE, 217 NULL, beri_intr_write, sc, &sc->write_ih)) { 218 device_printf(sc->dev, "Unable to setup write intr\n"); 219 return (1); 220 } 221 222 sc->opened = 1; 223 224 /* Clear write buffer */ 225 c = get_control_reg(sc, 1); 226 c.in = c.out; 227 c.cdes = 0; 228 set_control_reg(sc, 1, &c); 229 230 /* Clear read buffer */ 231 c = get_control_reg(sc, 0); 232 c.out = c.in; 233 c.cdes = 0; 234 set_control_reg(sc, 0, &c); 235 236 return (0); 237 } 238 239 static int 240 beri_close(struct cdev *dev, int flags __unused, 241 int fmt __unused, struct thread *td __unused) 242 { 243 struct beri_softc *sc; 244 245 sc = dev->si_drv1; 246 247 if (sc->opened) { 248 sc->opened = 0; 249 250 /* Unsetup interrupt handlers */ 251 bus_teardown_intr(sc->dev, sc->res[1], sc->read_ih); 252 bus_teardown_intr(sc->dev, sc->res[2], sc->write_ih); 253 } 254 255 return (0); 256 } 257 258 static int 259 beri_rdwr(struct cdev *dev, struct uio *uio, int ioflag) 260 { 261 struct beri_softc *sc; 262 uint32_t offset; 263 control_reg_t c; 264 uint16_t *ptr; 265 uint8_t *dst; 266 int stock; 267 int dir; 268 int amount; 269 int count; 270 271 sc = dev->si_drv1; 272 273 dir = uio->uio_rw ? 1 : 0; 274 275 c = get_control_reg(sc, dir); 276 stock = get_stock(sc, dir, &c); 277 if (stock < uio->uio_resid) { 278 device_printf(sc->dev, "Err: no data/space available\n"); 279 return (1); 280 } 281 282 amount = uio->uio_resid; 283 ptr = dir ? &c.in : &c.out; 284 count = (sc->data_size - *ptr); 285 286 offset = dir ? sc->data_write : sc->data_read; 287 dst = (uint8_t *)(sc->bsh + offset); 288 289 if (amount <= count) { 290 uiomove(dst + *ptr, amount, uio); 291 } else { 292 uiomove(dst + *ptr, count, uio); 293 uiomove(dst, (amount - count), uio); 294 } 295 296 *ptr = (*ptr + amount) % sc->data_size; 297 set_control_reg(sc, dir, &c); 298 299 return (0); 300 } 301 302 static int 303 beri_kqread(struct knote *kn, long hint) 304 { 305 struct beri_softc *sc; 306 control_reg_t c; 307 int stock; 308 309 sc = kn->kn_hook; 310 311 c = get_control_reg(sc, 0); 312 stock = get_stock(sc, 0, &c); 313 if (stock) { 314 kn->kn_data = stock; 315 return (1); 316 } 317 318 kn->kn_data = 0; 319 320 /* Wait at least one new byte in buffer */ 321 c.interrupt_level = 1; 322 323 /* Enable interrupts */ 324 c.cdes |= (CDES_INT_EN); 325 set_control_reg(sc, 0, &c); 326 327 return (0); 328 } 329 330 static int 331 beri_kqwrite(struct knote *kn, long hint) 332 { 333 struct beri_softc *sc; 334 control_reg_t c; 335 int stock; 336 337 sc = kn->kn_hook; 338 339 c = get_control_reg(sc, 1); 340 stock = get_stock(sc, 1, &c); 341 if (stock) { 342 kn->kn_data = stock; 343 return (1); 344 } 345 346 kn->kn_data = 0; 347 348 /* Wait at least one free position in buffer */ 349 c.interrupt_level = sc->data_size - 2; 350 351 /* Enable interrupts */ 352 c.cdes |= (CDES_INT_EN); 353 set_control_reg(sc, 1, &c); 354 355 return (0); 356 } 357 358 static void 359 beri_kqdetach(struct knote *kn) 360 { 361 struct beri_softc *sc; 362 363 sc = kn->kn_hook; 364 365 knlist_remove(&sc->beri_rsel.si_note, kn, 0); 366 } 367 368 static struct filterops beri_read_filterops = { 369 .f_isfd = 1, 370 .f_attach = NULL, 371 .f_detach = beri_kqdetach, 372 .f_event = beri_kqread, 373 }; 374 375 static struct filterops beri_write_filterops = { 376 .f_isfd = 1, 377 .f_attach = NULL, 378 .f_detach = beri_kqdetach, 379 .f_event = beri_kqwrite, 380 }; 381 382 static int 383 beri_kqfilter(struct cdev *dev, struct knote *kn) 384 { 385 struct beri_softc *sc; 386 387 sc = dev->si_drv1; 388 389 switch(kn->kn_filter) { 390 case EVFILT_READ: 391 kn->kn_fop = &beri_read_filterops; 392 break; 393 case EVFILT_WRITE: 394 kn->kn_fop = &beri_write_filterops; 395 break; 396 default: 397 return(EINVAL); 398 } 399 400 kn->kn_hook = sc; 401 knlist_add(&sc->beri_rsel.si_note, kn, 0); 402 403 return (0); 404 } 405 406 static struct cdevsw beri_cdevsw = { 407 .d_version = D_VERSION, 408 .d_open = beri_open, 409 .d_close = beri_close, 410 .d_write = beri_rdwr, 411 .d_read = beri_rdwr, 412 .d_kqfilter = beri_kqfilter, 413 .d_name = "beri ring buffer", 414 }; 415 416 static int 417 parse_fdt(struct beri_softc *sc) 418 { 419 pcell_t dts_value[0]; 420 phandle_t node; 421 int len; 422 423 if ((node = ofw_bus_get_node(sc->dev)) == -1) 424 return (ENXIO); 425 426 /* get device name */ 427 if (OF_getprop(ofw_bus_get_node(sc->dev), "device_name", 428 &sc->devname, sizeof(sc->devname)) <= 0) { 429 device_printf(sc->dev, "Can't get device_name\n"); 430 return (ENXIO); 431 } 432 433 if ((len = OF_getproplen(node, "data_size")) <= 0) 434 return (ENXIO); 435 OF_getencprop(node, "data_size", dts_value, len); 436 sc->data_size = dts_value[0]; 437 438 if ((len = OF_getproplen(node, "data_read")) <= 0) 439 return (ENXIO); 440 OF_getencprop(node, "data_read", dts_value, len); 441 sc->data_read = dts_value[0]; 442 443 if ((len = OF_getproplen(node, "data_write")) <= 0) 444 return (ENXIO); 445 OF_getencprop(node, "data_write", dts_value, len); 446 sc->data_write = dts_value[0]; 447 448 if ((len = OF_getproplen(node, "control_read")) <= 0) 449 return (ENXIO); 450 OF_getencprop(node, "control_read", dts_value, len); 451 sc->control_read = dts_value[0]; 452 453 if ((len = OF_getproplen(node, "control_write")) <= 0) 454 return (ENXIO); 455 OF_getencprop(node, "control_write", dts_value, len); 456 sc->control_write = dts_value[0]; 457 458 return (0); 459 } 460 461 static int 462 beri_probe(device_t dev) 463 { 464 465 if (!ofw_bus_status_okay(dev)) 466 return (ENXIO); 467 468 if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-ring")) 469 return (ENXIO); 470 471 device_set_desc(dev, "SRI-Cambridge BERI ring buffer"); 472 return (BUS_PROBE_DEFAULT); 473 } 474 475 static int 476 beri_attach(device_t dev) 477 { 478 struct beri_softc *sc; 479 480 sc = device_get_softc(dev); 481 sc->dev = dev; 482 483 if (bus_alloc_resources(dev, beri_spec, sc->res)) { 484 device_printf(dev, "could not allocate resources\n"); 485 return (ENXIO); 486 } 487 488 /* Memory interface */ 489 sc->bst = rman_get_bustag(sc->res[0]); 490 sc->bsh = rman_get_bushandle(sc->res[0]); 491 492 if (parse_fdt(sc)) { 493 device_printf(sc->dev, "Can't get FDT values\n"); 494 return (ENXIO); 495 } 496 497 sc->cdev = make_dev(&beri_cdevsw, 0, UID_ROOT, GID_WHEEL, 498 S_IRWXU, "%s", sc->devname); 499 if (sc->cdev == NULL) { 500 device_printf(dev, "Failed to create character device.\n"); 501 return (ENXIO); 502 } 503 504 sc->cdev->si_drv1 = sc; 505 506 mtx_init(&sc->beri_mtx, "beri_mtx", NULL, MTX_DEF); 507 knlist_init_mtx(&sc->beri_rsel.si_note, &sc->beri_mtx); 508 509 return (0); 510 } 511 512 static device_method_t beri_methods[] = { 513 DEVMETHOD(device_probe, beri_probe), 514 DEVMETHOD(device_attach, beri_attach), 515 { 0, 0 } 516 }; 517 518 static driver_t beri_driver = { 519 "beri_ring", 520 beri_methods, 521 sizeof(struct beri_softc), 522 }; 523 524 DRIVER_MODULE(beri_ring, simplebus, beri_driver, 0, 0); 525