1 /*- 2 * Copyright (c) 2016-2018 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 /* Altera mSGDMA driver. */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "opt_platform.h" 37 #include <sys/param.h> 38 #include <sys/endian.h> 39 #include <sys/systm.h> 40 #include <sys/conf.h> 41 #include <sys/bus.h> 42 #include <sys/kernel.h> 43 #include <sys/kthread.h> 44 #include <sys/sglist.h> 45 #include <sys/module.h> 46 #include <sys/lock.h> 47 #include <sys/mutex.h> 48 #include <sys/resource.h> 49 #include <sys/rman.h> 50 51 #include <machine/bus.h> 52 #include <machine/fdt.h> 53 #include <machine/cache.h> 54 55 #ifdef FDT 56 #include <dev/fdt/fdt_common.h> 57 #include <dev/ofw/ofw_bus.h> 58 #include <dev/ofw/ofw_bus_subr.h> 59 #endif 60 61 #include <dev/xdma/xdma.h> 62 #include "xdma_if.h" 63 #include "opt_altera_msgdma.h" 64 65 #include <dev/altera/msgdma/msgdma.h> 66 67 #define MSGDMA_DEBUG 68 #undef MSGDMA_DEBUG 69 70 #ifdef MSGDMA_DEBUG 71 #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) 72 #else 73 #define dprintf(fmt, ...) 74 #endif 75 76 #define MSGDMA_NCHANNELS 1 77 78 struct msgdma_channel { 79 struct msgdma_softc *sc; 80 struct mtx mtx; 81 xdma_channel_t *xchan; 82 struct proc *p; 83 int used; 84 int index; 85 int idx_head; 86 int idx_tail; 87 88 struct msgdma_desc **descs; 89 bus_dma_segment_t *descs_phys; 90 uint32_t descs_num; 91 bus_dma_tag_t dma_tag; 92 bus_dmamap_t *dma_map; 93 uint32_t map_descr; 94 uint8_t map_err; 95 uint32_t descs_used_count; 96 }; 97 98 struct msgdma_softc { 99 device_t dev; 100 struct resource *res[3]; 101 bus_space_tag_t bst; 102 bus_space_handle_t bsh; 103 bus_space_tag_t bst_d; 104 bus_space_handle_t bsh_d; 105 void *ih; 106 struct msgdma_desc desc; 107 struct msgdma_channel channels[MSGDMA_NCHANNELS]; 108 }; 109 110 static struct resource_spec msgdma_spec[] = { 111 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 112 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 113 { SYS_RES_IRQ, 0, RF_ACTIVE }, 114 { -1, 0 } 115 }; 116 117 #define HWTYPE_NONE 0 118 #define HWTYPE_STD 1 119 120 static struct ofw_compat_data compat_data[] = { 121 { "altr,msgdma-16.0", HWTYPE_STD }, 122 { "altr,msgdma-1.0", HWTYPE_STD }, 123 { NULL, HWTYPE_NONE }, 124 }; 125 126 static int msgdma_probe(device_t dev); 127 static int msgdma_attach(device_t dev); 128 static int msgdma_detach(device_t dev); 129 130 static inline uint32_t 131 msgdma_next_desc(struct msgdma_channel *chan, uint32_t curidx) 132 { 133 134 return ((curidx + 1) % chan->descs_num); 135 } 136 137 static void 138 msgdma_intr(void *arg) 139 { 140 xdma_transfer_status_t status; 141 struct xdma_transfer_status st; 142 struct msgdma_desc *desc; 143 struct msgdma_channel *chan; 144 struct xdma_channel *xchan; 145 struct msgdma_softc *sc; 146 uint32_t tot_copied; 147 148 sc = arg; 149 chan = &sc->channels[0]; 150 xchan = chan->xchan; 151 152 dprintf("%s(%d): status 0x%08x next_descr 0x%08x, control 0x%08x\n", 153 __func__, device_get_unit(sc->dev), 154 READ4_DESC(sc, PF_STATUS), 155 READ4_DESC(sc, PF_NEXT_LO), 156 READ4_DESC(sc, PF_CONTROL)); 157 158 tot_copied = 0; 159 160 while (chan->idx_tail != chan->idx_head) { 161 dprintf("%s: idx_tail %d idx_head %d\n", __func__, 162 chan->idx_tail, chan->idx_head); 163 bus_dmamap_sync(chan->dma_tag, chan->dma_map[chan->idx_tail], 164 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 165 166 desc = chan->descs[chan->idx_tail]; 167 if ((le32toh(desc->control) & CONTROL_OWN) != 0) { 168 break; 169 } 170 171 tot_copied += le32toh(desc->transferred); 172 st.error = 0; 173 st.transferred = le32toh(desc->transferred); 174 xchan_seg_done(xchan, &st); 175 176 chan->idx_tail = msgdma_next_desc(chan, chan->idx_tail); 177 atomic_subtract_int(&chan->descs_used_count, 1); 178 } 179 180 WRITE4_DESC(sc, PF_STATUS, PF_STATUS_IRQ); 181 182 /* Finish operation */ 183 status.error = 0; 184 status.transferred = tot_copied; 185 xdma_callback(chan->xchan, &status); 186 } 187 188 static int 189 msgdma_reset(struct msgdma_softc *sc) 190 { 191 int timeout; 192 193 dprintf("%s: read status: %x\n", __func__, READ4(sc, 0x00)); 194 dprintf("%s: read control: %x\n", __func__, READ4(sc, 0x04)); 195 dprintf("%s: read 1: %x\n", __func__, READ4(sc, 0x08)); 196 dprintf("%s: read 2: %x\n", __func__, READ4(sc, 0x0C)); 197 198 WRITE4(sc, DMA_CONTROL, CONTROL_RESET); 199 200 timeout = 100; 201 do { 202 if ((READ4(sc, DMA_STATUS) & STATUS_RESETTING) == 0) 203 break; 204 } while (timeout--); 205 206 dprintf("timeout %d\n", timeout); 207 208 if (timeout == 0) 209 return (-1); 210 211 dprintf("%s: read control after reset: %x\n", 212 __func__, READ4(sc, DMA_CONTROL)); 213 214 return (0); 215 } 216 217 static int 218 msgdma_probe(device_t dev) 219 { 220 int hwtype; 221 222 if (!ofw_bus_status_okay(dev)) 223 return (ENXIO); 224 225 hwtype = ofw_bus_search_compatible(dev, compat_data)->ocd_data; 226 if (hwtype == HWTYPE_NONE) 227 return (ENXIO); 228 229 device_set_desc(dev, "Altera mSGDMA"); 230 231 return (BUS_PROBE_DEFAULT); 232 } 233 234 static int 235 msgdma_attach(device_t dev) 236 { 237 struct msgdma_softc *sc; 238 phandle_t xref, node; 239 int err; 240 241 sc = device_get_softc(dev); 242 sc->dev = dev; 243 244 if (bus_alloc_resources(dev, msgdma_spec, sc->res)) { 245 device_printf(dev, "could not allocate resources for device\n"); 246 return (ENXIO); 247 } 248 249 /* CSR memory interface */ 250 sc->bst = rman_get_bustag(sc->res[0]); 251 sc->bsh = rman_get_bushandle(sc->res[0]); 252 253 /* Descriptor memory interface */ 254 sc->bst_d = rman_get_bustag(sc->res[1]); 255 sc->bsh_d = rman_get_bushandle(sc->res[1]); 256 257 /* Setup interrupt handler */ 258 err = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE, 259 NULL, msgdma_intr, sc, &sc->ih); 260 if (err) { 261 device_printf(dev, "Unable to alloc interrupt resource.\n"); 262 return (ENXIO); 263 } 264 265 node = ofw_bus_get_node(dev); 266 xref = OF_xref_from_node(node); 267 OF_device_register_xref(xref, dev); 268 269 if (msgdma_reset(sc) != 0) 270 return (-1); 271 272 WRITE4(sc, DMA_CONTROL, CONTROL_GIEM); 273 274 return (0); 275 } 276 277 static int 278 msgdma_detach(device_t dev) 279 { 280 struct msgdma_softc *sc; 281 282 sc = device_get_softc(dev); 283 284 return (0); 285 } 286 287 static void 288 msgdma_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 289 { 290 struct msgdma_channel *chan; 291 292 chan = (struct msgdma_channel *)arg; 293 KASSERT(chan != NULL, ("xchan is NULL")); 294 295 if (err) { 296 chan->map_err = 1; 297 return; 298 } 299 300 chan->descs_phys[chan->map_descr].ds_addr = segs[0].ds_addr; 301 chan->descs_phys[chan->map_descr].ds_len = segs[0].ds_len; 302 303 dprintf("map desc %d: descs phys %lx len %ld\n", 304 chan->map_descr, segs[0].ds_addr, segs[0].ds_len); 305 } 306 307 static int 308 msgdma_desc_free(struct msgdma_softc *sc, struct msgdma_channel *chan) 309 { 310 struct msgdma_desc *desc; 311 int nsegments; 312 int i; 313 314 nsegments = chan->descs_num; 315 316 for (i = 0; i < nsegments; i++) { 317 desc = chan->descs[i]; 318 bus_dmamap_unload(chan->dma_tag, chan->dma_map[i]); 319 bus_dmamem_free(chan->dma_tag, desc, chan->dma_map[i]); 320 } 321 322 bus_dma_tag_destroy(chan->dma_tag); 323 free(chan->descs, M_DEVBUF); 324 free(chan->dma_map, M_DEVBUF); 325 free(chan->descs_phys, M_DEVBUF); 326 327 return (0); 328 } 329 330 static int 331 msgdma_desc_alloc(struct msgdma_softc *sc, struct msgdma_channel *chan, 332 uint32_t desc_size, uint32_t align) 333 { 334 int nsegments; 335 int err; 336 int i; 337 338 nsegments = chan->descs_num; 339 340 dprintf("%s: nseg %d\n", __func__, nsegments); 341 342 err = bus_dma_tag_create( 343 bus_get_dma_tag(sc->dev), 344 align, 0, /* alignment, boundary */ 345 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 346 BUS_SPACE_MAXADDR, /* highaddr */ 347 NULL, NULL, /* filter, filterarg */ 348 desc_size, 1, /* maxsize, nsegments*/ 349 desc_size, 0, /* maxsegsize, flags */ 350 NULL, NULL, /* lockfunc, lockarg */ 351 &chan->dma_tag); 352 if (err) { 353 device_printf(sc->dev, 354 "%s: Can't create bus_dma tag.\n", __func__); 355 return (-1); 356 } 357 358 /* Descriptors. */ 359 chan->descs = malloc(nsegments * sizeof(struct msgdma_desc *), 360 M_DEVBUF, (M_WAITOK | M_ZERO)); 361 if (chan->descs == NULL) { 362 device_printf(sc->dev, 363 "%s: Can't allocate memory.\n", __func__); 364 return (-1); 365 } 366 chan->dma_map = malloc(nsegments * sizeof(bus_dmamap_t), 367 M_DEVBUF, (M_WAITOK | M_ZERO)); 368 chan->descs_phys = malloc(nsegments * sizeof(bus_dma_segment_t), 369 M_DEVBUF, (M_WAITOK | M_ZERO)); 370 371 /* Allocate bus_dma memory for each descriptor. */ 372 for (i = 0; i < nsegments; i++) { 373 err = bus_dmamem_alloc(chan->dma_tag, (void **)&chan->descs[i], 374 BUS_DMA_WAITOK | BUS_DMA_ZERO, &chan->dma_map[i]); 375 if (err) { 376 device_printf(sc->dev, 377 "%s: Can't allocate memory for descriptors.\n", 378 __func__); 379 return (-1); 380 } 381 382 chan->map_err = 0; 383 chan->map_descr = i; 384 err = bus_dmamap_load(chan->dma_tag, chan->dma_map[i], chan->descs[i], 385 desc_size, msgdma_dmamap_cb, chan, BUS_DMA_WAITOK); 386 if (err) { 387 device_printf(sc->dev, 388 "%s: Can't load DMA map.\n", __func__); 389 return (-1); 390 } 391 392 if (chan->map_err != 0) { 393 device_printf(sc->dev, 394 "%s: Can't load DMA map.\n", __func__); 395 return (-1); 396 } 397 } 398 399 return (0); 400 } 401 402 static int 403 msgdma_channel_alloc(device_t dev, struct xdma_channel *xchan) 404 { 405 struct msgdma_channel *chan; 406 struct msgdma_softc *sc; 407 int i; 408 409 sc = device_get_softc(dev); 410 411 for (i = 0; i < MSGDMA_NCHANNELS; i++) { 412 chan = &sc->channels[i]; 413 if (chan->used == 0) { 414 chan->xchan = xchan; 415 xchan->chan = (void *)chan; 416 if ((xchan->caps & XCHAN_CAP_IOMMU) == 0) 417 xchan->caps |= XCHAN_CAP_BUSDMA; 418 chan->index = i; 419 chan->sc = sc; 420 chan->used = 1; 421 chan->idx_head = 0; 422 chan->idx_tail = 0; 423 chan->descs_used_count = 0; 424 chan->descs_num = 1024; 425 426 return (0); 427 } 428 } 429 430 return (-1); 431 } 432 433 static int 434 msgdma_channel_free(device_t dev, struct xdma_channel *xchan) 435 { 436 struct msgdma_channel *chan; 437 struct msgdma_softc *sc; 438 439 sc = device_get_softc(dev); 440 441 chan = (struct msgdma_channel *)xchan->chan; 442 443 msgdma_desc_free(sc, chan); 444 445 chan->used = 0; 446 447 return (0); 448 } 449 450 static int 451 msgdma_channel_capacity(device_t dev, xdma_channel_t *xchan, 452 uint32_t *capacity) 453 { 454 struct msgdma_channel *chan; 455 uint32_t c; 456 457 chan = (struct msgdma_channel *)xchan->chan; 458 459 /* At least one descriptor must be left empty. */ 460 c = (chan->descs_num - chan->descs_used_count - 1); 461 462 *capacity = c; 463 464 return (0); 465 } 466 467 static int 468 msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan, 469 struct xdma_sglist *sg, uint32_t sg_n) 470 { 471 struct msgdma_channel *chan; 472 struct msgdma_desc *desc; 473 struct msgdma_softc *sc; 474 bus_addr_t src_addr_lo; 475 bus_addr_t dst_addr_lo; 476 uint32_t len; 477 uint32_t tmp; 478 int i; 479 480 sc = device_get_softc(dev); 481 482 chan = (struct msgdma_channel *)xchan->chan; 483 484 for (i = 0; i < sg_n; i++) { 485 src_addr_lo = sg[i].src_addr; 486 dst_addr_lo = sg[i].dst_addr; 487 len = (uint32_t)sg[i].len; 488 489 dprintf("%s: src %x dst %x len %d\n", __func__, 490 src_addr_lo, dst_addr_lo, len); 491 492 desc = chan->descs[chan->idx_head]; 493 #if defined(ALTERA_MSGDMA_DESC_EXT) || defined(ALTERA_MSGDMA_DESC_PF_EXT) 494 desc->read_hi = htole32(src_addr_lo >> 32); 495 desc->write_hi = htole32(dst_addr_lo >> 32); 496 #endif 497 desc->read_lo = htole32(src_addr_lo); 498 desc->write_lo = htole32(dst_addr_lo); 499 desc->length = htole32(len); 500 desc->transferred = 0; 501 desc->status = 0; 502 desc->reserved = 0; 503 desc->control = 0; 504 505 if (sg[i].direction == XDMA_MEM_TO_DEV) { 506 if (sg[i].first == 1) { 507 desc->control |= htole32(CONTROL_GEN_SOP); 508 } 509 510 if (sg[i].last == 1) { 511 desc->control |= htole32(CONTROL_GEN_EOP); 512 desc->control |= htole32(CONTROL_TC_IRQ_EN | 513 CONTROL_ET_IRQ_EN | CONTROL_ERR_M); 514 } 515 } else { 516 desc->control |= htole32(CONTROL_END_ON_EOP | (1 << 13)); 517 desc->control |= htole32(CONTROL_TC_IRQ_EN | 518 CONTROL_ET_IRQ_EN | CONTROL_ERR_M); 519 } 520 521 tmp = chan->idx_head; 522 523 atomic_add_int(&chan->descs_used_count, 1); 524 chan->idx_head = msgdma_next_desc(chan, chan->idx_head); 525 526 desc->control |= htole32(CONTROL_OWN | CONTROL_GO); 527 528 bus_dmamap_sync(chan->dma_tag, chan->dma_map[tmp], 529 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 530 } 531 532 return (0); 533 } 534 535 static int 536 msgdma_channel_prep_sg(device_t dev, struct xdma_channel *xchan) 537 { 538 struct msgdma_channel *chan; 539 struct msgdma_desc *desc; 540 struct msgdma_softc *sc; 541 uint32_t addr; 542 uint32_t reg; 543 int ret; 544 int i; 545 546 sc = device_get_softc(dev); 547 548 dprintf("%s(%d)\n", __func__, device_get_unit(dev)); 549 550 chan = (struct msgdma_channel *)xchan->chan; 551 552 ret = msgdma_desc_alloc(sc, chan, sizeof(struct msgdma_desc), 16); 553 if (ret != 0) { 554 device_printf(sc->dev, 555 "%s: Can't allocate descriptors.\n", __func__); 556 return (-1); 557 } 558 559 for (i = 0; i < chan->descs_num; i++) { 560 desc = chan->descs[i]; 561 562 if (i == (chan->descs_num - 1)) { 563 desc->next = htole32(chan->descs_phys[0].ds_addr); 564 } else { 565 desc->next = htole32(chan->descs_phys[i+1].ds_addr); 566 } 567 568 dprintf("%s(%d): desc %d vaddr %lx next paddr %x\n", __func__, 569 device_get_unit(dev), i, (uint64_t)desc, le32toh(desc->next)); 570 } 571 572 addr = chan->descs_phys[0].ds_addr; 573 WRITE4_DESC(sc, PF_NEXT_LO, addr); 574 WRITE4_DESC(sc, PF_NEXT_HI, 0); 575 WRITE4_DESC(sc, PF_POLL_FREQ, 1000); 576 577 reg = (PF_CONTROL_GIEM | PF_CONTROL_DESC_POLL_EN); 578 reg |= PF_CONTROL_RUN; 579 WRITE4_DESC(sc, PF_CONTROL, reg); 580 581 return (0); 582 } 583 584 static int 585 msgdma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd) 586 { 587 struct msgdma_channel *chan; 588 struct msgdma_softc *sc; 589 590 sc = device_get_softc(dev); 591 592 chan = (struct msgdma_channel *)xchan->chan; 593 594 switch (cmd) { 595 case XDMA_CMD_BEGIN: 596 case XDMA_CMD_TERMINATE: 597 case XDMA_CMD_PAUSE: 598 /* TODO: implement me */ 599 return (-1); 600 } 601 602 return (0); 603 } 604 605 #ifdef FDT 606 static int 607 msgdma_ofw_md_data(device_t dev, pcell_t *cells, int ncells, void **ptr) 608 { 609 610 return (0); 611 } 612 #endif 613 614 static device_method_t msgdma_methods[] = { 615 /* Device interface */ 616 DEVMETHOD(device_probe, msgdma_probe), 617 DEVMETHOD(device_attach, msgdma_attach), 618 DEVMETHOD(device_detach, msgdma_detach), 619 620 /* xDMA Interface */ 621 DEVMETHOD(xdma_channel_alloc, msgdma_channel_alloc), 622 DEVMETHOD(xdma_channel_free, msgdma_channel_free), 623 DEVMETHOD(xdma_channel_control, msgdma_channel_control), 624 625 /* xDMA SG Interface */ 626 DEVMETHOD(xdma_channel_capacity, msgdma_channel_capacity), 627 DEVMETHOD(xdma_channel_prep_sg, msgdma_channel_prep_sg), 628 DEVMETHOD(xdma_channel_submit_sg, msgdma_channel_submit_sg), 629 630 #ifdef FDT 631 DEVMETHOD(xdma_ofw_md_data, msgdma_ofw_md_data), 632 #endif 633 634 DEVMETHOD_END 635 }; 636 637 static driver_t msgdma_driver = { 638 "msgdma", 639 msgdma_methods, 640 sizeof(struct msgdma_softc), 641 }; 642 643 EARLY_DRIVER_MODULE(msgdma, simplebus, msgdma_driver, 0, 0, 644 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 645