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