1 /* $NetBSD: satmgr.c,v 1.2 2010/06/03 10:44:21 phx Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/device.h> 36 #include <sys/conf.h> 37 #include <sys/proc.h> 38 #include <sys/vnode.h> 39 #include <sys/select.h> 40 #include <sys/poll.h> 41 #include <sys/callout.h> 42 #include <sys/sysctl.h> 43 #include <sys/reboot.h> 44 #include <sys/intr.h> 45 46 #include <dev/sysmon/sysmonvar.h> 47 #include <dev/sysmon/sysmon_taskq.h> 48 49 #include <dev/ic/comreg.h> 50 51 #include <machine/bus.h> 52 #include <machine/intr.h> 53 #include <machine/bootinfo.h> 54 55 #include <sandpoint/sandpoint/eumbvar.h> 56 #include "locators.h" 57 58 struct satmgr_softc { 59 device_t sc_dev; 60 bus_space_tag_t sc_iot; 61 bus_space_handle_t sc_ioh; 62 struct selinfo sc_rsel; 63 callout_t sc_ch_wdog; 64 callout_t sc_ch_pbutton; 65 struct sysmon_pswitch sc_sm_pbutton; 66 int sc_open; 67 void *sc_si; 68 uint32_t sc_ierror, sc_overr; 69 kmutex_t sc_lock; 70 kcondvar_t sc_rdcv, sc_wrcv; 71 char sc_rd_buf[16], *sc_rd_lim, *sc_rd_cur, *sc_rd_ptr; 72 char sc_wr_buf[16], *sc_wr_lim, *sc_wr_cur, *sc_wr_ptr; 73 int sc_rd_cnt, sc_wr_cnt; 74 }; 75 76 static int satmgr_match(device_t, cfdata_t, void *); 77 static void satmgr_attach(device_t, device_t, void *); 78 79 CFATTACH_DECL_NEW(satmgr, sizeof(struct satmgr_softc), 80 satmgr_match, satmgr_attach, NULL, NULL); 81 extern struct cfdriver satmgr_cd; 82 83 static int found = 0; 84 extern void (*md_reboot)(int); 85 86 static dev_type_open(satopen); 87 static dev_type_close(satclose); 88 static dev_type_read(satread); 89 static dev_type_write(satwrite); 90 static dev_type_poll(satpoll); 91 static dev_type_kqfilter(satkqfilter); 92 93 const struct cdevsw satmgr_cdevsw = { 94 satopen, satclose, satread, satwrite, noioctl, 95 nostop, notty, satpoll, nommap, satkqfilter, D_OTHER 96 }; 97 98 static void satmgr_reboot(int); 99 static int satmgr_sysctl_wdogenable(SYSCTLFN_PROTO); 100 static void wdog_tickle(void *); 101 static void send_sat(struct satmgr_softc *, const char *); 102 static int hwintr(void *); 103 static void rxintr(struct satmgr_softc *); 104 static void txintr(struct satmgr_softc *); 105 static void startoutput(struct satmgr_softc *); 106 static void swintr(void *); 107 static void kbutton(struct satmgr_softc *, int); 108 static void sbutton(struct satmgr_softc *, int); 109 static void qbutton(struct satmgr_softc *, int); 110 static void guarded_pbutton(void *); 111 static void sched_sysmon_pbutton(void *); 112 113 struct satmsg { 114 const char *family; 115 const char *reboot, *poweroff; 116 void (*dispatch)(struct satmgr_softc *, int); 117 }; 118 119 static const struct satmsg satmodel[] = { 120 { "kurobox", "CCGG", "EEGG", kbutton }, 121 { "synology", "C", "1", sbutton }, 122 { "qnap", "f", "A", qbutton } 123 }; 124 static const struct satmsg *satmgr_msg; 125 126 /* single byte stride register layout */ 127 #define RBR 0 128 #define THR 0 129 #define DLB 0 130 #define IER 1 131 #define DMB 1 132 #define IIR 2 133 #define LCR 3 134 #define LSR 5 135 #define CSR_READ(t,r) bus_space_read_1((t)->sc_iot, (t)->sc_ioh, (r)) 136 #define CSR_WRITE(t,r,v) bus_space_write_1((t)->sc_iot, (t)->sc_ioh, (r), (v)) 137 138 static int satmgr_wdog; 139 140 static int 141 satmgr_match(device_t parent, cfdata_t match, void *aux) 142 { 143 struct eumb_attach_args *eaa = aux; 144 int unit = eaa->eumb_unit; 145 146 if (unit == EUMBCF_UNIT_DEFAULT && found == 0) 147 return (1); 148 if (unit == 0 || unit == 1) 149 return (1); 150 return (0); 151 } 152 153 static void 154 satmgr_attach(device_t parent, device_t self, void *aux) 155 { 156 struct eumb_attach_args *eaa = aux; 157 struct satmgr_softc *sc = device_private(self); 158 struct btinfo_prodfamily *pfam; 159 int i, sataddr, epicirq; 160 161 found = 1; 162 163 if ((pfam = lookup_bootinfo(BTINFO_PRODFAMILY)) == NULL) 164 goto notavail; 165 satmgr_msg = NULL; 166 for (i = 0; i < (int)(sizeof(satmodel)/sizeof(satmodel[0])); i++) { 167 if (strcmp(pfam->name, satmodel[i].family) == 0) { 168 satmgr_msg = &satmodel[i]; 169 break; 170 } 171 } 172 if (satmgr_msg == NULL) 173 goto notavail; 174 175 aprint_normal(": button manager (%s)\n", satmgr_msg->family); 176 177 sc->sc_dev = self; 178 sataddr = (eaa->eumb_unit == 0) ? 0x4500 : 0x4600; 179 sc->sc_iot = eaa->eumb_bt; 180 bus_space_map(eaa->eumb_bt, sataddr, 0x20, 0, &sc->sc_ioh); 181 sc->sc_open = 0; 182 sc->sc_rd_cnt = 0; 183 sc->sc_rd_cur = sc->sc_rd_ptr = &sc->sc_rd_buf[0]; 184 sc->sc_rd_lim = sc->sc_rd_cur + sizeof(sc->sc_rd_buf); 185 sc->sc_wr_cnt = 0; 186 sc->sc_wr_cur = sc->sc_wr_ptr = &sc->sc_wr_buf[0]; 187 sc->sc_wr_lim = sc->sc_wr_cur + sizeof(sc->sc_wr_buf); 188 sc->sc_ierror = sc->sc_overr = 0; 189 selinit(&sc->sc_rsel); 190 callout_init(&sc->sc_ch_wdog, 0); 191 callout_init(&sc->sc_ch_pbutton, 0); 192 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH); 193 cv_init(&sc->sc_rdcv, "satrd"); 194 cv_init(&sc->sc_wrcv, "satwr"); 195 196 epicirq = (eaa->eumb_unit == 0) ? 24 : 25; 197 intr_establish(epicirq + 16, IST_LEVEL, IPL_SERIAL, hwintr, sc); 198 sc->sc_si = softint_establish(SOFTINT_SERIAL, swintr, sc); 199 200 CSR_WRITE(sc, IER, 0x7f); /* all but MSR */ 201 202 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 203 aprint_error_dev(sc->sc_dev, "couldn't establish handler\n"); 204 205 sysmon_task_queue_init(); 206 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); 207 sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev); 208 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 209 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) 210 aprint_error_dev(sc->sc_dev, 211 "unable to register power button with sysmon\n"); 212 213 if (strcmp(satmgr_msg->family, "kurobox") == 0) { 214 const struct sysctlnode *rnode; 215 struct sysctllog *clog; 216 217 /* create machdep.satmgr.* subtree */ 218 clog = NULL; 219 sysctl_createv(&clog, 0, NULL, &rnode, 220 CTLFLAG_PERMANENT, 221 CTLTYPE_NODE, "machdep", NULL, 222 NULL, 0, NULL, 0, 223 CTL_MACHDEP, CTL_EOL); 224 sysctl_createv(&clog, 0, &rnode, &rnode, 225 CTLFLAG_PERMANENT, 226 CTLTYPE_NODE, "satmgr", NULL, 227 NULL, 0, NULL, 0, 228 CTL_CREATE, CTL_EOL); 229 sysctl_createv(&clog, 0, &rnode, NULL, 230 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 231 CTLTYPE_INT, "hwwdog_enable", 232 SYSCTL_DESCR("watchdog enable"), 233 satmgr_sysctl_wdogenable, 0, NULL, 0, 234 CTL_CREATE, CTL_EOL); 235 } 236 237 md_reboot = satmgr_reboot; /* cpu_reboot() hook */ 238 return; 239 240 notavail: 241 aprint_normal(": button manager (not supported)\n"); 242 } 243 244 static void 245 satmgr_reboot(int howto) 246 { 247 const char *msg; 248 struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0); 249 250 if ((howto & RB_POWERDOWN) == RB_AUTOBOOT) 251 msg = satmgr_msg->reboot; /* REBOOT */ 252 else 253 msg = satmgr_msg->poweroff; /* HALT or POWERDOWN */ 254 send_sat(sc, msg); 255 tsleep(satmgr_reboot, PWAIT, "reboot", 0); 256 /*NOTREACHED*/ 257 } 258 259 static int 260 satmgr_sysctl_wdogenable(SYSCTLFN_ARGS) 261 { 262 int error, t; 263 struct sysctlnode node; 264 struct satmgr_softc *sc; 265 266 node = *rnode; 267 t = satmgr_wdog; 268 node.sysctl_data = &t; 269 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 270 if (error || newp == NULL) 271 return error; 272 273 if (t < 0 || t > 1) 274 return EINVAL; 275 276 sc = device_lookup_private(&satmgr_cd, 0); 277 if (t == 1) { 278 callout_setfunc(&sc->sc_ch_wdog, wdog_tickle, sc); 279 callout_schedule(&sc->sc_ch_wdog, 90 * hz); 280 send_sat(sc, "JJ"); 281 } 282 else { 283 callout_stop(&sc->sc_ch_wdog); 284 send_sat(sc, "KK"); 285 } 286 return 0; 287 } 288 289 /* disarm watchdog timer periodically */ 290 static void 291 wdog_tickle(void *arg) 292 { 293 struct satmgr_softc *sc = arg; 294 295 send_sat(sc, "GG"); 296 callout_schedule(&sc->sc_ch_wdog, 90 * hz); 297 } 298 299 static void 300 send_sat(struct satmgr_softc *sc, const char *msg) 301 { 302 unsigned lsr, ch, n; 303 304 again: 305 do { 306 lsr = CSR_READ(sc, LSR); 307 } while ((lsr & LSR_TXRDY) == 0); 308 n = 16; /* FIFO depth */ 309 while ((ch = *msg++) != '\0' && n-- > 0) { 310 CSR_WRITE(sc, THR, ch); 311 } 312 if (ch != '\0') 313 goto again; 314 } 315 316 static int 317 satopen(dev_t dev, int flags, int fmt, struct lwp *l) 318 { 319 struct satmgr_softc *sc; 320 321 sc = device_lookup_private(&satmgr_cd, 0); 322 if (sc == NULL) 323 return ENXIO; 324 if (sc->sc_open > 0) 325 return EBUSY; 326 sc->sc_open = 1; 327 return 0; 328 } 329 330 static int 331 satclose(dev_t dev, int flags, int fmt, struct lwp *l) 332 { 333 struct satmgr_softc *sc; 334 335 sc = device_lookup_private(&satmgr_cd, 0); 336 if (sc == NULL) 337 return ENXIO; 338 KASSERT(sc->sc_open > 0); 339 sc->sc_open = 0; 340 return 0; 341 } 342 343 static int 344 satread(dev_t dev, struct uio *uio, int flags) 345 { 346 struct satmgr_softc *sc; 347 size_t n; 348 int error; 349 350 sc = device_lookup_private(&satmgr_cd, 0); 351 if (sc == NULL) 352 return ENXIO; 353 354 mutex_enter(&sc->sc_lock); 355 if (sc->sc_rd_cnt == 0 && (flags & IO_NDELAY)) { 356 error = EWOULDBLOCK; 357 goto out; 358 } 359 error = 0; 360 while (sc->sc_rd_cnt == 0) { 361 error = cv_wait_sig(&sc->sc_rdcv, &sc->sc_lock); 362 if (error) 363 goto out; 364 } 365 while (uio->uio_resid > 0 && sc->sc_rd_cnt > 0) { 366 n = min(sc->sc_rd_cnt, uio->uio_resid); 367 n = min(n, sc->sc_rd_lim - sc->sc_rd_ptr); 368 error = uiomove(sc->sc_rd_ptr, n, uio); 369 if (error) 370 goto out; 371 sc->sc_rd_cnt -= n; 372 sc->sc_rd_ptr += n; 373 if (sc->sc_rd_ptr == sc->sc_rd_lim) 374 sc->sc_rd_ptr = &sc->sc_rd_buf[0]; 375 } 376 out: 377 mutex_exit(&sc->sc_lock); 378 return error; 379 } 380 381 static int 382 satwrite(dev_t dev, struct uio *uio, int flags) 383 { 384 struct satmgr_softc *sc; 385 int error; 386 size_t n; 387 388 sc = device_lookup_private(&satmgr_cd, 0); 389 if (sc == NULL) 390 return ENXIO; 391 392 mutex_enter(&sc->sc_lock); 393 if (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf) && (flags & IO_NDELAY)) { 394 error = EWOULDBLOCK; 395 goto out; 396 } 397 error = 0; 398 while (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf)) { 399 error = cv_wait_sig(&sc->sc_wrcv, &sc->sc_lock); 400 if (error) 401 goto out; 402 } 403 while (uio->uio_resid > 0 && sc->sc_wr_cnt < sizeof(sc->sc_wr_buf)) { 404 n = min(uio->uio_resid, sizeof(sc->sc_wr_buf)); 405 n = min(n, sc->sc_wr_lim - sc->sc_wr_cur); 406 error = uiomove(sc->sc_wr_cur, n, uio); 407 if (error) 408 goto out; 409 sc->sc_wr_cnt += n; 410 sc->sc_wr_cur += n; 411 if (sc->sc_wr_cur == sc->sc_wr_lim) 412 sc->sc_wr_cur = &sc->sc_wr_buf[0]; 413 } 414 startoutput(sc); /* start xmit */ 415 out: 416 mutex_exit(&sc->sc_lock); 417 return error; 418 } 419 420 static int 421 satpoll(dev_t dev, int events, struct lwp *l) 422 { 423 struct satmgr_softc *sc; 424 int revents = 0; 425 426 sc = device_lookup_private(&satmgr_cd, 0); 427 mutex_enter(&sc->sc_lock); 428 if (events & (POLLIN | POLLRDNORM)) { 429 if (sc->sc_rd_cnt) 430 revents |= events & (POLLIN | POLLRDNORM); 431 else 432 selrecord(l, &sc->sc_rsel); 433 } 434 mutex_exit(&sc->sc_lock); 435 436 return revents; 437 } 438 439 static void 440 filt_rdetach(struct knote *kn) 441 { 442 struct satmgr_softc *sc = kn->kn_hook; 443 444 mutex_enter(&sc->sc_lock); 445 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); 446 mutex_exit(&sc->sc_lock); 447 } 448 449 static int 450 filt_read(struct knote *kn, long hint) 451 { 452 struct satmgr_softc *sc = kn->kn_hook; 453 454 kn->kn_data = sc->sc_rd_cnt; 455 return (kn->kn_data > 0); 456 } 457 458 static const struct filterops read_filtops = 459 { 1, NULL, filt_rdetach, filt_read }; 460 461 static int 462 satkqfilter(dev_t dev, struct knote *kn) 463 { 464 struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0); 465 struct klist *klist; 466 467 switch (kn->kn_filter) { 468 case EVFILT_READ: 469 klist = &sc->sc_rsel.sel_klist; 470 kn->kn_fop = &read_filtops; 471 break; 472 473 default: 474 return (EINVAL); 475 } 476 477 kn->kn_hook = sc; 478 479 mutex_enter(&sc->sc_lock); 480 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 481 mutex_exit(&sc->sc_lock); 482 483 return (0); 484 } 485 486 static int 487 hwintr(void *arg) 488 { 489 struct satmgr_softc *sc = arg; 490 int iir; 491 492 mutex_spin_enter(&sc->sc_lock); 493 iir = CSR_READ(sc, IIR) & IIR_IMASK; 494 if (iir == IIR_NOPEND) { 495 mutex_spin_exit(&sc->sc_lock); 496 return 0; 497 } 498 do { 499 switch (iir) { 500 case IIR_RLS: /* LSR updated */ 501 case IIR_RXRDY: /* RxFIFO has been accumulated */ 502 case IIR_RXTOUT:/* receive timeout occurred */ 503 rxintr(sc); 504 break; 505 case IIR_TXRDY: /* TxFIFO is ready to swallow data */ 506 txintr(sc); 507 break; 508 case IIR_MLSC: /* MSR updated */ 509 break; 510 } 511 iir = CSR_READ(sc, IIR) & IIR_IMASK; 512 } while (iir != IIR_NOPEND); 513 mutex_spin_exit(&sc->sc_lock); 514 return 1; 515 } 516 517 static void 518 rxintr(struct satmgr_softc *sc) 519 { 520 int lsr, ch; 521 522 lsr = CSR_READ(sc, LSR); 523 if (lsr & LSR_OE) 524 sc->sc_overr++; 525 ch = -1; 526 while (lsr & LSR_RXRDY) { 527 if (lsr & (LSR_BI | LSR_FE | LSR_PE)) { 528 (void) CSR_READ(sc, RBR); 529 sc->sc_ierror++; 530 lsr = CSR_READ(sc, LSR); 531 continue; 532 } 533 ch = CSR_READ(sc, RBR); 534 if (sc->sc_rd_cnt < sizeof(sc->sc_rd_buf)) { 535 *sc->sc_rd_cur = ch; 536 if (++sc->sc_rd_cur == sc->sc_rd_lim) 537 sc->sc_rd_cur = &sc->sc_rd_buf[0]; 538 sc->sc_rd_cnt += 1; 539 } 540 lsr = CSR_READ(sc, LSR); 541 } 542 if (ch != -1) 543 softint_schedule(sc->sc_si); 544 } 545 546 static void 547 txintr(struct satmgr_softc *sc) 548 { 549 550 cv_signal(&sc->sc_wrcv); 551 startoutput(sc); 552 } 553 554 static void 555 startoutput(struct satmgr_softc *sc) 556 { 557 int n, ch; 558 559 n = min(sc->sc_wr_cnt, 16); 560 while ((ch = *sc->sc_wr_ptr) && n-- > 0) { 561 CSR_WRITE(sc, THR, ch); 562 if (++sc->sc_wr_ptr == sc->sc_wr_lim) 563 sc->sc_wr_ptr = &sc->sc_wr_buf[0]; 564 sc->sc_wr_cnt -= 1; 565 } 566 } 567 568 static void 569 swintr(void *arg) 570 { 571 struct satmgr_softc *sc = arg; 572 char *ptr; 573 int n; 574 575 /* we're now in softint(9) context */ 576 mutex_spin_enter(&sc->sc_lock); 577 ptr = sc->sc_rd_ptr; 578 for (n = 0; n < sc->sc_rd_cnt; n++) { 579 (*satmgr_msg->dispatch)(sc, *ptr); 580 if (++ptr == sc->sc_rd_lim) 581 ptr = &sc->sc_rd_buf[0]; 582 } 583 if (sc->sc_open == 0) { 584 sc->sc_rd_cnt = 0; 585 sc->sc_rd_ptr = ptr; 586 mutex_spin_exit(&sc->sc_lock); 587 return; /* drop characters down to floor */ 588 } 589 cv_signal(&sc->sc_rdcv); 590 selnotify(&sc->sc_rsel, 0, 0); 591 mutex_spin_exit(&sc->sc_lock); 592 } 593 594 static void 595 kbutton(struct satmgr_softc *sc, int ch) 596 { 597 598 switch (ch) { 599 case '!': 600 /* schedule 3 second poweroff guard time */ 601 if (callout_pending(&sc->sc_ch_pbutton) == true) 602 callout_stop(&sc->sc_ch_pbutton); 603 callout_reset(&sc->sc_ch_pbutton, 604 3 * hz, guarded_pbutton, sc); 605 break; 606 case ' ': 607 if (callout_expired(&sc->sc_ch_pbutton) == false) 608 callout_stop(&sc->sc_ch_pbutton); 609 else 610 /* should never come here */; 611 break; 612 case '#': 613 case '"': 614 break; 615 } 616 } 617 618 static void 619 sbutton(struct satmgr_softc *sc, int ch) 620 { 621 622 switch (ch) { 623 case '0': 624 /* notified after 3 secord guard time */ 625 sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc); 626 break; 627 case 'a': 628 case '`': 629 break; 630 } 631 } 632 633 static void 634 qbutton(struct satmgr_softc *sc, int ch) 635 { 636 /* research in progress */ 637 } 638 639 static void 640 guarded_pbutton(void *arg) 641 { 642 struct satmgr_softc *sc = arg; 643 644 /* we're now in callout(9) context */ 645 sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc); 646 send_sat(sc, "UU"); 647 } 648 649 static void 650 sched_sysmon_pbutton(void *arg) 651 { 652 struct satmgr_softc *sc = arg; 653 654 /* we're now in kthread(9) context */ 655 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED); 656 } 657