1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * The "lombus" driver provides access to the LOMlite2 virtual registers, 26 * so that its clients (children) need not be concerned with the details 27 * of the access mechanism, which in this case is implemented via a 28 * packet-based protocol over a serial link connected to one of the serial 29 * ports of the SuperIO (SIO) chip. 30 * 31 * On the other hand, this driver doesn't generally know what the virtual 32 * registers signify - only the clients need this information. 33 */ 34 35 36 /* 37 * Header files 38 */ 39 40 #include <sys/types.h> 41 #include <sys/conf.h> 42 #include <sys/debug.h> 43 #include <sys/errno.h> 44 #include <sys/file.h> 45 #include <sys/intr.h> 46 #include <sys/kmem.h> 47 #include <sys/membar.h> 48 #include <sys/modctl.h> 49 #include <sys/note.h> 50 #include <sys/open.h> 51 #include <sys/poll.h> 52 #include <sys/spl.h> 53 #include <sys/stat.h> 54 #include <sys/strlog.h> 55 56 #include <sys/ddi.h> 57 #include <sys/sunddi.h> 58 #include <sys/sunndi.h> 59 60 #include <sys/lombus.h> 61 62 63 #if defined(NDI_ACC_HDL_V2) 64 65 /* 66 * Compiling for Solaris 9+ with access handle enhancements 67 */ 68 #define HANDLE_TYPE ndi_acc_handle_t 69 #define HANDLE_ADDR(hdlp) (hdlp->ah_addr) 70 #define HANDLE_FAULT(hdlp) (hdlp->ah_fault) 71 #define HANDLE_MAPLEN(hdlp) (hdlp->ah_len) 72 #define HANDLE_PRIVATE(hdlp) (hdlp->ah_bus_private) 73 74 #else 75 76 /* 77 * Compatibility definitions for backport to Solaris 8 78 */ 79 #define HANDLE_TYPE ddi_acc_impl_t 80 #define HANDLE_ADDR(hdlp) (hdlp->ahi_common.ah_addr) 81 #define HANDLE_FAULT(hdlp) (hdlp->ahi_fault) 82 #define HANDLE_MAPLEN(hdlp) (hdlp->ahi_common.ah_len) 83 #define HANDLE_PRIVATE(hdlp) (hdlp->ahi_common.ah_bus_private) 84 85 #define ddi_driver_major(dip) ddi_name_to_major(ddi_binding_name(dip)) 86 87 #endif /* NDI_ACC_HDL_V2 */ 88 89 90 /* 91 * Local definitions 92 */ 93 #define MYNAME "lombus" 94 #define NOMAJOR (~(major_t)0) 95 #define DUMMY_VALUE (~(int8_t)0) 96 97 #define LOMBUS_INST_TO_MINOR(i) (i) 98 #define LOMBUS_MINOR_TO_INST(m) (m) 99 100 #define LOMBUS_DUMMY_ADDRESS ((caddr_t)0x0CADD1ED) 101 #define ADDR_TO_OFFSET(a, hdlp) ((caddr_t)(a) - HANDLE_ADDR(hdlp)) 102 #define ADDR_TO_VREG(a) ((caddr_t)(a) - LOMBUS_DUMMY_ADDRESS) 103 #define VREG_TO_ADDR(v) (LOMBUS_DUMMY_ADDRESS + (v)) 104 105 106 /* 107 * The following definitions are taken from the datasheet 108 * for the National Semiconductor PC87317 (SuperIO) chip. 109 * 110 * This chip implements UART functionality as logical device 6. 111 * It provides all sorts of wierd modes and extensions, but we 112 * have chosen to use only the 16550-compatible features 113 * ("non-extended mode"). 114 * 115 * Hardware: serial chip register numbers 116 */ 117 #define SIO_RXD 0 /* read */ 118 #define SIO_TXD 0 /* write */ 119 #define SIO_IER 1 120 #define SIO_EIR 2 /* read */ 121 #define SIO_FCR 2 /* write */ 122 #define SIO_LCR 3 123 #define SIO_BSR 3 /* wierd */ 124 #define SIO_MCR 4 125 #define SIO_LSR 5 126 #define SIO_MSR 6 127 #define SIO_SCR 7 128 129 #define SIO_LBGDL 0 /* bank 1 */ 130 #define SIO_LBGDH 1 /* bank 1 */ 131 132 /* 133 * Hardware: serial chip register bits 134 */ 135 #define SIO_IER_RXHDL_IE 0x01 136 #define SIO_IER_STD 0x00 137 138 #define SIO_EIR_IPF 0x01 139 #define SIO_EIR_IPR0 0x02 140 #define SIO_EIR_IPR1 0x04 141 #define SIO_EIR_RXFT 0x08 142 #define SIO_EIR_FEN0 0x40 143 #define SIO_EIR_FEN1 0x80 144 145 #define SIO_FCR_FIFO_EN 0x01 146 #define SIO_FCR_RXSR 0x02 147 #define SIO_FCR_TXSR 0x04 148 #define SIO_FCR_RXFTH0 0x40 149 #define SIO_FCR_RXFTH1 0x80 150 #define SIO_FCR_STD (SIO_FCR_RXFTH0|SIO_FCR_FIFO_EN) 151 152 #define SIO_LCR_WLS0 0x01 153 #define SIO_LCR_WLS1 0x02 154 #define SIO_LCR_STB 0x04 155 #define SIO_LCR_PEN 0x08 156 #define SIO_LCR_EPS 0x10 157 #define SIO_LCR_STKP 0x20 158 #define SIO_LCR_SBRK 0x40 159 #define SIO_LCR_BKSE 0x80 160 #define SIO_LCR_8BIT (SIO_LCR_WLS0|SIO_LCR_WLS1) 161 #define SIO_LCR_EPAR (SIO_LCR_PEN|SIO_LCR_EPS) 162 #define SIO_LCR_STD (SIO_LCR_8BIT|SIO_LCR_EPAR) 163 164 #define SIO_BSR_BANK0 (SIO_LCR_STD) 165 #define SIO_BSR_BANK1 (SIO_LCR_BKSE|SIO_LCR_STD) 166 167 #define SIO_MCR_DTR 0x01 168 #define SIO_MCR_RTS 0x02 169 #define SIO_MCR_ISEN 0x08 170 #define SIO_MCR_STD (SIO_MCR_ISEN) 171 172 #define SIO_LSR_RXDA 0x01 173 #define SIO_LSR_OE 0x02 174 #define SIO_LSR_PE 0x04 175 #define SIO_LSR_FE 0x08 176 #define SIO_LSR_BRKE 0x10 177 #define SIO_LSR_TXRDY 0x20 178 #define SIO_LSR_TXEMP 0x40 179 #define SIO_LSR_ER_INF 0x80 180 181 #define SIO_MSR_DCTS 0x01 182 #define SIO_MSR_DDSR 0x02 183 #define SIO_MSR_TERI 0x04 184 #define SIO_MSR_DDCD 0x08 185 #define SIO_MSR_CTS 0x10 186 #define SIO_MSR_DSR 0x20 187 #define SIO_MSR_RI 0x40 188 #define SIO_MSR_DCD 0x80 189 190 /* 191 * Min/max/default baud rates, and a macro to convert from a baud 192 * rate to the number (divisor) to put in the baud rate registers 193 */ 194 #define SIO_BAUD_MIN 50 195 #define SIO_BAUD_MAX 115200 196 #define SIO_BAUD_DEFAULT 38400 197 #define SIO_BAUD_TO_DIVISOR(b) (115200 / (b)) 198 199 200 /* 201 * Packet format ... 202 */ 203 #define LOMBUS_MASK 0xc0 /* Byte-type bits */ 204 #define LOMBUS_PARAM 0x00 /* Parameter byte: 0b0xxxxxxx */ 205 #define LOMBUS_LAST 0x80 /* Last byte of packet */ 206 #define LOMBUS_CMD 0x80 /* Command byte: 0b10###XWV */ 207 #define LOMBUS_STATUS 0xc0 /* Status byte: 0b11###AEV */ 208 209 #define LOMBUS_SEQ 0x38 /* Sequence number bits */ 210 #define LOMBUS_SEQ_LSB 0x08 /* Sequence number LSB */ 211 #define LOMBUS_CMD_XADDR 0x04 /* Extended (2-byte) addressing */ 212 #define LOMBUS_CMD_WRITE 0x02 /* Write command */ 213 #define LOMBUS_CMD_WMSB 0x01 /* Set MSB on Write */ 214 #define LOMBUS_CMD_READ 0x01 /* Read command */ 215 #define LOMBUS_CMD_NOP 0x00 /* NOP command */ 216 217 #define LOMBUS_STATUS_ASYNC 0x04 /* Asynchronous event pending */ 218 #define LOMBUS_STATUS_ERR 0x02 /* Error in command processing */ 219 #define LOMBUS_STATUS_MSB 0x01 /* MSB of Value read */ 220 221 #define LOMBUS_VREG_LO(x) ((x) & ((1 << 7) - 1)) 222 #define LOMBUS_VREG_HI(x) ((x) >> 7) 223 224 #define LOMBUS_BUFSIZE 8 225 226 227 /* 228 * Time periods, in nanoseconds 229 * 230 * Note that LOMBUS_ONE_SEC and some other time 231 * periods are defined in <sys/lombus.h> 232 */ 233 #define LOMBUS_CMD_POLL (LOMBUS_ONE_SEC/20) 234 #define LOMBUS_CTS_POLL (LOMBUS_ONE_SEC/20) 235 #define LOMBUS_CTS_TIMEOUT (LOMBUS_ONE_SEC*2) 236 237 238 /* 239 * Local datatypes 240 */ 241 enum lombus_cmdstate { 242 LOMBUS_CMDSTATE_IDLE, 243 LOMBUS_CMDSTATE_BUSY, 244 LOMBUS_CMDSTATE_WAITING, 245 LOMBUS_CMDSTATE_READY, 246 LOMBUS_CMDSTATE_ERROR 247 }; 248 249 250 /* 251 * This driver's soft-state structure 252 */ 253 254 struct lombus_state { 255 /* 256 * Configuration data, set during attach 257 */ 258 dev_info_t *dip; 259 major_t majornum; 260 int instance; 261 262 ddi_acc_handle_t sio_handle; 263 uint8_t *sio_regs; 264 ddi_softintr_t softid; 265 ddi_periodic_t cycid; /* periodical callback */ 266 267 /* 268 * Parameters derived from .conf properties 269 */ 270 boolean_t allow_echo; 271 int baud; 272 uint32_t debug; 273 boolean_t fake_cts; 274 275 /* 276 * Hardware mutex (initialised using <hw_iblk>), 277 * used to prevent retriggering the softint while 278 * it's still fetching data out of the chip FIFO. 279 */ 280 kmutex_t hw_mutex[1]; 281 ddi_iblock_cookie_t hw_iblk; 282 283 /* 284 * Data protected by the hardware mutex: the watchdog-patting 285 * protocol data (since the dog can be patted from a high-level 286 * cyclic), and the interrupt-enabled flag. 287 */ 288 hrtime_t hw_last_pat; 289 boolean_t hw_int_enabled; 290 291 /* 292 * Flag to indicate that we've incurred a hardware fault on 293 * accesses to the SIO; once this is set, we fake all further 294 * accesses in order not to provoke additional bus errors. 295 */ 296 boolean_t sio_fault; 297 298 /* 299 * Serial protocol state data, protected by lo_mutex 300 * (which is initialised using <lo_iblk>) 301 */ 302 kmutex_t lo_mutex[1]; 303 ddi_iblock_cookie_t lo_iblk; 304 kcondvar_t lo_cv[1]; 305 306 volatile enum lombus_cmdstate cmdstate; 307 clock_t deadline; 308 uint8_t cmdbuf[LOMBUS_BUFSIZE]; 309 uint8_t reply[LOMBUS_BUFSIZE]; 310 uint8_t async; 311 uint8_t index; 312 uint8_t result; 313 uint8_t sequence; 314 uint32_t error; 315 }; 316 317 /* 318 * The auxiliary structure attached to each child 319 * (the child's parent-private-data points to this). 320 */ 321 struct lombus_child_info { 322 lombus_regspec_t *rsp; 323 int nregs; 324 }; 325 326 327 /* 328 * Local data 329 */ 330 331 static void *lombus_statep; 332 333 static major_t lombus_major = NOMAJOR; 334 335 static ddi_device_acc_attr_t lombus_dev_acc_attr[1] = 336 { 337 DDI_DEVICE_ATTR_V0, 338 DDI_STRUCTURE_LE_ACC, 339 DDI_STRICTORDER_ACC 340 }; 341 342 343 /* 344 * General utility routines ... 345 */ 346 347 static void 348 lombus_trace(struct lombus_state *ssp, char code, const char *caller, 349 const char *fmt, ...) 350 { 351 char buf[256]; 352 char *p; 353 va_list va; 354 355 if (ssp->debug & (1 << (code-'@'))) { 356 p = buf; 357 snprintf(p, sizeof (buf) - (p - buf), 358 "%s/%s: ", MYNAME, caller); 359 p += strlen(p); 360 361 va_start(va, fmt); 362 vsnprintf(p, sizeof (buf) - (p - buf), fmt, va); 363 va_end(va); 364 365 buf[sizeof (buf) - 1] = '\0'; 366 strlog(ssp->majornum, ssp->instance, code, SL_TRACE, buf); 367 } 368 } 369 370 static struct lombus_state * 371 lombus_getstate(dev_info_t *dip, int instance, const char *caller) 372 { 373 struct lombus_state *ssp = NULL; 374 dev_info_t *sdip = NULL; 375 major_t dmaj = NOMAJOR; 376 377 if (dip != NULL) { 378 /* 379 * Use the instance number from the <dip>; also, 380 * check that it really corresponds to this driver 381 */ 382 instance = ddi_get_instance(dip); 383 dmaj = ddi_driver_major(dip); 384 if (lombus_major == NOMAJOR && dmaj != NOMAJOR) 385 lombus_major = dmaj; 386 else if (dmaj != lombus_major) { 387 cmn_err(CE_WARN, 388 "%s: major number mismatch (%d vs. %d) in %s()," 389 "probably due to child misconfiguration", 390 MYNAME, lombus_major, dmaj, caller); 391 instance = -1; 392 } 393 } 394 395 if (instance >= 0) 396 ssp = ddi_get_soft_state(lombus_statep, instance); 397 if (ssp != NULL) { 398 sdip = ssp->dip; 399 if (dip == NULL && sdip == NULL) 400 ssp = NULL; 401 else if (dip != NULL && sdip != NULL && sdip != dip) { 402 cmn_err(CE_WARN, 403 "%s: devinfo mismatch (%p vs. %p) in %s(), " 404 "probably due to child misconfiguration", 405 MYNAME, (void *)dip, (void *)sdip, caller); 406 ssp = NULL; 407 } 408 } 409 410 return (ssp); 411 } 412 413 /* 414 * Lowest-level serial I/O chip register read/write 415 */ 416 417 static void 418 sio_put_reg(struct lombus_state *ssp, uint_t reg, uint8_t val) 419 { 420 lombus_trace(ssp, 'P', "sio_put_reg", "REG[%d] <- $%02x", reg, val); 421 422 if (ssp->sio_handle != NULL && !ssp->sio_fault) { 423 /* 424 * The chip is mapped as "I/O" (e.g. with the side-effect 425 * bit on SPARC), therefore accesses are required to be 426 * in-order, with no value cacheing. However, there can 427 * still be write-behind buffering, so it is not guaranteed 428 * that a write actually reaches the chip in a given time. 429 * 430 * To force the access right through to the chip, we follow 431 * the write with another write (to the SCRATCH register) 432 * and a read (of the value just written to the SCRATCH 433 * register). The SCRATCH register is specifically provided 434 * for temporary data and has no effect on the SIO's own 435 * operation, making it ideal as a synchronising mechanism. 436 * 437 * If we didn't do this, it would be possible that the new 438 * value wouldn't reach the chip (and have the *intended* 439 * side-effects, such as disabling interrupts), for such a 440 * long time that the processor could execute a *lot* of 441 * instructions - including exiting the interrupt service 442 * routine and re-enabling interrupts. This effect was 443 * observed to lead to spurious (unclaimed) interrupts in 444 * some circumstances. 445 * 446 * This will no longer be needed once "synchronous" access 447 * handles are available (see PSARC/2000/269 and 2000/531). 448 */ 449 ddi_put8(ssp->sio_handle, ssp->sio_regs + reg, val); 450 ddi_put8(ssp->sio_handle, ssp->sio_regs + SIO_SCR, val); 451 membar_sync(); 452 (void) ddi_get8(ssp->sio_handle, ssp->sio_regs + SIO_SCR); 453 } 454 } 455 456 static uint8_t 457 sio_get_reg(struct lombus_state *ssp, uint_t reg) 458 { 459 uint8_t val; 460 461 if (ssp->sio_handle && !ssp->sio_fault) 462 val = ddi_get8(ssp->sio_handle, ssp->sio_regs + reg); 463 else 464 val = DUMMY_VALUE; 465 466 lombus_trace(ssp, 'G', "sio_get_reg", "$%02x <- REG[%d]", val, reg); 467 468 return (val); 469 } 470 471 static void 472 sio_check_fault_status(struct lombus_state *ssp) 473 { 474 ssp->sio_fault = ddi_check_acc_handle(ssp->sio_handle) != DDI_SUCCESS; 475 } 476 477 static boolean_t 478 sio_faulty(struct lombus_state *ssp) 479 { 480 if (!ssp->sio_fault) 481 sio_check_fault_status(ssp); 482 return (ssp->sio_fault); 483 } 484 485 486 /* 487 * Check for data ready. 488 */ 489 static boolean_t 490 sio_data_ready(struct lombus_state *ssp) 491 { 492 uint8_t status; 493 494 /* 495 * Data is available if the RXDA bit in the LSR is nonzero 496 * (if reading it didn't incur a fault). 497 */ 498 status = sio_get_reg(ssp, SIO_LSR); 499 return ((status & SIO_LSR_RXDA) != 0 && !sio_faulty(ssp)); 500 } 501 502 /* 503 * Check for LOM ready 504 */ 505 static boolean_t 506 sio_lom_ready(struct lombus_state *ssp) 507 { 508 uint8_t status; 509 boolean_t rslt; 510 511 /* 512 * The LOM is ready if the CTS bit in the MSR is 1, meaning 513 * that the /CTS signal is being asserted (driven LOW) - 514 * unless we incurred a fault in trying to read the MSR! 515 * 516 * For debugging, we force the result to TRUE if the FAKE flag is set 517 */ 518 status = sio_get_reg(ssp, SIO_MSR); 519 rslt = (status & SIO_MSR_CTS) != 0 && !sio_faulty(ssp); 520 521 lombus_trace(ssp, 'R', "sio_lom_ready", "S $%02x R %d F %d", 522 status, rslt, ssp->fake_cts); 523 524 return (rslt || ssp->fake_cts); 525 } 526 527 #if 0 528 /* 529 * Check for interrupt pending 530 */ 531 static boolean_t 532 sio_irq_pending(struct lombus_state *ssp) 533 { 534 uint8_t status; 535 boolean_t rslt; 536 537 /* 538 * An interrupt is pending if the IPF bit in the EIR is 0, 539 * assuming we didn't incur a fault in trying to ready it. 540 * 541 * Note: we expect that every time we read this register 542 * (which is only done from the interrupt service routine), 543 * we will see $11001100 (RX FIFO timeout interrupt pending). 544 */ 545 status = sio_get_reg(ssp, SIO_EIR); 546 547 rslt = (status & SIO_EIR_IPF) == 0 && !sio_faulty(ssp); 548 lombus_trace(ssp, 'I', "sio_irq_pending", "S $%02x R %d", 549 status, rslt); 550 551 /* 552 * To investigate whether we're getting any abnormal interrupts 553 * this code checks that the status value is as expected, and that 554 * chip-level interrupts are supposed to be enabled at this time. 555 * This will cause a PANIC (on a driver compiled with DEBUG) if 556 * all is not as expected ... 557 */ 558 ASSERT(status == 0xCC); 559 ASSERT(ssp->hw_int_enabled); 560 561 return (rslt); 562 } 563 #endif /* 0 */ 564 565 /* 566 * Enable/disable interrupts 567 */ 568 static void 569 lombus_set_irq(struct lombus_state *ssp, boolean_t newstate) 570 { 571 uint8_t val; 572 573 val = newstate ? SIO_IER_RXHDL_IE : 0; 574 sio_put_reg(ssp, SIO_IER, SIO_IER_STD | val); 575 ssp->hw_int_enabled = newstate; 576 } 577 578 /* 579 * Assert/deassert RTS 580 */ 581 static void 582 lombus_toggle_rts(struct lombus_state *ssp) 583 { 584 uint8_t val; 585 586 val = sio_get_reg(ssp, SIO_MCR); 587 val &= SIO_MCR_RTS; 588 val ^= SIO_MCR_RTS; 589 val |= SIO_MCR_STD; 590 sio_put_reg(ssp, SIO_MCR, val); 591 } 592 593 594 /* 595 * High-level interrupt handler: 596 * Checks whether initialisation is complete (to avoid a race 597 * with mutex_init()), and whether chip interrupts are enabled. 598 * If not, the interrupt's not for us, so just return UNCLAIMED. 599 * Otherwise, disable the interrupt, trigger a softint, and return 600 * CLAIMED. The softint handler will then do all the real work. 601 * 602 * NOTE: the chip interrupt capability is only re-enabled once the 603 * receive code has run, but that can be called from a poll loop 604 * or cyclic callback as well as from the softint. So it's *not* 605 * guaranteed that there really is a chip interrupt pending here, 606 * 'cos the work may already have been done and the reason for the 607 * interrupt gone away before we get here. 608 * 609 * OTOH, if we come through here twice without the receive code 610 * having run in between, that's definitely wrong. In such an 611 * event, we would notice that chip interrupts haven't yet been 612 * re-enabled and return UNCLAIMED, allowing the system's jabber 613 * protect code (if any) to do its job. 614 */ 615 static uint_t 616 lombus_hi_intr(caddr_t arg) 617 { 618 struct lombus_state *ssp = (void *)arg; 619 uint_t claim; 620 621 claim = DDI_INTR_UNCLAIMED; 622 if (ssp->cycid != NULL) { 623 mutex_enter(ssp->hw_mutex); 624 if (ssp->hw_int_enabled) { 625 lombus_set_irq(ssp, B_FALSE); 626 ddi_trigger_softintr(ssp->softid); 627 claim = DDI_INTR_CLAIMED; 628 } 629 mutex_exit(ssp->hw_mutex); 630 } 631 632 return (claim); 633 } 634 635 /* 636 * Packet receive handler 637 * 638 * This routine should be called from the low-level softint, or the 639 * cyclic callback, or lombus_cmd() (for polled operation), with the 640 * low-level mutex already held. 641 */ 642 static void 643 lombus_receive(struct lombus_state *ssp) 644 { 645 boolean_t ready = B_FALSE; 646 uint8_t data = 0; 647 uint8_t rcvd = 0; 648 uint8_t tmp; 649 650 lombus_trace(ssp, 'S', "lombus_receive", 651 "state %d; error $%x", 652 ssp->cmdstate, ssp->error); 653 654 /* 655 * Check for access faults before starting the receive 656 * loop (we don't want to cause bus errors or suchlike 657 * unpleasantness in the event that the SIO has died). 658 */ 659 if (!sio_faulty(ssp)) { 660 /* 661 * Read bytes from the FIFO until they're all gone, 662 * or we find the 'END OF PACKET' set on one, or 663 * our buffer overflows (which must be an error) 664 */ 665 mutex_enter(ssp->hw_mutex); 666 while (sio_data_ready(ssp)) { 667 data = sio_get_reg(ssp, SIO_RXD); 668 ssp->reply[rcvd = ssp->index] = data; 669 if (++rcvd >= LOMBUS_BUFSIZE) 670 break; 671 ssp->index = rcvd; 672 if (data & LOMBUS_LAST) 673 break; 674 } 675 lombus_set_irq(ssp, B_TRUE); 676 mutex_exit(ssp->hw_mutex); 677 } 678 679 lombus_trace(ssp, 'S', "lombus_receive", 680 "rcvd %d: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x", 681 rcvd, 682 ssp->reply[0], ssp->reply[1], 683 ssp->reply[2], ssp->reply[3], 684 ssp->reply[4], ssp->reply[5], 685 ssp->reply[6], ssp->reply[7]); 686 687 if (ssp->cmdstate != LOMBUS_CMDSTATE_WAITING) { 688 /* 689 * We're not expecting any data in this state, so if 690 * we DID receive any data, we just throw it away by 691 * resetting the buffer index to 0. 692 */ 693 ssp->index = 0; 694 } else if (rcvd == 0) { 695 /* 696 * No bytes received this time through (though there 697 * might be a partial packet sitting in the buffer). 698 * If it seems the LOM is taking too long to respond, 699 * we'll assume it's died and return an error. 700 */ 701 if (ddi_get_lbolt() > ssp->deadline) { 702 ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 703 ssp->error = LOMBUS_ERR_TIMEOUT; 704 ready = B_TRUE; 705 } 706 } else if (rcvd >= LOMBUS_BUFSIZE) { 707 /* 708 * Buffer overflow; discard the data & treat as an error 709 * (even if the last byte read did claim to terminate a 710 * packet, it can't be a valid one 'cos it's too long!) 711 */ 712 ssp->index = 0; 713 ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 714 ssp->error = LOMBUS_ERR_OFLOW; 715 ready = B_TRUE; 716 } else if ((data & LOMBUS_LAST) == 0) { 717 /* 718 * Packet not yet complete; leave the partial packet in 719 * the buffer for later ... 720 */ 721 _NOTE(EMPTY) 722 ; 723 } else if ((data & LOMBUS_MASK) != LOMBUS_STATUS) { 724 /* 725 * Invalid "status" byte - maybe an echo of the command? 726 * 727 * As a debugging feature, we allow for this, assuming 728 * that if the LOM has echoed the command byte, it has 729 * also echoed all the parameter bytes before starting 730 * command processing. So, we dump out the buffer and 731 * then clear it, so we can go back to looking for the 732 * real reply. 733 * 734 * Otherwise, we just drop the data & flag an error. 735 */ 736 if (ssp->allow_echo) { 737 lombus_trace(ssp, 'E', "lombus_receive", 738 "echo $%02x $%02x $%02x $%02x " 739 "$%02x $%02x $%02x $%02x", 740 ssp->reply[0], ssp->reply[1], 741 ssp->reply[2], ssp->reply[3], 742 ssp->reply[4], ssp->reply[5], 743 ssp->reply[6], ssp->reply[7]); 744 ssp->index = 0; 745 } else { 746 ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 747 ssp->error = LOMBUS_ERR_BADSTATUS; 748 ready = B_TRUE; 749 } 750 } else if ((data & LOMBUS_SEQ) != ssp->sequence) { 751 /* 752 * Wrong sequence number! Flag this as an error 753 */ 754 ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 755 ssp->error = LOMBUS_ERR_SEQUENCE; 756 ready = B_TRUE; 757 } else { 758 /* 759 * Finally, we know that's it's a valid reply to our 760 * last command. Update the ASYNC status, derive the 761 * reply parameter (if any), and check the ERROR bit 762 * to find out what the parameter means. 763 * 764 * Note that not all the values read/assigned here 765 * are meaningful, but it doesn't matter; the waiting 766 * thread will know which one(s) it should check. 767 */ 768 ssp->async = (data & LOMBUS_STATUS_ASYNC) ? 1 : 0; 769 tmp = ((data & LOMBUS_STATUS_MSB) ? 0x80 : 0) | ssp->reply[0]; 770 if (data & LOMBUS_STATUS_ERR) { 771 ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 772 ssp->error = tmp; 773 } else { 774 ssp->cmdstate = LOMBUS_CMDSTATE_READY; 775 ssp->result = tmp; 776 } 777 ready = B_TRUE; 778 } 779 780 lombus_trace(ssp, 'T', "lombus_receive", 781 "rcvd %d; last $%02x; state %d; error $%x; ready %d", 782 rcvd, data, ssp->cmdstate, ssp->error, ready); 783 784 if (ready) 785 cv_broadcast(ssp->lo_cv); 786 } 787 788 /* 789 * Low-level softint handler 790 * 791 * This routine should be triggered whenever there's a byte to be read 792 */ 793 static uint_t 794 lombus_softint(caddr_t arg) 795 { 796 struct lombus_state *ssp = (void *)arg; 797 798 mutex_enter(ssp->lo_mutex); 799 lombus_receive(ssp); 800 mutex_exit(ssp->lo_mutex); 801 802 return (DDI_INTR_CLAIMED); 803 } 804 805 /* 806 * Cyclic handler: just calls the receive routine, in case interrupts 807 * are not being delivered and in order to handle command timeout 808 */ 809 static void 810 lombus_cyclic(void *arg) 811 { 812 struct lombus_state *ssp = (void *)arg; 813 814 mutex_enter(ssp->lo_mutex); 815 lombus_receive(ssp); 816 mutex_exit(ssp->lo_mutex); 817 } 818 819 820 /* 821 * Serial protocol 822 * 823 * This routine builds a command and sets it in progress. 824 */ 825 static uint8_t 826 lombus_cmd(HANDLE_TYPE *hdlp, ptrdiff_t vreg, uint_t val, uint_t cmd) 827 { 828 struct lombus_state *ssp; 829 clock_t start; 830 uint8_t *p; 831 832 /* 833 * First of all, wait for the interface to be available. 834 * 835 * NOTE: we blow through all the mutex/cv/state checking and 836 * preempt any command in progress if the system is panicking! 837 */ 838 ssp = HANDLE_PRIVATE(hdlp); 839 mutex_enter(ssp->lo_mutex); 840 while (ssp->cmdstate != LOMBUS_CMDSTATE_IDLE && !panicstr) 841 cv_wait(ssp->lo_cv, ssp->lo_mutex); 842 843 ssp->cmdstate = LOMBUS_CMDSTATE_BUSY; 844 ssp->sequence = (ssp->sequence + LOMBUS_SEQ_LSB) & LOMBUS_SEQ; 845 846 /* 847 * We have exclusive ownership, so assemble the command (backwards): 848 * 849 * [byte 0] Command: modified by XADDR and/or WMSB bits 850 * [Optional] Parameter: Value to write (low 7 bits) 851 * [Optional] Parameter: Register number (high 7 bits) 852 * [Optional] Parameter: Register number (low 7 bits) 853 */ 854 p = &ssp->cmdbuf[0]; 855 *p++ = LOMBUS_CMD | ssp->sequence | cmd; 856 switch (cmd) { 857 case LOMBUS_CMD_WRITE: 858 *p++ = val & 0x7f; 859 if (val >= 0x80) 860 ssp->cmdbuf[0] |= LOMBUS_CMD_WMSB; 861 /*FALLTHRU*/ 862 case LOMBUS_CMD_READ: 863 if (LOMBUS_VREG_HI(vreg) != 0) { 864 *p++ = LOMBUS_VREG_HI(vreg); 865 ssp->cmdbuf[0] |= LOMBUS_CMD_XADDR; 866 } 867 *p++ = LOMBUS_VREG_LO(vreg); 868 /*FALLTHRU*/ 869 case LOMBUS_CMD_NOP: 870 break; 871 } 872 873 /* 874 * Check and update the SIO h/w fault status before accessing 875 * the chip registers. If there's a (new or previous) fault, 876 * we'll run through the protocol but won't really touch the 877 * hardware and all commands will timeout. If a previously 878 * discovered fault has now gone away (!), then we can (try to) 879 * proceed with the new command (probably a probe). 880 */ 881 sio_check_fault_status(ssp); 882 883 /* 884 * Wait up to LOMBUS_CTS_TIMEOUT (2 seconds) for the LOM to tell 885 * us that it's ready for the next command. If it doesn't, though, 886 * we'll send it anyway, on the basis that the CTS signal might be 887 * open- or short-circuited (or the LOM firmware forgot to set it, 888 * or the LOM just got reset, or whatever ...) 889 */ 890 start = ddi_get_lbolt(); 891 ssp->deadline = start + drv_usectohz(LOMBUS_CTS_TIMEOUT/1000); 892 while (!sio_lom_ready(ssp)) { 893 if (ddi_get_lbolt() > ssp->deadline) 894 break; 895 896 cv_reltimedwait(ssp->lo_cv, ssp->lo_mutex, 897 drv_usectohz(LOMBUS_CTS_POLL/1000), TR_CLOCK_TICK); 898 } 899 900 /* 901 * Either the LOM is ready, or we timed out waiting for CTS. 902 * In either case, we're going to send the command now by 903 * stuffing the packet into the Tx FIFO, reversing it as we go. 904 * We call lombus_receive() first to ensure there isn't any 905 * garbage left in the Rx FIFO from an earlier command that 906 * timed out (or was pre-empted by a PANIC!). This also makes 907 * sure that SIO interrupts are enabled so we'll see the reply 908 * more quickly (the poll loop below will still work even if 909 * interrupts aren't enabled, but it will take longer). 910 */ 911 lombus_receive(ssp); 912 mutex_enter(ssp->hw_mutex); 913 while (p > ssp->cmdbuf) 914 sio_put_reg(ssp, SIO_TXD, *--p); 915 mutex_exit(ssp->hw_mutex); 916 917 /* 918 * Prepare for the reply (to be processed by the interrupt/cyclic 919 * handler and/or polling loop below), then wait for a response 920 * or timeout. 921 */ 922 start = ddi_get_lbolt(); 923 ssp->deadline = start + drv_usectohz(LOMBUS_CMD_TIMEOUT/1000); 924 ssp->error = 0; 925 ssp->index = 0; 926 ssp->result = DUMMY_VALUE; 927 ssp->cmdstate = LOMBUS_CMDSTATE_WAITING; 928 while (ssp->cmdstate == LOMBUS_CMDSTATE_WAITING) { 929 if (cv_reltimedwait(ssp->lo_cv, ssp->lo_mutex, 930 drv_usectohz(LOMBUS_CMD_POLL/1000), TR_CLOCK_TICK) == -1) 931 lombus_receive(ssp); 932 } 933 934 /* 935 * The return value may not be meaningful but retrieve it anyway 936 */ 937 val = ssp->result; 938 if (sio_faulty(ssp)) { 939 val = DUMMY_VALUE; 940 HANDLE_FAULT(hdlp) = LOMBUS_ERR_SIOHW; 941 } else if (ssp->cmdstate != LOMBUS_CMDSTATE_READY) { 942 /* 943 * Some problem here ... transfer the error code from 944 * the per-instance state to the per-handle fault flag. 945 * The error code shouldn't be zero! 946 */ 947 if (ssp->error != 0) 948 HANDLE_FAULT(hdlp) = ssp->error; 949 else 950 HANDLE_FAULT(hdlp) = LOMBUS_ERR_BADERRCODE; 951 } 952 953 /* 954 * All done now! 955 */ 956 ssp->index = 0; 957 ssp->cmdstate = LOMBUS_CMDSTATE_IDLE; 958 cv_broadcast(ssp->lo_cv); 959 mutex_exit(ssp->lo_mutex); 960 961 return (val); 962 } 963 964 965 /* 966 * Space 0 - LOM virtual register access 967 * Only 8-bit accesses are supported. 968 */ 969 static uint8_t 970 lombus_vreg_get8(HANDLE_TYPE *hdlp, uint8_t *addr) 971 { 972 ptrdiff_t offset; 973 974 /* 975 * Check the offset that the caller has added to the base address 976 * against the length of the mapping originally requested. 977 */ 978 offset = ADDR_TO_OFFSET(addr, hdlp); 979 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 980 /* 981 * Invalid access - flag a fault and return a dummy value 982 */ 983 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 984 return (DUMMY_VALUE); 985 } 986 987 /* 988 * Derive the virtual register number and run the command 989 */ 990 return (lombus_cmd(hdlp, ADDR_TO_VREG(addr), 0, LOMBUS_CMD_READ)); 991 } 992 993 static void 994 lombus_vreg_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val) 995 { 996 ptrdiff_t offset; 997 998 /* 999 * Check the offset that the caller has added to the base address 1000 * against the length of the mapping originally requested. 1001 */ 1002 offset = ADDR_TO_OFFSET(addr, hdlp); 1003 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 1004 /* 1005 * Invalid access - flag a fault and return 1006 */ 1007 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 1008 return; 1009 } 1010 1011 /* 1012 * Derive the virtual register number and run the command 1013 */ 1014 (void) lombus_cmd(hdlp, ADDR_TO_VREG(addr), val, LOMBUS_CMD_WRITE); 1015 } 1016 1017 static void 1018 lombus_vreg_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 1019 uint8_t *dev_addr, size_t repcount, uint_t flags) 1020 { 1021 size_t inc; 1022 1023 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1024 for (; repcount--; dev_addr += inc) 1025 *host_addr++ = lombus_vreg_get8(hdlp, dev_addr); 1026 } 1027 1028 static void 1029 lombus_vreg_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 1030 uint8_t *dev_addr, size_t repcount, uint_t flags) 1031 { 1032 size_t inc; 1033 1034 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1035 for (; repcount--; dev_addr += inc) 1036 lombus_vreg_put8(hdlp, dev_addr, *host_addr++); 1037 } 1038 1039 1040 /* 1041 * Space 1 - LOM watchdog pat register access 1042 * Only 8-bit accesses are supported. 1043 * 1044 * Reads have no effect and return 0. 1045 * 1046 * Writes pat the dog by toggling the RTS line iff enough time has 1047 * elapsed since last time we toggled it. 1048 * 1049 * Multi-byte reads (using ddi_rep_get8(9F)) are a fairly inefficient 1050 * way of zeroing the destination area ;-) and still won't pat the dog. 1051 * 1052 * Multi-byte writes (using ddi_rep_put8(9F)) will almost certainly 1053 * only count as a single pat, no matter how many bytes the caller 1054 * says to write, as the inter-pat time is VERY long compared with 1055 * the time it will take to read the memory source area. 1056 */ 1057 1058 static uint8_t 1059 lombus_pat_get8(HANDLE_TYPE *hdlp, uint8_t *addr) 1060 { 1061 ptrdiff_t offset; 1062 1063 /* 1064 * Check the offset that the caller has added to the base address 1065 * against the length of the mapping originally requested. 1066 */ 1067 offset = ADDR_TO_OFFSET(addr, hdlp); 1068 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 1069 /* 1070 * Invalid access - flag a fault and return a dummy value 1071 */ 1072 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 1073 return (DUMMY_VALUE); 1074 } 1075 1076 return (0); 1077 } 1078 1079 static void 1080 lombus_pat_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val) 1081 { 1082 struct lombus_state *ssp; 1083 ptrdiff_t offset; 1084 hrtime_t now; 1085 1086 _NOTE(ARGUNUSED(val)) 1087 1088 /* 1089 * Check the offset that the caller has added to the base address 1090 * against the length of the mapping originally requested. 1091 */ 1092 offset = ADDR_TO_OFFSET(addr, hdlp); 1093 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 1094 /* 1095 * Invalid access - flag a fault and return 1096 */ 1097 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 1098 return; 1099 } 1100 1101 ssp = HANDLE_PRIVATE(hdlp); 1102 mutex_enter(ssp->hw_mutex); 1103 now = gethrtime(); 1104 if ((now - ssp->hw_last_pat) >= LOMBUS_MIN_PAT) { 1105 lombus_toggle_rts(ssp); 1106 ssp->hw_last_pat = now; 1107 } 1108 mutex_exit(ssp->hw_mutex); 1109 } 1110 1111 static void 1112 lombus_pat_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 1113 uint8_t *dev_addr, size_t repcount, uint_t flags) 1114 { 1115 size_t inc; 1116 1117 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1118 for (; repcount--; dev_addr += inc) 1119 *host_addr++ = lombus_pat_get8(hdlp, dev_addr); 1120 } 1121 1122 static void 1123 lombus_pat_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 1124 uint8_t *dev_addr, size_t repcount, uint_t flags) 1125 { 1126 size_t inc; 1127 1128 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1129 for (; repcount--; dev_addr += inc) 1130 lombus_pat_put8(hdlp, dev_addr, *host_addr++); 1131 } 1132 1133 1134 /* 1135 * Space 2 - LOM async event flag register access 1136 * Only 16-bit accesses are supported. 1137 */ 1138 static uint16_t 1139 lombus_event_get16(HANDLE_TYPE *hdlp, uint16_t *addr) 1140 { 1141 struct lombus_state *ssp; 1142 ptrdiff_t offset; 1143 1144 /* 1145 * Check the offset that the caller has added to the base address 1146 * against the length of the mapping orignally requested. 1147 */ 1148 offset = ADDR_TO_OFFSET(addr, hdlp); 1149 if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) { 1150 /* 1151 * Invalid access - flag a fault and return a dummy value 1152 */ 1153 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 1154 return (DUMMY_VALUE); 1155 } 1156 1157 /* 1158 * Return the value of the asynchronous-event-pending flag 1159 * as passed back by the LOM at the end of the last command. 1160 */ 1161 ssp = HANDLE_PRIVATE(hdlp); 1162 return (ssp->async); 1163 } 1164 1165 static void 1166 lombus_event_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val) 1167 { 1168 ptrdiff_t offset; 1169 1170 _NOTE(ARGUNUSED(val)) 1171 1172 /* 1173 * Check the offset that the caller has added to the base address 1174 * against the length of the mapping originally requested. 1175 */ 1176 offset = ADDR_TO_OFFSET(addr, hdlp); 1177 if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) { 1178 /* 1179 * Invalid access - flag a fault and return 1180 */ 1181 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 1182 return; 1183 } 1184 1185 /* 1186 * The user can't overwrite the asynchronous-event-pending flag! 1187 */ 1188 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_RO; 1189 } 1190 1191 static void 1192 lombus_event_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 1193 uint16_t *dev_addr, size_t repcount, uint_t flags) 1194 { 1195 size_t inc; 1196 1197 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1198 for (; repcount--; dev_addr += inc) 1199 *host_addr++ = lombus_event_get16(hdlp, dev_addr); 1200 } 1201 1202 static void 1203 lombus_event_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 1204 uint16_t *dev_addr, size_t repcount, uint_t flags) 1205 { 1206 size_t inc; 1207 1208 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1209 for (; repcount--; dev_addr += inc) 1210 lombus_event_put16(hdlp, dev_addr, *host_addr++); 1211 } 1212 1213 1214 /* 1215 * All spaces - access handle fault information 1216 * Only 32-bit accesses are supported. 1217 */ 1218 static uint32_t 1219 lombus_meta_get32(HANDLE_TYPE *hdlp, uint32_t *addr) 1220 { 1221 struct lombus_state *ssp; 1222 ptrdiff_t offset; 1223 1224 /* 1225 * Derive the offset that the caller has added to the base 1226 * address originally returned, and use it to determine 1227 * which meta-register is to be accessed ... 1228 */ 1229 offset = ADDR_TO_OFFSET(addr, hdlp); 1230 switch (offset) { 1231 case LOMBUS_FAULT_REG: 1232 /* 1233 * This meta-register provides a code for the most 1234 * recent virtual register access fault, if any. 1235 */ 1236 return (HANDLE_FAULT(hdlp)); 1237 1238 case LOMBUS_PROBE_REG: 1239 /* 1240 * Reading this meta-register clears any existing fault 1241 * (at the virtual, not the hardware access layer), then 1242 * runs a NOP command and returns the fault code from that. 1243 */ 1244 HANDLE_FAULT(hdlp) = 0; 1245 lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP); 1246 return (HANDLE_FAULT(hdlp)); 1247 1248 case LOMBUS_ASYNC_REG: 1249 /* 1250 * Obsolescent - but still supported for backwards 1251 * compatibility. This is an alias for the newer 1252 * LOMBUS_EVENT_REG, but doesn't require a separate 1253 * "reg" entry and ddi_regs_map_setup() call. 1254 * 1255 * It returns the value of the asynchronous-event-pending 1256 * flag as passed back by the LOM at the end of the last 1257 * completed command. 1258 */ 1259 ssp = HANDLE_PRIVATE(hdlp); 1260 return (ssp->async); 1261 1262 default: 1263 /* 1264 * Invalid access - flag a fault and return a dummy value 1265 */ 1266 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1267 return (DUMMY_VALUE); 1268 } 1269 } 1270 1271 static void 1272 lombus_meta_put32(HANDLE_TYPE *hdlp, uint32_t *addr, uint32_t val) 1273 { 1274 ptrdiff_t offset; 1275 1276 /* 1277 * Derive the offset that the caller has added to the base 1278 * address originally returned, and use it to determine 1279 * which meta-register is to be accessed ... 1280 */ 1281 offset = ADDR_TO_OFFSET(addr, hdlp); 1282 switch (offset) { 1283 case LOMBUS_FAULT_REG: 1284 /* 1285 * This meta-register contains a code for the most 1286 * recent virtual register access fault, if any. 1287 * It can be cleared simply by writing 0 to it. 1288 */ 1289 HANDLE_FAULT(hdlp) = val; 1290 return; 1291 1292 case LOMBUS_PROBE_REG: 1293 /* 1294 * Writing this meta-register clears any existing fault 1295 * (at the virtual, not the hardware acess layer), then 1296 * runs a NOP command. The caller can check the fault 1297 * code later if required. 1298 */ 1299 HANDLE_FAULT(hdlp) = 0; 1300 lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP); 1301 return; 1302 1303 default: 1304 /* 1305 * Invalid access - flag a fault 1306 */ 1307 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1308 return; 1309 } 1310 } 1311 1312 static void 1313 lombus_meta_rep_get32(HANDLE_TYPE *hdlp, uint32_t *host_addr, 1314 uint32_t *dev_addr, size_t repcount, uint_t flags) 1315 { 1316 size_t inc; 1317 1318 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1319 for (; repcount--; dev_addr += inc) 1320 *host_addr++ = lombus_meta_get32(hdlp, dev_addr); 1321 } 1322 1323 static void 1324 lombus_meta_rep_put32(HANDLE_TYPE *hdlp, uint32_t *host_addr, 1325 uint32_t *dev_addr, size_t repcount, uint_t flags) 1326 { 1327 size_t inc; 1328 1329 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 1330 for (; repcount--; dev_addr += inc) 1331 lombus_meta_put32(hdlp, dev_addr, *host_addr++); 1332 } 1333 1334 1335 /* 1336 * Finally, some dummy functions for all unsupported access 1337 * space/size/mode combinations ... 1338 */ 1339 static uint8_t 1340 lombus_no_get8(HANDLE_TYPE *hdlp, uint8_t *addr) 1341 { 1342 _NOTE(ARGUNUSED(addr)) 1343 1344 /* 1345 * Invalid access - flag a fault and return a dummy value 1346 */ 1347 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1348 return (DUMMY_VALUE); 1349 } 1350 1351 static void 1352 lombus_no_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val) 1353 { 1354 _NOTE(ARGUNUSED(addr, val)) 1355 1356 /* 1357 * Invalid access - flag a fault 1358 */ 1359 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1360 } 1361 1362 static void 1363 lombus_no_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 1364 uint8_t *dev_addr, size_t repcount, uint_t flags) 1365 { 1366 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 1367 1368 /* 1369 * Invalid access - flag a fault 1370 */ 1371 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1372 } 1373 1374 static void 1375 lombus_no_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 1376 uint8_t *dev_addr, size_t repcount, uint_t flags) 1377 { 1378 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 1379 1380 /* 1381 * Invalid access - flag a fault 1382 */ 1383 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1384 } 1385 1386 static uint16_t 1387 lombus_no_get16(HANDLE_TYPE *hdlp, uint16_t *addr) 1388 { 1389 _NOTE(ARGUNUSED(addr)) 1390 1391 /* 1392 * Invalid access - flag a fault and return a dummy value 1393 */ 1394 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1395 return (DUMMY_VALUE); 1396 } 1397 1398 static void 1399 lombus_no_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val) 1400 { 1401 _NOTE(ARGUNUSED(addr, val)) 1402 1403 /* 1404 * Invalid access - flag a fault 1405 */ 1406 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1407 } 1408 1409 static void 1410 lombus_no_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 1411 uint16_t *dev_addr, size_t repcount, uint_t flags) 1412 { 1413 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 1414 1415 /* 1416 * Invalid access - flag a fault 1417 */ 1418 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1419 } 1420 1421 static void 1422 lombus_no_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 1423 uint16_t *dev_addr, size_t repcount, uint_t flags) 1424 { 1425 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 1426 1427 /* 1428 * Invalid access - flag a fault 1429 */ 1430 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1431 } 1432 1433 static uint64_t 1434 lombus_no_get64(HANDLE_TYPE *hdlp, uint64_t *addr) 1435 { 1436 _NOTE(ARGUNUSED(addr)) 1437 1438 /* 1439 * Invalid access - flag a fault and return a dummy value 1440 */ 1441 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1442 return (DUMMY_VALUE); 1443 } 1444 1445 static void 1446 lombus_no_put64(HANDLE_TYPE *hdlp, uint64_t *addr, uint64_t val) 1447 { 1448 _NOTE(ARGUNUSED(addr, val)) 1449 1450 /* 1451 * Invalid access - flag a fault 1452 */ 1453 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1454 } 1455 1456 static void 1457 lombus_no_rep_get64(HANDLE_TYPE *hdlp, uint64_t *host_addr, 1458 uint64_t *dev_addr, size_t repcount, uint_t flags) 1459 { 1460 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 1461 1462 /* 1463 * Invalid access - flag a fault 1464 */ 1465 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1466 } 1467 1468 static void 1469 lombus_no_rep_put64(HANDLE_TYPE *hdlp, uint64_t *host_addr, 1470 uint64_t *dev_addr, size_t repcount, uint_t flags) 1471 { 1472 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 1473 1474 /* 1475 * Invalid access - flag a fault 1476 */ 1477 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 1478 } 1479 1480 static int 1481 lombus_acc_fault_check(HANDLE_TYPE *hdlp) 1482 { 1483 return (HANDLE_FAULT(hdlp) != 0); 1484 } 1485 1486 1487 /* 1488 * Hardware setup - put the SIO chip in the required operational 1489 * state, with all our favourite parameters programmed correctly. 1490 * This routine leaves all SIO interrupts disabled. 1491 */ 1492 1493 static void 1494 lombus_hw_reset(struct lombus_state *ssp) 1495 { 1496 uint16_t divisor; 1497 1498 /* 1499 * Disable interrupts, soft reset Tx and Rx circuitry, 1500 * reselect standard modes (bits/char, parity, etc). 1501 */ 1502 lombus_set_irq(ssp, B_FALSE); 1503 sio_put_reg(ssp, SIO_FCR, SIO_FCR_RXSR | SIO_FCR_TXSR); 1504 sio_put_reg(ssp, SIO_LCR, SIO_LCR_STD); 1505 1506 /* 1507 * Select the proper baud rate; if the value is invalid 1508 * (presumably 0, i.e. not specified, but also if the 1509 * "baud" property is set to some silly value), we assume 1510 * the default. 1511 */ 1512 if (ssp->baud < SIO_BAUD_MIN || ssp->baud > SIO_BAUD_MAX) 1513 divisor = SIO_BAUD_TO_DIVISOR(SIO_BAUD_DEFAULT); 1514 else 1515 divisor = SIO_BAUD_TO_DIVISOR(ssp->baud); 1516 1517 /* 1518 * According to the datasheet, it is forbidden for the divisor 1519 * register to be zero. So when loading the register in two 1520 * steps, we have to make sure that the temporary value formed 1521 * between loads is nonzero. However, we can't rely on either 1522 * half already having a nonzero value, as the datasheet also 1523 * says that these registers are indeterminate after a reset! 1524 * So, we explicitly set the low byte to a non-zero value first; 1525 * then we can safely load the high byte, and then the correct 1526 * value for the low byte, without the result ever being zero. 1527 */ 1528 sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK1); 1529 sio_put_reg(ssp, SIO_LBGDL, 0xff); 1530 sio_put_reg(ssp, SIO_LBGDH, divisor >> 8); 1531 sio_put_reg(ssp, SIO_LBGDL, divisor & 0xff); 1532 sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK0); 1533 1534 /* 1535 * Program the remaining device registers as required 1536 */ 1537 sio_put_reg(ssp, SIO_MCR, SIO_MCR_STD); 1538 sio_put_reg(ssp, SIO_FCR, SIO_FCR_STD); 1539 } 1540 1541 1542 /* 1543 * Higher-level setup & teardown 1544 */ 1545 1546 static void 1547 lombus_offline(struct lombus_state *ssp) 1548 { 1549 if (ssp->sio_handle != NULL) 1550 ddi_regs_map_free(&ssp->sio_handle); 1551 ssp->sio_handle = NULL; 1552 ssp->sio_regs = NULL; 1553 } 1554 1555 static int 1556 lombus_online(struct lombus_state *ssp) 1557 { 1558 ddi_acc_handle_t h; 1559 caddr_t p; 1560 int nregs; 1561 int err; 1562 1563 if (ddi_dev_nregs(ssp->dip, &nregs) != DDI_SUCCESS) 1564 nregs = 0; 1565 1566 switch (nregs) { 1567 default: 1568 case 1: 1569 /* 1570 * regset 0 represents the SIO operating registers 1571 */ 1572 err = ddi_regs_map_setup(ssp->dip, 0, &p, 0, 0, 1573 lombus_dev_acc_attr, &h); 1574 lombus_trace(ssp, 'O', "online", 1575 "regmap 0 status %d addr $%p", err, p); 1576 if (err != DDI_SUCCESS) 1577 return (EIO); 1578 1579 ssp->sio_handle = h; 1580 ssp->sio_regs = (void *)p; 1581 break; 1582 1583 case 0: 1584 /* 1585 * If no registers are defined, succeed vacuously; 1586 * commands will be accepted, but we fake the accesses. 1587 */ 1588 break; 1589 } 1590 1591 /* 1592 * Now that the registers are mapped, we can initialise the SIO h/w 1593 */ 1594 lombus_hw_reset(ssp); 1595 return (0); 1596 } 1597 1598 1599 /* 1600 * Nexus routines 1601 */ 1602 1603 #if defined(NDI_ACC_HDL_V2) 1604 1605 static const ndi_acc_fns_t lombus_vreg_acc_fns = { 1606 NDI_ACC_FNS_CURRENT, 1607 NDI_ACC_FNS_V1, 1608 1609 lombus_vreg_get8, 1610 lombus_vreg_put8, 1611 lombus_vreg_rep_get8, 1612 lombus_vreg_rep_put8, 1613 1614 lombus_no_get16, 1615 lombus_no_put16, 1616 lombus_no_rep_get16, 1617 lombus_no_rep_put16, 1618 1619 lombus_meta_get32, 1620 lombus_meta_put32, 1621 lombus_meta_rep_get32, 1622 lombus_meta_rep_put32, 1623 1624 lombus_no_get64, 1625 lombus_no_put64, 1626 lombus_no_rep_get64, 1627 lombus_no_rep_put64, 1628 1629 lombus_acc_fault_check 1630 }; 1631 1632 static const ndi_acc_fns_t lombus_pat_acc_fns = { 1633 NDI_ACC_FNS_CURRENT, 1634 NDI_ACC_FNS_V1, 1635 1636 lombus_pat_get8, 1637 lombus_pat_put8, 1638 lombus_pat_rep_get8, 1639 lombus_pat_rep_put8, 1640 1641 lombus_no_get16, 1642 lombus_no_put16, 1643 lombus_no_rep_get16, 1644 lombus_no_rep_put16, 1645 1646 lombus_meta_get32, 1647 lombus_meta_put32, 1648 lombus_meta_rep_get32, 1649 lombus_meta_rep_put32, 1650 1651 lombus_no_get64, 1652 lombus_no_put64, 1653 lombus_no_rep_get64, 1654 lombus_no_rep_put64, 1655 1656 lombus_acc_fault_check 1657 }; 1658 1659 static const ndi_acc_fns_t lombus_event_acc_fns = { 1660 NDI_ACC_FNS_CURRENT, 1661 NDI_ACC_FNS_V1, 1662 1663 lombus_no_get8, 1664 lombus_no_put8, 1665 lombus_no_rep_get8, 1666 lombus_no_rep_put8, 1667 1668 lombus_event_get16, 1669 lombus_event_put16, 1670 lombus_event_rep_get16, 1671 lombus_event_rep_put16, 1672 1673 lombus_meta_get32, 1674 lombus_meta_put32, 1675 lombus_meta_rep_get32, 1676 lombus_meta_rep_put32, 1677 1678 lombus_no_get64, 1679 lombus_no_put64, 1680 lombus_no_rep_get64, 1681 lombus_no_rep_put64, 1682 1683 lombus_acc_fault_check 1684 }; 1685 1686 static int 1687 lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op, 1688 int space, caddr_t vaddr, off_t len, 1689 ndi_acc_handle_t *hdlp, caddr_t *addrp) 1690 { 1691 switch (op) { 1692 default: 1693 return (DDI_ME_UNIMPLEMENTED); 1694 1695 case DDI_MO_MAP_LOCKED: 1696 switch (space) { 1697 default: 1698 return (DDI_ME_REGSPEC_RANGE); 1699 1700 case LOMBUS_VREG_SPACE: 1701 ndi_set_acc_fns(hdlp, &lombus_vreg_acc_fns); 1702 break; 1703 1704 case LOMBUS_PAT_SPACE: 1705 ndi_set_acc_fns(hdlp, &lombus_pat_acc_fns); 1706 break; 1707 1708 case LOMBUS_EVENT_SPACE: 1709 ndi_set_acc_fns(hdlp, &lombus_event_acc_fns); 1710 break; 1711 } 1712 hdlp->ah_addr = *addrp = vaddr; 1713 hdlp->ah_len = len; 1714 hdlp->ah_bus_private = ssp; 1715 return (DDI_SUCCESS); 1716 1717 case DDI_MO_UNMAP: 1718 *addrp = NULL; 1719 hdlp->ah_bus_private = NULL; 1720 return (DDI_SUCCESS); 1721 } 1722 } 1723 1724 #else 1725 1726 static int 1727 lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op, 1728 int space, caddr_t vaddr, off_t len, 1729 ddi_acc_hdl_t *hdlp, caddr_t *addrp) 1730 { 1731 ddi_acc_impl_t *aip = hdlp->ah_platform_private; 1732 1733 switch (op) { 1734 default: 1735 return (DDI_ME_UNIMPLEMENTED); 1736 1737 case DDI_MO_MAP_LOCKED: 1738 switch (space) { 1739 default: 1740 return (DDI_ME_REGSPEC_RANGE); 1741 1742 case LOMBUS_VREG_SPACE: 1743 aip->ahi_get8 = lombus_vreg_get8; 1744 aip->ahi_put8 = lombus_vreg_put8; 1745 aip->ahi_rep_get8 = lombus_vreg_rep_get8; 1746 aip->ahi_rep_put8 = lombus_vreg_rep_put8; 1747 1748 aip->ahi_get16 = lombus_no_get16; 1749 aip->ahi_put16 = lombus_no_put16; 1750 aip->ahi_rep_get16 = lombus_no_rep_get16; 1751 aip->ahi_rep_put16 = lombus_no_rep_put16; 1752 1753 aip->ahi_get32 = lombus_meta_get32; 1754 aip->ahi_put32 = lombus_meta_put32; 1755 aip->ahi_rep_get32 = lombus_meta_rep_get32; 1756 aip->ahi_rep_put32 = lombus_meta_rep_put32; 1757 1758 aip->ahi_get64 = lombus_no_get64; 1759 aip->ahi_put64 = lombus_no_put64; 1760 aip->ahi_rep_get64 = lombus_no_rep_get64; 1761 aip->ahi_rep_put64 = lombus_no_rep_put64; 1762 1763 aip->ahi_fault_check = lombus_acc_fault_check; 1764 break; 1765 1766 case LOMBUS_PAT_SPACE: 1767 aip->ahi_get8 = lombus_pat_get8; 1768 aip->ahi_put8 = lombus_pat_put8; 1769 aip->ahi_rep_get8 = lombus_pat_rep_get8; 1770 aip->ahi_rep_put8 = lombus_pat_rep_put8; 1771 1772 aip->ahi_get16 = lombus_no_get16; 1773 aip->ahi_put16 = lombus_no_put16; 1774 aip->ahi_rep_get16 = lombus_no_rep_get16; 1775 aip->ahi_rep_put16 = lombus_no_rep_put16; 1776 1777 aip->ahi_get32 = lombus_meta_get32; 1778 aip->ahi_put32 = lombus_meta_put32; 1779 aip->ahi_rep_get32 = lombus_meta_rep_get32; 1780 aip->ahi_rep_put32 = lombus_meta_rep_put32; 1781 1782 aip->ahi_get64 = lombus_no_get64; 1783 aip->ahi_put64 = lombus_no_put64; 1784 aip->ahi_rep_get64 = lombus_no_rep_get64; 1785 aip->ahi_rep_put64 = lombus_no_rep_put64; 1786 1787 aip->ahi_fault_check = lombus_acc_fault_check; 1788 break; 1789 1790 case LOMBUS_EVENT_SPACE: 1791 aip->ahi_get8 = lombus_no_get8; 1792 aip->ahi_put8 = lombus_no_put8; 1793 aip->ahi_rep_get8 = lombus_no_rep_get8; 1794 aip->ahi_rep_put8 = lombus_no_rep_put8; 1795 1796 aip->ahi_get16 = lombus_event_get16; 1797 aip->ahi_put16 = lombus_event_put16; 1798 aip->ahi_rep_get16 = lombus_event_rep_get16; 1799 aip->ahi_rep_put16 = lombus_event_rep_put16; 1800 1801 aip->ahi_get32 = lombus_meta_get32; 1802 aip->ahi_put32 = lombus_meta_put32; 1803 aip->ahi_rep_get32 = lombus_meta_rep_get32; 1804 aip->ahi_rep_put32 = lombus_meta_rep_put32; 1805 1806 aip->ahi_get64 = lombus_no_get64; 1807 aip->ahi_put64 = lombus_no_put64; 1808 aip->ahi_rep_get64 = lombus_no_rep_get64; 1809 aip->ahi_rep_put64 = lombus_no_rep_put64; 1810 1811 aip->ahi_fault_check = lombus_acc_fault_check; 1812 break; 1813 } 1814 hdlp->ah_addr = *addrp = vaddr; 1815 hdlp->ah_len = len; 1816 hdlp->ah_bus_private = ssp; 1817 return (DDI_SUCCESS); 1818 1819 case DDI_MO_UNMAP: 1820 *addrp = NULL; 1821 hdlp->ah_bus_private = NULL; 1822 return (DDI_SUCCESS); 1823 } 1824 } 1825 1826 #endif /* NDI_ACC_HDL_V2 */ 1827 1828 static int 1829 lombus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 1830 off_t off, off_t len, caddr_t *addrp) 1831 { 1832 struct lombus_child_info *lcip; 1833 struct lombus_state *ssp; 1834 lombus_regspec_t *rsp; 1835 1836 if ((ssp = lombus_getstate(dip, -1, "lombus_map")) == NULL) 1837 return (DDI_FAILURE); /* this "can't happen" */ 1838 1839 /* 1840 * Validate mapping request ... 1841 */ 1842 1843 if (mp->map_flags != DDI_MF_KERNEL_MAPPING) 1844 return (DDI_ME_UNSUPPORTED); 1845 if (mp->map_handlep == NULL) 1846 return (DDI_ME_UNSUPPORTED); 1847 if (mp->map_type != DDI_MT_RNUMBER) 1848 return (DDI_ME_UNIMPLEMENTED); 1849 if ((lcip = ddi_get_parent_data(rdip)) == NULL) 1850 return (DDI_ME_INVAL); 1851 if ((rsp = lcip->rsp) == NULL) 1852 return (DDI_ME_INVAL); 1853 if (mp->map_obj.rnumber >= lcip->nregs) 1854 return (DDI_ME_RNUMBER_RANGE); 1855 rsp += mp->map_obj.rnumber; 1856 if (off < 0 || off >= rsp->lombus_size) 1857 return (DDI_ME_INVAL); 1858 if (len == 0) 1859 len = rsp->lombus_size-off; 1860 if (len < 0) 1861 return (DDI_ME_INVAL); 1862 if (off+len < 0 || off+len > rsp->lombus_size) 1863 return (DDI_ME_INVAL); 1864 1865 return (lombus_map_handle(ssp, mp->map_op, 1866 rsp->lombus_space, VREG_TO_ADDR(rsp->lombus_base+off), len, 1867 mp->map_handlep, addrp)); 1868 } 1869 1870 static int 1871 lombus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, 1872 void *arg, void *result) 1873 { 1874 struct lombus_child_info *lcip; 1875 struct lombus_state *ssp; 1876 lombus_regspec_t *rsp; 1877 dev_info_t *cdip; 1878 char addr[32]; 1879 uint_t nregs; 1880 uint_t rnum; 1881 int *regs; 1882 int limit; 1883 int err; 1884 int i; 1885 1886 if ((ssp = lombus_getstate(dip, -1, "lombus_ctlops")) == NULL) 1887 return (DDI_FAILURE); /* this "can't happen" */ 1888 1889 switch (op) { 1890 default: 1891 break; 1892 1893 case DDI_CTLOPS_INITCHILD: 1894 /* 1895 * First, look up and validate the "reg" property. 1896 * 1897 * It must be a non-empty integer array containing a set 1898 * of triples. Once we've verified that, we can treat it 1899 * as an array of type lombus_regspec_t[], which defines 1900 * the meaning of the elements of each triple: 1901 * + the first element of each triple must be a valid space 1902 * + the second and third elements (base, size) of each 1903 * triple must define a valid subrange of that space 1904 * If it passes all the tests, we save it away for future 1905 * reference in the child's parent-private-data field. 1906 */ 1907 cdip = arg; 1908 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, 1909 DDI_PROP_DONTPASS, "reg", ®s, &nregs); 1910 lombus_trace(ssp, 'C', "initchild", 1911 "prop status %d size %d", err, nregs); 1912 if (err != DDI_PROP_SUCCESS) 1913 return (DDI_FAILURE); 1914 1915 err = (nregs <= 0 || (nregs % LOMBUS_REGSPEC_SIZE) != 0); 1916 nregs /= LOMBUS_REGSPEC_SIZE; 1917 rsp = (lombus_regspec_t *)regs; 1918 for (i = 0; i < nregs && !err; ++i) { 1919 switch (rsp[i].lombus_space) { 1920 default: 1921 limit = 0; 1922 err = 1; 1923 break; 1924 1925 case LOMBUS_VREG_SPACE: 1926 limit = LOMBUS_MAX_REG+1; 1927 break; 1928 1929 case LOMBUS_PAT_SPACE: 1930 limit = LOMBUS_PAT_REG+1; 1931 break; 1932 1933 case LOMBUS_EVENT_SPACE: 1934 limit = LOMBUS_EVENT_REG+1; 1935 break; 1936 } 1937 1938 err |= (rsp[i].lombus_base < 0); 1939 err |= (rsp[i].lombus_base >= limit); 1940 1941 if (rsp[i].lombus_size == 0) 1942 rsp[i].lombus_size = limit-rsp[i].lombus_base; 1943 err |= (rsp[i].lombus_size < 0); 1944 1945 err |= (rsp[i].lombus_base+rsp[i].lombus_size < 0); 1946 err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit); 1947 } 1948 1949 if (err) { 1950 ddi_prop_free(regs); 1951 return (DDI_FAILURE); 1952 } 1953 1954 lcip = kmem_zalloc(sizeof (*lcip), KM_SLEEP); 1955 lcip->nregs = nregs; 1956 lcip->rsp = rsp; 1957 ddi_set_parent_data(cdip, lcip); 1958 1959 (void) snprintf(addr, sizeof (addr), 1960 "%x,%x", rsp[0].lombus_space, rsp[0].lombus_base); 1961 ddi_set_name_addr(cdip, addr); 1962 1963 return (DDI_SUCCESS); 1964 1965 case DDI_CTLOPS_UNINITCHILD: 1966 cdip = arg; 1967 ddi_set_name_addr(cdip, NULL); 1968 lcip = ddi_get_parent_data(cdip); 1969 ddi_set_parent_data(cdip, NULL); 1970 ddi_prop_free(lcip->rsp); 1971 kmem_free(lcip, sizeof (*lcip)); 1972 return (DDI_SUCCESS); 1973 1974 case DDI_CTLOPS_REPORTDEV: 1975 if (rdip == NULL) 1976 return (DDI_FAILURE); 1977 1978 cmn_err(CE_CONT, "?LOM device: %s@%s, %s#%d\n", 1979 ddi_node_name(rdip), ddi_get_name_addr(rdip), 1980 ddi_driver_name(dip), ddi_get_instance(dip)); 1981 1982 return (DDI_SUCCESS); 1983 1984 case DDI_CTLOPS_REGSIZE: 1985 if ((lcip = ddi_get_parent_data(rdip)) == NULL) 1986 return (DDI_FAILURE); 1987 if ((rnum = *(uint_t *)arg) >= lcip->nregs) 1988 return (DDI_FAILURE); 1989 *(off_t *)result = lcip->rsp[rnum].lombus_size; 1990 return (DDI_SUCCESS); 1991 1992 case DDI_CTLOPS_NREGS: 1993 if ((lcip = ddi_get_parent_data(rdip)) == NULL) 1994 return (DDI_FAILURE); 1995 *(int *)result = lcip->nregs; 1996 return (DDI_SUCCESS); 1997 } 1998 1999 return (ddi_ctlops(dip, rdip, op, arg, result)); 2000 } 2001 2002 2003 /* 2004 * Clean up on detach or failure of attach 2005 */ 2006 static int 2007 lombus_unattach(struct lombus_state *ssp, int instance) 2008 { 2009 if (ssp != NULL) { 2010 lombus_hw_reset(ssp); 2011 if (ssp->cycid != NULL) { 2012 ddi_periodic_delete(ssp->cycid); 2013 ssp->cycid = NULL; 2014 if (ssp->sio_handle != NULL) 2015 ddi_remove_intr(ssp->dip, 0, ssp->hw_iblk); 2016 ddi_remove_softintr(ssp->softid); 2017 cv_destroy(ssp->lo_cv); 2018 mutex_destroy(ssp->lo_mutex); 2019 mutex_destroy(ssp->hw_mutex); 2020 } 2021 lombus_offline(ssp); 2022 ddi_set_driver_private(ssp->dip, NULL); 2023 } 2024 2025 ddi_soft_state_free(lombus_statep, instance); 2026 return (DDI_FAILURE); 2027 } 2028 2029 /* 2030 * Autoconfiguration routines 2031 */ 2032 2033 static int 2034 lombus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2035 { 2036 struct lombus_state *ssp = NULL; 2037 int instance; 2038 int err; 2039 2040 switch (cmd) { 2041 default: 2042 return (DDI_FAILURE); 2043 2044 case DDI_ATTACH: 2045 break; 2046 } 2047 2048 /* 2049 * Allocate the soft-state structure 2050 */ 2051 instance = ddi_get_instance(dip); 2052 if (ddi_soft_state_zalloc(lombus_statep, instance) != DDI_SUCCESS) 2053 return (DDI_FAILURE); 2054 if ((ssp = lombus_getstate(dip, instance, "lombus_attach")) == NULL) 2055 return (lombus_unattach(ssp, instance)); 2056 ddi_set_driver_private(dip, ssp); 2057 2058 /* 2059 * Initialise devinfo-related fields 2060 */ 2061 ssp->dip = dip; 2062 ssp->majornum = ddi_driver_major(dip); 2063 ssp->instance = instance; 2064 2065 /* 2066 * Set various options from .conf properties 2067 */ 2068 ssp->allow_echo = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2069 DDI_PROP_DONTPASS, "allow-lom-echo", 0) != 0; 2070 ssp->baud = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2071 DDI_PROP_DONTPASS, "baud-rate", 0); 2072 ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2073 DDI_PROP_DONTPASS, "debug", 0); 2074 ssp->fake_cts = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2075 DDI_PROP_DONTPASS, "fake-cts", 0) != 0; 2076 2077 /* 2078 * Initialise current state & time 2079 */ 2080 ssp->cmdstate = LOMBUS_CMDSTATE_IDLE; 2081 ssp->hw_last_pat = gethrtime(); 2082 ssp->cycid = NULL; 2083 2084 /* 2085 * Online the hardware ... 2086 */ 2087 err = lombus_online(ssp); 2088 if (err != 0) 2089 return (lombus_unattach(ssp, instance)); 2090 2091 /* 2092 * Install soft and hard interrupt handler(s) 2093 * Initialise mutexes and cv 2094 * Start cyclic callbacks 2095 * Enable interrupts 2096 */ 2097 err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ssp->softid, 2098 &ssp->lo_iblk, NULL, lombus_softint, (caddr_t)ssp); 2099 if (err != DDI_SUCCESS) 2100 return (lombus_unattach(ssp, instance)); 2101 2102 if (ssp->sio_handle != NULL) 2103 err = ddi_add_intr(dip, 0, &ssp->hw_iblk, NULL, 2104 lombus_hi_intr, (caddr_t)ssp); 2105 2106 mutex_init(ssp->hw_mutex, NULL, MUTEX_DRIVER, ssp->hw_iblk); 2107 mutex_init(ssp->lo_mutex, NULL, MUTEX_DRIVER, ssp->lo_iblk); 2108 cv_init(ssp->lo_cv, NULL, CV_DRIVER, NULL); 2109 2110 /* 2111 * Register a periodical handler. 2112 */ 2113 ssp->cycid = ddi_periodic_add(lombus_cyclic, ssp, LOMBUS_ONE_SEC, 2114 DDI_IPL_1); 2115 2116 /* 2117 * Final check before enabling h/w interrupts - did 2118 * we successfully install the h/w interrupt handler? 2119 */ 2120 if (err != DDI_SUCCESS) 2121 return (lombus_unattach(ssp, instance)); 2122 2123 lombus_set_irq(ssp, B_TRUE); 2124 2125 /* 2126 * All done, report success 2127 */ 2128 ddi_report_dev(dip); 2129 return (DDI_SUCCESS); 2130 } 2131 2132 2133 static int 2134 lombus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2135 { 2136 struct lombus_state *ssp; 2137 int instance; 2138 2139 switch (cmd) { 2140 default: 2141 return (DDI_FAILURE); 2142 2143 case DDI_DETACH: 2144 break; 2145 } 2146 2147 instance = ddi_get_instance(dip); 2148 if ((ssp = lombus_getstate(dip, instance, "lombus_detach")) == NULL) 2149 return (DDI_FAILURE); /* this "can't happen" */ 2150 2151 (void) lombus_unattach(ssp, instance); 2152 return (DDI_SUCCESS); 2153 } 2154 2155 static int 2156 lombus_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 2157 { 2158 struct lombus_state *ssp; 2159 2160 _NOTE(ARGUNUSED(cmd)) 2161 2162 if ((ssp = lombus_getstate(dip, -1, "lombus_reset")) == NULL) 2163 return (DDI_FAILURE); 2164 2165 lombus_hw_reset(ssp); 2166 return (DDI_SUCCESS); 2167 } 2168 2169 2170 /* 2171 * System interface structures 2172 */ 2173 2174 static struct cb_ops lombus_cb_ops = 2175 { 2176 nodev, /* b/c open */ 2177 nodev, /* b/c close */ 2178 nodev, /* b strategy */ 2179 nodev, /* b print */ 2180 nodev, /* b dump */ 2181 nodev, /* c read */ 2182 nodev, /* c write */ 2183 nodev, /* c ioctl */ 2184 nodev, /* c devmap */ 2185 nodev, /* c mmap */ 2186 nodev, /* c segmap */ 2187 nochpoll, /* c poll */ 2188 ddi_prop_op, /* b/c prop_op */ 2189 NULL, /* c streamtab */ 2190 D_MP | D_NEW /* b/c flags */ 2191 }; 2192 2193 static struct bus_ops lombus_bus_ops = 2194 { 2195 BUSO_REV, /* revision */ 2196 lombus_map, /* bus_map */ 2197 0, /* get_intrspec */ 2198 0, /* add_intrspec */ 2199 0, /* remove_intrspec */ 2200 i_ddi_map_fault, /* map_fault */ 2201 ddi_no_dma_map, /* dma_map */ 2202 ddi_no_dma_allochdl, /* allocate DMA handle */ 2203 ddi_no_dma_freehdl, /* free DMA handle */ 2204 ddi_no_dma_bindhdl, /* bind DMA handle */ 2205 ddi_no_dma_unbindhdl, /* unbind DMA handle */ 2206 ddi_no_dma_flush, /* flush DMA */ 2207 ddi_no_dma_win, /* move DMA window */ 2208 ddi_no_dma_mctl, /* generic DMA control */ 2209 lombus_ctlops, /* generic control */ 2210 ddi_bus_prop_op, /* prop_op */ 2211 ndi_busop_get_eventcookie, /* get_eventcookie */ 2212 ndi_busop_add_eventcall, /* add_eventcall */ 2213 ndi_busop_remove_eventcall, /* remove_eventcall */ 2214 ndi_post_event, /* post_event */ 2215 0, /* interrupt control */ 2216 0, /* bus_config */ 2217 0, /* bus_unconfig */ 2218 0, /* bus_fm_init */ 2219 0, /* bus_fm_fini */ 2220 0, /* bus_fm_access_enter */ 2221 0, /* bus_fm_access_exit */ 2222 0, /* bus_power */ 2223 i_ddi_intr_ops /* bus_intr_op */ 2224 }; 2225 2226 static struct dev_ops lombus_dev_ops = 2227 { 2228 DEVO_REV, 2229 0, /* refcount */ 2230 ddi_no_info, /* getinfo */ 2231 nulldev, /* identify */ 2232 nulldev, /* probe */ 2233 lombus_attach, /* attach */ 2234 lombus_detach, /* detach */ 2235 lombus_reset, /* reset */ 2236 &lombus_cb_ops, /* driver operations */ 2237 &lombus_bus_ops, /* bus operations */ 2238 NULL, /* power */ 2239 ddi_quiesce_not_supported, /* devo_quiesce */ 2240 }; 2241 2242 static struct modldrv modldrv = 2243 { 2244 &mod_driverops, 2245 "lombus driver", 2246 &lombus_dev_ops 2247 }; 2248 2249 static struct modlinkage modlinkage = 2250 { 2251 MODREV_1, 2252 { 2253 &modldrv, 2254 NULL 2255 } 2256 }; 2257 2258 2259 /* 2260 * Dynamic loader interface code 2261 */ 2262 2263 int 2264 _init(void) 2265 { 2266 int err; 2267 2268 err = ddi_soft_state_init(&lombus_statep, 2269 sizeof (struct lombus_state), 0); 2270 if (err == DDI_SUCCESS) 2271 if ((err = mod_install(&modlinkage)) != 0) { 2272 ddi_soft_state_fini(&lombus_statep); 2273 } 2274 2275 return (err); 2276 } 2277 2278 int 2279 _info(struct modinfo *mip) 2280 { 2281 return (mod_info(&modlinkage, mip)); 2282 } 2283 2284 int 2285 _fini(void) 2286 { 2287 int err; 2288 2289 if ((err = mod_remove(&modlinkage)) == 0) { 2290 ddi_soft_state_fini(&lombus_statep); 2291 lombus_major = NOMAJOR; 2292 } 2293 2294 return (err); 2295 } 2296