13db86aabSstevel /* 23db86aabSstevel * CDDL HEADER START 33db86aabSstevel * 43db86aabSstevel * The contents of this file are subject to the terms of the 5dd4eeefdSeota * Common Development and Distribution License (the "License"). 6dd4eeefdSeota * You may not use this file except in compliance with the License. 73db86aabSstevel * 83db86aabSstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93db86aabSstevel * or http://www.opensolaris.org/os/licensing. 103db86aabSstevel * See the License for the specific language governing permissions 113db86aabSstevel * and limitations under the License. 123db86aabSstevel * 133db86aabSstevel * When distributing Covered Code, include this CDDL HEADER in each 143db86aabSstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153db86aabSstevel * If applicable, add the following below this CDDL HEADER, with the 163db86aabSstevel * fields enclosed by brackets "[]" replaced with your own identifying 173db86aabSstevel * information: Portions Copyright [yyyy] [name of copyright owner] 183db86aabSstevel * 193db86aabSstevel * CDDL HEADER END 203db86aabSstevel */ 213db86aabSstevel /* 22d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233db86aabSstevel * Use is subject to license terms. 243db86aabSstevel * 253db86aabSstevel * The "lombus" driver provides access to the LOMlite2 virtual registers, 263db86aabSstevel * so that its clients (children) need not be concerned with the details 273db86aabSstevel * of the access mechanism, which in this case is implemented via a 283db86aabSstevel * packet-based protocol over a serial link connected to one of the serial 293db86aabSstevel * ports of the SuperIO (SIO) chip. 303db86aabSstevel * 313db86aabSstevel * On the other hand, this driver doesn't generally know what the virtual 323db86aabSstevel * registers signify - only the clients need this information. 333db86aabSstevel */ 343db86aabSstevel 353db86aabSstevel 363db86aabSstevel /* 373db86aabSstevel * Header files 383db86aabSstevel */ 393db86aabSstevel 403db86aabSstevel #include <sys/types.h> 413db86aabSstevel #include <sys/conf.h> 423db86aabSstevel #include <sys/debug.h> 433db86aabSstevel #include <sys/errno.h> 443db86aabSstevel #include <sys/file.h> 453db86aabSstevel #include <sys/intr.h> 463db86aabSstevel #include <sys/kmem.h> 473db86aabSstevel #include <sys/membar.h> 483db86aabSstevel #include <sys/modctl.h> 493db86aabSstevel #include <sys/note.h> 503db86aabSstevel #include <sys/open.h> 513db86aabSstevel #include <sys/poll.h> 523db86aabSstevel #include <sys/spl.h> 533db86aabSstevel #include <sys/stat.h> 543db86aabSstevel #include <sys/strlog.h> 553db86aabSstevel 563db86aabSstevel #include <sys/ddi.h> 573db86aabSstevel #include <sys/sunddi.h> 583db86aabSstevel #include <sys/sunndi.h> 593db86aabSstevel 603db86aabSstevel #include <sys/lombus.h> 613db86aabSstevel 623db86aabSstevel 633db86aabSstevel #if defined(NDI_ACC_HDL_V2) 643db86aabSstevel 653db86aabSstevel /* 663db86aabSstevel * Compiling for Solaris 9+ with access handle enhancements 673db86aabSstevel */ 683db86aabSstevel #define HANDLE_TYPE ndi_acc_handle_t 693db86aabSstevel #define HANDLE_ADDR(hdlp) (hdlp->ah_addr) 703db86aabSstevel #define HANDLE_FAULT(hdlp) (hdlp->ah_fault) 713db86aabSstevel #define HANDLE_MAPLEN(hdlp) (hdlp->ah_len) 723db86aabSstevel #define HANDLE_PRIVATE(hdlp) (hdlp->ah_bus_private) 733db86aabSstevel 743db86aabSstevel #else 753db86aabSstevel 763db86aabSstevel /* 773db86aabSstevel * Compatibility definitions for backport to Solaris 8 783db86aabSstevel */ 793db86aabSstevel #define HANDLE_TYPE ddi_acc_impl_t 803db86aabSstevel #define HANDLE_ADDR(hdlp) (hdlp->ahi_common.ah_addr) 813db86aabSstevel #define HANDLE_FAULT(hdlp) (hdlp->ahi_fault) 823db86aabSstevel #define HANDLE_MAPLEN(hdlp) (hdlp->ahi_common.ah_len) 833db86aabSstevel #define HANDLE_PRIVATE(hdlp) (hdlp->ahi_common.ah_bus_private) 843db86aabSstevel 853db86aabSstevel #define ddi_driver_major(dip) ddi_name_to_major(ddi_binding_name(dip)) 863db86aabSstevel 873db86aabSstevel #endif /* NDI_ACC_HDL_V2 */ 883db86aabSstevel 893db86aabSstevel 903db86aabSstevel /* 913db86aabSstevel * Local definitions 923db86aabSstevel */ 933db86aabSstevel #define MYNAME "lombus" 943db86aabSstevel #define NOMAJOR (~(major_t)0) 953db86aabSstevel #define DUMMY_VALUE (~(int8_t)0) 963db86aabSstevel 973db86aabSstevel #define LOMBUS_INST_TO_MINOR(i) (i) 983db86aabSstevel #define LOMBUS_MINOR_TO_INST(m) (m) 993db86aabSstevel 1003db86aabSstevel #define LOMBUS_DUMMY_ADDRESS ((caddr_t)0x0CADD1ED) 1013db86aabSstevel #define ADDR_TO_OFFSET(a, hdlp) ((caddr_t)(a) - HANDLE_ADDR(hdlp)) 1023db86aabSstevel #define ADDR_TO_VREG(a) ((caddr_t)(a) - LOMBUS_DUMMY_ADDRESS) 1033db86aabSstevel #define VREG_TO_ADDR(v) (LOMBUS_DUMMY_ADDRESS + (v)) 1043db86aabSstevel 1053db86aabSstevel 1063db86aabSstevel /* 1073db86aabSstevel * The following definitions are taken from the datasheet 1083db86aabSstevel * for the National Semiconductor PC87317 (SuperIO) chip. 1093db86aabSstevel * 1103db86aabSstevel * This chip implements UART functionality as logical device 6. 1113db86aabSstevel * It provides all sorts of wierd modes and extensions, but we 1123db86aabSstevel * have chosen to use only the 16550-compatible features 1133db86aabSstevel * ("non-extended mode"). 1143db86aabSstevel * 1153db86aabSstevel * Hardware: serial chip register numbers 1163db86aabSstevel */ 1173db86aabSstevel #define SIO_RXD 0 /* read */ 1183db86aabSstevel #define SIO_TXD 0 /* write */ 1193db86aabSstevel #define SIO_IER 1 1203db86aabSstevel #define SIO_EIR 2 /* read */ 1213db86aabSstevel #define SIO_FCR 2 /* write */ 1223db86aabSstevel #define SIO_LCR 3 1233db86aabSstevel #define SIO_BSR 3 /* wierd */ 1243db86aabSstevel #define SIO_MCR 4 1253db86aabSstevel #define SIO_LSR 5 1263db86aabSstevel #define SIO_MSR 6 1273db86aabSstevel #define SIO_SCR 7 1283db86aabSstevel 1293db86aabSstevel #define SIO_LBGDL 0 /* bank 1 */ 1303db86aabSstevel #define SIO_LBGDH 1 /* bank 1 */ 1313db86aabSstevel 1323db86aabSstevel /* 1333db86aabSstevel * Hardware: serial chip register bits 1343db86aabSstevel */ 1353db86aabSstevel #define SIO_IER_RXHDL_IE 0x01 1363db86aabSstevel #define SIO_IER_STD 0x00 1373db86aabSstevel 1383db86aabSstevel #define SIO_EIR_IPF 0x01 1393db86aabSstevel #define SIO_EIR_IPR0 0x02 1403db86aabSstevel #define SIO_EIR_IPR1 0x04 1413db86aabSstevel #define SIO_EIR_RXFT 0x08 1423db86aabSstevel #define SIO_EIR_FEN0 0x40 1433db86aabSstevel #define SIO_EIR_FEN1 0x80 1443db86aabSstevel 1453db86aabSstevel #define SIO_FCR_FIFO_EN 0x01 1463db86aabSstevel #define SIO_FCR_RXSR 0x02 1473db86aabSstevel #define SIO_FCR_TXSR 0x04 1483db86aabSstevel #define SIO_FCR_RXFTH0 0x40 1493db86aabSstevel #define SIO_FCR_RXFTH1 0x80 1503db86aabSstevel #define SIO_FCR_STD (SIO_FCR_RXFTH0|SIO_FCR_FIFO_EN) 1513db86aabSstevel 1523db86aabSstevel #define SIO_LCR_WLS0 0x01 1533db86aabSstevel #define SIO_LCR_WLS1 0x02 1543db86aabSstevel #define SIO_LCR_STB 0x04 1553db86aabSstevel #define SIO_LCR_PEN 0x08 1563db86aabSstevel #define SIO_LCR_EPS 0x10 1573db86aabSstevel #define SIO_LCR_STKP 0x20 1583db86aabSstevel #define SIO_LCR_SBRK 0x40 1593db86aabSstevel #define SIO_LCR_BKSE 0x80 1603db86aabSstevel #define SIO_LCR_8BIT (SIO_LCR_WLS0|SIO_LCR_WLS1) 1613db86aabSstevel #define SIO_LCR_EPAR (SIO_LCR_PEN|SIO_LCR_EPS) 1623db86aabSstevel #define SIO_LCR_STD (SIO_LCR_8BIT|SIO_LCR_EPAR) 1633db86aabSstevel 1643db86aabSstevel #define SIO_BSR_BANK0 (SIO_LCR_STD) 1653db86aabSstevel #define SIO_BSR_BANK1 (SIO_LCR_BKSE|SIO_LCR_STD) 1663db86aabSstevel 1673db86aabSstevel #define SIO_MCR_DTR 0x01 1683db86aabSstevel #define SIO_MCR_RTS 0x02 1693db86aabSstevel #define SIO_MCR_ISEN 0x08 1703db86aabSstevel #define SIO_MCR_STD (SIO_MCR_ISEN) 1713db86aabSstevel 1723db86aabSstevel #define SIO_LSR_RXDA 0x01 1733db86aabSstevel #define SIO_LSR_OE 0x02 1743db86aabSstevel #define SIO_LSR_PE 0x04 1753db86aabSstevel #define SIO_LSR_FE 0x08 1763db86aabSstevel #define SIO_LSR_BRKE 0x10 1773db86aabSstevel #define SIO_LSR_TXRDY 0x20 1783db86aabSstevel #define SIO_LSR_TXEMP 0x40 1793db86aabSstevel #define SIO_LSR_ER_INF 0x80 1803db86aabSstevel 1813db86aabSstevel #define SIO_MSR_DCTS 0x01 1823db86aabSstevel #define SIO_MSR_DDSR 0x02 1833db86aabSstevel #define SIO_MSR_TERI 0x04 1843db86aabSstevel #define SIO_MSR_DDCD 0x08 1853db86aabSstevel #define SIO_MSR_CTS 0x10 1863db86aabSstevel #define SIO_MSR_DSR 0x20 1873db86aabSstevel #define SIO_MSR_RI 0x40 1883db86aabSstevel #define SIO_MSR_DCD 0x80 1893db86aabSstevel 1903db86aabSstevel /* 1913db86aabSstevel * Min/max/default baud rates, and a macro to convert from a baud 1923db86aabSstevel * rate to the number (divisor) to put in the baud rate registers 1933db86aabSstevel */ 1943db86aabSstevel #define SIO_BAUD_MIN 50 1953db86aabSstevel #define SIO_BAUD_MAX 115200 1963db86aabSstevel #define SIO_BAUD_DEFAULT 38400 1973db86aabSstevel #define SIO_BAUD_TO_DIVISOR(b) (115200 / (b)) 1983db86aabSstevel 1993db86aabSstevel 2003db86aabSstevel /* 2013db86aabSstevel * Packet format ... 2023db86aabSstevel */ 2033db86aabSstevel #define LOMBUS_MASK 0xc0 /* Byte-type bits */ 2043db86aabSstevel #define LOMBUS_PARAM 0x00 /* Parameter byte: 0b0xxxxxxx */ 2053db86aabSstevel #define LOMBUS_LAST 0x80 /* Last byte of packet */ 2063db86aabSstevel #define LOMBUS_CMD 0x80 /* Command byte: 0b10###XWV */ 2073db86aabSstevel #define LOMBUS_STATUS 0xc0 /* Status byte: 0b11###AEV */ 2083db86aabSstevel 2093db86aabSstevel #define LOMBUS_SEQ 0x38 /* Sequence number bits */ 2103db86aabSstevel #define LOMBUS_SEQ_LSB 0x08 /* Sequence number LSB */ 2113db86aabSstevel #define LOMBUS_CMD_XADDR 0x04 /* Extended (2-byte) addressing */ 2123db86aabSstevel #define LOMBUS_CMD_WRITE 0x02 /* Write command */ 2133db86aabSstevel #define LOMBUS_CMD_WMSB 0x01 /* Set MSB on Write */ 2143db86aabSstevel #define LOMBUS_CMD_READ 0x01 /* Read command */ 2153db86aabSstevel #define LOMBUS_CMD_NOP 0x00 /* NOP command */ 2163db86aabSstevel 2173db86aabSstevel #define LOMBUS_STATUS_ASYNC 0x04 /* Asynchronous event pending */ 2183db86aabSstevel #define LOMBUS_STATUS_ERR 0x02 /* Error in command processing */ 2193db86aabSstevel #define LOMBUS_STATUS_MSB 0x01 /* MSB of Value read */ 2203db86aabSstevel 2213db86aabSstevel #define LOMBUS_VREG_LO(x) ((x) & ((1 << 7) - 1)) 2223db86aabSstevel #define LOMBUS_VREG_HI(x) ((x) >> 7) 2233db86aabSstevel 2243db86aabSstevel #define LOMBUS_BUFSIZE 8 2253db86aabSstevel 2263db86aabSstevel 2273db86aabSstevel /* 2283db86aabSstevel * Time periods, in nanoseconds 2293db86aabSstevel * 2303db86aabSstevel * Note that LOMBUS_ONE_SEC and some other time 2313db86aabSstevel * periods are defined in <sys/lombus.h> 2323db86aabSstevel */ 2333db86aabSstevel #define LOMBUS_CMD_POLL (LOMBUS_ONE_SEC/20) 2343db86aabSstevel #define LOMBUS_CTS_POLL (LOMBUS_ONE_SEC/20) 2353db86aabSstevel #define LOMBUS_CTS_TIMEOUT (LOMBUS_ONE_SEC*2) 2363db86aabSstevel 2373db86aabSstevel 2383db86aabSstevel /* 2393db86aabSstevel * Local datatypes 2403db86aabSstevel */ 2413db86aabSstevel enum lombus_cmdstate { 2423db86aabSstevel LOMBUS_CMDSTATE_IDLE, 2433db86aabSstevel LOMBUS_CMDSTATE_BUSY, 2443db86aabSstevel LOMBUS_CMDSTATE_WAITING, 2453db86aabSstevel LOMBUS_CMDSTATE_READY, 2463db86aabSstevel LOMBUS_CMDSTATE_ERROR 2473db86aabSstevel }; 2483db86aabSstevel 2493db86aabSstevel 2503db86aabSstevel /* 2513db86aabSstevel * This driver's soft-state structure 2523db86aabSstevel */ 2533db86aabSstevel 2543db86aabSstevel struct lombus_state { 2553db86aabSstevel /* 2563db86aabSstevel * Configuration data, set during attach 2573db86aabSstevel */ 2583db86aabSstevel dev_info_t *dip; 2593db86aabSstevel major_t majornum; 2603db86aabSstevel int instance; 2613db86aabSstevel 2623db86aabSstevel ddi_acc_handle_t sio_handle; 2633db86aabSstevel uint8_t *sio_regs; 2643db86aabSstevel ddi_softintr_t softid; 265dd4eeefdSeota ddi_periodic_t cycid; /* periodical callback */ 2663db86aabSstevel 2673db86aabSstevel /* 2683db86aabSstevel * Parameters derived from .conf properties 2693db86aabSstevel */ 2703db86aabSstevel boolean_t allow_echo; 2713db86aabSstevel int baud; 2723db86aabSstevel uint32_t debug; 2733db86aabSstevel boolean_t fake_cts; 2743db86aabSstevel 2753db86aabSstevel /* 2763db86aabSstevel * Hardware mutex (initialised using <hw_iblk>), 2773db86aabSstevel * used to prevent retriggering the softint while 2783db86aabSstevel * it's still fetching data out of the chip FIFO. 2793db86aabSstevel */ 2803db86aabSstevel kmutex_t hw_mutex[1]; 2813db86aabSstevel ddi_iblock_cookie_t hw_iblk; 2823db86aabSstevel 2833db86aabSstevel /* 2843db86aabSstevel * Data protected by the hardware mutex: the watchdog-patting 2853db86aabSstevel * protocol data (since the dog can be patted from a high-level 2863db86aabSstevel * cyclic), and the interrupt-enabled flag. 2873db86aabSstevel */ 2883db86aabSstevel hrtime_t hw_last_pat; 2893db86aabSstevel boolean_t hw_int_enabled; 2903db86aabSstevel 2913db86aabSstevel /* 2923db86aabSstevel * Flag to indicate that we've incurred a hardware fault on 2933db86aabSstevel * accesses to the SIO; once this is set, we fake all further 2943db86aabSstevel * accesses in order not to provoke additional bus errors. 2953db86aabSstevel */ 2963db86aabSstevel boolean_t sio_fault; 2973db86aabSstevel 2983db86aabSstevel /* 2993db86aabSstevel * Serial protocol state data, protected by lo_mutex 3003db86aabSstevel * (which is initialised using <lo_iblk>) 3013db86aabSstevel */ 3023db86aabSstevel kmutex_t lo_mutex[1]; 3033db86aabSstevel ddi_iblock_cookie_t lo_iblk; 3043db86aabSstevel kcondvar_t lo_cv[1]; 3053db86aabSstevel 3063db86aabSstevel volatile enum lombus_cmdstate cmdstate; 3073db86aabSstevel clock_t deadline; 3083db86aabSstevel uint8_t cmdbuf[LOMBUS_BUFSIZE]; 3093db86aabSstevel uint8_t reply[LOMBUS_BUFSIZE]; 3103db86aabSstevel uint8_t async; 3113db86aabSstevel uint8_t index; 3123db86aabSstevel uint8_t result; 3133db86aabSstevel uint8_t sequence; 3143db86aabSstevel uint32_t error; 3153db86aabSstevel }; 3163db86aabSstevel 3173db86aabSstevel /* 3183db86aabSstevel * The auxiliary structure attached to each child 3193db86aabSstevel * (the child's parent-private-data points to this). 3203db86aabSstevel */ 3213db86aabSstevel struct lombus_child_info { 3223db86aabSstevel lombus_regspec_t *rsp; 3233db86aabSstevel int nregs; 3243db86aabSstevel }; 3253db86aabSstevel 3263db86aabSstevel 3273db86aabSstevel /* 3283db86aabSstevel * Local data 3293db86aabSstevel */ 3303db86aabSstevel 3313db86aabSstevel static void *lombus_statep; 3323db86aabSstevel 3333db86aabSstevel static major_t lombus_major = NOMAJOR; 3343db86aabSstevel 3353db86aabSstevel static ddi_device_acc_attr_t lombus_dev_acc_attr[1] = 3363db86aabSstevel { 3373db86aabSstevel DDI_DEVICE_ATTR_V0, 3383db86aabSstevel DDI_STRUCTURE_LE_ACC, 3393db86aabSstevel DDI_STRICTORDER_ACC 3403db86aabSstevel }; 3413db86aabSstevel 3423db86aabSstevel 3433db86aabSstevel /* 3443db86aabSstevel * General utility routines ... 3453db86aabSstevel */ 3463db86aabSstevel 3473db86aabSstevel static void 3483db86aabSstevel lombus_trace(struct lombus_state *ssp, char code, const char *caller, 3493db86aabSstevel const char *fmt, ...) 3503db86aabSstevel { 3513db86aabSstevel char buf[256]; 3523db86aabSstevel char *p; 3533db86aabSstevel va_list va; 3543db86aabSstevel 3553db86aabSstevel if (ssp->debug & (1 << (code-'@'))) { 3563db86aabSstevel p = buf; 357*07d06da5SSurya Prakki (void) snprintf(p, sizeof (buf) - (p - buf), 3583db86aabSstevel "%s/%s: ", MYNAME, caller); 3593db86aabSstevel p += strlen(p); 3603db86aabSstevel 3613db86aabSstevel va_start(va, fmt); 362*07d06da5SSurya Prakki (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va); 3633db86aabSstevel va_end(va); 3643db86aabSstevel 3653db86aabSstevel buf[sizeof (buf) - 1] = '\0'; 366*07d06da5SSurya Prakki (void) strlog(ssp->majornum, ssp->instance, code, SL_TRACE, 367*07d06da5SSurya Prakki buf); 3683db86aabSstevel } 3693db86aabSstevel } 3703db86aabSstevel 3713db86aabSstevel static struct lombus_state * 3723db86aabSstevel lombus_getstate(dev_info_t *dip, int instance, const char *caller) 3733db86aabSstevel { 3743db86aabSstevel struct lombus_state *ssp = NULL; 3753db86aabSstevel dev_info_t *sdip = NULL; 3763db86aabSstevel major_t dmaj = NOMAJOR; 3773db86aabSstevel 3783db86aabSstevel if (dip != NULL) { 3793db86aabSstevel /* 3803db86aabSstevel * Use the instance number from the <dip>; also, 3813db86aabSstevel * check that it really corresponds to this driver 3823db86aabSstevel */ 3833db86aabSstevel instance = ddi_get_instance(dip); 3843db86aabSstevel dmaj = ddi_driver_major(dip); 3853db86aabSstevel if (lombus_major == NOMAJOR && dmaj != NOMAJOR) 3863db86aabSstevel lombus_major = dmaj; 3873db86aabSstevel else if (dmaj != lombus_major) { 3883db86aabSstevel cmn_err(CE_WARN, 3893db86aabSstevel "%s: major number mismatch (%d vs. %d) in %s()," 3903db86aabSstevel "probably due to child misconfiguration", 3913db86aabSstevel MYNAME, lombus_major, dmaj, caller); 3923db86aabSstevel instance = -1; 3933db86aabSstevel } 3943db86aabSstevel } 3953db86aabSstevel 3963db86aabSstevel if (instance >= 0) 3973db86aabSstevel ssp = ddi_get_soft_state(lombus_statep, instance); 3983db86aabSstevel if (ssp != NULL) { 3993db86aabSstevel sdip = ssp->dip; 4003db86aabSstevel if (dip == NULL && sdip == NULL) 4013db86aabSstevel ssp = NULL; 4023db86aabSstevel else if (dip != NULL && sdip != NULL && sdip != dip) { 4033db86aabSstevel cmn_err(CE_WARN, 4043db86aabSstevel "%s: devinfo mismatch (%p vs. %p) in %s(), " 4053db86aabSstevel "probably due to child misconfiguration", 4063db86aabSstevel MYNAME, (void *)dip, (void *)sdip, caller); 4073db86aabSstevel ssp = NULL; 4083db86aabSstevel } 4093db86aabSstevel } 4103db86aabSstevel 4113db86aabSstevel return (ssp); 4123db86aabSstevel } 4133db86aabSstevel 4143db86aabSstevel /* 4153db86aabSstevel * Lowest-level serial I/O chip register read/write 4163db86aabSstevel */ 4173db86aabSstevel 4183db86aabSstevel static void 4193db86aabSstevel sio_put_reg(struct lombus_state *ssp, uint_t reg, uint8_t val) 4203db86aabSstevel { 4213db86aabSstevel lombus_trace(ssp, 'P', "sio_put_reg", "REG[%d] <- $%02x", reg, val); 4223db86aabSstevel 4233db86aabSstevel if (ssp->sio_handle != NULL && !ssp->sio_fault) { 4243db86aabSstevel /* 4253db86aabSstevel * The chip is mapped as "I/O" (e.g. with the side-effect 4263db86aabSstevel * bit on SPARC), therefore accesses are required to be 4273db86aabSstevel * in-order, with no value cacheing. However, there can 4283db86aabSstevel * still be write-behind buffering, so it is not guaranteed 4293db86aabSstevel * that a write actually reaches the chip in a given time. 4303db86aabSstevel * 4313db86aabSstevel * To force the access right through to the chip, we follow 4323db86aabSstevel * the write with another write (to the SCRATCH register) 4333db86aabSstevel * and a read (of the value just written to the SCRATCH 4343db86aabSstevel * register). The SCRATCH register is specifically provided 4353db86aabSstevel * for temporary data and has no effect on the SIO's own 4363db86aabSstevel * operation, making it ideal as a synchronising mechanism. 4373db86aabSstevel * 4383db86aabSstevel * If we didn't do this, it would be possible that the new 4393db86aabSstevel * value wouldn't reach the chip (and have the *intended* 4403db86aabSstevel * side-effects, such as disabling interrupts), for such a 4413db86aabSstevel * long time that the processor could execute a *lot* of 4423db86aabSstevel * instructions - including exiting the interrupt service 4433db86aabSstevel * routine and re-enabling interrupts. This effect was 4443db86aabSstevel * observed to lead to spurious (unclaimed) interrupts in 4453db86aabSstevel * some circumstances. 4463db86aabSstevel * 4473db86aabSstevel * This will no longer be needed once "synchronous" access 4483db86aabSstevel * handles are available (see PSARC/2000/269 and 2000/531). 4493db86aabSstevel */ 4503db86aabSstevel ddi_put8(ssp->sio_handle, ssp->sio_regs + reg, val); 4513db86aabSstevel ddi_put8(ssp->sio_handle, ssp->sio_regs + SIO_SCR, val); 4523db86aabSstevel membar_sync(); 4533db86aabSstevel (void) ddi_get8(ssp->sio_handle, ssp->sio_regs + SIO_SCR); 4543db86aabSstevel } 4553db86aabSstevel } 4563db86aabSstevel 4573db86aabSstevel static uint8_t 4583db86aabSstevel sio_get_reg(struct lombus_state *ssp, uint_t reg) 4593db86aabSstevel { 4603db86aabSstevel uint8_t val; 4613db86aabSstevel 4623db86aabSstevel if (ssp->sio_handle && !ssp->sio_fault) 4633db86aabSstevel val = ddi_get8(ssp->sio_handle, ssp->sio_regs + reg); 4643db86aabSstevel else 4653db86aabSstevel val = DUMMY_VALUE; 4663db86aabSstevel 4673db86aabSstevel lombus_trace(ssp, 'G', "sio_get_reg", "$%02x <- REG[%d]", val, reg); 4683db86aabSstevel 4693db86aabSstevel return (val); 4703db86aabSstevel } 4713db86aabSstevel 4723db86aabSstevel static void 4733db86aabSstevel sio_check_fault_status(struct lombus_state *ssp) 4743db86aabSstevel { 4753db86aabSstevel ssp->sio_fault = ddi_check_acc_handle(ssp->sio_handle) != DDI_SUCCESS; 4763db86aabSstevel } 4773db86aabSstevel 4783db86aabSstevel static boolean_t 4793db86aabSstevel sio_faulty(struct lombus_state *ssp) 4803db86aabSstevel { 4813db86aabSstevel if (!ssp->sio_fault) 4823db86aabSstevel sio_check_fault_status(ssp); 4833db86aabSstevel return (ssp->sio_fault); 4843db86aabSstevel } 4853db86aabSstevel 4863db86aabSstevel 4873db86aabSstevel /* 4883db86aabSstevel * Check for data ready. 4893db86aabSstevel */ 4903db86aabSstevel static boolean_t 4913db86aabSstevel sio_data_ready(struct lombus_state *ssp) 4923db86aabSstevel { 4933db86aabSstevel uint8_t status; 4943db86aabSstevel 4953db86aabSstevel /* 4963db86aabSstevel * Data is available if the RXDA bit in the LSR is nonzero 4973db86aabSstevel * (if reading it didn't incur a fault). 4983db86aabSstevel */ 4993db86aabSstevel status = sio_get_reg(ssp, SIO_LSR); 5003db86aabSstevel return ((status & SIO_LSR_RXDA) != 0 && !sio_faulty(ssp)); 5013db86aabSstevel } 5023db86aabSstevel 5033db86aabSstevel /* 5043db86aabSstevel * Check for LOM ready 5053db86aabSstevel */ 5063db86aabSstevel static boolean_t 5073db86aabSstevel sio_lom_ready(struct lombus_state *ssp) 5083db86aabSstevel { 5093db86aabSstevel uint8_t status; 5103db86aabSstevel boolean_t rslt; 5113db86aabSstevel 5123db86aabSstevel /* 5133db86aabSstevel * The LOM is ready if the CTS bit in the MSR is 1, meaning 5143db86aabSstevel * that the /CTS signal is being asserted (driven LOW) - 5153db86aabSstevel * unless we incurred a fault in trying to read the MSR! 5163db86aabSstevel * 5173db86aabSstevel * For debugging, we force the result to TRUE if the FAKE flag is set 5183db86aabSstevel */ 5193db86aabSstevel status = sio_get_reg(ssp, SIO_MSR); 5203db86aabSstevel rslt = (status & SIO_MSR_CTS) != 0 && !sio_faulty(ssp); 5213db86aabSstevel 5223db86aabSstevel lombus_trace(ssp, 'R', "sio_lom_ready", "S $%02x R %d F %d", 5233db86aabSstevel status, rslt, ssp->fake_cts); 5243db86aabSstevel 5253db86aabSstevel return (rslt || ssp->fake_cts); 5263db86aabSstevel } 5273db86aabSstevel 5283db86aabSstevel #if 0 5293db86aabSstevel /* 5303db86aabSstevel * Check for interrupt pending 5313db86aabSstevel */ 5323db86aabSstevel static boolean_t 5333db86aabSstevel sio_irq_pending(struct lombus_state *ssp) 5343db86aabSstevel { 5353db86aabSstevel uint8_t status; 5363db86aabSstevel boolean_t rslt; 5373db86aabSstevel 5383db86aabSstevel /* 5393db86aabSstevel * An interrupt is pending if the IPF bit in the EIR is 0, 5403db86aabSstevel * assuming we didn't incur a fault in trying to ready it. 5413db86aabSstevel * 5423db86aabSstevel * Note: we expect that every time we read this register 5433db86aabSstevel * (which is only done from the interrupt service routine), 5443db86aabSstevel * we will see $11001100 (RX FIFO timeout interrupt pending). 5453db86aabSstevel */ 5463db86aabSstevel status = sio_get_reg(ssp, SIO_EIR); 5473db86aabSstevel 5483db86aabSstevel rslt = (status & SIO_EIR_IPF) == 0 && !sio_faulty(ssp); 5493db86aabSstevel lombus_trace(ssp, 'I', "sio_irq_pending", "S $%02x R %d", 5503db86aabSstevel status, rslt); 5513db86aabSstevel 5523db86aabSstevel /* 5533db86aabSstevel * To investigate whether we're getting any abnormal interrupts 5543db86aabSstevel * this code checks that the status value is as expected, and that 5553db86aabSstevel * chip-level interrupts are supposed to be enabled at this time. 5563db86aabSstevel * This will cause a PANIC (on a driver compiled with DEBUG) if 5573db86aabSstevel * all is not as expected ... 5583db86aabSstevel */ 5593db86aabSstevel ASSERT(status == 0xCC); 5603db86aabSstevel ASSERT(ssp->hw_int_enabled); 5613db86aabSstevel 5623db86aabSstevel return (rslt); 5633db86aabSstevel } 5643db86aabSstevel #endif /* 0 */ 5653db86aabSstevel 5663db86aabSstevel /* 5673db86aabSstevel * Enable/disable interrupts 5683db86aabSstevel */ 5693db86aabSstevel static void 5703db86aabSstevel lombus_set_irq(struct lombus_state *ssp, boolean_t newstate) 5713db86aabSstevel { 5723db86aabSstevel uint8_t val; 5733db86aabSstevel 5743db86aabSstevel val = newstate ? SIO_IER_RXHDL_IE : 0; 5753db86aabSstevel sio_put_reg(ssp, SIO_IER, SIO_IER_STD | val); 5763db86aabSstevel ssp->hw_int_enabled = newstate; 5773db86aabSstevel } 5783db86aabSstevel 5793db86aabSstevel /* 5803db86aabSstevel * Assert/deassert RTS 5813db86aabSstevel */ 5823db86aabSstevel static void 5833db86aabSstevel lombus_toggle_rts(struct lombus_state *ssp) 5843db86aabSstevel { 5853db86aabSstevel uint8_t val; 5863db86aabSstevel 5873db86aabSstevel val = sio_get_reg(ssp, SIO_MCR); 5883db86aabSstevel val &= SIO_MCR_RTS; 5893db86aabSstevel val ^= SIO_MCR_RTS; 5903db86aabSstevel val |= SIO_MCR_STD; 5913db86aabSstevel sio_put_reg(ssp, SIO_MCR, val); 5923db86aabSstevel } 5933db86aabSstevel 5943db86aabSstevel 5953db86aabSstevel /* 5963db86aabSstevel * High-level interrupt handler: 5973db86aabSstevel * Checks whether initialisation is complete (to avoid a race 5983db86aabSstevel * with mutex_init()), and whether chip interrupts are enabled. 5993db86aabSstevel * If not, the interrupt's not for us, so just return UNCLAIMED. 6003db86aabSstevel * Otherwise, disable the interrupt, trigger a softint, and return 6013db86aabSstevel * CLAIMED. The softint handler will then do all the real work. 6023db86aabSstevel * 6033db86aabSstevel * NOTE: the chip interrupt capability is only re-enabled once the 6043db86aabSstevel * receive code has run, but that can be called from a poll loop 6053db86aabSstevel * or cyclic callback as well as from the softint. So it's *not* 6063db86aabSstevel * guaranteed that there really is a chip interrupt pending here, 6073db86aabSstevel * 'cos the work may already have been done and the reason for the 6083db86aabSstevel * interrupt gone away before we get here. 6093db86aabSstevel * 6103db86aabSstevel * OTOH, if we come through here twice without the receive code 6113db86aabSstevel * having run in between, that's definitely wrong. In such an 6123db86aabSstevel * event, we would notice that chip interrupts haven't yet been 6133db86aabSstevel * re-enabled and return UNCLAIMED, allowing the system's jabber 6143db86aabSstevel * protect code (if any) to do its job. 6153db86aabSstevel */ 6163db86aabSstevel static uint_t 6173db86aabSstevel lombus_hi_intr(caddr_t arg) 6183db86aabSstevel { 6193db86aabSstevel struct lombus_state *ssp = (void *)arg; 6203db86aabSstevel uint_t claim; 6213db86aabSstevel 6223db86aabSstevel claim = DDI_INTR_UNCLAIMED; 623dd4eeefdSeota if (ssp->cycid != NULL) { 6243db86aabSstevel mutex_enter(ssp->hw_mutex); 6253db86aabSstevel if (ssp->hw_int_enabled) { 6263db86aabSstevel lombus_set_irq(ssp, B_FALSE); 6273db86aabSstevel ddi_trigger_softintr(ssp->softid); 6283db86aabSstevel claim = DDI_INTR_CLAIMED; 6293db86aabSstevel } 6303db86aabSstevel mutex_exit(ssp->hw_mutex); 6313db86aabSstevel } 6323db86aabSstevel 6333db86aabSstevel return (claim); 6343db86aabSstevel } 6353db86aabSstevel 6363db86aabSstevel /* 6373db86aabSstevel * Packet receive handler 6383db86aabSstevel * 6393db86aabSstevel * This routine should be called from the low-level softint, or the 6403db86aabSstevel * cyclic callback, or lombus_cmd() (for polled operation), with the 6413db86aabSstevel * low-level mutex already held. 6423db86aabSstevel */ 6433db86aabSstevel static void 6443db86aabSstevel lombus_receive(struct lombus_state *ssp) 6453db86aabSstevel { 6463db86aabSstevel boolean_t ready = B_FALSE; 6473db86aabSstevel uint8_t data = 0; 6483db86aabSstevel uint8_t rcvd = 0; 6493db86aabSstevel uint8_t tmp; 6503db86aabSstevel 6513db86aabSstevel lombus_trace(ssp, 'S', "lombus_receive", 6523db86aabSstevel "state %d; error $%x", 6533db86aabSstevel ssp->cmdstate, ssp->error); 6543db86aabSstevel 6553db86aabSstevel /* 6563db86aabSstevel * Check for access faults before starting the receive 6573db86aabSstevel * loop (we don't want to cause bus errors or suchlike 6583db86aabSstevel * unpleasantness in the event that the SIO has died). 6593db86aabSstevel */ 6603db86aabSstevel if (!sio_faulty(ssp)) { 6613db86aabSstevel /* 6623db86aabSstevel * Read bytes from the FIFO until they're all gone, 6633db86aabSstevel * or we find the 'END OF PACKET' set on one, or 6643db86aabSstevel * our buffer overflows (which must be an error) 6653db86aabSstevel */ 6663db86aabSstevel mutex_enter(ssp->hw_mutex); 6673db86aabSstevel while (sio_data_ready(ssp)) { 6683db86aabSstevel data = sio_get_reg(ssp, SIO_RXD); 6693db86aabSstevel ssp->reply[rcvd = ssp->index] = data; 6703db86aabSstevel if (++rcvd >= LOMBUS_BUFSIZE) 6713db86aabSstevel break; 6723db86aabSstevel ssp->index = rcvd; 6733db86aabSstevel if (data & LOMBUS_LAST) 6743db86aabSstevel break; 6753db86aabSstevel } 6763db86aabSstevel lombus_set_irq(ssp, B_TRUE); 6773db86aabSstevel mutex_exit(ssp->hw_mutex); 6783db86aabSstevel } 6793db86aabSstevel 6803db86aabSstevel lombus_trace(ssp, 'S', "lombus_receive", 6813db86aabSstevel "rcvd %d: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x", 6823db86aabSstevel rcvd, 6833db86aabSstevel ssp->reply[0], ssp->reply[1], 6843db86aabSstevel ssp->reply[2], ssp->reply[3], 6853db86aabSstevel ssp->reply[4], ssp->reply[5], 6863db86aabSstevel ssp->reply[6], ssp->reply[7]); 6873db86aabSstevel 6883db86aabSstevel if (ssp->cmdstate != LOMBUS_CMDSTATE_WAITING) { 6893db86aabSstevel /* 6903db86aabSstevel * We're not expecting any data in this state, so if 6913db86aabSstevel * we DID receive any data, we just throw it away by 6923db86aabSstevel * resetting the buffer index to 0. 6933db86aabSstevel */ 6943db86aabSstevel ssp->index = 0; 6953db86aabSstevel } else if (rcvd == 0) { 6963db86aabSstevel /* 6973db86aabSstevel * No bytes received this time through (though there 6983db86aabSstevel * might be a partial packet sitting in the buffer). 6993db86aabSstevel * If it seems the LOM is taking too long to respond, 7003db86aabSstevel * we'll assume it's died and return an error. 7013db86aabSstevel */ 7023db86aabSstevel if (ddi_get_lbolt() > ssp->deadline) { 7033db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 7043db86aabSstevel ssp->error = LOMBUS_ERR_TIMEOUT; 7053db86aabSstevel ready = B_TRUE; 7063db86aabSstevel } 7073db86aabSstevel } else if (rcvd >= LOMBUS_BUFSIZE) { 7083db86aabSstevel /* 7093db86aabSstevel * Buffer overflow; discard the data & treat as an error 7103db86aabSstevel * (even if the last byte read did claim to terminate a 7113db86aabSstevel * packet, it can't be a valid one 'cos it's too long!) 7123db86aabSstevel */ 7133db86aabSstevel ssp->index = 0; 7143db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 7153db86aabSstevel ssp->error = LOMBUS_ERR_OFLOW; 7163db86aabSstevel ready = B_TRUE; 7173db86aabSstevel } else if ((data & LOMBUS_LAST) == 0) { 7183db86aabSstevel /* 7193db86aabSstevel * Packet not yet complete; leave the partial packet in 7203db86aabSstevel * the buffer for later ... 7213db86aabSstevel */ 7223db86aabSstevel _NOTE(EMPTY) 7233db86aabSstevel ; 7243db86aabSstevel } else if ((data & LOMBUS_MASK) != LOMBUS_STATUS) { 7253db86aabSstevel /* 7263db86aabSstevel * Invalid "status" byte - maybe an echo of the command? 7273db86aabSstevel * 7283db86aabSstevel * As a debugging feature, we allow for this, assuming 7293db86aabSstevel * that if the LOM has echoed the command byte, it has 7303db86aabSstevel * also echoed all the parameter bytes before starting 7313db86aabSstevel * command processing. So, we dump out the buffer and 7323db86aabSstevel * then clear it, so we can go back to looking for the 7333db86aabSstevel * real reply. 7343db86aabSstevel * 7353db86aabSstevel * Otherwise, we just drop the data & flag an error. 7363db86aabSstevel */ 7373db86aabSstevel if (ssp->allow_echo) { 7383db86aabSstevel lombus_trace(ssp, 'E', "lombus_receive", 7393db86aabSstevel "echo $%02x $%02x $%02x $%02x " 7403db86aabSstevel "$%02x $%02x $%02x $%02x", 7413db86aabSstevel ssp->reply[0], ssp->reply[1], 7423db86aabSstevel ssp->reply[2], ssp->reply[3], 7433db86aabSstevel ssp->reply[4], ssp->reply[5], 7443db86aabSstevel ssp->reply[6], ssp->reply[7]); 7453db86aabSstevel ssp->index = 0; 7463db86aabSstevel } else { 7473db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 7483db86aabSstevel ssp->error = LOMBUS_ERR_BADSTATUS; 7493db86aabSstevel ready = B_TRUE; 7503db86aabSstevel } 7513db86aabSstevel } else if ((data & LOMBUS_SEQ) != ssp->sequence) { 7523db86aabSstevel /* 7533db86aabSstevel * Wrong sequence number! Flag this as an error 7543db86aabSstevel */ 7553db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 7563db86aabSstevel ssp->error = LOMBUS_ERR_SEQUENCE; 7573db86aabSstevel ready = B_TRUE; 7583db86aabSstevel } else { 7593db86aabSstevel /* 7603db86aabSstevel * Finally, we know that's it's a valid reply to our 7613db86aabSstevel * last command. Update the ASYNC status, derive the 7623db86aabSstevel * reply parameter (if any), and check the ERROR bit 7633db86aabSstevel * to find out what the parameter means. 7643db86aabSstevel * 7653db86aabSstevel * Note that not all the values read/assigned here 7663db86aabSstevel * are meaningful, but it doesn't matter; the waiting 7673db86aabSstevel * thread will know which one(s) it should check. 7683db86aabSstevel */ 7693db86aabSstevel ssp->async = (data & LOMBUS_STATUS_ASYNC) ? 1 : 0; 7703db86aabSstevel tmp = ((data & LOMBUS_STATUS_MSB) ? 0x80 : 0) | ssp->reply[0]; 7713db86aabSstevel if (data & LOMBUS_STATUS_ERR) { 7723db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_ERROR; 7733db86aabSstevel ssp->error = tmp; 7743db86aabSstevel } else { 7753db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_READY; 7763db86aabSstevel ssp->result = tmp; 7773db86aabSstevel } 7783db86aabSstevel ready = B_TRUE; 7793db86aabSstevel } 7803db86aabSstevel 7813db86aabSstevel lombus_trace(ssp, 'T', "lombus_receive", 7823db86aabSstevel "rcvd %d; last $%02x; state %d; error $%x; ready %d", 7833db86aabSstevel rcvd, data, ssp->cmdstate, ssp->error, ready); 7843db86aabSstevel 7853db86aabSstevel if (ready) 7863db86aabSstevel cv_broadcast(ssp->lo_cv); 7873db86aabSstevel } 7883db86aabSstevel 7893db86aabSstevel /* 7903db86aabSstevel * Low-level softint handler 7913db86aabSstevel * 7923db86aabSstevel * This routine should be triggered whenever there's a byte to be read 7933db86aabSstevel */ 7943db86aabSstevel static uint_t 7953db86aabSstevel lombus_softint(caddr_t arg) 7963db86aabSstevel { 7973db86aabSstevel struct lombus_state *ssp = (void *)arg; 7983db86aabSstevel 7993db86aabSstevel mutex_enter(ssp->lo_mutex); 8003db86aabSstevel lombus_receive(ssp); 8013db86aabSstevel mutex_exit(ssp->lo_mutex); 8023db86aabSstevel 8033db86aabSstevel return (DDI_INTR_CLAIMED); 8043db86aabSstevel } 8053db86aabSstevel 8063db86aabSstevel /* 8073db86aabSstevel * Cyclic handler: just calls the receive routine, in case interrupts 8083db86aabSstevel * are not being delivered and in order to handle command timeout 8093db86aabSstevel */ 8103db86aabSstevel static void 8113db86aabSstevel lombus_cyclic(void *arg) 8123db86aabSstevel { 8133db86aabSstevel struct lombus_state *ssp = (void *)arg; 8143db86aabSstevel 8153db86aabSstevel mutex_enter(ssp->lo_mutex); 8163db86aabSstevel lombus_receive(ssp); 8173db86aabSstevel mutex_exit(ssp->lo_mutex); 8183db86aabSstevel } 8193db86aabSstevel 8203db86aabSstevel 8213db86aabSstevel /* 8223db86aabSstevel * Serial protocol 8233db86aabSstevel * 8243db86aabSstevel * This routine builds a command and sets it in progress. 8253db86aabSstevel */ 8263db86aabSstevel static uint8_t 8273db86aabSstevel lombus_cmd(HANDLE_TYPE *hdlp, ptrdiff_t vreg, uint_t val, uint_t cmd) 8283db86aabSstevel { 8293db86aabSstevel struct lombus_state *ssp; 8303db86aabSstevel clock_t start; 8313db86aabSstevel uint8_t *p; 8323db86aabSstevel 8333db86aabSstevel /* 8343db86aabSstevel * First of all, wait for the interface to be available. 8353db86aabSstevel * 8363db86aabSstevel * NOTE: we blow through all the mutex/cv/state checking and 8373db86aabSstevel * preempt any command in progress if the system is panicking! 8383db86aabSstevel */ 8393db86aabSstevel ssp = HANDLE_PRIVATE(hdlp); 8403db86aabSstevel mutex_enter(ssp->lo_mutex); 8413db86aabSstevel while (ssp->cmdstate != LOMBUS_CMDSTATE_IDLE && !panicstr) 8423db86aabSstevel cv_wait(ssp->lo_cv, ssp->lo_mutex); 8433db86aabSstevel 8443db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_BUSY; 8453db86aabSstevel ssp->sequence = (ssp->sequence + LOMBUS_SEQ_LSB) & LOMBUS_SEQ; 8463db86aabSstevel 8473db86aabSstevel /* 8483db86aabSstevel * We have exclusive ownership, so assemble the command (backwards): 8493db86aabSstevel * 8503db86aabSstevel * [byte 0] Command: modified by XADDR and/or WMSB bits 8513db86aabSstevel * [Optional] Parameter: Value to write (low 7 bits) 8523db86aabSstevel * [Optional] Parameter: Register number (high 7 bits) 8533db86aabSstevel * [Optional] Parameter: Register number (low 7 bits) 8543db86aabSstevel */ 8553db86aabSstevel p = &ssp->cmdbuf[0]; 8563db86aabSstevel *p++ = LOMBUS_CMD | ssp->sequence | cmd; 8573db86aabSstevel switch (cmd) { 8583db86aabSstevel case LOMBUS_CMD_WRITE: 8593db86aabSstevel *p++ = val & 0x7f; 8603db86aabSstevel if (val >= 0x80) 8613db86aabSstevel ssp->cmdbuf[0] |= LOMBUS_CMD_WMSB; 8623db86aabSstevel /*FALLTHRU*/ 8633db86aabSstevel case LOMBUS_CMD_READ: 8643db86aabSstevel if (LOMBUS_VREG_HI(vreg) != 0) { 8653db86aabSstevel *p++ = LOMBUS_VREG_HI(vreg); 8663db86aabSstevel ssp->cmdbuf[0] |= LOMBUS_CMD_XADDR; 8673db86aabSstevel } 8683db86aabSstevel *p++ = LOMBUS_VREG_LO(vreg); 8693db86aabSstevel /*FALLTHRU*/ 8703db86aabSstevel case LOMBUS_CMD_NOP: 8713db86aabSstevel break; 8723db86aabSstevel } 8733db86aabSstevel 8743db86aabSstevel /* 8753db86aabSstevel * Check and update the SIO h/w fault status before accessing 8763db86aabSstevel * the chip registers. If there's a (new or previous) fault, 8773db86aabSstevel * we'll run through the protocol but won't really touch the 8783db86aabSstevel * hardware and all commands will timeout. If a previously 8793db86aabSstevel * discovered fault has now gone away (!), then we can (try to) 8803db86aabSstevel * proceed with the new command (probably a probe). 8813db86aabSstevel */ 8823db86aabSstevel sio_check_fault_status(ssp); 8833db86aabSstevel 8843db86aabSstevel /* 8853db86aabSstevel * Wait up to LOMBUS_CTS_TIMEOUT (2 seconds) for the LOM to tell 8863db86aabSstevel * us that it's ready for the next command. If it doesn't, though, 8873db86aabSstevel * we'll send it anyway, on the basis that the CTS signal might be 8883db86aabSstevel * open- or short-circuited (or the LOM firmware forgot to set it, 8893db86aabSstevel * or the LOM just got reset, or whatever ...) 8903db86aabSstevel */ 8913db86aabSstevel start = ddi_get_lbolt(); 8923db86aabSstevel ssp->deadline = start + drv_usectohz(LOMBUS_CTS_TIMEOUT/1000); 8933db86aabSstevel while (!sio_lom_ready(ssp)) { 894d3d50737SRafael Vanoni if (ddi_get_lbolt() > ssp->deadline) 8953db86aabSstevel break; 896d3d50737SRafael Vanoni 897*07d06da5SSurya Prakki (void) cv_reltimedwait(ssp->lo_cv, ssp->lo_mutex, 898d3d50737SRafael Vanoni drv_usectohz(LOMBUS_CTS_POLL/1000), TR_CLOCK_TICK); 8993db86aabSstevel } 9003db86aabSstevel 9013db86aabSstevel /* 9023db86aabSstevel * Either the LOM is ready, or we timed out waiting for CTS. 9033db86aabSstevel * In either case, we're going to send the command now by 9043db86aabSstevel * stuffing the packet into the Tx FIFO, reversing it as we go. 9053db86aabSstevel * We call lombus_receive() first to ensure there isn't any 9063db86aabSstevel * garbage left in the Rx FIFO from an earlier command that 9073db86aabSstevel * timed out (or was pre-empted by a PANIC!). This also makes 9083db86aabSstevel * sure that SIO interrupts are enabled so we'll see the reply 9093db86aabSstevel * more quickly (the poll loop below will still work even if 9103db86aabSstevel * interrupts aren't enabled, but it will take longer). 9113db86aabSstevel */ 9123db86aabSstevel lombus_receive(ssp); 9133db86aabSstevel mutex_enter(ssp->hw_mutex); 9143db86aabSstevel while (p > ssp->cmdbuf) 9153db86aabSstevel sio_put_reg(ssp, SIO_TXD, *--p); 9163db86aabSstevel mutex_exit(ssp->hw_mutex); 9173db86aabSstevel 9183db86aabSstevel /* 9193db86aabSstevel * Prepare for the reply (to be processed by the interrupt/cyclic 9203db86aabSstevel * handler and/or polling loop below), then wait for a response 9213db86aabSstevel * or timeout. 9223db86aabSstevel */ 9233db86aabSstevel start = ddi_get_lbolt(); 9243db86aabSstevel ssp->deadline = start + drv_usectohz(LOMBUS_CMD_TIMEOUT/1000); 9253db86aabSstevel ssp->error = 0; 9263db86aabSstevel ssp->index = 0; 9273db86aabSstevel ssp->result = DUMMY_VALUE; 9283db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_WAITING; 9293db86aabSstevel while (ssp->cmdstate == LOMBUS_CMDSTATE_WAITING) { 930d3d50737SRafael Vanoni if (cv_reltimedwait(ssp->lo_cv, ssp->lo_mutex, 931d3d50737SRafael Vanoni drv_usectohz(LOMBUS_CMD_POLL/1000), TR_CLOCK_TICK) == -1) 9323db86aabSstevel lombus_receive(ssp); 9333db86aabSstevel } 9343db86aabSstevel 9353db86aabSstevel /* 9363db86aabSstevel * The return value may not be meaningful but retrieve it anyway 9373db86aabSstevel */ 9383db86aabSstevel val = ssp->result; 9393db86aabSstevel if (sio_faulty(ssp)) { 9403db86aabSstevel val = DUMMY_VALUE; 9413db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_SIOHW; 9423db86aabSstevel } else if (ssp->cmdstate != LOMBUS_CMDSTATE_READY) { 9433db86aabSstevel /* 9443db86aabSstevel * Some problem here ... transfer the error code from 9453db86aabSstevel * the per-instance state to the per-handle fault flag. 9463db86aabSstevel * The error code shouldn't be zero! 9473db86aabSstevel */ 9483db86aabSstevel if (ssp->error != 0) 9493db86aabSstevel HANDLE_FAULT(hdlp) = ssp->error; 9503db86aabSstevel else 9513db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_BADERRCODE; 9523db86aabSstevel } 9533db86aabSstevel 9543db86aabSstevel /* 9553db86aabSstevel * All done now! 9563db86aabSstevel */ 9573db86aabSstevel ssp->index = 0; 9583db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_IDLE; 9593db86aabSstevel cv_broadcast(ssp->lo_cv); 9603db86aabSstevel mutex_exit(ssp->lo_mutex); 9613db86aabSstevel 9623db86aabSstevel return (val); 9633db86aabSstevel } 9643db86aabSstevel 9653db86aabSstevel 9663db86aabSstevel /* 9673db86aabSstevel * Space 0 - LOM virtual register access 9683db86aabSstevel * Only 8-bit accesses are supported. 9693db86aabSstevel */ 9703db86aabSstevel static uint8_t 9713db86aabSstevel lombus_vreg_get8(HANDLE_TYPE *hdlp, uint8_t *addr) 9723db86aabSstevel { 9733db86aabSstevel ptrdiff_t offset; 9743db86aabSstevel 9753db86aabSstevel /* 9763db86aabSstevel * Check the offset that the caller has added to the base address 9773db86aabSstevel * against the length of the mapping originally requested. 9783db86aabSstevel */ 9793db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 9803db86aabSstevel if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 9813db86aabSstevel /* 9823db86aabSstevel * Invalid access - flag a fault and return a dummy value 9833db86aabSstevel */ 9843db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 9853db86aabSstevel return (DUMMY_VALUE); 9863db86aabSstevel } 9873db86aabSstevel 9883db86aabSstevel /* 9893db86aabSstevel * Derive the virtual register number and run the command 9903db86aabSstevel */ 9913db86aabSstevel return (lombus_cmd(hdlp, ADDR_TO_VREG(addr), 0, LOMBUS_CMD_READ)); 9923db86aabSstevel } 9933db86aabSstevel 9943db86aabSstevel static void 9953db86aabSstevel lombus_vreg_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val) 9963db86aabSstevel { 9973db86aabSstevel ptrdiff_t offset; 9983db86aabSstevel 9993db86aabSstevel /* 10003db86aabSstevel * Check the offset that the caller has added to the base address 10013db86aabSstevel * against the length of the mapping originally requested. 10023db86aabSstevel */ 10033db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 10043db86aabSstevel if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 10053db86aabSstevel /* 10063db86aabSstevel * Invalid access - flag a fault and return 10073db86aabSstevel */ 10083db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 10093db86aabSstevel return; 10103db86aabSstevel } 10113db86aabSstevel 10123db86aabSstevel /* 10133db86aabSstevel * Derive the virtual register number and run the command 10143db86aabSstevel */ 10153db86aabSstevel (void) lombus_cmd(hdlp, ADDR_TO_VREG(addr), val, LOMBUS_CMD_WRITE); 10163db86aabSstevel } 10173db86aabSstevel 10183db86aabSstevel static void 10193db86aabSstevel lombus_vreg_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 10203db86aabSstevel uint8_t *dev_addr, size_t repcount, uint_t flags) 10213db86aabSstevel { 10223db86aabSstevel size_t inc; 10233db86aabSstevel 10243db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 10253db86aabSstevel for (; repcount--; dev_addr += inc) 10263db86aabSstevel *host_addr++ = lombus_vreg_get8(hdlp, dev_addr); 10273db86aabSstevel } 10283db86aabSstevel 10293db86aabSstevel static void 10303db86aabSstevel lombus_vreg_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 10313db86aabSstevel uint8_t *dev_addr, size_t repcount, uint_t flags) 10323db86aabSstevel { 10333db86aabSstevel size_t inc; 10343db86aabSstevel 10353db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 10363db86aabSstevel for (; repcount--; dev_addr += inc) 10373db86aabSstevel lombus_vreg_put8(hdlp, dev_addr, *host_addr++); 10383db86aabSstevel } 10393db86aabSstevel 10403db86aabSstevel 10413db86aabSstevel /* 10423db86aabSstevel * Space 1 - LOM watchdog pat register access 10433db86aabSstevel * Only 8-bit accesses are supported. 10443db86aabSstevel * 10453db86aabSstevel * Reads have no effect and return 0. 10463db86aabSstevel * 10473db86aabSstevel * Writes pat the dog by toggling the RTS line iff enough time has 10483db86aabSstevel * elapsed since last time we toggled it. 10493db86aabSstevel * 10503db86aabSstevel * Multi-byte reads (using ddi_rep_get8(9F)) are a fairly inefficient 10513db86aabSstevel * way of zeroing the destination area ;-) and still won't pat the dog. 10523db86aabSstevel * 10533db86aabSstevel * Multi-byte writes (using ddi_rep_put8(9F)) will almost certainly 10543db86aabSstevel * only count as a single pat, no matter how many bytes the caller 10553db86aabSstevel * says to write, as the inter-pat time is VERY long compared with 10563db86aabSstevel * the time it will take to read the memory source area. 10573db86aabSstevel */ 10583db86aabSstevel 10593db86aabSstevel static uint8_t 10603db86aabSstevel lombus_pat_get8(HANDLE_TYPE *hdlp, uint8_t *addr) 10613db86aabSstevel { 10623db86aabSstevel ptrdiff_t offset; 10633db86aabSstevel 10643db86aabSstevel /* 10653db86aabSstevel * Check the offset that the caller has added to the base address 10663db86aabSstevel * against the length of the mapping originally requested. 10673db86aabSstevel */ 10683db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 10693db86aabSstevel if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 10703db86aabSstevel /* 10713db86aabSstevel * Invalid access - flag a fault and return a dummy value 10723db86aabSstevel */ 10733db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 10743db86aabSstevel return (DUMMY_VALUE); 10753db86aabSstevel } 10763db86aabSstevel 10773db86aabSstevel return (0); 10783db86aabSstevel } 10793db86aabSstevel 10803db86aabSstevel static void 10813db86aabSstevel lombus_pat_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val) 10823db86aabSstevel { 10833db86aabSstevel struct lombus_state *ssp; 10843db86aabSstevel ptrdiff_t offset; 10853db86aabSstevel hrtime_t now; 10863db86aabSstevel 10873db86aabSstevel _NOTE(ARGUNUSED(val)) 10883db86aabSstevel 10893db86aabSstevel /* 10903db86aabSstevel * Check the offset that the caller has added to the base address 10913db86aabSstevel * against the length of the mapping originally requested. 10923db86aabSstevel */ 10933db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 10943db86aabSstevel if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) { 10953db86aabSstevel /* 10963db86aabSstevel * Invalid access - flag a fault and return 10973db86aabSstevel */ 10983db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 10993db86aabSstevel return; 11003db86aabSstevel } 11013db86aabSstevel 11023db86aabSstevel ssp = HANDLE_PRIVATE(hdlp); 11033db86aabSstevel mutex_enter(ssp->hw_mutex); 11043db86aabSstevel now = gethrtime(); 11053db86aabSstevel if ((now - ssp->hw_last_pat) >= LOMBUS_MIN_PAT) { 11063db86aabSstevel lombus_toggle_rts(ssp); 11073db86aabSstevel ssp->hw_last_pat = now; 11083db86aabSstevel } 11093db86aabSstevel mutex_exit(ssp->hw_mutex); 11103db86aabSstevel } 11113db86aabSstevel 11123db86aabSstevel static void 11133db86aabSstevel lombus_pat_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 11143db86aabSstevel uint8_t *dev_addr, size_t repcount, uint_t flags) 11153db86aabSstevel { 11163db86aabSstevel size_t inc; 11173db86aabSstevel 11183db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 11193db86aabSstevel for (; repcount--; dev_addr += inc) 11203db86aabSstevel *host_addr++ = lombus_pat_get8(hdlp, dev_addr); 11213db86aabSstevel } 11223db86aabSstevel 11233db86aabSstevel static void 11243db86aabSstevel lombus_pat_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 11253db86aabSstevel uint8_t *dev_addr, size_t repcount, uint_t flags) 11263db86aabSstevel { 11273db86aabSstevel size_t inc; 11283db86aabSstevel 11293db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 11303db86aabSstevel for (; repcount--; dev_addr += inc) 11313db86aabSstevel lombus_pat_put8(hdlp, dev_addr, *host_addr++); 11323db86aabSstevel } 11333db86aabSstevel 11343db86aabSstevel 11353db86aabSstevel /* 11363db86aabSstevel * Space 2 - LOM async event flag register access 11373db86aabSstevel * Only 16-bit accesses are supported. 11383db86aabSstevel */ 11393db86aabSstevel static uint16_t 11403db86aabSstevel lombus_event_get16(HANDLE_TYPE *hdlp, uint16_t *addr) 11413db86aabSstevel { 11423db86aabSstevel struct lombus_state *ssp; 11433db86aabSstevel ptrdiff_t offset; 11443db86aabSstevel 11453db86aabSstevel /* 11463db86aabSstevel * Check the offset that the caller has added to the base address 11473db86aabSstevel * against the length of the mapping orignally requested. 11483db86aabSstevel */ 11493db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 11503db86aabSstevel if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) { 11513db86aabSstevel /* 11523db86aabSstevel * Invalid access - flag a fault and return a dummy value 11533db86aabSstevel */ 11543db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 11553db86aabSstevel return (DUMMY_VALUE); 11563db86aabSstevel } 11573db86aabSstevel 11583db86aabSstevel /* 11593db86aabSstevel * Return the value of the asynchronous-event-pending flag 11603db86aabSstevel * as passed back by the LOM at the end of the last command. 11613db86aabSstevel */ 11623db86aabSstevel ssp = HANDLE_PRIVATE(hdlp); 11633db86aabSstevel return (ssp->async); 11643db86aabSstevel } 11653db86aabSstevel 11663db86aabSstevel static void 11673db86aabSstevel lombus_event_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val) 11683db86aabSstevel { 11693db86aabSstevel ptrdiff_t offset; 11703db86aabSstevel 11713db86aabSstevel _NOTE(ARGUNUSED(val)) 11723db86aabSstevel 11733db86aabSstevel /* 11743db86aabSstevel * Check the offset that the caller has added to the base address 11753db86aabSstevel * against the length of the mapping originally requested. 11763db86aabSstevel */ 11773db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 11783db86aabSstevel if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) { 11793db86aabSstevel /* 11803db86aabSstevel * Invalid access - flag a fault and return 11813db86aabSstevel */ 11823db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM; 11833db86aabSstevel return; 11843db86aabSstevel } 11853db86aabSstevel 11863db86aabSstevel /* 11873db86aabSstevel * The user can't overwrite the asynchronous-event-pending flag! 11883db86aabSstevel */ 11893db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_RO; 11903db86aabSstevel } 11913db86aabSstevel 11923db86aabSstevel static void 11933db86aabSstevel lombus_event_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 11943db86aabSstevel uint16_t *dev_addr, size_t repcount, uint_t flags) 11953db86aabSstevel { 11963db86aabSstevel size_t inc; 11973db86aabSstevel 11983db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 11993db86aabSstevel for (; repcount--; dev_addr += inc) 12003db86aabSstevel *host_addr++ = lombus_event_get16(hdlp, dev_addr); 12013db86aabSstevel } 12023db86aabSstevel 12033db86aabSstevel static void 12043db86aabSstevel lombus_event_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 12053db86aabSstevel uint16_t *dev_addr, size_t repcount, uint_t flags) 12063db86aabSstevel { 12073db86aabSstevel size_t inc; 12083db86aabSstevel 12093db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 12103db86aabSstevel for (; repcount--; dev_addr += inc) 12113db86aabSstevel lombus_event_put16(hdlp, dev_addr, *host_addr++); 12123db86aabSstevel } 12133db86aabSstevel 12143db86aabSstevel 12153db86aabSstevel /* 12163db86aabSstevel * All spaces - access handle fault information 12173db86aabSstevel * Only 32-bit accesses are supported. 12183db86aabSstevel */ 12193db86aabSstevel static uint32_t 12203db86aabSstevel lombus_meta_get32(HANDLE_TYPE *hdlp, uint32_t *addr) 12213db86aabSstevel { 12223db86aabSstevel struct lombus_state *ssp; 12233db86aabSstevel ptrdiff_t offset; 12243db86aabSstevel 12253db86aabSstevel /* 12263db86aabSstevel * Derive the offset that the caller has added to the base 12273db86aabSstevel * address originally returned, and use it to determine 12283db86aabSstevel * which meta-register is to be accessed ... 12293db86aabSstevel */ 12303db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 12313db86aabSstevel switch (offset) { 12323db86aabSstevel case LOMBUS_FAULT_REG: 12333db86aabSstevel /* 12343db86aabSstevel * This meta-register provides a code for the most 12353db86aabSstevel * recent virtual register access fault, if any. 12363db86aabSstevel */ 12373db86aabSstevel return (HANDLE_FAULT(hdlp)); 12383db86aabSstevel 12393db86aabSstevel case LOMBUS_PROBE_REG: 12403db86aabSstevel /* 12413db86aabSstevel * Reading this meta-register clears any existing fault 12423db86aabSstevel * (at the virtual, not the hardware access layer), then 12433db86aabSstevel * runs a NOP command and returns the fault code from that. 12443db86aabSstevel */ 12453db86aabSstevel HANDLE_FAULT(hdlp) = 0; 1246*07d06da5SSurya Prakki (void) lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP); 12473db86aabSstevel return (HANDLE_FAULT(hdlp)); 12483db86aabSstevel 12493db86aabSstevel case LOMBUS_ASYNC_REG: 12503db86aabSstevel /* 12513db86aabSstevel * Obsolescent - but still supported for backwards 12523db86aabSstevel * compatibility. This is an alias for the newer 12533db86aabSstevel * LOMBUS_EVENT_REG, but doesn't require a separate 12543db86aabSstevel * "reg" entry and ddi_regs_map_setup() call. 12553db86aabSstevel * 12563db86aabSstevel * It returns the value of the asynchronous-event-pending 12573db86aabSstevel * flag as passed back by the LOM at the end of the last 12583db86aabSstevel * completed command. 12593db86aabSstevel */ 12603db86aabSstevel ssp = HANDLE_PRIVATE(hdlp); 12613db86aabSstevel return (ssp->async); 12623db86aabSstevel 12633db86aabSstevel default: 12643db86aabSstevel /* 12653db86aabSstevel * Invalid access - flag a fault and return a dummy value 12663db86aabSstevel */ 12673db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 12683db86aabSstevel return (DUMMY_VALUE); 12693db86aabSstevel } 12703db86aabSstevel } 12713db86aabSstevel 12723db86aabSstevel static void 12733db86aabSstevel lombus_meta_put32(HANDLE_TYPE *hdlp, uint32_t *addr, uint32_t val) 12743db86aabSstevel { 12753db86aabSstevel ptrdiff_t offset; 12763db86aabSstevel 12773db86aabSstevel /* 12783db86aabSstevel * Derive the offset that the caller has added to the base 12793db86aabSstevel * address originally returned, and use it to determine 12803db86aabSstevel * which meta-register is to be accessed ... 12813db86aabSstevel */ 12823db86aabSstevel offset = ADDR_TO_OFFSET(addr, hdlp); 12833db86aabSstevel switch (offset) { 12843db86aabSstevel case LOMBUS_FAULT_REG: 12853db86aabSstevel /* 12863db86aabSstevel * This meta-register contains a code for the most 12873db86aabSstevel * recent virtual register access fault, if any. 12883db86aabSstevel * It can be cleared simply by writing 0 to it. 12893db86aabSstevel */ 12903db86aabSstevel HANDLE_FAULT(hdlp) = val; 12913db86aabSstevel return; 12923db86aabSstevel 12933db86aabSstevel case LOMBUS_PROBE_REG: 12943db86aabSstevel /* 12953db86aabSstevel * Writing this meta-register clears any existing fault 12963db86aabSstevel * (at the virtual, not the hardware acess layer), then 12973db86aabSstevel * runs a NOP command. The caller can check the fault 12983db86aabSstevel * code later if required. 12993db86aabSstevel */ 13003db86aabSstevel HANDLE_FAULT(hdlp) = 0; 1301*07d06da5SSurya Prakki (void) lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP); 13023db86aabSstevel return; 13033db86aabSstevel 13043db86aabSstevel default: 13053db86aabSstevel /* 13063db86aabSstevel * Invalid access - flag a fault 13073db86aabSstevel */ 13083db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 13093db86aabSstevel return; 13103db86aabSstevel } 13113db86aabSstevel } 13123db86aabSstevel 13133db86aabSstevel static void 13143db86aabSstevel lombus_meta_rep_get32(HANDLE_TYPE *hdlp, uint32_t *host_addr, 13153db86aabSstevel uint32_t *dev_addr, size_t repcount, uint_t flags) 13163db86aabSstevel { 13173db86aabSstevel size_t inc; 13183db86aabSstevel 13193db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 13203db86aabSstevel for (; repcount--; dev_addr += inc) 13213db86aabSstevel *host_addr++ = lombus_meta_get32(hdlp, dev_addr); 13223db86aabSstevel } 13233db86aabSstevel 13243db86aabSstevel static void 13253db86aabSstevel lombus_meta_rep_put32(HANDLE_TYPE *hdlp, uint32_t *host_addr, 13263db86aabSstevel uint32_t *dev_addr, size_t repcount, uint_t flags) 13273db86aabSstevel { 13283db86aabSstevel size_t inc; 13293db86aabSstevel 13303db86aabSstevel inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0; 13313db86aabSstevel for (; repcount--; dev_addr += inc) 13323db86aabSstevel lombus_meta_put32(hdlp, dev_addr, *host_addr++); 13333db86aabSstevel } 13343db86aabSstevel 13353db86aabSstevel 13363db86aabSstevel /* 13373db86aabSstevel * Finally, some dummy functions for all unsupported access 13383db86aabSstevel * space/size/mode combinations ... 13393db86aabSstevel */ 13403db86aabSstevel static uint8_t 13413db86aabSstevel lombus_no_get8(HANDLE_TYPE *hdlp, uint8_t *addr) 13423db86aabSstevel { 13433db86aabSstevel _NOTE(ARGUNUSED(addr)) 13443db86aabSstevel 13453db86aabSstevel /* 13463db86aabSstevel * Invalid access - flag a fault and return a dummy value 13473db86aabSstevel */ 13483db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 13493db86aabSstevel return (DUMMY_VALUE); 13503db86aabSstevel } 13513db86aabSstevel 13523db86aabSstevel static void 13533db86aabSstevel lombus_no_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val) 13543db86aabSstevel { 13553db86aabSstevel _NOTE(ARGUNUSED(addr, val)) 13563db86aabSstevel 13573db86aabSstevel /* 13583db86aabSstevel * Invalid access - flag a fault 13593db86aabSstevel */ 13603db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 13613db86aabSstevel } 13623db86aabSstevel 13633db86aabSstevel static void 13643db86aabSstevel lombus_no_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 13653db86aabSstevel uint8_t *dev_addr, size_t repcount, uint_t flags) 13663db86aabSstevel { 13673db86aabSstevel _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 13683db86aabSstevel 13693db86aabSstevel /* 13703db86aabSstevel * Invalid access - flag a fault 13713db86aabSstevel */ 13723db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 13733db86aabSstevel } 13743db86aabSstevel 13753db86aabSstevel static void 13763db86aabSstevel lombus_no_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr, 13773db86aabSstevel uint8_t *dev_addr, size_t repcount, uint_t flags) 13783db86aabSstevel { 13793db86aabSstevel _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 13803db86aabSstevel 13813db86aabSstevel /* 13823db86aabSstevel * Invalid access - flag a fault 13833db86aabSstevel */ 13843db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 13853db86aabSstevel } 13863db86aabSstevel 13873db86aabSstevel static uint16_t 13883db86aabSstevel lombus_no_get16(HANDLE_TYPE *hdlp, uint16_t *addr) 13893db86aabSstevel { 13903db86aabSstevel _NOTE(ARGUNUSED(addr)) 13913db86aabSstevel 13923db86aabSstevel /* 13933db86aabSstevel * Invalid access - flag a fault and return a dummy value 13943db86aabSstevel */ 13953db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 13963db86aabSstevel return (DUMMY_VALUE); 13973db86aabSstevel } 13983db86aabSstevel 13993db86aabSstevel static void 14003db86aabSstevel lombus_no_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val) 14013db86aabSstevel { 14023db86aabSstevel _NOTE(ARGUNUSED(addr, val)) 14033db86aabSstevel 14043db86aabSstevel /* 14053db86aabSstevel * Invalid access - flag a fault 14063db86aabSstevel */ 14073db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 14083db86aabSstevel } 14093db86aabSstevel 14103db86aabSstevel static void 14113db86aabSstevel lombus_no_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 14123db86aabSstevel uint16_t *dev_addr, size_t repcount, uint_t flags) 14133db86aabSstevel { 14143db86aabSstevel _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 14153db86aabSstevel 14163db86aabSstevel /* 14173db86aabSstevel * Invalid access - flag a fault 14183db86aabSstevel */ 14193db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 14203db86aabSstevel } 14213db86aabSstevel 14223db86aabSstevel static void 14233db86aabSstevel lombus_no_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr, 14243db86aabSstevel uint16_t *dev_addr, size_t repcount, uint_t flags) 14253db86aabSstevel { 14263db86aabSstevel _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 14273db86aabSstevel 14283db86aabSstevel /* 14293db86aabSstevel * Invalid access - flag a fault 14303db86aabSstevel */ 14313db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 14323db86aabSstevel } 14333db86aabSstevel 14343db86aabSstevel static uint64_t 14353db86aabSstevel lombus_no_get64(HANDLE_TYPE *hdlp, uint64_t *addr) 14363db86aabSstevel { 14373db86aabSstevel _NOTE(ARGUNUSED(addr)) 14383db86aabSstevel 14393db86aabSstevel /* 14403db86aabSstevel * Invalid access - flag a fault and return a dummy value 14413db86aabSstevel */ 14423db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 14433db86aabSstevel return (DUMMY_VALUE); 14443db86aabSstevel } 14453db86aabSstevel 14463db86aabSstevel static void 14473db86aabSstevel lombus_no_put64(HANDLE_TYPE *hdlp, uint64_t *addr, uint64_t val) 14483db86aabSstevel { 14493db86aabSstevel _NOTE(ARGUNUSED(addr, val)) 14503db86aabSstevel 14513db86aabSstevel /* 14523db86aabSstevel * Invalid access - flag a fault 14533db86aabSstevel */ 14543db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 14553db86aabSstevel } 14563db86aabSstevel 14573db86aabSstevel static void 14583db86aabSstevel lombus_no_rep_get64(HANDLE_TYPE *hdlp, uint64_t *host_addr, 14593db86aabSstevel uint64_t *dev_addr, size_t repcount, uint_t flags) 14603db86aabSstevel { 14613db86aabSstevel _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 14623db86aabSstevel 14633db86aabSstevel /* 14643db86aabSstevel * Invalid access - flag a fault 14653db86aabSstevel */ 14663db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 14673db86aabSstevel } 14683db86aabSstevel 14693db86aabSstevel static void 14703db86aabSstevel lombus_no_rep_put64(HANDLE_TYPE *hdlp, uint64_t *host_addr, 14713db86aabSstevel uint64_t *dev_addr, size_t repcount, uint_t flags) 14723db86aabSstevel { 14733db86aabSstevel _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags)) 14743db86aabSstevel 14753db86aabSstevel /* 14763db86aabSstevel * Invalid access - flag a fault 14773db86aabSstevel */ 14783db86aabSstevel HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE; 14793db86aabSstevel } 14803db86aabSstevel 14813db86aabSstevel static int 14823db86aabSstevel lombus_acc_fault_check(HANDLE_TYPE *hdlp) 14833db86aabSstevel { 14843db86aabSstevel return (HANDLE_FAULT(hdlp) != 0); 14853db86aabSstevel } 14863db86aabSstevel 14873db86aabSstevel 14883db86aabSstevel /* 14893db86aabSstevel * Hardware setup - put the SIO chip in the required operational 14903db86aabSstevel * state, with all our favourite parameters programmed correctly. 14913db86aabSstevel * This routine leaves all SIO interrupts disabled. 14923db86aabSstevel */ 14933db86aabSstevel 14943db86aabSstevel static void 14953db86aabSstevel lombus_hw_reset(struct lombus_state *ssp) 14963db86aabSstevel { 14973db86aabSstevel uint16_t divisor; 14983db86aabSstevel 14993db86aabSstevel /* 15003db86aabSstevel * Disable interrupts, soft reset Tx and Rx circuitry, 15013db86aabSstevel * reselect standard modes (bits/char, parity, etc). 15023db86aabSstevel */ 15033db86aabSstevel lombus_set_irq(ssp, B_FALSE); 15043db86aabSstevel sio_put_reg(ssp, SIO_FCR, SIO_FCR_RXSR | SIO_FCR_TXSR); 15053db86aabSstevel sio_put_reg(ssp, SIO_LCR, SIO_LCR_STD); 15063db86aabSstevel 15073db86aabSstevel /* 15083db86aabSstevel * Select the proper baud rate; if the value is invalid 15093db86aabSstevel * (presumably 0, i.e. not specified, but also if the 15103db86aabSstevel * "baud" property is set to some silly value), we assume 15113db86aabSstevel * the default. 15123db86aabSstevel */ 15133db86aabSstevel if (ssp->baud < SIO_BAUD_MIN || ssp->baud > SIO_BAUD_MAX) 15143db86aabSstevel divisor = SIO_BAUD_TO_DIVISOR(SIO_BAUD_DEFAULT); 15153db86aabSstevel else 15163db86aabSstevel divisor = SIO_BAUD_TO_DIVISOR(ssp->baud); 15173db86aabSstevel 15183db86aabSstevel /* 15193db86aabSstevel * According to the datasheet, it is forbidden for the divisor 15203db86aabSstevel * register to be zero. So when loading the register in two 15213db86aabSstevel * steps, we have to make sure that the temporary value formed 15223db86aabSstevel * between loads is nonzero. However, we can't rely on either 15233db86aabSstevel * half already having a nonzero value, as the datasheet also 15243db86aabSstevel * says that these registers are indeterminate after a reset! 15253db86aabSstevel * So, we explicitly set the low byte to a non-zero value first; 15263db86aabSstevel * then we can safely load the high byte, and then the correct 15273db86aabSstevel * value for the low byte, without the result ever being zero. 15283db86aabSstevel */ 15293db86aabSstevel sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK1); 15303db86aabSstevel sio_put_reg(ssp, SIO_LBGDL, 0xff); 15313db86aabSstevel sio_put_reg(ssp, SIO_LBGDH, divisor >> 8); 15323db86aabSstevel sio_put_reg(ssp, SIO_LBGDL, divisor & 0xff); 15333db86aabSstevel sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK0); 15343db86aabSstevel 15353db86aabSstevel /* 15363db86aabSstevel * Program the remaining device registers as required 15373db86aabSstevel */ 15383db86aabSstevel sio_put_reg(ssp, SIO_MCR, SIO_MCR_STD); 15393db86aabSstevel sio_put_reg(ssp, SIO_FCR, SIO_FCR_STD); 15403db86aabSstevel } 15413db86aabSstevel 15423db86aabSstevel 15433db86aabSstevel /* 15443db86aabSstevel * Higher-level setup & teardown 15453db86aabSstevel */ 15463db86aabSstevel 15473db86aabSstevel static void 15483db86aabSstevel lombus_offline(struct lombus_state *ssp) 15493db86aabSstevel { 15503db86aabSstevel if (ssp->sio_handle != NULL) 15513db86aabSstevel ddi_regs_map_free(&ssp->sio_handle); 15523db86aabSstevel ssp->sio_handle = NULL; 15533db86aabSstevel ssp->sio_regs = NULL; 15543db86aabSstevel } 15553db86aabSstevel 15563db86aabSstevel static int 15573db86aabSstevel lombus_online(struct lombus_state *ssp) 15583db86aabSstevel { 15593db86aabSstevel ddi_acc_handle_t h; 15603db86aabSstevel caddr_t p; 15613db86aabSstevel int nregs; 15623db86aabSstevel int err; 15633db86aabSstevel 15643db86aabSstevel if (ddi_dev_nregs(ssp->dip, &nregs) != DDI_SUCCESS) 15653db86aabSstevel nregs = 0; 15663db86aabSstevel 15673db86aabSstevel switch (nregs) { 15683db86aabSstevel default: 15693db86aabSstevel case 1: 15703db86aabSstevel /* 15713db86aabSstevel * regset 0 represents the SIO operating registers 15723db86aabSstevel */ 15733db86aabSstevel err = ddi_regs_map_setup(ssp->dip, 0, &p, 0, 0, 15743db86aabSstevel lombus_dev_acc_attr, &h); 15753db86aabSstevel lombus_trace(ssp, 'O', "online", 15763db86aabSstevel "regmap 0 status %d addr $%p", err, p); 15773db86aabSstevel if (err != DDI_SUCCESS) 15783db86aabSstevel return (EIO); 15793db86aabSstevel 15803db86aabSstevel ssp->sio_handle = h; 15813db86aabSstevel ssp->sio_regs = (void *)p; 15823db86aabSstevel break; 15833db86aabSstevel 15843db86aabSstevel case 0: 15853db86aabSstevel /* 15863db86aabSstevel * If no registers are defined, succeed vacuously; 15873db86aabSstevel * commands will be accepted, but we fake the accesses. 15883db86aabSstevel */ 15893db86aabSstevel break; 15903db86aabSstevel } 15913db86aabSstevel 15923db86aabSstevel /* 15933db86aabSstevel * Now that the registers are mapped, we can initialise the SIO h/w 15943db86aabSstevel */ 15953db86aabSstevel lombus_hw_reset(ssp); 15963db86aabSstevel return (0); 15973db86aabSstevel } 15983db86aabSstevel 15993db86aabSstevel 16003db86aabSstevel /* 16013db86aabSstevel * Nexus routines 16023db86aabSstevel */ 16033db86aabSstevel 16043db86aabSstevel #if defined(NDI_ACC_HDL_V2) 16053db86aabSstevel 16063db86aabSstevel static const ndi_acc_fns_t lombus_vreg_acc_fns = { 16073db86aabSstevel NDI_ACC_FNS_CURRENT, 16083db86aabSstevel NDI_ACC_FNS_V1, 16093db86aabSstevel 16103db86aabSstevel lombus_vreg_get8, 16113db86aabSstevel lombus_vreg_put8, 16123db86aabSstevel lombus_vreg_rep_get8, 16133db86aabSstevel lombus_vreg_rep_put8, 16143db86aabSstevel 16153db86aabSstevel lombus_no_get16, 16163db86aabSstevel lombus_no_put16, 16173db86aabSstevel lombus_no_rep_get16, 16183db86aabSstevel lombus_no_rep_put16, 16193db86aabSstevel 16203db86aabSstevel lombus_meta_get32, 16213db86aabSstevel lombus_meta_put32, 16223db86aabSstevel lombus_meta_rep_get32, 16233db86aabSstevel lombus_meta_rep_put32, 16243db86aabSstevel 16253db86aabSstevel lombus_no_get64, 16263db86aabSstevel lombus_no_put64, 16273db86aabSstevel lombus_no_rep_get64, 16283db86aabSstevel lombus_no_rep_put64, 16293db86aabSstevel 16303db86aabSstevel lombus_acc_fault_check 16313db86aabSstevel }; 16323db86aabSstevel 16333db86aabSstevel static const ndi_acc_fns_t lombus_pat_acc_fns = { 16343db86aabSstevel NDI_ACC_FNS_CURRENT, 16353db86aabSstevel NDI_ACC_FNS_V1, 16363db86aabSstevel 16373db86aabSstevel lombus_pat_get8, 16383db86aabSstevel lombus_pat_put8, 16393db86aabSstevel lombus_pat_rep_get8, 16403db86aabSstevel lombus_pat_rep_put8, 16413db86aabSstevel 16423db86aabSstevel lombus_no_get16, 16433db86aabSstevel lombus_no_put16, 16443db86aabSstevel lombus_no_rep_get16, 16453db86aabSstevel lombus_no_rep_put16, 16463db86aabSstevel 16473db86aabSstevel lombus_meta_get32, 16483db86aabSstevel lombus_meta_put32, 16493db86aabSstevel lombus_meta_rep_get32, 16503db86aabSstevel lombus_meta_rep_put32, 16513db86aabSstevel 16523db86aabSstevel lombus_no_get64, 16533db86aabSstevel lombus_no_put64, 16543db86aabSstevel lombus_no_rep_get64, 16553db86aabSstevel lombus_no_rep_put64, 16563db86aabSstevel 16573db86aabSstevel lombus_acc_fault_check 16583db86aabSstevel }; 16593db86aabSstevel 16603db86aabSstevel static const ndi_acc_fns_t lombus_event_acc_fns = { 16613db86aabSstevel NDI_ACC_FNS_CURRENT, 16623db86aabSstevel NDI_ACC_FNS_V1, 16633db86aabSstevel 16643db86aabSstevel lombus_no_get8, 16653db86aabSstevel lombus_no_put8, 16663db86aabSstevel lombus_no_rep_get8, 16673db86aabSstevel lombus_no_rep_put8, 16683db86aabSstevel 16693db86aabSstevel lombus_event_get16, 16703db86aabSstevel lombus_event_put16, 16713db86aabSstevel lombus_event_rep_get16, 16723db86aabSstevel lombus_event_rep_put16, 16733db86aabSstevel 16743db86aabSstevel lombus_meta_get32, 16753db86aabSstevel lombus_meta_put32, 16763db86aabSstevel lombus_meta_rep_get32, 16773db86aabSstevel lombus_meta_rep_put32, 16783db86aabSstevel 16793db86aabSstevel lombus_no_get64, 16803db86aabSstevel lombus_no_put64, 16813db86aabSstevel lombus_no_rep_get64, 16823db86aabSstevel lombus_no_rep_put64, 16833db86aabSstevel 16843db86aabSstevel lombus_acc_fault_check 16853db86aabSstevel }; 16863db86aabSstevel 16873db86aabSstevel static int 16883db86aabSstevel lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op, 16893db86aabSstevel int space, caddr_t vaddr, off_t len, 16903db86aabSstevel ndi_acc_handle_t *hdlp, caddr_t *addrp) 16913db86aabSstevel { 16923db86aabSstevel switch (op) { 16933db86aabSstevel default: 16943db86aabSstevel return (DDI_ME_UNIMPLEMENTED); 16953db86aabSstevel 16963db86aabSstevel case DDI_MO_MAP_LOCKED: 16973db86aabSstevel switch (space) { 16983db86aabSstevel default: 16993db86aabSstevel return (DDI_ME_REGSPEC_RANGE); 17003db86aabSstevel 17013db86aabSstevel case LOMBUS_VREG_SPACE: 17023db86aabSstevel ndi_set_acc_fns(hdlp, &lombus_vreg_acc_fns); 17033db86aabSstevel break; 17043db86aabSstevel 17053db86aabSstevel case LOMBUS_PAT_SPACE: 17063db86aabSstevel ndi_set_acc_fns(hdlp, &lombus_pat_acc_fns); 17073db86aabSstevel break; 17083db86aabSstevel 17093db86aabSstevel case LOMBUS_EVENT_SPACE: 17103db86aabSstevel ndi_set_acc_fns(hdlp, &lombus_event_acc_fns); 17113db86aabSstevel break; 17123db86aabSstevel } 17133db86aabSstevel hdlp->ah_addr = *addrp = vaddr; 17143db86aabSstevel hdlp->ah_len = len; 17153db86aabSstevel hdlp->ah_bus_private = ssp; 17163db86aabSstevel return (DDI_SUCCESS); 17173db86aabSstevel 17183db86aabSstevel case DDI_MO_UNMAP: 17193db86aabSstevel *addrp = NULL; 17203db86aabSstevel hdlp->ah_bus_private = NULL; 17213db86aabSstevel return (DDI_SUCCESS); 17223db86aabSstevel } 17233db86aabSstevel } 17243db86aabSstevel 17253db86aabSstevel #else 17263db86aabSstevel 17273db86aabSstevel static int 17283db86aabSstevel lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op, 17293db86aabSstevel int space, caddr_t vaddr, off_t len, 17303db86aabSstevel ddi_acc_hdl_t *hdlp, caddr_t *addrp) 17313db86aabSstevel { 17323db86aabSstevel ddi_acc_impl_t *aip = hdlp->ah_platform_private; 17333db86aabSstevel 17343db86aabSstevel switch (op) { 17353db86aabSstevel default: 17363db86aabSstevel return (DDI_ME_UNIMPLEMENTED); 17373db86aabSstevel 17383db86aabSstevel case DDI_MO_MAP_LOCKED: 17393db86aabSstevel switch (space) { 17403db86aabSstevel default: 17413db86aabSstevel return (DDI_ME_REGSPEC_RANGE); 17423db86aabSstevel 17433db86aabSstevel case LOMBUS_VREG_SPACE: 17443db86aabSstevel aip->ahi_get8 = lombus_vreg_get8; 17453db86aabSstevel aip->ahi_put8 = lombus_vreg_put8; 17463db86aabSstevel aip->ahi_rep_get8 = lombus_vreg_rep_get8; 17473db86aabSstevel aip->ahi_rep_put8 = lombus_vreg_rep_put8; 17483db86aabSstevel 17493db86aabSstevel aip->ahi_get16 = lombus_no_get16; 17503db86aabSstevel aip->ahi_put16 = lombus_no_put16; 17513db86aabSstevel aip->ahi_rep_get16 = lombus_no_rep_get16; 17523db86aabSstevel aip->ahi_rep_put16 = lombus_no_rep_put16; 17533db86aabSstevel 17543db86aabSstevel aip->ahi_get32 = lombus_meta_get32; 17553db86aabSstevel aip->ahi_put32 = lombus_meta_put32; 17563db86aabSstevel aip->ahi_rep_get32 = lombus_meta_rep_get32; 17573db86aabSstevel aip->ahi_rep_put32 = lombus_meta_rep_put32; 17583db86aabSstevel 17593db86aabSstevel aip->ahi_get64 = lombus_no_get64; 17603db86aabSstevel aip->ahi_put64 = lombus_no_put64; 17613db86aabSstevel aip->ahi_rep_get64 = lombus_no_rep_get64; 17623db86aabSstevel aip->ahi_rep_put64 = lombus_no_rep_put64; 17633db86aabSstevel 17643db86aabSstevel aip->ahi_fault_check = lombus_acc_fault_check; 17653db86aabSstevel break; 17663db86aabSstevel 17673db86aabSstevel case LOMBUS_PAT_SPACE: 17683db86aabSstevel aip->ahi_get8 = lombus_pat_get8; 17693db86aabSstevel aip->ahi_put8 = lombus_pat_put8; 17703db86aabSstevel aip->ahi_rep_get8 = lombus_pat_rep_get8; 17713db86aabSstevel aip->ahi_rep_put8 = lombus_pat_rep_put8; 17723db86aabSstevel 17733db86aabSstevel aip->ahi_get16 = lombus_no_get16; 17743db86aabSstevel aip->ahi_put16 = lombus_no_put16; 17753db86aabSstevel aip->ahi_rep_get16 = lombus_no_rep_get16; 17763db86aabSstevel aip->ahi_rep_put16 = lombus_no_rep_put16; 17773db86aabSstevel 17783db86aabSstevel aip->ahi_get32 = lombus_meta_get32; 17793db86aabSstevel aip->ahi_put32 = lombus_meta_put32; 17803db86aabSstevel aip->ahi_rep_get32 = lombus_meta_rep_get32; 17813db86aabSstevel aip->ahi_rep_put32 = lombus_meta_rep_put32; 17823db86aabSstevel 17833db86aabSstevel aip->ahi_get64 = lombus_no_get64; 17843db86aabSstevel aip->ahi_put64 = lombus_no_put64; 17853db86aabSstevel aip->ahi_rep_get64 = lombus_no_rep_get64; 17863db86aabSstevel aip->ahi_rep_put64 = lombus_no_rep_put64; 17873db86aabSstevel 17883db86aabSstevel aip->ahi_fault_check = lombus_acc_fault_check; 17893db86aabSstevel break; 17903db86aabSstevel 17913db86aabSstevel case LOMBUS_EVENT_SPACE: 17923db86aabSstevel aip->ahi_get8 = lombus_no_get8; 17933db86aabSstevel aip->ahi_put8 = lombus_no_put8; 17943db86aabSstevel aip->ahi_rep_get8 = lombus_no_rep_get8; 17953db86aabSstevel aip->ahi_rep_put8 = lombus_no_rep_put8; 17963db86aabSstevel 17973db86aabSstevel aip->ahi_get16 = lombus_event_get16; 17983db86aabSstevel aip->ahi_put16 = lombus_event_put16; 17993db86aabSstevel aip->ahi_rep_get16 = lombus_event_rep_get16; 18003db86aabSstevel aip->ahi_rep_put16 = lombus_event_rep_put16; 18013db86aabSstevel 18023db86aabSstevel aip->ahi_get32 = lombus_meta_get32; 18033db86aabSstevel aip->ahi_put32 = lombus_meta_put32; 18043db86aabSstevel aip->ahi_rep_get32 = lombus_meta_rep_get32; 18053db86aabSstevel aip->ahi_rep_put32 = lombus_meta_rep_put32; 18063db86aabSstevel 18073db86aabSstevel aip->ahi_get64 = lombus_no_get64; 18083db86aabSstevel aip->ahi_put64 = lombus_no_put64; 18093db86aabSstevel aip->ahi_rep_get64 = lombus_no_rep_get64; 18103db86aabSstevel aip->ahi_rep_put64 = lombus_no_rep_put64; 18113db86aabSstevel 18123db86aabSstevel aip->ahi_fault_check = lombus_acc_fault_check; 18133db86aabSstevel break; 18143db86aabSstevel } 18153db86aabSstevel hdlp->ah_addr = *addrp = vaddr; 18163db86aabSstevel hdlp->ah_len = len; 18173db86aabSstevel hdlp->ah_bus_private = ssp; 18183db86aabSstevel return (DDI_SUCCESS); 18193db86aabSstevel 18203db86aabSstevel case DDI_MO_UNMAP: 18213db86aabSstevel *addrp = NULL; 18223db86aabSstevel hdlp->ah_bus_private = NULL; 18233db86aabSstevel return (DDI_SUCCESS); 18243db86aabSstevel } 18253db86aabSstevel } 18263db86aabSstevel 18273db86aabSstevel #endif /* NDI_ACC_HDL_V2 */ 18283db86aabSstevel 18293db86aabSstevel static int 18303db86aabSstevel lombus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 18313db86aabSstevel off_t off, off_t len, caddr_t *addrp) 18323db86aabSstevel { 18333db86aabSstevel struct lombus_child_info *lcip; 18343db86aabSstevel struct lombus_state *ssp; 18353db86aabSstevel lombus_regspec_t *rsp; 18363db86aabSstevel 18373db86aabSstevel if ((ssp = lombus_getstate(dip, -1, "lombus_map")) == NULL) 18383db86aabSstevel return (DDI_FAILURE); /* this "can't happen" */ 18393db86aabSstevel 18403db86aabSstevel /* 18413db86aabSstevel * Validate mapping request ... 18423db86aabSstevel */ 18433db86aabSstevel 18443db86aabSstevel if (mp->map_flags != DDI_MF_KERNEL_MAPPING) 18453db86aabSstevel return (DDI_ME_UNSUPPORTED); 18463db86aabSstevel if (mp->map_handlep == NULL) 18473db86aabSstevel return (DDI_ME_UNSUPPORTED); 18483db86aabSstevel if (mp->map_type != DDI_MT_RNUMBER) 18493db86aabSstevel return (DDI_ME_UNIMPLEMENTED); 18503db86aabSstevel if ((lcip = ddi_get_parent_data(rdip)) == NULL) 18513db86aabSstevel return (DDI_ME_INVAL); 18523db86aabSstevel if ((rsp = lcip->rsp) == NULL) 18533db86aabSstevel return (DDI_ME_INVAL); 18543db86aabSstevel if (mp->map_obj.rnumber >= lcip->nregs) 18553db86aabSstevel return (DDI_ME_RNUMBER_RANGE); 18563db86aabSstevel rsp += mp->map_obj.rnumber; 18573db86aabSstevel if (off < 0 || off >= rsp->lombus_size) 18583db86aabSstevel return (DDI_ME_INVAL); 18593db86aabSstevel if (len == 0) 18603db86aabSstevel len = rsp->lombus_size-off; 18613db86aabSstevel if (len < 0) 18623db86aabSstevel return (DDI_ME_INVAL); 18633db86aabSstevel if (off+len < 0 || off+len > rsp->lombus_size) 18643db86aabSstevel return (DDI_ME_INVAL); 18653db86aabSstevel 18663db86aabSstevel return (lombus_map_handle(ssp, mp->map_op, 18673db86aabSstevel rsp->lombus_space, VREG_TO_ADDR(rsp->lombus_base+off), len, 18683db86aabSstevel mp->map_handlep, addrp)); 18693db86aabSstevel } 18703db86aabSstevel 18713db86aabSstevel static int 18723db86aabSstevel lombus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, 18733db86aabSstevel void *arg, void *result) 18743db86aabSstevel { 18753db86aabSstevel struct lombus_child_info *lcip; 18763db86aabSstevel struct lombus_state *ssp; 18773db86aabSstevel lombus_regspec_t *rsp; 18783db86aabSstevel dev_info_t *cdip; 18793db86aabSstevel char addr[32]; 18803db86aabSstevel uint_t nregs; 18813db86aabSstevel uint_t rnum; 18823db86aabSstevel int *regs; 18833db86aabSstevel int limit; 18843db86aabSstevel int err; 18853db86aabSstevel int i; 18863db86aabSstevel 18873db86aabSstevel if ((ssp = lombus_getstate(dip, -1, "lombus_ctlops")) == NULL) 18883db86aabSstevel return (DDI_FAILURE); /* this "can't happen" */ 18893db86aabSstevel 18903db86aabSstevel switch (op) { 18913db86aabSstevel default: 18923db86aabSstevel break; 18933db86aabSstevel 18943db86aabSstevel case DDI_CTLOPS_INITCHILD: 18953db86aabSstevel /* 18963db86aabSstevel * First, look up and validate the "reg" property. 18973db86aabSstevel * 18983db86aabSstevel * It must be a non-empty integer array containing a set 18993db86aabSstevel * of triples. Once we've verified that, we can treat it 19003db86aabSstevel * as an array of type lombus_regspec_t[], which defines 19013db86aabSstevel * the meaning of the elements of each triple: 19023db86aabSstevel * + the first element of each triple must be a valid space 19033db86aabSstevel * + the second and third elements (base, size) of each 19043db86aabSstevel * triple must define a valid subrange of that space 19053db86aabSstevel * If it passes all the tests, we save it away for future 19063db86aabSstevel * reference in the child's parent-private-data field. 19073db86aabSstevel */ 19083db86aabSstevel cdip = arg; 19093db86aabSstevel err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, 19103db86aabSstevel DDI_PROP_DONTPASS, "reg", ®s, &nregs); 19113db86aabSstevel lombus_trace(ssp, 'C', "initchild", 19123db86aabSstevel "prop status %d size %d", err, nregs); 19133db86aabSstevel if (err != DDI_PROP_SUCCESS) 19143db86aabSstevel return (DDI_FAILURE); 19153db86aabSstevel 19163db86aabSstevel err = (nregs <= 0 || (nregs % LOMBUS_REGSPEC_SIZE) != 0); 19173db86aabSstevel nregs /= LOMBUS_REGSPEC_SIZE; 19183db86aabSstevel rsp = (lombus_regspec_t *)regs; 19193db86aabSstevel for (i = 0; i < nregs && !err; ++i) { 19203db86aabSstevel switch (rsp[i].lombus_space) { 19213db86aabSstevel default: 19223db86aabSstevel limit = 0; 19233db86aabSstevel err = 1; 19243db86aabSstevel break; 19253db86aabSstevel 19263db86aabSstevel case LOMBUS_VREG_SPACE: 19273db86aabSstevel limit = LOMBUS_MAX_REG+1; 19283db86aabSstevel break; 19293db86aabSstevel 19303db86aabSstevel case LOMBUS_PAT_SPACE: 19313db86aabSstevel limit = LOMBUS_PAT_REG+1; 19323db86aabSstevel break; 19333db86aabSstevel 19343db86aabSstevel case LOMBUS_EVENT_SPACE: 19353db86aabSstevel limit = LOMBUS_EVENT_REG+1; 19363db86aabSstevel break; 19373db86aabSstevel } 19383db86aabSstevel 19393db86aabSstevel err |= (rsp[i].lombus_base < 0); 19403db86aabSstevel err |= (rsp[i].lombus_base >= limit); 19413db86aabSstevel 19423db86aabSstevel if (rsp[i].lombus_size == 0) 19433db86aabSstevel rsp[i].lombus_size = limit-rsp[i].lombus_base; 19443db86aabSstevel err |= (rsp[i].lombus_size < 0); 19453db86aabSstevel 19463db86aabSstevel err |= (rsp[i].lombus_base+rsp[i].lombus_size < 0); 19473db86aabSstevel err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit); 19483db86aabSstevel } 19493db86aabSstevel 19503db86aabSstevel if (err) { 19513db86aabSstevel ddi_prop_free(regs); 19523db86aabSstevel return (DDI_FAILURE); 19533db86aabSstevel } 19543db86aabSstevel 19553db86aabSstevel lcip = kmem_zalloc(sizeof (*lcip), KM_SLEEP); 19563db86aabSstevel lcip->nregs = nregs; 19573db86aabSstevel lcip->rsp = rsp; 19583db86aabSstevel ddi_set_parent_data(cdip, lcip); 19593db86aabSstevel 19603db86aabSstevel (void) snprintf(addr, sizeof (addr), 19613db86aabSstevel "%x,%x", rsp[0].lombus_space, rsp[0].lombus_base); 19623db86aabSstevel ddi_set_name_addr(cdip, addr); 19633db86aabSstevel 19643db86aabSstevel return (DDI_SUCCESS); 19653db86aabSstevel 19663db86aabSstevel case DDI_CTLOPS_UNINITCHILD: 19673db86aabSstevel cdip = arg; 19683db86aabSstevel ddi_set_name_addr(cdip, NULL); 19693db86aabSstevel lcip = ddi_get_parent_data(cdip); 19703db86aabSstevel ddi_set_parent_data(cdip, NULL); 19713db86aabSstevel ddi_prop_free(lcip->rsp); 19723db86aabSstevel kmem_free(lcip, sizeof (*lcip)); 19733db86aabSstevel return (DDI_SUCCESS); 19743db86aabSstevel 19753db86aabSstevel case DDI_CTLOPS_REPORTDEV: 19763db86aabSstevel if (rdip == NULL) 19773db86aabSstevel return (DDI_FAILURE); 19783db86aabSstevel 19793db86aabSstevel cmn_err(CE_CONT, "?LOM device: %s@%s, %s#%d\n", 19803db86aabSstevel ddi_node_name(rdip), ddi_get_name_addr(rdip), 19813db86aabSstevel ddi_driver_name(dip), ddi_get_instance(dip)); 19823db86aabSstevel 19833db86aabSstevel return (DDI_SUCCESS); 19843db86aabSstevel 19853db86aabSstevel case DDI_CTLOPS_REGSIZE: 19863db86aabSstevel if ((lcip = ddi_get_parent_data(rdip)) == NULL) 19873db86aabSstevel return (DDI_FAILURE); 19883db86aabSstevel if ((rnum = *(uint_t *)arg) >= lcip->nregs) 19893db86aabSstevel return (DDI_FAILURE); 19903db86aabSstevel *(off_t *)result = lcip->rsp[rnum].lombus_size; 19913db86aabSstevel return (DDI_SUCCESS); 19923db86aabSstevel 19933db86aabSstevel case DDI_CTLOPS_NREGS: 19943db86aabSstevel if ((lcip = ddi_get_parent_data(rdip)) == NULL) 19953db86aabSstevel return (DDI_FAILURE); 19963db86aabSstevel *(int *)result = lcip->nregs; 19973db86aabSstevel return (DDI_SUCCESS); 19983db86aabSstevel } 19993db86aabSstevel 20003db86aabSstevel return (ddi_ctlops(dip, rdip, op, arg, result)); 20013db86aabSstevel } 20023db86aabSstevel 20033db86aabSstevel 20043db86aabSstevel /* 20053db86aabSstevel * Clean up on detach or failure of attach 20063db86aabSstevel */ 20073db86aabSstevel static int 20083db86aabSstevel lombus_unattach(struct lombus_state *ssp, int instance) 20093db86aabSstevel { 20103db86aabSstevel if (ssp != NULL) { 20113db86aabSstevel lombus_hw_reset(ssp); 2012dd4eeefdSeota if (ssp->cycid != NULL) { 2013dd4eeefdSeota ddi_periodic_delete(ssp->cycid); 2014dd4eeefdSeota ssp->cycid = NULL; 20153db86aabSstevel if (ssp->sio_handle != NULL) 20163db86aabSstevel ddi_remove_intr(ssp->dip, 0, ssp->hw_iblk); 20173db86aabSstevel ddi_remove_softintr(ssp->softid); 20183db86aabSstevel cv_destroy(ssp->lo_cv); 20193db86aabSstevel mutex_destroy(ssp->lo_mutex); 20203db86aabSstevel mutex_destroy(ssp->hw_mutex); 20213db86aabSstevel } 20223db86aabSstevel lombus_offline(ssp); 20233db86aabSstevel ddi_set_driver_private(ssp->dip, NULL); 20243db86aabSstevel } 20253db86aabSstevel 20263db86aabSstevel ddi_soft_state_free(lombus_statep, instance); 20273db86aabSstevel return (DDI_FAILURE); 20283db86aabSstevel } 20293db86aabSstevel 20303db86aabSstevel /* 20313db86aabSstevel * Autoconfiguration routines 20323db86aabSstevel */ 20333db86aabSstevel 20343db86aabSstevel static int 20353db86aabSstevel lombus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 20363db86aabSstevel { 20373db86aabSstevel struct lombus_state *ssp = NULL; 20383db86aabSstevel int instance; 20393db86aabSstevel int err; 20403db86aabSstevel 20413db86aabSstevel switch (cmd) { 20423db86aabSstevel default: 20433db86aabSstevel return (DDI_FAILURE); 20443db86aabSstevel 20453db86aabSstevel case DDI_ATTACH: 20463db86aabSstevel break; 20473db86aabSstevel } 20483db86aabSstevel 20493db86aabSstevel /* 20503db86aabSstevel * Allocate the soft-state structure 20513db86aabSstevel */ 20523db86aabSstevel instance = ddi_get_instance(dip); 20533db86aabSstevel if (ddi_soft_state_zalloc(lombus_statep, instance) != DDI_SUCCESS) 20543db86aabSstevel return (DDI_FAILURE); 20553db86aabSstevel if ((ssp = lombus_getstate(dip, instance, "lombus_attach")) == NULL) 20563db86aabSstevel return (lombus_unattach(ssp, instance)); 20573db86aabSstevel ddi_set_driver_private(dip, ssp); 20583db86aabSstevel 20593db86aabSstevel /* 20603db86aabSstevel * Initialise devinfo-related fields 20613db86aabSstevel */ 20623db86aabSstevel ssp->dip = dip; 20633db86aabSstevel ssp->majornum = ddi_driver_major(dip); 20643db86aabSstevel ssp->instance = instance; 20653db86aabSstevel 20663db86aabSstevel /* 20673db86aabSstevel * Set various options from .conf properties 20683db86aabSstevel */ 20693db86aabSstevel ssp->allow_echo = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 20703db86aabSstevel DDI_PROP_DONTPASS, "allow-lom-echo", 0) != 0; 20713db86aabSstevel ssp->baud = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 20723db86aabSstevel DDI_PROP_DONTPASS, "baud-rate", 0); 20733db86aabSstevel ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 20743db86aabSstevel DDI_PROP_DONTPASS, "debug", 0); 20753db86aabSstevel ssp->fake_cts = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 20763db86aabSstevel DDI_PROP_DONTPASS, "fake-cts", 0) != 0; 20773db86aabSstevel 20783db86aabSstevel /* 20793db86aabSstevel * Initialise current state & time 20803db86aabSstevel */ 20813db86aabSstevel ssp->cmdstate = LOMBUS_CMDSTATE_IDLE; 20823db86aabSstevel ssp->hw_last_pat = gethrtime(); 2083dd4eeefdSeota ssp->cycid = NULL; 20843db86aabSstevel 20853db86aabSstevel /* 20863db86aabSstevel * Online the hardware ... 20873db86aabSstevel */ 20883db86aabSstevel err = lombus_online(ssp); 20893db86aabSstevel if (err != 0) 20903db86aabSstevel return (lombus_unattach(ssp, instance)); 20913db86aabSstevel 20923db86aabSstevel /* 20933db86aabSstevel * Install soft and hard interrupt handler(s) 20943db86aabSstevel * Initialise mutexes and cv 20953db86aabSstevel * Start cyclic callbacks 20963db86aabSstevel * Enable interrupts 20973db86aabSstevel */ 20983db86aabSstevel err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ssp->softid, 20993db86aabSstevel &ssp->lo_iblk, NULL, lombus_softint, (caddr_t)ssp); 21003db86aabSstevel if (err != DDI_SUCCESS) 21013db86aabSstevel return (lombus_unattach(ssp, instance)); 21023db86aabSstevel 21033db86aabSstevel if (ssp->sio_handle != NULL) 21043db86aabSstevel err = ddi_add_intr(dip, 0, &ssp->hw_iblk, NULL, 21053db86aabSstevel lombus_hi_intr, (caddr_t)ssp); 21063db86aabSstevel 21073db86aabSstevel mutex_init(ssp->hw_mutex, NULL, MUTEX_DRIVER, ssp->hw_iblk); 21083db86aabSstevel mutex_init(ssp->lo_mutex, NULL, MUTEX_DRIVER, ssp->lo_iblk); 21093db86aabSstevel cv_init(ssp->lo_cv, NULL, CV_DRIVER, NULL); 21103db86aabSstevel 2111dd4eeefdSeota /* 2112dd4eeefdSeota * Register a periodical handler. 2113dd4eeefdSeota */ 2114dd4eeefdSeota ssp->cycid = ddi_periodic_add(lombus_cyclic, ssp, LOMBUS_ONE_SEC, 2115dd4eeefdSeota DDI_IPL_1); 21163db86aabSstevel 21173db86aabSstevel /* 21183db86aabSstevel * Final check before enabling h/w interrupts - did 21193db86aabSstevel * we successfully install the h/w interrupt handler? 21203db86aabSstevel */ 21213db86aabSstevel if (err != DDI_SUCCESS) 21223db86aabSstevel return (lombus_unattach(ssp, instance)); 21233db86aabSstevel 21243db86aabSstevel lombus_set_irq(ssp, B_TRUE); 21253db86aabSstevel 21263db86aabSstevel /* 21273db86aabSstevel * All done, report success 21283db86aabSstevel */ 21293db86aabSstevel ddi_report_dev(dip); 21303db86aabSstevel return (DDI_SUCCESS); 21313db86aabSstevel } 21323db86aabSstevel 21333db86aabSstevel 21343db86aabSstevel static int 21353db86aabSstevel lombus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 21363db86aabSstevel { 21373db86aabSstevel struct lombus_state *ssp; 21383db86aabSstevel int instance; 21393db86aabSstevel 21403db86aabSstevel switch (cmd) { 21413db86aabSstevel default: 21423db86aabSstevel return (DDI_FAILURE); 21433db86aabSstevel 21443db86aabSstevel case DDI_DETACH: 21453db86aabSstevel break; 21463db86aabSstevel } 21473db86aabSstevel 21483db86aabSstevel instance = ddi_get_instance(dip); 21493db86aabSstevel if ((ssp = lombus_getstate(dip, instance, "lombus_detach")) == NULL) 21503db86aabSstevel return (DDI_FAILURE); /* this "can't happen" */ 21513db86aabSstevel 21523db86aabSstevel (void) lombus_unattach(ssp, instance); 21533db86aabSstevel return (DDI_SUCCESS); 21543db86aabSstevel } 21553db86aabSstevel 21563db86aabSstevel static int 21573db86aabSstevel lombus_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 21583db86aabSstevel { 21593db86aabSstevel struct lombus_state *ssp; 21603db86aabSstevel 21613db86aabSstevel _NOTE(ARGUNUSED(cmd)) 21623db86aabSstevel 21633db86aabSstevel if ((ssp = lombus_getstate(dip, -1, "lombus_reset")) == NULL) 21643db86aabSstevel return (DDI_FAILURE); 21653db86aabSstevel 21663db86aabSstevel lombus_hw_reset(ssp); 21673db86aabSstevel return (DDI_SUCCESS); 21683db86aabSstevel } 21693db86aabSstevel 21703db86aabSstevel 21713db86aabSstevel /* 21723db86aabSstevel * System interface structures 21733db86aabSstevel */ 21743db86aabSstevel 21753db86aabSstevel static struct cb_ops lombus_cb_ops = 21763db86aabSstevel { 21773db86aabSstevel nodev, /* b/c open */ 21783db86aabSstevel nodev, /* b/c close */ 21793db86aabSstevel nodev, /* b strategy */ 21803db86aabSstevel nodev, /* b print */ 21813db86aabSstevel nodev, /* b dump */ 21823db86aabSstevel nodev, /* c read */ 21833db86aabSstevel nodev, /* c write */ 21843db86aabSstevel nodev, /* c ioctl */ 21853db86aabSstevel nodev, /* c devmap */ 21863db86aabSstevel nodev, /* c mmap */ 21873db86aabSstevel nodev, /* c segmap */ 21883db86aabSstevel nochpoll, /* c poll */ 21893db86aabSstevel ddi_prop_op, /* b/c prop_op */ 21903db86aabSstevel NULL, /* c streamtab */ 21913db86aabSstevel D_MP | D_NEW /* b/c flags */ 21923db86aabSstevel }; 21933db86aabSstevel 21943db86aabSstevel static struct bus_ops lombus_bus_ops = 21953db86aabSstevel { 21963db86aabSstevel BUSO_REV, /* revision */ 21973db86aabSstevel lombus_map, /* bus_map */ 21983db86aabSstevel 0, /* get_intrspec */ 21993db86aabSstevel 0, /* add_intrspec */ 22003db86aabSstevel 0, /* remove_intrspec */ 22013db86aabSstevel i_ddi_map_fault, /* map_fault */ 22023db86aabSstevel ddi_no_dma_map, /* dma_map */ 22033db86aabSstevel ddi_no_dma_allochdl, /* allocate DMA handle */ 22043db86aabSstevel ddi_no_dma_freehdl, /* free DMA handle */ 22053db86aabSstevel ddi_no_dma_bindhdl, /* bind DMA handle */ 22063db86aabSstevel ddi_no_dma_unbindhdl, /* unbind DMA handle */ 22073db86aabSstevel ddi_no_dma_flush, /* flush DMA */ 22083db86aabSstevel ddi_no_dma_win, /* move DMA window */ 22093db86aabSstevel ddi_no_dma_mctl, /* generic DMA control */ 22103db86aabSstevel lombus_ctlops, /* generic control */ 22113db86aabSstevel ddi_bus_prop_op, /* prop_op */ 22123db86aabSstevel ndi_busop_get_eventcookie, /* get_eventcookie */ 22133db86aabSstevel ndi_busop_add_eventcall, /* add_eventcall */ 22143db86aabSstevel ndi_busop_remove_eventcall, /* remove_eventcall */ 22153db86aabSstevel ndi_post_event, /* post_event */ 22163db86aabSstevel 0, /* interrupt control */ 22173db86aabSstevel 0, /* bus_config */ 22183db86aabSstevel 0, /* bus_unconfig */ 22193db86aabSstevel 0, /* bus_fm_init */ 22203db86aabSstevel 0, /* bus_fm_fini */ 22213db86aabSstevel 0, /* bus_fm_access_enter */ 22223db86aabSstevel 0, /* bus_fm_access_exit */ 22233db86aabSstevel 0, /* bus_power */ 22243db86aabSstevel i_ddi_intr_ops /* bus_intr_op */ 22253db86aabSstevel }; 22263db86aabSstevel 22273db86aabSstevel static struct dev_ops lombus_dev_ops = 22283db86aabSstevel { 22293db86aabSstevel DEVO_REV, 22303db86aabSstevel 0, /* refcount */ 22313db86aabSstevel ddi_no_info, /* getinfo */ 22323db86aabSstevel nulldev, /* identify */ 22333db86aabSstevel nulldev, /* probe */ 22343db86aabSstevel lombus_attach, /* attach */ 22353db86aabSstevel lombus_detach, /* detach */ 22363db86aabSstevel lombus_reset, /* reset */ 22373db86aabSstevel &lombus_cb_ops, /* driver operations */ 223819397407SSherry Moore &lombus_bus_ops, /* bus operations */ 223919397407SSherry Moore NULL, /* power */ 224019397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 22413db86aabSstevel }; 22423db86aabSstevel 22433db86aabSstevel static struct modldrv modldrv = 22443db86aabSstevel { 22453db86aabSstevel &mod_driverops, 224619397407SSherry Moore "lombus driver", 22473db86aabSstevel &lombus_dev_ops 22483db86aabSstevel }; 22493db86aabSstevel 22503db86aabSstevel static struct modlinkage modlinkage = 22513db86aabSstevel { 22523db86aabSstevel MODREV_1, 22533db86aabSstevel { 22543db86aabSstevel &modldrv, 22553db86aabSstevel NULL 22563db86aabSstevel } 22573db86aabSstevel }; 22583db86aabSstevel 22593db86aabSstevel 22603db86aabSstevel /* 22613db86aabSstevel * Dynamic loader interface code 22623db86aabSstevel */ 22633db86aabSstevel 22643db86aabSstevel int 22653db86aabSstevel _init(void) 22663db86aabSstevel { 22673db86aabSstevel int err; 22683db86aabSstevel 22693db86aabSstevel err = ddi_soft_state_init(&lombus_statep, 22703db86aabSstevel sizeof (struct lombus_state), 0); 22713db86aabSstevel if (err == DDI_SUCCESS) 22723db86aabSstevel if ((err = mod_install(&modlinkage)) != 0) { 22733db86aabSstevel ddi_soft_state_fini(&lombus_statep); 22743db86aabSstevel } 22753db86aabSstevel 22763db86aabSstevel return (err); 22773db86aabSstevel } 22783db86aabSstevel 22793db86aabSstevel int 22803db86aabSstevel _info(struct modinfo *mip) 22813db86aabSstevel { 22823db86aabSstevel return (mod_info(&modlinkage, mip)); 22833db86aabSstevel } 22843db86aabSstevel 22853db86aabSstevel int 22863db86aabSstevel _fini(void) 22873db86aabSstevel { 22883db86aabSstevel int err; 22893db86aabSstevel 22903db86aabSstevel if ((err = mod_remove(&modlinkage)) == 0) { 22913db86aabSstevel ddi_soft_state_fini(&lombus_statep); 22923db86aabSstevel lombus_major = NOMAJOR; 22933db86aabSstevel } 22943db86aabSstevel 22953db86aabSstevel return (err); 22963db86aabSstevel } 2297