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