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