1 /* $NetBSD: maple.c,v 1.22 2002/12/06 15:49:31 itohy Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by ITOH Yasufumi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 2001 Marcus Comstedt 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by Marcus Comstedt. 54 * 4. Neither the name of The NetBSD Foundation nor the names of its 55 * contributors may be used to endorse or promote products derived 56 * from this software without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 59 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 60 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 61 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 62 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 64 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 65 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 66 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 67 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 68 * POSSIBILITY OF SUCH DAMAGE. 69 */ 70 71 #include <sys/param.h> 72 #include <sys/device.h> 73 #include <sys/fcntl.h> 74 #include <sys/kernel.h> 75 #include <sys/kthread.h> 76 #include <sys/poll.h> 77 #include <sys/select.h> 78 #include <sys/proc.h> 79 #include <sys/signalvar.h> 80 #include <sys/systm.h> 81 #include <sys/conf.h> 82 83 #include <uvm/uvm_extern.h> 84 85 #include <machine/cpu.h> 86 #include <machine/bus.h> 87 #include <machine/sysasicvar.h> 88 #include <sh3/pmap.h> 89 90 #include <dreamcast/dev/maple/maple.h> 91 #include <dreamcast/dev/maple/mapleconf.h> 92 #include <dreamcast/dev/maple/maplevar.h> 93 #include <dreamcast/dev/maple/maplereg.h> 94 #include <dreamcast/dev/maple/mapleio.h> 95 96 #include "locators.h" 97 98 /* Internal macros, functions, and variables. */ 99 100 #define MAPLE_CALLOUT_TICKS 2 101 102 #define MAPLEBUSUNIT(dev) (minor(dev)>>5) 103 #define MAPLEPORT(dev) ((minor(dev) & 0x18) >> 3) 104 #define MAPLESUBUNIT(dev) (minor(dev) & 0x7) 105 106 /* interrupt priority level */ 107 #define IPL_MAPLE IPL_BIO 108 #define splmaple() splbio() 109 110 /* 111 * Function declarations. 112 */ 113 static int maplematch(struct device *, struct cfdata *, void *); 114 static void mapleattach(struct device *, struct device *, void *); 115 static void maple_create_event_thread(void *); 116 static void maple_scanbus(struct maple_softc *); 117 static char * maple_unit_name(char *, int port, int subunit); 118 static void maple_begin_txbuf(struct maple_softc *); 119 static int maple_end_txbuf(struct maple_softc *); 120 static void maple_queue_command(struct maple_softc *, struct maple_unit *, 121 int command, int datalen, void *dataaddr); 122 static void maple_write_command(struct maple_softc *, struct maple_unit *, 123 int, int, void *); 124 static void maple_start(struct maple_softc *sc); 125 static void maple_start_poll(struct maple_softc *); 126 static void maple_check_subunit_change(struct maple_softc *, 127 struct maple_unit *); 128 static void maple_check_unit_change(struct maple_softc *, 129 struct maple_unit *); 130 static void maple_print_unit(void *, const char *); 131 static int maplesubmatch(struct device *, struct cfdata *, void *); 132 static int mapleprint(void *, const char *); 133 static void maple_attach_unit(struct maple_softc *, struct maple_unit *); 134 static void maple_detach_unit_nofix(struct maple_softc *, 135 struct maple_unit *); 136 static void maple_detach_unit(struct maple_softc *, struct maple_unit *); 137 static void maple_queue_cmds(struct maple_softc *, 138 struct maple_cmdq_head *); 139 static void maple_unit_probe(struct maple_softc *); 140 static void maple_unit_ping(struct maple_softc *); 141 static int maple_send_defered_periodic(struct maple_softc *); 142 static void maple_send_periodic(struct maple_softc *); 143 static void maple_remove_from_queues(struct maple_softc *, 144 struct maple_unit *); 145 static int maple_retry(struct maple_softc *, struct maple_unit *, 146 enum maple_dma_stat); 147 static void maple_queue_retry(struct maple_softc *); 148 static void maple_check_responses(struct maple_softc *); 149 static void maple_event_thread(void *); 150 static int maple_intr(void *); 151 static void maple_callout(void *); 152 153 int maple_alloc_dma(size_t, vaddr_t *, paddr_t *); 154 #if 0 155 void maple_free_dma(paddr_t, size_t); 156 #endif 157 158 /* 159 * Global variables. 160 */ 161 int maple_polling; /* Are we polling? (Debugger mode) */ 162 163 CFATTACH_DECL(maple, sizeof(struct maple_softc), 164 maplematch, mapleattach, NULL, NULL); 165 166 extern struct cfdriver maple_cd; 167 168 dev_type_open(mapleopen); 169 dev_type_close(mapleclose); 170 dev_type_ioctl(mapleioctl); 171 172 const struct cdevsw maple_cdevsw = { 173 mapleopen, mapleclose, noread, nowrite, mapleioctl, 174 nostop, notty, nopoll, nommap, nokqfilter, 175 }; 176 177 static int 178 maplematch(struct device *parent, struct cfdata *cf, void *aux) 179 { 180 181 return (1); 182 } 183 184 static void 185 mapleattach(struct device *parent, struct device *self, void *aux) 186 { 187 struct maple_softc *sc; 188 struct maple_unit *u; 189 vaddr_t dmabuffer; 190 paddr_t dmabuffer_phys; 191 u_int32_t *p; 192 int port, subunit, f; 193 194 sc = (struct maple_softc *)self; 195 196 printf(": %s\n", sysasic_intr_string(IPL_MAPLE)); 197 198 if (maple_alloc_dma(MAPLE_DMABUF_SIZE, &dmabuffer, &dmabuffer_phys)) { 199 printf("%s: unable to allocate DMA buffers.\n", 200 sc->sc_dev.dv_xname); 201 return; 202 } 203 204 p = (u_int32_t *)dmabuffer; 205 206 for (port = 0; port < MAPLE_PORTS; port++) 207 for (subunit = 0; subunit < MAPLE_SUBUNITS; subunit++) { 208 u = &sc->sc_unit[port][subunit]; 209 u->port = port; 210 u->subunit = subunit; 211 u->u_dma_stat = MAPLE_DMA_IDLE; 212 u->u_rxbuf = p; 213 u->u_rxbuf_phys = SH3_P2SEG_TO_PHYS(p); 214 p += 256; 215 216 for (f = 0; f < MAPLE_NFUNC; f++) { 217 u->u_func[f].f_funcno = f; 218 u->u_func[f].f_unit = u; 219 } 220 } 221 222 sc->sc_txbuf = p; 223 sc->sc_txbuf_phys = SH3_P2SEG_TO_PHYS(p); 224 225 SIMPLEQ_INIT(&sc->sc_retryq); 226 TAILQ_INIT(&sc->sc_probeq); 227 TAILQ_INIT(&sc->sc_pingq); 228 TAILQ_INIT(&sc->sc_periodicq); 229 TAILQ_INIT(&sc->sc_periodicdeferq); 230 TAILQ_INIT(&sc->sc_acmdq); 231 TAILQ_INIT(&sc->sc_pcmdq); 232 233 MAPLE_RESET = RESET_MAGIC; 234 MAPLE_RESET2 = 0; 235 236 MAPLE_SPEED = SPEED_2MBPS | TIMEOUT(50000); 237 238 MAPLE_ENABLE = 1; 239 240 maple_polling = 1; 241 maple_scanbus(sc); 242 243 callout_init(&sc->maple_callout_ch); 244 245 sc->sc_intrhand = sysasic_intr_establish(SYSASIC_EVENT_MAPLE_DMADONE, 246 IPL_MAPLE, maple_intr, sc); 247 248 config_pending_incr(); /* create thread before mounting root */ 249 kthread_create(maple_create_event_thread, sc); 250 } 251 252 static void 253 maple_create_event_thread(void *arg) 254 { 255 struct maple_softc *sc = arg; 256 257 if (kthread_create1(maple_event_thread, sc, &sc->event_thread, 258 "%s", sc->sc_dev.dv_xname) == 0) 259 return; 260 261 panic("%s: unable to create event thread", sc->sc_dev.dv_xname); 262 } 263 264 /* 265 * initial device attach 266 */ 267 static void 268 maple_scanbus(struct maple_softc *sc) 269 { 270 struct maple_unit *u; 271 int port; 272 int last_port, last_subunit; 273 int i; 274 275 KASSERT(cold && maple_polling); 276 277 /* probe all ports */ 278 for (port = 0; port < MAPLE_PORTS; port++) { 279 u = &sc->sc_unit[port][0]; 280 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 281 { 282 char buf[16]; 283 printf("%s: queued to probe 1\n", 284 maple_unit_name(buf, u->port, u->subunit)); 285 } 286 #endif 287 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 288 u->u_queuestat = MAPLE_QUEUE_PROBE; 289 } 290 291 last_port = last_subunit = -1; 292 maple_begin_txbuf(sc); 293 while ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 294 /* 295 * Check wrap condition 296 */ 297 if (u->port < last_port || u->subunit <= last_subunit) 298 break; 299 last_port = u->port; 300 if (u->port == MAPLE_PORTS - 1) 301 last_subunit = u->subunit; 302 303 maple_unit_probe(sc); 304 for (i = 10 /* just not forever */; maple_end_txbuf(sc); i--) { 305 maple_start_poll(sc); 306 maple_check_responses(sc); 307 if (i == 0) 308 break; 309 /* attach may issue cmds */ 310 maple_queue_cmds(sc, &sc->sc_acmdq); 311 } 312 } 313 } 314 315 void 316 maple_run_polling(struct device *dev) 317 { 318 struct maple_softc *sc; 319 int port, subunit; 320 int i; 321 322 sc = (struct maple_softc *)dev; 323 324 /* 325 * first, make sure polling works 326 */ 327 while (MAPLE_STATE != 0) /* XXX may lost a DMA cycle */ 328 ; 329 330 /* XXX this will break internal state */ 331 for (port = 0; port < MAPLE_PORTS; port++) 332 for (subunit = 0; subunit < MAPLE_SUBUNITS; subunit++) 333 sc->sc_unit[port][subunit].u_dma_stat = MAPLE_DMA_IDLE; 334 SIMPLEQ_INIT(&sc->sc_retryq); /* XXX discard current retrys */ 335 336 /* 337 * do polling (periodic status check only) 338 */ 339 maple_begin_txbuf(sc); 340 maple_send_defered_periodic(sc); 341 maple_send_periodic(sc); 342 for (i = 10 /* just not forever */; maple_end_txbuf(sc); i--) { 343 maple_start_poll(sc); 344 maple_check_responses(sc); 345 if (i == 0) 346 break; 347 348 /* maple_check_responses() has executed maple_begin_txbuf() */ 349 maple_queue_retry(sc); 350 maple_send_defered_periodic(sc); 351 } 352 } 353 354 static char * 355 maple_unit_name(char *buf, int port, int subunit) 356 { 357 358 sprintf(buf, "maple%c", port + 'A'); 359 if (subunit) 360 sprintf(buf+6, "%d", subunit); 361 362 return buf; 363 } 364 365 int 366 maple_alloc_dma(size_t size, vaddr_t *vap, paddr_t *pap) 367 { 368 extern paddr_t avail_start, avail_end; /* from pmap.c */ 369 struct pglist mlist; 370 struct vm_page *m; 371 int error; 372 373 size = round_page(size); 374 375 error = uvm_pglistalloc(size, avail_start, avail_end - PAGE_SIZE, 376 0, 0, &mlist, 1, 0); 377 if (error) 378 return (error); 379 380 m = TAILQ_FIRST(&mlist); 381 *pap = VM_PAGE_TO_PHYS(m); 382 *vap = SH3_PHYS_TO_P2SEG(VM_PAGE_TO_PHYS(m)); 383 384 return (0); 385 } 386 387 #if 0 /* currently unused */ 388 void 389 maple_free_dma(paddr_t paddr, size_t size) 390 { 391 struct pglist mlist; 392 struct vm_page *m; 393 bus_addr_t addr; 394 395 TAILQ_INIT(&mlist); 396 for (addr = paddr; addr < paddr + size; addr += PAGE_SIZE) { 397 m = PHYS_TO_VM_PAGE(addr); 398 TAILQ_INSERT_TAIL(&mlist, m, pageq); 399 } 400 uvm_pglistfree(&mlist); 401 } 402 #endif 403 404 static void 405 maple_begin_txbuf(struct maple_softc *sc) 406 { 407 408 sc->sc_txlink = sc->sc_txpos = sc->sc_txbuf; 409 SIMPLEQ_INIT(&sc->sc_dmaq); 410 } 411 412 static int 413 maple_end_txbuf(struct maple_softc *sc) 414 { 415 416 /* if no frame have been written, we can't mark the 417 list end, and so the DMA must not be activated */ 418 if (sc->sc_txpos == sc->sc_txbuf) 419 return (0); 420 421 *sc->sc_txlink |= 0x80000000; 422 423 return (1); 424 } 425 426 static const int8_t subunit_code[] = { 0x20, 0x01, 0x02, 0x04, 0x08, 0x10 }; 427 428 static void 429 maple_queue_command(struct maple_softc *sc, struct maple_unit *u, 430 int command, int datalen, void *dataaddr) 431 { 432 int to, from; 433 u_int32_t *p = sc->sc_txpos; 434 435 /* Max data length = 255 longs = 1020 bytes */ 436 KASSERT(datalen >= 0 && datalen <= 255); 437 438 /* Compute sender and recipient address */ 439 from = u->port << 6; 440 to = from | subunit_code[u->subunit]; 441 442 sc->sc_txlink = p; 443 444 /* Set length of packet and destination port (A-D) */ 445 *p++ = datalen | (u->port << 16); 446 447 /* Write address to receive buffer where the response 448 frame should be put */ 449 *p++ = u->u_rxbuf_phys; 450 451 /* Create the frame header. The fields are assembled "backwards" 452 because of the Maple Bus big-endianness. */ 453 *p++ = (command & 0xff) | (to << 8) | (from << 16) | (datalen << 24); 454 455 /* Copy parameter data, if any */ 456 if (datalen > 0) { 457 u_int32_t *param = dataaddr; 458 int i; 459 for (i = 0; i < datalen; i++) 460 *p++ = *param++; 461 } 462 463 sc->sc_txpos = p; 464 465 SIMPLEQ_INSERT_TAIL(&sc->sc_dmaq, u, u_dmaq); 466 } 467 468 static void 469 maple_write_command(struct maple_softc *sc, struct maple_unit *u, int command, 470 int datalen, void *dataaddr) 471 { 472 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 473 char buf[16]; 474 475 if (u->u_retrycnt) 476 printf("%s: retrycnt %d\n", 477 maple_unit_name(buf, u->port, u->subunit), u->u_retrycnt); 478 #endif 479 u->u_retrycnt = 0; 480 u->u_command = command; 481 u->u_datalen = datalen; 482 u->u_dataaddr = dataaddr; 483 484 maple_queue_command(sc, u, command, datalen, dataaddr); 485 } 486 487 /* start DMA */ 488 static void 489 maple_start(struct maple_softc *sc) 490 { 491 492 MAPLE_DMAADDR = sc->sc_txbuf_phys; 493 MAPLE_STATE = 1; 494 } 495 496 /* start DMA -- wait until DMA done */ 497 static void 498 maple_start_poll(struct maple_softc *sc) 499 { 500 501 MAPLE_DMAADDR = sc->sc_txbuf_phys; 502 MAPLE_STATE = 1; 503 while (MAPLE_STATE != 0) 504 ; 505 } 506 507 static void 508 maple_check_subunit_change(struct maple_softc *sc, struct maple_unit *u) 509 { 510 struct maple_unit *u1; 511 int port; 512 int8_t unit_map; 513 int units, un; 514 int i; 515 516 KASSERT(u->subunit == 0); 517 518 port = u->port; 519 unit_map = ((int8_t *) u->u_rxbuf)[2]; 520 if (sc->sc_port_unit_map[port] == unit_map) 521 return; 522 523 units = ((unit_map & 0x1f) << 1) | 1; 524 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 525 { 526 char buf[16]; 527 printf("%s: unit_map 0x%x -> 0x%x (units 0x%x)\n", 528 maple_unit_name(buf, u->port, u->subunit), 529 sc->sc_port_unit_map[port], unit_map, units); 530 } 531 #endif 532 #if 0 /* this detects unit removal rapidly but is not reliable */ 533 /* check for unit change */ 534 un = sc->sc_port_units[port] & ~units; 535 536 /* detach removed devices */ 537 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 538 if (un & (1 << i)) 539 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 540 #endif 541 542 sc->sc_port_unit_map[port] = unit_map; 543 544 /* schedule scanning child devices */ 545 un = units & ~sc->sc_port_units[port]; 546 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 547 if (un & (1 << i)) { 548 u1 = &sc->sc_unit[port][i]; 549 maple_remove_from_queues(sc, u1); 550 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 551 { 552 char buf[16]; 553 printf("%s: queued to probe 2\n", 554 maple_unit_name(buf, u1->port, u1->subunit)); 555 } 556 #endif 557 TAILQ_INSERT_HEAD(&sc->sc_probeq, u1, u_q); 558 u1->u_queuestat = MAPLE_QUEUE_PROBE; 559 u1->u_proberetry = 0; 560 } 561 } 562 563 static void 564 maple_check_unit_change(struct maple_softc *sc, struct maple_unit *u) 565 { 566 struct maple_devinfo *newinfo = (void *) (u->u_rxbuf + 1); 567 int port, subunit; 568 569 port = u->port; 570 subunit = u->subunit; 571 if (memcmp(&u->devinfo, newinfo, sizeof(struct maple_devinfo)) == 0) 572 goto out; /* no change */ 573 574 /* unit inserted */ 575 576 /* attach this device */ 577 u->devinfo = *newinfo; 578 maple_attach_unit(sc, u); 579 580 out: 581 maple_remove_from_queues(sc, u); 582 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 583 { 584 char buf[16]; 585 printf("%s: queued to ping\n", 586 maple_unit_name(buf, u->port, u->subunit)); 587 } 588 #endif 589 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 590 u->u_queuestat = MAPLE_QUEUE_PING; 591 } 592 593 static void 594 maple_print_unit(void *aux, const char *pnp) 595 { 596 struct maple_attach_args *ma = aux; 597 int port, subunit; 598 char buf[16]; 599 char *prod, *p, oc; 600 601 port = ma->ma_unit->port; 602 subunit = ma->ma_unit->subunit; 603 604 if (pnp != NULL) 605 printf("%s at %s", maple_unit_name(buf, port, subunit), pnp); 606 607 printf(" port %d", port); 608 609 if (subunit != 0) 610 printf(" subunit %d", subunit); 611 612 #ifdef MAPLE_DEBUG 613 printf(": a %#x c %#x fn %#x d %#x,%#x,%#x", 614 ma->ma_devinfo->di_area_code, 615 ma->ma_devinfo->di_connector_direction, 616 ntohl(ma->ma_devinfo->di_func), 617 ntohl(ma->ma_devinfo->di_function_data[0]), 618 ntohl(ma->ma_devinfo->di_function_data[1]), 619 ntohl(ma->ma_devinfo->di_function_data[2])); 620 #endif 621 622 /* nul termination */ 623 prod = ma->ma_devinfo->di_product_name; 624 for (p = prod + sizeof ma->ma_devinfo->di_product_name; p >= prod; p--) 625 if (p[-1] != '\0' && p[-1] != ' ') 626 break; 627 oc = *p; 628 *p = '\0'; 629 630 printf(": %s", prod); 631 632 *p = oc; /* restore */ 633 } 634 635 static int 636 maplesubmatch(struct device *parent, struct cfdata *match, void *aux) 637 { 638 struct maple_attach_args *ma = aux; 639 640 if (match->cf_loc[MAPLECF_PORT] != MAPLECF_PORT_DEFAULT && 641 match->cf_loc[MAPLECF_PORT] != ma->ma_unit->port) 642 return (0); 643 644 if (match->cf_loc[MAPLECF_SUBUNIT] != MAPLECF_SUBUNIT_DEFAULT && 645 match->cf_loc[MAPLECF_SUBUNIT] != ma->ma_unit->subunit) 646 return (0); 647 648 return (config_match(parent, match, aux)); 649 } 650 651 static int 652 mapleprint(void *aux, const char *str) 653 { 654 struct maple_attach_args *ma = aux; 655 656 #ifdef MAPLE_DEBUG 657 if (str) 658 printf("%s", str); 659 printf(" function %d", ma->ma_function); 660 661 return UNCONF; 662 #else /* quiet */ 663 if (!str) 664 printf(" function %d", ma->ma_function); 665 666 return QUIET; 667 #endif 668 } 669 670 static void 671 maple_attach_unit(struct maple_softc *sc, struct maple_unit *u) 672 { 673 struct maple_attach_args ma; 674 u_int32_t func; 675 int f; 676 char oldxname[16]; 677 678 ma.ma_unit = u; 679 ma.ma_devinfo = &u->devinfo; 680 ma.ma_basedevinfo = &sc->sc_unit[u->port][0].devinfo; 681 func = ntohl(ma.ma_devinfo->di_func); 682 683 maple_print_unit(&ma, sc->sc_dev.dv_xname); 684 printf("\n"); 685 strcpy(oldxname, sc->sc_dev.dv_xname); 686 maple_unit_name(sc->sc_dev.dv_xname, u->port, u->subunit); 687 688 for (f = 0; f < MAPLE_NFUNC; f++) { 689 u->u_func[f].f_callback = NULL; 690 u->u_func[f].f_arg = NULL; 691 u->u_func[f].f_cmdstat = MAPLE_CMDSTAT_NONE; 692 u->u_func[f].f_dev = NULL; 693 if (func & MAPLE_FUNC(f)) { 694 ma.ma_function = f; 695 u->u_func[f].f_dev = config_found_sm(&sc->sc_dev, &ma, 696 mapleprint, maplesubmatch); 697 u->u_ping_func = f; /* XXX using largest func */ 698 } 699 } 700 strcpy(sc->sc_dev.dv_xname, oldxname); 701 702 sc->sc_port_units[u->port] |= 1 << u->subunit; 703 } 704 705 static void 706 maple_detach_unit_nofix(struct maple_softc *sc, struct maple_unit *u) 707 { 708 struct maple_func *fn; 709 struct device *dev; 710 struct maple_unit *u1; 711 int port; 712 int error; 713 int i; 714 char buf[16]; 715 716 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 717 printf("%s: remove\n", maple_unit_name(buf, u->port, u->subunit)); 718 #endif 719 maple_remove_from_queues(sc, u); 720 port = u->port; 721 sc->sc_port_units[port] &= ~(1 << u->subunit); 722 723 if (u->subunit == 0) { 724 for (i = MAPLE_SUBUNITS - 1; i > 0; i--) 725 maple_detach_unit_nofix(sc, &sc->sc_unit[port][i]); 726 } 727 728 for (fn = u->u_func; fn < &u->u_func[MAPLE_NFUNC]; fn++) { 729 if ((dev = fn->f_dev) != NULL) { 730 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 731 printf("%s: detaching func %d\n", 732 maple_unit_name(buf, port, u->subunit), 733 fn->f_funcno); 734 #endif 735 736 /* 737 * Remove functions from command queue. 738 */ 739 switch (fn->f_cmdstat) { 740 case MAPLE_CMDSTAT_ASYNC: 741 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 742 TAILQ_REMOVE(&sc->sc_acmdq, fn, f_cmdq); 743 break; 744 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 745 case MAPLE_CMDSTAT_PERIODIC: 746 TAILQ_REMOVE(&sc->sc_pcmdq, fn, f_cmdq); 747 break; 748 default: 749 break; 750 } 751 752 /* 753 * Detach devices. 754 */ 755 if ((error = config_detach(fn->f_dev, DETACH_FORCE))) { 756 printf("%s: failed to detach %s (func %d), errno %d\n", 757 maple_unit_name(buf, port, u->subunit), 758 fn->f_dev->dv_xname, fn->f_funcno, error); 759 } 760 } 761 762 maple_enable_periodic(&sc->sc_dev, u, fn->f_funcno, 0); 763 764 fn->f_dev = NULL; 765 fn->f_callback = NULL; 766 fn->f_arg = NULL; 767 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 768 } 769 if (u->u_dma_stat == MAPLE_DMA_RETRY) { 770 /* XXX expensive? */ 771 SIMPLEQ_FOREACH(u1, &sc->sc_retryq, u_dmaq) { 772 if (u1 == u) { 773 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 774 printf("%s: abort retry\n", 775 maple_unit_name(buf, port, u->subunit)); 776 #endif 777 SIMPLEQ_REMOVE(&sc->sc_retryq, u, maple_unit, 778 u_dmaq); 779 break; 780 } 781 } 782 } 783 u->u_dma_stat = MAPLE_DMA_IDLE; 784 u->u_noping = 0; 785 /* u->u_dma_func = uninitialized; */ 786 KASSERT(u->getcond_func_set == 0); 787 memset(&u->devinfo, 0, sizeof(struct maple_devinfo)); 788 789 if (u->subunit == 0) { 790 sc->sc_port_unit_map[port] = 0; 791 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 792 { 793 char buf[16]; 794 printf("%s: queued to probe 3\n", 795 maple_unit_name(buf, port, u->subunit)); 796 } 797 #endif 798 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q); 799 u->u_queuestat = MAPLE_QUEUE_PROBE; 800 } 801 } 802 803 static void 804 maple_detach_unit(struct maple_softc *sc, struct maple_unit *u) 805 { 806 807 maple_detach_unit_nofix(sc, u); 808 if (u->subunit != 0) 809 sc->sc_port_unit_map[u->port] &= ~(1 << (u->subunit - 1)); 810 } 811 812 /* 813 * Send a command (called by drivers) 814 * 815 * The "cataaddr" must not point at temporary storage like stack. 816 * Only one command (per function) is valid at a time. 817 */ 818 void 819 maple_command(struct device *dev, struct maple_unit *u, int func, 820 int command, int datalen, void *dataaddr, int flags) 821 { 822 struct maple_softc *sc = (void *) dev; 823 struct maple_func *fn; 824 int s; 825 826 KASSERT(func >= 0 && func < 32); 827 KASSERT(command); 828 KASSERT((flags & ~MAPLE_FLAG_CMD_PERIODIC_TIMING) == 0); 829 830 s = splsoftclock(); 831 832 fn = &u->u_func[func]; 833 #if 1 /*def DIAGNOSTIC*/ 834 {char buf[16]; 835 if (fn->f_cmdstat != MAPLE_CMDSTAT_NONE) 836 panic("maple_command: %s func %d: requesting more than one commands", 837 maple_unit_name(buf, u->port, u->subunit), func); 838 } 839 #endif 840 fn->f_command = command; 841 fn->f_datalen = datalen; 842 fn->f_dataaddr = dataaddr; 843 if (flags & MAPLE_FLAG_CMD_PERIODIC_TIMING) { 844 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 845 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 846 } else { 847 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 848 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 849 wakeup(&sc->sc_event); /* wake for async event */ 850 } 851 splx(s); 852 } 853 854 static void 855 maple_queue_cmds(struct maple_softc *sc, 856 struct maple_cmdq_head *head) 857 { 858 struct maple_func *fn, *nextfn; 859 struct maple_unit *u; 860 861 /* 862 * Note: since the queue element may be queued immediately, 863 * we can't use TAILQ_FOREACH. 864 */ 865 fn = TAILQ_FIRST(head); 866 TAILQ_INIT(head); 867 for ( ; fn; fn = nextfn) { 868 nextfn = TAILQ_NEXT(fn, f_cmdq); 869 870 KASSERT(fn->f_cmdstat != MAPLE_CMDSTAT_NONE); 871 u = fn->f_unit; 872 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 873 maple_write_command(sc, u, 874 fn->f_command, fn->f_datalen, fn->f_dataaddr); 875 u->u_dma_stat = (fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC || 876 fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC_PERIODICQ) ? 877 MAPLE_DMA_ACMD : MAPLE_DMA_PCMD; 878 u->u_dma_func = fn->f_funcno; 879 fn->f_cmdstat = MAPLE_CMDSTAT_NONE; 880 } else if (u->u_dma_stat == MAPLE_DMA_RETRY) { 881 /* unit is busy --- try again */ 882 /* 883 * always add to periodic command queue 884 * (wait until the next periodic timing), 885 * since the unit will never be freed until the 886 * next periodic timing. 887 */ 888 switch (fn->f_cmdstat) { 889 case MAPLE_CMDSTAT_ASYNC: 890 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC_PERIODICQ; 891 break; 892 case MAPLE_CMDSTAT_PERIODIC_DEFERED: 893 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC; 894 break; 895 default: 896 break; 897 } 898 TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq); 899 } else { 900 /* unit is busy --- try again */ 901 /* 902 * always add to async command queue 903 * (process immediately) 904 */ 905 switch (fn->f_cmdstat) { 906 case MAPLE_CMDSTAT_ASYNC_PERIODICQ: 907 fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC; 908 break; 909 case MAPLE_CMDSTAT_PERIODIC: 910 fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC_DEFERED; 911 break; 912 default: 913 break; 914 } 915 TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq); 916 } 917 } 918 } 919 920 /* schedule probing a device */ 921 static void 922 maple_unit_probe(struct maple_softc *sc) 923 { 924 struct maple_unit *u; 925 926 if ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) { 927 KASSERT(u->u_dma_stat == MAPLE_DMA_IDLE); 928 KASSERT(u->u_queuestat == MAPLE_QUEUE_PROBE); 929 maple_remove_from_queues(sc, u); 930 maple_write_command(sc, u, MAPLE_COMMAND_DEVINFO, 0, NULL); 931 u->u_dma_stat = MAPLE_DMA_PROBE; 932 /* u->u_dma_func = ignored; */ 933 } 934 } 935 936 /* 937 * Enable/disable unit pinging (called by drivers) 938 */ 939 /* ARGSUSED */ 940 void 941 maple_enable_unit_ping(struct device *dev, struct maple_unit *u, 942 int func, int enable) 943 { 944 #if 0 /* currently unused */ 945 struct maple_softc *sc = (void *) dev; 946 #endif 947 948 if (enable) 949 u->u_noping &= ~MAPLE_FUNC(func); 950 else 951 u->u_noping |= MAPLE_FUNC(func); 952 } 953 954 /* schedule pinging a device */ 955 static void 956 maple_unit_ping(struct maple_softc *sc) 957 { 958 struct maple_unit *u; 959 struct maple_func *fn; 960 961 if ((u = TAILQ_FIRST(&sc->sc_pingq)) != NULL) { 962 KASSERT(u->u_queuestat == MAPLE_QUEUE_PING); 963 maple_remove_from_queues(sc, u); 964 if (u->u_dma_stat == MAPLE_DMA_IDLE && u->u_noping == 0) { 965 fn = &u->u_func[u->u_ping_func]; 966 fn->f_work = htonl(MAPLE_FUNC(u->u_ping_func)); 967 maple_write_command(sc, u, MAPLE_COMMAND_GETCOND, 968 1, &fn->f_work); 969 u->u_dma_stat = MAPLE_DMA_PING; 970 /* u->u_dma_func = XXX; */ 971 } else { 972 /* no need if periodic */ 973 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 974 u->u_queuestat = MAPLE_QUEUE_PING; 975 } 976 } 977 } 978 979 /* 980 * Enable/disable periodic GETCOND (called by drivers) 981 */ 982 void 983 maple_enable_periodic(struct device *dev, struct maple_unit *u, 984 int func, int on) 985 { 986 struct maple_softc *sc = (void *) dev; 987 struct maple_func *fn; 988 989 KASSERT(func >= 0 && func < 32); 990 991 fn = &u->u_func[func]; 992 993 if (on) { 994 if (fn->f_periodic_stat == MAPLE_PERIODIC_NONE) { 995 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 996 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 997 u->getcond_func_set |= MAPLE_FUNC(func); 998 } 999 } else { 1000 if (fn->f_periodic_stat == MAPLE_PERIODIC_INQ) 1001 TAILQ_REMOVE(&sc->sc_periodicq, fn, f_periodicq); 1002 else if (fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED) 1003 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1004 fn->f_periodic_stat = MAPLE_PERIODIC_NONE; 1005 u->getcond_func_set &= ~MAPLE_FUNC(func); 1006 } 1007 } 1008 1009 /* 1010 * queue periodic GETCOND 1011 */ 1012 static int 1013 maple_send_defered_periodic(struct maple_softc *sc) 1014 { 1015 struct maple_unit *u; 1016 struct maple_func *fn, *nextfn; 1017 int defer_remain = 0; 1018 1019 for (fn = TAILQ_FIRST(&sc->sc_periodicdeferq); fn; fn = nextfn) { 1020 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED); 1021 1022 nextfn = TAILQ_NEXT(fn, f_periodicq); 1023 1024 u = fn->f_unit; 1025 if (u->u_dma_stat == MAPLE_DMA_IDLE || 1026 u->u_dma_stat == MAPLE_DMA_RETRY) { 1027 /* 1028 * if IDLE -> queue this request 1029 * if RETRY -> the unit never be freed until the next 1030 * periodic timing, so just restore to 1031 * the normal periodic queue. 1032 */ 1033 TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq); 1034 TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq); 1035 fn->f_periodic_stat = MAPLE_PERIODIC_INQ; 1036 1037 if (u->u_dma_stat == MAPLE_DMA_IDLE) { 1038 /* 1039 * queue periodic command 1040 */ 1041 fn->f_work = htonl(MAPLE_FUNC(fn->f_funcno)); 1042 maple_write_command(sc, u, 1043 MAPLE_COMMAND_GETCOND, 1, &fn->f_work); 1044 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1045 u->u_dma_func = fn->f_funcno; 1046 } 1047 } else { 1048 defer_remain = 1; 1049 } 1050 } 1051 1052 return defer_remain; 1053 } 1054 1055 static void 1056 maple_send_periodic(struct maple_softc *sc) 1057 { 1058 struct maple_unit *u; 1059 struct maple_func *fn, *nextfn; 1060 1061 for (fn = TAILQ_FIRST(&sc->sc_periodicq); fn; fn = nextfn) { 1062 KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_INQ); 1063 1064 nextfn = TAILQ_NEXT(fn, f_periodicq); 1065 1066 u = fn->f_unit; 1067 if (u->u_dma_stat != MAPLE_DMA_IDLE) { 1068 if (u->u_dma_stat != MAPLE_DMA_RETRY) { 1069 /* 1070 * can't be queued --- move to defered queue 1071 */ 1072 TAILQ_REMOVE(&sc->sc_periodicq, fn, 1073 f_periodicq); 1074 TAILQ_INSERT_TAIL(&sc->sc_periodicdeferq, fn, 1075 f_periodicq); 1076 fn->f_periodic_stat = MAPLE_PERIODIC_DEFERED; 1077 } 1078 } else { 1079 /* 1080 * queue periodic command 1081 */ 1082 fn->f_work = htonl(MAPLE_FUNC(fn->f_funcno)); 1083 maple_write_command(sc, u, MAPLE_COMMAND_GETCOND, 1084 1, &fn->f_work); 1085 u->u_dma_stat = MAPLE_DMA_PERIODIC; 1086 u->u_dma_func = fn->f_funcno; 1087 } 1088 } 1089 } 1090 1091 static void 1092 maple_remove_from_queues(struct maple_softc *sc, struct maple_unit *u) 1093 { 1094 1095 /* remove from queues */ 1096 if (u->u_queuestat == MAPLE_QUEUE_PROBE) 1097 TAILQ_REMOVE(&sc->sc_probeq, u, u_q); 1098 else if (u->u_queuestat == MAPLE_QUEUE_PING) 1099 TAILQ_REMOVE(&sc->sc_pingq, u, u_q); 1100 #ifdef DIAGNOSTIC 1101 else if (u->u_queuestat != MAPLE_QUEUE_NONE) 1102 panic("maple_remove_from_queues: queuestat %d", u->u_queuestat); 1103 #endif 1104 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1105 if (u->u_queuestat != MAPLE_QUEUE_NONE) { 1106 char buf[16]; 1107 printf("%s: dequeued\n", 1108 maple_unit_name(buf, u->port, u->subunit)); 1109 } 1110 #endif 1111 1112 u->u_queuestat = MAPLE_QUEUE_NONE; 1113 } 1114 1115 /* 1116 * retry current command at next periodic timing 1117 */ 1118 static int 1119 maple_retry(struct maple_softc *sc, struct maple_unit *u, 1120 enum maple_dma_stat st) 1121 { 1122 1123 KASSERT(st != MAPLE_DMA_IDLE && st != MAPLE_DMA_RETRY); 1124 1125 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1126 if (u->u_retrycnt == 0) { 1127 char buf[16]; 1128 printf("%s: retrying: %#x, %#x, %p\n", 1129 maple_unit_name(buf, u->port, u->subunit), 1130 u->u_command, u->u_datalen, u->u_dataaddr); 1131 } 1132 #endif 1133 if (u->u_retrycnt >= MAPLE_RETRY_MAX) 1134 return 1; 1135 1136 u->u_retrycnt++; 1137 1138 u->u_saved_dma_stat = st; 1139 u->u_dma_stat = MAPLE_DMA_RETRY; /* no new command before retry done */ 1140 SIMPLEQ_INSERT_TAIL(&sc->sc_retryq, u, u_dmaq); 1141 1142 return 0; 1143 } 1144 1145 static void 1146 maple_queue_retry(struct maple_softc *sc) 1147 { 1148 struct maple_unit *u, *nextu; 1149 1150 /* 1151 * Note: since the queue element is queued immediately 1152 * in maple_queue_command, we can't use SIMPLEQ_FOREACH. 1153 */ 1154 for (u = SIMPLEQ_FIRST(&sc->sc_retryq); u; u = nextu) { 1155 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1156 1157 /* 1158 * Retrying is in the highest priority, and the unit shall 1159 * always be free. 1160 */ 1161 KASSERT(u->u_dma_stat == MAPLE_DMA_RETRY); 1162 maple_queue_command(sc, u, u->u_command, u->u_datalen, 1163 u->u_dataaddr); 1164 u->u_dma_stat = u->u_saved_dma_stat; 1165 1166 #ifdef DIAGNOSTIC 1167 KASSERT(u->u_saved_dma_stat != MAPLE_DMA_IDLE); 1168 u->u_saved_dma_stat = MAPLE_DMA_IDLE; 1169 #endif 1170 } 1171 SIMPLEQ_INIT(&sc->sc_retryq); 1172 } 1173 1174 /* 1175 * Process DMA results. 1176 * Requires kernel context. 1177 */ 1178 static void 1179 maple_check_responses(struct maple_softc *sc) 1180 { 1181 struct maple_unit *u, *nextu; 1182 struct maple_func *fn; 1183 maple_response_t response; 1184 int func_code, len; 1185 int flags; 1186 char buf[16]; 1187 1188 /* 1189 * Note: since the queue element may be queued immediately, 1190 * we can't use SIMPLEQ_FOREACH. 1191 */ 1192 for (u = SIMPLEQ_FIRST(&sc->sc_dmaq), maple_begin_txbuf(sc); 1193 u; u = nextu) { 1194 nextu = SIMPLEQ_NEXT(u, u_dmaq); 1195 1196 if (u->u_dma_stat == MAPLE_DMA_IDLE) 1197 continue; /* just detached or DDB was active */ 1198 1199 /* 1200 * check for retransmission 1201 */ 1202 if ((response = u->u_rxbuf[0]) == MAPLE_RESPONSE_AGAIN) { 1203 if (maple_retry(sc, u, u->u_dma_stat) == 0) 1204 continue; 1205 /* else pass error to upper layer */ 1206 } 1207 1208 len = (u->u_rxbuf[0] >> 24); /* length in long */ 1209 len <<= 2; /* length in byte */ 1210 1211 /* 1212 * call handler 1213 */ 1214 if (u->u_dma_stat == MAPLE_DMA_PERIODIC) { 1215 /* 1216 * periodic GETCOND 1217 */ 1218 u->u_dma_stat = MAPLE_DMA_IDLE; 1219 func_code = u->u_dma_func; 1220 if (response == MAPLE_RESPONSE_DATATRF && len > 0 && 1221 ntohl(u->u_rxbuf[1]) == MAPLE_FUNC(func_code)) { 1222 fn = &u->u_func[func_code]; 1223 if (fn->f_dev) 1224 (*fn->f_callback)(fn->f_arg, 1225 (void *)u->u_rxbuf, len, 1226 MAPLE_FLAG_PERIODIC); 1227 } else if (response == MAPLE_RESPONSE_NONE) { 1228 /* XXX OK? */ 1229 /* detach */ 1230 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1231 printf("%s: func: %d: periodic response %d\n", 1232 maple_unit_name(buf, u->port, u->subunit), 1233 u->u_dma_func, 1234 response); 1235 #endif 1236 /* 1237 * Some 3rd party devices sometimes 1238 * do not respond. 1239 */ 1240 if (maple_retry(sc, u, MAPLE_DMA_PERIODIC)) 1241 maple_detach_unit(sc, u); 1242 } 1243 /* XXX check unexpected conditions? */ 1244 1245 } else if (u->u_dma_stat == MAPLE_DMA_PROBE) { 1246 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1247 u->u_dma_stat = MAPLE_DMA_IDLE; 1248 switch (response) { 1249 default: 1250 case MAPLE_RESPONSE_NONE: 1251 /* 1252 * Do not use maple_retry(), which conflicts 1253 * with probe structure. 1254 */ 1255 if (u->subunit != 0 && 1256 ++u->u_proberetry > MAPLE_PROBERETRY_MAX) { 1257 printf("%s: no response\n", 1258 maple_unit_name(buf, 1259 u->port, u->subunit)); 1260 } else { 1261 /* probe again */ 1262 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2 1263 printf("%s: queued to probe 4\n", 1264 maple_unit_name(buf, u->port, u->subunit)); 1265 #endif 1266 TAILQ_INSERT_TAIL(&sc->sc_probeq, u, 1267 u_q); 1268 u->u_queuestat = MAPLE_QUEUE_PROBE; 1269 } 1270 break; 1271 case MAPLE_RESPONSE_DEVINFO: 1272 /* check if the unit is changed */ 1273 maple_check_unit_change(sc, u); 1274 break; 1275 } 1276 1277 } else if (u->u_dma_stat == MAPLE_DMA_PING) { 1278 KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE); 1279 u->u_dma_stat = MAPLE_DMA_IDLE; 1280 switch (response) { 1281 default: 1282 case MAPLE_RESPONSE_NONE: 1283 /* 1284 * Some 3rd party devices sometimes 1285 * do not respond. 1286 */ 1287 if (maple_retry(sc, u, MAPLE_DMA_PING)) { 1288 /* detach */ 1289 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1290 printf("%s: ping response %d\n", 1291 maple_unit_name(buf, u->port, 1292 u->subunit), 1293 response); 1294 #endif 1295 maple_detach_unit(sc, u); 1296 } 1297 break; 1298 case MAPLE_RESPONSE_BADCMD: 1299 case MAPLE_RESPONSE_BADFUNC: 1300 case MAPLE_RESPONSE_DATATRF: 1301 TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q); 1302 u->u_queuestat = MAPLE_QUEUE_PING; 1303 break; 1304 } 1305 1306 } else { 1307 /* 1308 * Note: Do not rely on the consistency of responses. 1309 */ 1310 1311 if (response == MAPLE_RESPONSE_NONE) { 1312 if (maple_retry(sc, u, u->u_dma_stat)) { 1313 /* detach */ 1314 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1315 printf("%s: command response %d\n", 1316 maple_unit_name(buf, u->port, 1317 u->subunit), 1318 response); 1319 #endif 1320 maple_detach_unit(sc, u); 1321 } 1322 continue; 1323 } 1324 1325 flags = (u->u_dma_stat == MAPLE_DMA_PCMD) ? 1326 MAPLE_FLAG_CMD_PERIODIC_TIMING : 0; 1327 u->u_dma_stat = MAPLE_DMA_IDLE; 1328 1329 func_code = u->u_dma_func; 1330 fn = &u->u_func[func_code]; 1331 if (fn->f_dev == NULL) { 1332 /* detached right now */ 1333 #ifdef MAPLE_DEBUG 1334 printf("%s: unknown function: function %d, response %d\n", 1335 maple_unit_name(buf, u->port, u->subunit), 1336 func_code, response); 1337 #endif 1338 continue; 1339 } 1340 if (fn->f_callback != NULL) { 1341 (*fn->f_callback)(fn->f_arg, 1342 (void *)u->u_rxbuf, len, flags); 1343 } 1344 } 1345 1346 /* 1347 * check for subunit change and schedule probing subunits 1348 */ 1349 if (u->subunit == 0 && response != MAPLE_RESPONSE_NONE && 1350 response != MAPLE_RESPONSE_AGAIN && 1351 ((int8_t *) u->u_rxbuf)[2] != sc->sc_port_unit_map[u->port]) 1352 maple_check_subunit_change(sc, u); 1353 } 1354 } 1355 1356 /* 1357 * Main Maple Bus thread 1358 */ 1359 static void 1360 maple_event_thread(void *arg) 1361 { 1362 struct maple_softc *sc = arg; 1363 unsigned cnt = 1; /* timing counter */ 1364 int s; 1365 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1366 int noreq = 0; 1367 #endif 1368 1369 #ifdef MAPLE_DEBUG 1370 printf("%s: forked event thread, pid %d\n", 1371 sc->sc_dev.dv_xname, sc->event_thread->p_pid); 1372 #endif 1373 1374 /* begin first DMA cycle */ 1375 maple_begin_txbuf(sc); 1376 1377 sc->sc_event = 1; 1378 1379 /* OK, continue booting system */ 1380 maple_polling = 0; 1381 config_pending_decr(); 1382 1383 for (;;) { 1384 /* 1385 * queue requests 1386 */ 1387 1388 /* queue async commands */ 1389 if (!TAILQ_EMPTY(&sc->sc_acmdq)) 1390 maple_queue_cmds(sc, &sc->sc_acmdq); 1391 1392 /* send defered periodic command */ 1393 if (!TAILQ_EMPTY(&sc->sc_periodicdeferq)) 1394 maple_send_defered_periodic(sc); 1395 1396 /* queue periodic commands */ 1397 if (sc->sc_event) { 1398 /* queue commands on periodic timing */ 1399 if (!TAILQ_EMPTY(&sc->sc_pcmdq)) 1400 maple_queue_cmds(sc, &sc->sc_pcmdq); 1401 1402 /* retry */ 1403 if (!SIMPLEQ_EMPTY(&sc->sc_retryq)) 1404 maple_queue_retry(sc); 1405 1406 if ((cnt & 31) == 0) /* XXX */ 1407 maple_unit_probe(sc); 1408 cnt++; 1409 1410 maple_send_periodic(sc); 1411 if ((cnt & 7) == 0) /* XXX */ 1412 maple_unit_ping(sc); 1413 1414 /* 1415 * schedule periodic event 1416 */ 1417 sc->sc_event = 0; 1418 callout_reset(&sc->maple_callout_ch, 1419 MAPLE_CALLOUT_TICKS, maple_callout, sc); 1420 } 1421 1422 if (maple_end_txbuf(sc)) { 1423 1424 /* 1425 * start DMA 1426 */ 1427 s = splmaple(); 1428 maple_start(sc); 1429 1430 /* 1431 * wait until DMA done 1432 */ 1433 if (tsleep(&sc->sc_dmadone, PWAIT, "mdma", hz) 1434 == EWOULDBLOCK) { 1435 /* was DDB active? */ 1436 printf("%s: timed out\n", sc->sc_dev.dv_xname); 1437 } 1438 splx(s); 1439 1440 /* 1441 * call handlers 1442 */ 1443 maple_check_responses(sc); 1444 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1445 noreq = 0; 1446 #endif 1447 } 1448 #if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1 1449 else { 1450 /* weird if occurs in succession */ 1451 #if MAPLE_DEBUG <= 2 1452 if (noreq) /* ignore first time */ 1453 #endif 1454 printf("%s: no request %d\n", 1455 sc->sc_dev.dv_xname, noreq); 1456 noreq++; 1457 } 1458 #endif 1459 1460 /* 1461 * wait for an event 1462 */ 1463 s = splsoftclock(); 1464 if (TAILQ_EMPTY(&sc->sc_acmdq) && sc->sc_event == 0 && 1465 TAILQ_EMPTY(&sc->sc_periodicdeferq)) { 1466 if (tsleep(&sc->sc_event, PWAIT, "mslp", hz) 1467 == EWOULDBLOCK) { 1468 printf("%s: event timed out\n", 1469 sc->sc_dev.dv_xname); 1470 } 1471 1472 } 1473 splx(s); 1474 1475 } 1476 1477 #if 0 /* maple root device can't be detached */ 1478 kthread_exit(0); 1479 /* NOTREACHED */ 1480 #endif 1481 } 1482 1483 static int 1484 maple_intr(void *arg) 1485 { 1486 struct maple_softc *sc = arg; 1487 1488 wakeup(&sc->sc_dmadone); 1489 1490 return 1; 1491 } 1492 1493 static void 1494 maple_callout(void *ctx) 1495 { 1496 struct maple_softc *sc = ctx; 1497 1498 sc->sc_event = 1; /* mark as periodic event */ 1499 wakeup(&sc->sc_event); 1500 } 1501 1502 /* 1503 * Install callback handler (called by drivers) 1504 */ 1505 /* ARGSUSED */ 1506 void 1507 maple_set_callback(struct device *dev, struct maple_unit *u, int func, 1508 void (*callback)(void *, struct maple_response *, int, int), void *arg) 1509 { 1510 #if 0 /* currently unused */ 1511 struct maple_softc *sc = (void *) dev; 1512 #endif 1513 struct maple_func *fn; 1514 1515 KASSERT(func >= 0 && func < MAPLE_NFUNC); 1516 1517 fn = &u->u_func[func]; 1518 1519 fn->f_callback = callback; 1520 fn->f_arg = arg; 1521 } 1522 1523 /* 1524 * Return function definition data (called by drivers) 1525 */ 1526 u_int32_t 1527 maple_get_function_data(struct maple_devinfo *devinfo, int function_code) 1528 { 1529 int i, p = 0; 1530 u_int32_t func; 1531 1532 func = ntohl(devinfo->di_func); 1533 for (i = 31; i >= 0; --i) 1534 if (func & MAPLE_FUNC(i)) { 1535 if (function_code == i) 1536 return ntohl(devinfo->di_function_data[p]); 1537 else 1538 if (++p >= 3) 1539 break; 1540 } 1541 1542 return (0); 1543 } 1544 1545 /* Generic maple device interface */ 1546 1547 int 1548 mapleopen(dev_t dev, int flag, int mode, struct proc *p) 1549 { 1550 struct maple_softc *sc; 1551 1552 sc = device_lookup(&maple_cd, MAPLEBUSUNIT(dev)); 1553 if (sc == NULL) /* make sure it was attached */ 1554 return (ENXIO); 1555 1556 if (MAPLEPORT(dev) >= MAPLE_PORTS) 1557 return (ENXIO); 1558 1559 if (MAPLESUBUNIT(dev) >= MAPLE_SUBUNITS) 1560 return (ENXIO); 1561 1562 if (!(sc->sc_port_units[MAPLEPORT(dev)] & (1 << MAPLESUBUNIT(dev)))) 1563 return (ENXIO); 1564 1565 sc->sc_port_units_open[MAPLEPORT(dev)] |= 1 << MAPLESUBUNIT(dev); 1566 1567 return (0); 1568 } 1569 1570 int 1571 mapleclose(dev_t dev, int flag, int mode, struct proc *p) 1572 { 1573 struct maple_softc *sc; 1574 1575 sc = device_lookup(&maple_cd, MAPLEBUSUNIT(dev)); 1576 1577 sc->sc_port_units_open[MAPLEPORT(dev)] &= ~(1 << MAPLESUBUNIT(dev)); 1578 1579 return (0); 1580 } 1581 1582 int 1583 maple_unit_ioctl(struct device *dev, struct maple_unit *u, u_long cmd, 1584 caddr_t data, int flag, struct proc *p) 1585 { 1586 struct maple_softc *sc = (struct maple_softc *)dev; 1587 1588 if (!(sc->sc_port_units[u->port] & (1 << u->subunit))) 1589 return (ENXIO); 1590 1591 switch(cmd) { 1592 case MAPLEIO_GDEVINFO: 1593 memcpy(data, &u->devinfo, sizeof(struct maple_devinfo)); 1594 break; 1595 default: 1596 return (EPASSTHROUGH); 1597 } 1598 1599 return (0); 1600 } 1601 1602 int 1603 mapleioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1604 { 1605 struct maple_softc *sc; 1606 struct maple_unit *u; 1607 1608 sc = device_lookup(&maple_cd, MAPLEBUSUNIT(dev)); 1609 u = &sc->sc_unit[MAPLEPORT(dev)][MAPLESUBUNIT(dev)]; 1610 1611 return (maple_unit_ioctl(&sc->sc_dev, u, cmd, data, flag, p)); 1612 } 1613