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