1098ca2bdSWarner Losh /*- 23c5656bfSArchie Cobbs * ichsmb.c 33c5656bfSArchie Cobbs * 4aad970f1SDavid E. O'Brien * Author: Archie Cobbs <archie@freebsd.org> 53c5656bfSArchie Cobbs * Copyright (c) 2000 Whistle Communications, Inc. 63c5656bfSArchie Cobbs * All rights reserved. 73c5656bfSArchie Cobbs * 83c5656bfSArchie Cobbs * Subject to the following obligations and disclaimer of warranty, use and 93c5656bfSArchie Cobbs * redistribution of this software, in source or object code forms, with or 103c5656bfSArchie Cobbs * without modifications are expressly permitted by Whistle Communications; 113c5656bfSArchie Cobbs * provided, however, that: 123c5656bfSArchie Cobbs * 1. Any and all reproductions of the source or object code must include the 133c5656bfSArchie Cobbs * copyright notice above and the following disclaimer of warranties; and 143c5656bfSArchie Cobbs * 2. No rights are granted, in any manner or form, to use Whistle 153c5656bfSArchie Cobbs * Communications, Inc. trademarks, including the mark "WHISTLE 163c5656bfSArchie Cobbs * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 173c5656bfSArchie Cobbs * such appears in the above copyright notice or in the software. 183c5656bfSArchie Cobbs * 193c5656bfSArchie Cobbs * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 203c5656bfSArchie Cobbs * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 213c5656bfSArchie Cobbs * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 223c5656bfSArchie Cobbs * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 233c5656bfSArchie Cobbs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 243c5656bfSArchie Cobbs * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 253c5656bfSArchie Cobbs * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 263c5656bfSArchie Cobbs * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 273c5656bfSArchie Cobbs * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 283c5656bfSArchie Cobbs * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 293c5656bfSArchie Cobbs * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 303c5656bfSArchie Cobbs * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 313c5656bfSArchie Cobbs * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 323c5656bfSArchie Cobbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 333c5656bfSArchie Cobbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 343c5656bfSArchie Cobbs * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 353c5656bfSArchie Cobbs * OF SUCH DAMAGE. 363c5656bfSArchie Cobbs */ 373c5656bfSArchie Cobbs 38aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 39aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 40aad970f1SDavid E. O'Brien 413c5656bfSArchie Cobbs /* 423c5656bfSArchie Cobbs * Support for the SMBus controller logical device which is part of the 433c5656bfSArchie Cobbs * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. 443a50ed55SArchie Cobbs * 453a50ed55SArchie Cobbs * This driver assumes that the generic SMBus code will ensure that 463a50ed55SArchie Cobbs * at most one process at a time calls into the SMBus methods below. 473c5656bfSArchie Cobbs */ 483c5656bfSArchie Cobbs 493c5656bfSArchie Cobbs #include <sys/param.h> 503c5656bfSArchie Cobbs #include <sys/systm.h> 513c5656bfSArchie Cobbs #include <sys/kernel.h> 523c5656bfSArchie Cobbs #include <sys/errno.h> 53f34fa851SJohn Baldwin #include <sys/lock.h> 547048a99cSJohn Baldwin #include <sys/module.h> 553a50ed55SArchie Cobbs #include <sys/mutex.h> 563c5656bfSArchie Cobbs #include <sys/syslog.h> 573c5656bfSArchie Cobbs #include <sys/bus.h> 583c5656bfSArchie Cobbs 593c5656bfSArchie Cobbs #include <machine/bus.h> 603c5656bfSArchie Cobbs #include <sys/rman.h> 613c5656bfSArchie Cobbs #include <machine/resource.h> 623c5656bfSArchie Cobbs 633c5656bfSArchie Cobbs #include <dev/smbus/smbconf.h> 643c5656bfSArchie Cobbs 653c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_var.h> 663c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_reg.h> 673c5656bfSArchie Cobbs 683c5656bfSArchie Cobbs /* 693c5656bfSArchie Cobbs * Enable debugging by defining ICHSMB_DEBUG to a non-zero value. 703c5656bfSArchie Cobbs */ 713c5656bfSArchie Cobbs #define ICHSMB_DEBUG 0 72a5f50ef9SJoerg Wunsch #if ICHSMB_DEBUG != 0 && defined(__CC_SUPPORTS___FUNC__) 733c5656bfSArchie Cobbs #define DBG(fmt, args...) \ 7485064e68SJohn Baldwin do { printf("%s: " fmt, __func__ , ## args); } while (0) 753c5656bfSArchie Cobbs #else 763c5656bfSArchie Cobbs #define DBG(fmt, args...) do { } while (0) 773c5656bfSArchie Cobbs #endif 783c5656bfSArchie Cobbs 793c5656bfSArchie Cobbs /* 803c5656bfSArchie Cobbs * Our child device driver name 813c5656bfSArchie Cobbs */ 823c5656bfSArchie Cobbs #define DRIVER_SMBUS "smbus" 833c5656bfSArchie Cobbs 843c5656bfSArchie Cobbs /* 853c5656bfSArchie Cobbs * Internal functions 863c5656bfSArchie Cobbs */ 873c5656bfSArchie Cobbs static int ichsmb_wait(sc_p sc); 883c5656bfSArchie Cobbs 893c5656bfSArchie Cobbs /******************************************************************** 903c5656bfSArchie Cobbs BUS-INDEPENDENT BUS METHODS 913c5656bfSArchie Cobbs ********************************************************************/ 923c5656bfSArchie Cobbs 933c5656bfSArchie Cobbs /* 943c5656bfSArchie Cobbs * Handle probe-time duties that are independent of the bus 953c5656bfSArchie Cobbs * our device lives on. 963c5656bfSArchie Cobbs */ 973c5656bfSArchie Cobbs int 983c5656bfSArchie Cobbs ichsmb_probe(device_t dev) 993c5656bfSArchie Cobbs { 100b77e575eSWarner Losh return (BUS_PROBE_DEFAULT); 1013c5656bfSArchie Cobbs } 1023c5656bfSArchie Cobbs 1033c5656bfSArchie Cobbs /* 1043c5656bfSArchie Cobbs * Handle attach-time duties that are independent of the bus 1053c5656bfSArchie Cobbs * our device lives on. 1063c5656bfSArchie Cobbs */ 1073c5656bfSArchie Cobbs int 1083c5656bfSArchie Cobbs ichsmb_attach(device_t dev) 1093c5656bfSArchie Cobbs { 1103c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1113c5656bfSArchie Cobbs int error; 1122e6e32daSTakanori Watanabe 11385064e68SJohn Baldwin /* Create mutex */ 11485064e68SJohn Baldwin mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF); 11585064e68SJohn Baldwin 1162e6e32daSTakanori Watanabe /* Add child: an instance of the "smbus" device */ 117fa6e2680SBrian Somers if ((sc->smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) { 11885064e68SJohn Baldwin device_printf(dev, "no \"%s\" child found\n", DRIVER_SMBUS); 11985064e68SJohn Baldwin error = ENXIO; 12085064e68SJohn Baldwin goto fail; 1212e6e32daSTakanori Watanabe } 1223c5656bfSArchie Cobbs 1233c5656bfSArchie Cobbs /* Clear interrupt conditions */ 1243c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, 0xff); 1253c5656bfSArchie Cobbs 12685064e68SJohn Baldwin /* Set up interrupt handler */ 12785064e68SJohn Baldwin error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, 12885064e68SJohn Baldwin ichsmb_device_intr, sc, &sc->irq_handle); 12985064e68SJohn Baldwin if (error != 0) { 13085064e68SJohn Baldwin device_printf(dev, "can't setup irq\n"); 13185064e68SJohn Baldwin goto fail; 1323c5656bfSArchie Cobbs } 1333c5656bfSArchie Cobbs 13485064e68SJohn Baldwin /* Attach "smbus" child */ 13585064e68SJohn Baldwin if ((error = bus_generic_attach(dev)) != 0) { 13685064e68SJohn Baldwin device_printf(dev, "failed to attach child: %d\n", error); 13785064e68SJohn Baldwin goto fail; 13885064e68SJohn Baldwin } 13985064e68SJohn Baldwin 1403a50ed55SArchie Cobbs return (0); 14185064e68SJohn Baldwin 14285064e68SJohn Baldwin fail: 14385064e68SJohn Baldwin mtx_destroy(&sc->mutex); 14485064e68SJohn Baldwin return (error); 1453c5656bfSArchie Cobbs } 1463c5656bfSArchie Cobbs 1473c5656bfSArchie Cobbs /******************************************************************** 1483c5656bfSArchie Cobbs SMBUS METHODS 1493c5656bfSArchie Cobbs ********************************************************************/ 1503c5656bfSArchie Cobbs 1513c5656bfSArchie Cobbs int 1527048a99cSJohn Baldwin ichsmb_callback(device_t dev, int index, void *data) 1533c5656bfSArchie Cobbs { 1543c5656bfSArchie Cobbs int smb_error = 0; 1553c5656bfSArchie Cobbs 1563c5656bfSArchie Cobbs DBG("index=%d how=%d\n", index, data ? *(int *)data : -1); 1573c5656bfSArchie Cobbs switch (index) { 1583c5656bfSArchie Cobbs case SMB_REQUEST_BUS: 1593c5656bfSArchie Cobbs break; 1603c5656bfSArchie Cobbs case SMB_RELEASE_BUS: 1613c5656bfSArchie Cobbs break; 1623c5656bfSArchie Cobbs default: 1633c5656bfSArchie Cobbs smb_error = SMB_EABORT; /* XXX */ 1643c5656bfSArchie Cobbs break; 1653c5656bfSArchie Cobbs } 1663c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1673c5656bfSArchie Cobbs return (smb_error); 1683c5656bfSArchie Cobbs } 1693c5656bfSArchie Cobbs 1703c5656bfSArchie Cobbs int 1713c5656bfSArchie Cobbs ichsmb_quick(device_t dev, u_char slave, int how) 1723c5656bfSArchie Cobbs { 1733c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1743c5656bfSArchie Cobbs int smb_error; 1753c5656bfSArchie Cobbs 1763c5656bfSArchie Cobbs DBG("slave=0x%02x how=%d\n", slave, how); 1773c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 1786e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 1793c5656bfSArchie Cobbs switch (how) { 1803c5656bfSArchie Cobbs case SMB_QREAD: 1813c5656bfSArchie Cobbs case SMB_QWRITE: 1829ed346baSBosko Milekic mtx_lock(&sc->mutex); 1833c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK; 1843c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 1853c5656bfSArchie Cobbs (slave << 1) | (how == SMB_QREAD ? 1863c5656bfSArchie Cobbs ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE)); 1873c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 1883c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 1893c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 1909ed346baSBosko Milekic mtx_unlock(&sc->mutex); 1913c5656bfSArchie Cobbs break; 1923c5656bfSArchie Cobbs default: 1933c5656bfSArchie Cobbs smb_error = SMB_ENOTSUPP; 1943c5656bfSArchie Cobbs } 1953c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1963c5656bfSArchie Cobbs return (smb_error); 1973c5656bfSArchie Cobbs } 1983c5656bfSArchie Cobbs 1993c5656bfSArchie Cobbs int 2003c5656bfSArchie Cobbs ichsmb_sendb(device_t dev, u_char slave, char byte) 2013c5656bfSArchie Cobbs { 2023c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2033c5656bfSArchie Cobbs int smb_error; 2043c5656bfSArchie Cobbs 2053c5656bfSArchie Cobbs DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte); 2063c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2076e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2089ed346baSBosko Milekic mtx_lock(&sc->mutex); 2093c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 2103c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2113c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2123c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, byte); 2133c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2143c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2153c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2169ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2173c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2183c5656bfSArchie Cobbs return (smb_error); 2193c5656bfSArchie Cobbs } 2203c5656bfSArchie Cobbs 2213c5656bfSArchie Cobbs int 2223c5656bfSArchie Cobbs ichsmb_recvb(device_t dev, u_char slave, char *byte) 2233c5656bfSArchie Cobbs { 2243c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2253c5656bfSArchie Cobbs int smb_error; 2263c5656bfSArchie Cobbs 2273c5656bfSArchie Cobbs DBG("slave=0x%02x\n", slave); 2283c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2296e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2309ed346baSBosko Milekic mtx_lock(&sc->mutex); 2313c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 2323c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2333c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 2343c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2353c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2363c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 2373c5656bfSArchie Cobbs *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 2389ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2393c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 2403c5656bfSArchie Cobbs return (smb_error); 2413c5656bfSArchie Cobbs } 2423c5656bfSArchie Cobbs 2433c5656bfSArchie Cobbs int 2443c5656bfSArchie Cobbs ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 2453c5656bfSArchie Cobbs { 2463c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2473c5656bfSArchie Cobbs int smb_error; 2483c5656bfSArchie Cobbs 2493c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n", 2503c5656bfSArchie Cobbs slave, (u_char)cmd, (u_char)byte); 2513c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2526e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2539ed346baSBosko Milekic mtx_lock(&sc->mutex); 2543c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 2553c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2563c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2573c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2583c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, byte); 2593c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2603c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2613c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2629ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2633c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2643c5656bfSArchie Cobbs return (smb_error); 2653c5656bfSArchie Cobbs } 2663c5656bfSArchie Cobbs 2673c5656bfSArchie Cobbs int 2683c5656bfSArchie Cobbs ichsmb_writew(device_t dev, u_char slave, char cmd, short word) 2693c5656bfSArchie Cobbs { 2703c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2713c5656bfSArchie Cobbs int smb_error; 2723c5656bfSArchie Cobbs 2733c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n", 2743c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)word); 2753c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2766e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2779ed346baSBosko Milekic mtx_lock(&sc->mutex); 2783c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 2793c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2803c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2813c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2823c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, word & 0xff); 2833c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, word >> 8); 2843c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2853c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2863c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2879ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2883c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2893c5656bfSArchie Cobbs return (smb_error); 2903c5656bfSArchie Cobbs } 2913c5656bfSArchie Cobbs 2923c5656bfSArchie Cobbs int 2933c5656bfSArchie Cobbs ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 2943c5656bfSArchie Cobbs { 2953c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2963c5656bfSArchie Cobbs int smb_error; 2973c5656bfSArchie Cobbs 2983c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 2993c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3006e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3019ed346baSBosko Milekic mtx_lock(&sc->mutex); 3023c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 3033c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3043c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 3053c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3063c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3073c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3083c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 3093c5656bfSArchie Cobbs *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 3109ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3113c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 3123c5656bfSArchie Cobbs return (smb_error); 3133c5656bfSArchie Cobbs } 3143c5656bfSArchie Cobbs 3153c5656bfSArchie Cobbs int 3163c5656bfSArchie Cobbs ichsmb_readw(device_t dev, u_char slave, char cmd, short *word) 3173c5656bfSArchie Cobbs { 3183c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3193c5656bfSArchie Cobbs int smb_error; 3203c5656bfSArchie Cobbs 3213c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 3223c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3236e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3249ed346baSBosko Milekic mtx_lock(&sc->mutex); 3253c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 3263c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3273c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 3283c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3293c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3303c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3313c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 3323c5656bfSArchie Cobbs *word = (bus_space_read_1(sc->io_bst, 3333c5656bfSArchie Cobbs sc->io_bsh, ICH_D0) & 0xff) 3343c5656bfSArchie Cobbs | (bus_space_read_1(sc->io_bst, 3353c5656bfSArchie Cobbs sc->io_bsh, ICH_D1) << 8); 3363c5656bfSArchie Cobbs } 3379ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3383c5656bfSArchie Cobbs DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word); 3393c5656bfSArchie Cobbs return (smb_error); 3403c5656bfSArchie Cobbs } 3413c5656bfSArchie Cobbs 3423c5656bfSArchie Cobbs int 3433c5656bfSArchie Cobbs ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 3443c5656bfSArchie Cobbs { 3453c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3463c5656bfSArchie Cobbs int smb_error; 3473c5656bfSArchie Cobbs 3483c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n", 3493c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)sdata); 3503c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3516e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3529ed346baSBosko Milekic mtx_lock(&sc->mutex); 3533c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL; 3543c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3553c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 3563c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3573c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, sdata & 0xff); 3583c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, sdata >> 8); 3593c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3603c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3613c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 3623c5656bfSArchie Cobbs *rdata = (bus_space_read_1(sc->io_bst, 3633c5656bfSArchie Cobbs sc->io_bsh, ICH_D0) & 0xff) 3643c5656bfSArchie Cobbs | (bus_space_read_1(sc->io_bst, 3653c5656bfSArchie Cobbs sc->io_bsh, ICH_D1) << 8); 3663c5656bfSArchie Cobbs } 3679ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3683c5656bfSArchie Cobbs DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata); 3693c5656bfSArchie Cobbs return (smb_error); 3703c5656bfSArchie Cobbs } 3713c5656bfSArchie Cobbs 3723c5656bfSArchie Cobbs int 3733c5656bfSArchie Cobbs ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 3743c5656bfSArchie Cobbs { 3753c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3763c5656bfSArchie Cobbs int smb_error; 3773c5656bfSArchie Cobbs 3783c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 3793c5656bfSArchie Cobbs #if ICHSMB_DEBUG 3803c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 3813c5656bfSArchie Cobbs { 3823c5656bfSArchie Cobbs u_char *p; 3833c5656bfSArchie Cobbs 3843c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 3853c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 3863c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 3873c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 3883c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 3893c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 3903c5656bfSArchie Cobbs } 3913c5656bfSArchie Cobbs } 3923c5656bfSArchie Cobbs #undef DISP 3933c5656bfSArchie Cobbs #endif 3943c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3956e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3963c5656bfSArchie Cobbs if (count < 1 || count > 32) 3977048a99cSJohn Baldwin return (SMB_EINVAL); 3983c5656bfSArchie Cobbs bcopy(buf, sc->block_data, count); 3993c5656bfSArchie Cobbs sc->block_count = count; 4003c5656bfSArchie Cobbs sc->block_index = 1; 4013c5656bfSArchie Cobbs sc->block_write = 1; 4023c5656bfSArchie Cobbs 4039ed346baSBosko Milekic mtx_lock(&sc->mutex); 4043c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 4053c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 4063c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 4073c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 4083c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); 4093c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_BLOCK_DB, buf[0]); 4103c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 4113c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4123c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 4139ed346baSBosko Milekic mtx_unlock(&sc->mutex); 4143c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4153c5656bfSArchie Cobbs return (smb_error); 4163c5656bfSArchie Cobbs } 4173c5656bfSArchie Cobbs 4183c5656bfSArchie Cobbs int 4197048a99cSJohn Baldwin ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 4203c5656bfSArchie Cobbs { 4213c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 4223c5656bfSArchie Cobbs int smb_error; 4233c5656bfSArchie Cobbs 4243c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 4253c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 4266e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 4277048a99cSJohn Baldwin if (*count < 1 || *count > 32) 4287048a99cSJohn Baldwin return (SMB_EINVAL); 4293c5656bfSArchie Cobbs bzero(sc->block_data, sizeof(sc->block_data)); 4307048a99cSJohn Baldwin sc->block_count = 0; 4313c5656bfSArchie Cobbs sc->block_index = 0; 4323c5656bfSArchie Cobbs sc->block_write = 0; 4333c5656bfSArchie Cobbs 4349ed346baSBosko Milekic mtx_lock(&sc->mutex); 4353c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 4363c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 4373c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 4383c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 4397048a99cSJohn Baldwin bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, *count); /* XXX? */ 4403c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 4413c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4427048a99cSJohn Baldwin if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 4437048a99cSJohn Baldwin bcopy(sc->block_data, buf, min(sc->block_count, *count)); 4447048a99cSJohn Baldwin *count = sc->block_count; 4457048a99cSJohn Baldwin } 4469ed346baSBosko Milekic mtx_unlock(&sc->mutex); 4473c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4483c5656bfSArchie Cobbs #if ICHSMB_DEBUG 4493c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 4503c5656bfSArchie Cobbs { 4513c5656bfSArchie Cobbs u_char *p; 4523c5656bfSArchie Cobbs 4533c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 4543c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 4553c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 4563c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 4573c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 4583c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 4593c5656bfSArchie Cobbs } 4603c5656bfSArchie Cobbs } 4613c5656bfSArchie Cobbs #undef DISP 4623c5656bfSArchie Cobbs #endif 4633c5656bfSArchie Cobbs return (smb_error); 4643c5656bfSArchie Cobbs } 4653c5656bfSArchie Cobbs 4663c5656bfSArchie Cobbs /******************************************************************** 4673c5656bfSArchie Cobbs OTHER FUNCTIONS 4683c5656bfSArchie Cobbs ********************************************************************/ 4693c5656bfSArchie Cobbs 4703c5656bfSArchie Cobbs /* 4713c5656bfSArchie Cobbs * This table describes what interrupts we should ever expect to 4723c5656bfSArchie Cobbs * see after each ICH command, not including the SMBALERT interrupt. 4733c5656bfSArchie Cobbs */ 4743c5656bfSArchie Cobbs static const u_int8_t ichsmb_state_irqs[] = { 4753c5656bfSArchie Cobbs /* quick */ 4763c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4773c5656bfSArchie Cobbs /* byte */ 4783c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4793c5656bfSArchie Cobbs /* byte data */ 4803c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4813c5656bfSArchie Cobbs /* word data */ 4823c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4833c5656bfSArchie Cobbs /* process call */ 4843c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4853c5656bfSArchie Cobbs /* block */ 4863c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 4873c5656bfSArchie Cobbs | ICH_HST_STA_BYTE_DONE_STS), 4883c5656bfSArchie Cobbs /* i2c read (not used) */ 4893c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 4903c5656bfSArchie Cobbs | ICH_HST_STA_BYTE_DONE_STS) 4913c5656bfSArchie Cobbs }; 4923c5656bfSArchie Cobbs 4933c5656bfSArchie Cobbs /* 4943c5656bfSArchie Cobbs * Interrupt handler. This handler is bus-independent. Note that our 4953c5656bfSArchie Cobbs * interrupt may be shared, so we must handle "false" interrupts. 4963c5656bfSArchie Cobbs */ 4973c5656bfSArchie Cobbs void 4983c5656bfSArchie Cobbs ichsmb_device_intr(void *cookie) 4993c5656bfSArchie Cobbs { 5003c5656bfSArchie Cobbs const sc_p sc = cookie; 5013c5656bfSArchie Cobbs const device_t dev = sc->dev; 5023c5656bfSArchie Cobbs const int maxloops = 16; 5033c5656bfSArchie Cobbs u_int8_t status; 5043c5656bfSArchie Cobbs u_int8_t ok_bits; 5053c5656bfSArchie Cobbs int cmd_index; 5063c5656bfSArchie Cobbs int count; 5073c5656bfSArchie Cobbs 5089ed346baSBosko Milekic mtx_lock(&sc->mutex); 5093c5656bfSArchie Cobbs for (count = 0; count < maxloops; count++) { 5103c5656bfSArchie Cobbs 5113c5656bfSArchie Cobbs /* Get and reset status bits */ 5123c5656bfSArchie Cobbs status = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA); 5133c5656bfSArchie Cobbs #if ICHSMB_DEBUG 5143c5656bfSArchie Cobbs if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY)) 5153c5656bfSArchie Cobbs || count > 0) { 5163c5656bfSArchie Cobbs DBG("%d stat=0x%02x\n", count, status); 5173c5656bfSArchie Cobbs } 5183c5656bfSArchie Cobbs #endif 5193c5656bfSArchie Cobbs status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY); 5203c5656bfSArchie Cobbs if (status == 0) 5213c5656bfSArchie Cobbs break; 5223c5656bfSArchie Cobbs 5233c5656bfSArchie Cobbs /* Check for unexpected interrupt */ 5243c5656bfSArchie Cobbs ok_bits = ICH_HST_STA_SMBALERT_STS; 5253c5656bfSArchie Cobbs cmd_index = sc->ich_cmd >> 2; 5263c5656bfSArchie Cobbs if (sc->ich_cmd != -1) { 5273c5656bfSArchie Cobbs KASSERT(cmd_index < sizeof(ichsmb_state_irqs), 5283c5656bfSArchie Cobbs ("%s: ich_cmd=%d", device_get_nameunit(dev), 5293c5656bfSArchie Cobbs sc->ich_cmd)); 5303c5656bfSArchie Cobbs ok_bits |= ichsmb_state_irqs[cmd_index]; 5313c5656bfSArchie Cobbs } 5323c5656bfSArchie Cobbs if ((status & ~ok_bits) != 0) { 53385064e68SJohn Baldwin device_printf(dev, "irq 0x%02x during %d\n", status, 53485064e68SJohn Baldwin cmd_index); 5353c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, 5363c5656bfSArchie Cobbs ICH_HST_STA, (status & ~ok_bits)); 5373c5656bfSArchie Cobbs continue; 5383c5656bfSArchie Cobbs } 5393c5656bfSArchie Cobbs 5403c5656bfSArchie Cobbs /* Handle SMBALERT interrupt */ 5413c5656bfSArchie Cobbs if (status & ICH_HST_STA_SMBALERT_STS) { 5423c5656bfSArchie Cobbs static int smbalert_count = 16; 5433c5656bfSArchie Cobbs if (smbalert_count > 0) { 54485064e68SJohn Baldwin device_printf(dev, "SMBALERT# rec'd\n"); 5453c5656bfSArchie Cobbs if (--smbalert_count == 0) { 54685064e68SJohn Baldwin device_printf(dev, 54785064e68SJohn Baldwin "not logging anymore\n"); 5483c5656bfSArchie Cobbs } 5493c5656bfSArchie Cobbs } 5503c5656bfSArchie Cobbs } 5513c5656bfSArchie Cobbs 5523c5656bfSArchie Cobbs /* Check for bus error */ 5533c5656bfSArchie Cobbs if (status & ICH_HST_STA_BUS_ERR) { 5543c5656bfSArchie Cobbs sc->smb_error = SMB_ECOLLI; /* XXX SMB_EBUSERR? */ 5553c5656bfSArchie Cobbs goto finished; 5563c5656bfSArchie Cobbs } 5573c5656bfSArchie Cobbs 5583c5656bfSArchie Cobbs /* Check for device error */ 5593c5656bfSArchie Cobbs if (status & ICH_HST_STA_DEV_ERR) { 5603c5656bfSArchie Cobbs sc->smb_error = SMB_ENOACK; /* or SMB_ETIMEOUT? */ 5613c5656bfSArchie Cobbs goto finished; 5623c5656bfSArchie Cobbs } 5633c5656bfSArchie Cobbs 5643c5656bfSArchie Cobbs /* Check for byte completion in block transfer */ 5653c5656bfSArchie Cobbs if (status & ICH_HST_STA_BYTE_DONE_STS) { 5663c5656bfSArchie Cobbs if (sc->block_write) { 5673c5656bfSArchie Cobbs if (sc->block_index < sc->block_count) { 5683c5656bfSArchie Cobbs 5693c5656bfSArchie Cobbs /* Write next byte */ 5703c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, 5713c5656bfSArchie Cobbs sc->io_bsh, ICH_BLOCK_DB, 5723c5656bfSArchie Cobbs sc->block_data[sc->block_index++]); 5733c5656bfSArchie Cobbs } 5743c5656bfSArchie Cobbs } else { 5753c5656bfSArchie Cobbs 5763c5656bfSArchie Cobbs /* First interrupt, get the count also */ 5773c5656bfSArchie Cobbs if (sc->block_index == 0) { 5783c5656bfSArchie Cobbs sc->block_count = bus_space_read_1( 5793c5656bfSArchie Cobbs sc->io_bst, sc->io_bsh, ICH_D0); 5803c5656bfSArchie Cobbs } 5813c5656bfSArchie Cobbs 5823c5656bfSArchie Cobbs /* Get next byte, if any */ 5833c5656bfSArchie Cobbs if (sc->block_index < sc->block_count) { 5843c5656bfSArchie Cobbs 5853c5656bfSArchie Cobbs /* Read next byte */ 5863c5656bfSArchie Cobbs sc->block_data[sc->block_index++] = 5873c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, 5883c5656bfSArchie Cobbs sc->io_bsh, ICH_BLOCK_DB); 5893c5656bfSArchie Cobbs 5903c5656bfSArchie Cobbs /* Set "LAST_BYTE" bit before reading 5913c5656bfSArchie Cobbs the last byte of block data */ 5923c5656bfSArchie Cobbs if (sc->block_index 5933c5656bfSArchie Cobbs >= sc->block_count - 1) { 5943c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, 5953c5656bfSArchie Cobbs sc->io_bsh, ICH_HST_CNT, 5963c5656bfSArchie Cobbs ICH_HST_CNT_LAST_BYTE 5973c5656bfSArchie Cobbs | ICH_HST_CNT_INTREN 5983c5656bfSArchie Cobbs | sc->ich_cmd); 5993c5656bfSArchie Cobbs } 6003c5656bfSArchie Cobbs } 6013c5656bfSArchie Cobbs } 6023c5656bfSArchie Cobbs } 6033c5656bfSArchie Cobbs 6043c5656bfSArchie Cobbs /* Check command completion */ 6053c5656bfSArchie Cobbs if (status & ICH_HST_STA_INTR) { 6063c5656bfSArchie Cobbs sc->smb_error = SMB_ENOERR; 6073c5656bfSArchie Cobbs finished: 6083c5656bfSArchie Cobbs sc->ich_cmd = -1; 6093c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, 6103c5656bfSArchie Cobbs ICH_HST_STA, status); 6113c5656bfSArchie Cobbs wakeup(sc); 6123c5656bfSArchie Cobbs break; 6133c5656bfSArchie Cobbs } 6143c5656bfSArchie Cobbs 6153c5656bfSArchie Cobbs /* Clear status bits and try again */ 6163c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, status); 6173c5656bfSArchie Cobbs } 6189ed346baSBosko Milekic mtx_unlock(&sc->mutex); 6193c5656bfSArchie Cobbs 6203c5656bfSArchie Cobbs /* Too many loops? */ 6213c5656bfSArchie Cobbs if (count == maxloops) { 62285064e68SJohn Baldwin device_printf(dev, "interrupt loop, status=0x%02x\n", 6233c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 6243c5656bfSArchie Cobbs } 6253c5656bfSArchie Cobbs } 6263c5656bfSArchie Cobbs 6273c5656bfSArchie Cobbs /* 6283a50ed55SArchie Cobbs * Wait for command completion. Assumes mutex is held. 6293c5656bfSArchie Cobbs * Returns an SMB_* error code. 6303c5656bfSArchie Cobbs */ 6313c5656bfSArchie Cobbs static int 6323c5656bfSArchie Cobbs ichsmb_wait(sc_p sc) 6333c5656bfSArchie Cobbs { 6343c5656bfSArchie Cobbs const device_t dev = sc->dev; 6353c5656bfSArchie Cobbs int error, smb_error; 6363c5656bfSArchie Cobbs 6373c5656bfSArchie Cobbs KASSERT(sc->ich_cmd != -1, 6386e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 6393a50ed55SArchie Cobbs mtx_assert(&sc->mutex, MA_OWNED); 6400d107412SBrian Somers error = msleep(sc, &sc->mutex, PZERO, "ichsmb", hz / 4); 6413a50ed55SArchie Cobbs DBG("msleep -> %d\n", error); 6423c5656bfSArchie Cobbs switch (error) { 6433c5656bfSArchie Cobbs case 0: 6443c5656bfSArchie Cobbs smb_error = sc->smb_error; 6453c5656bfSArchie Cobbs break; 6463c5656bfSArchie Cobbs case EWOULDBLOCK: 64785064e68SJohn Baldwin device_printf(dev, "device timeout, status=0x%02x\n", 6483c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 6493c5656bfSArchie Cobbs sc->ich_cmd = -1; 6503c5656bfSArchie Cobbs smb_error = SMB_ETIMEOUT; 6513c5656bfSArchie Cobbs break; 6523c5656bfSArchie Cobbs default: 6533c5656bfSArchie Cobbs smb_error = SMB_EABORT; 6543c5656bfSArchie Cobbs break; 6553c5656bfSArchie Cobbs } 6563c5656bfSArchie Cobbs return (smb_error); 6573c5656bfSArchie Cobbs } 6583c5656bfSArchie Cobbs 6593c5656bfSArchie Cobbs /* 6603c5656bfSArchie Cobbs * Release resources associated with device. 6613c5656bfSArchie Cobbs */ 6623c5656bfSArchie Cobbs void 6633c5656bfSArchie Cobbs ichsmb_release_resources(sc_p sc) 6643c5656bfSArchie Cobbs { 6653c5656bfSArchie Cobbs const device_t dev = sc->dev; 6663c5656bfSArchie Cobbs 6673c5656bfSArchie Cobbs if (sc->irq_handle != NULL) { 6683c5656bfSArchie Cobbs bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 6693c5656bfSArchie Cobbs sc->irq_handle = NULL; 6703c5656bfSArchie Cobbs } 6713c5656bfSArchie Cobbs if (sc->irq_res != NULL) { 6723c5656bfSArchie Cobbs bus_release_resource(dev, 6733c5656bfSArchie Cobbs SYS_RES_IRQ, sc->irq_rid, sc->irq_res); 6743c5656bfSArchie Cobbs sc->irq_res = NULL; 6753c5656bfSArchie Cobbs } 6763c5656bfSArchie Cobbs if (sc->io_res != NULL) { 6773c5656bfSArchie Cobbs bus_release_resource(dev, 6783c5656bfSArchie Cobbs SYS_RES_IOPORT, sc->io_rid, sc->io_res); 6793c5656bfSArchie Cobbs sc->io_res = NULL; 6803c5656bfSArchie Cobbs } 6813c5656bfSArchie Cobbs } 6823c5656bfSArchie Cobbs 6837048a99cSJohn Baldwin int 6847048a99cSJohn Baldwin ichsmb_detach(device_t dev) 6852e6e32daSTakanori Watanabe { 6862e6e32daSTakanori Watanabe const sc_p sc = device_get_softc(dev); 6877048a99cSJohn Baldwin int error; 688fa6e2680SBrian Somers 6897048a99cSJohn Baldwin error = bus_generic_detach(dev); 6907048a99cSJohn Baldwin if (error) 6917048a99cSJohn Baldwin return (error); 6922e6e32daSTakanori Watanabe device_delete_child(dev, sc->smb); 6932e6e32daSTakanori Watanabe ichsmb_release_resources(sc); 6947048a99cSJohn Baldwin mtx_destroy(&sc->mutex); 6952e6e32daSTakanori Watanabe 6962e6e32daSTakanori Watanabe return 0; 6972e6e32daSTakanori Watanabe } 6987048a99cSJohn Baldwin 6997048a99cSJohn Baldwin DRIVER_MODULE(smbus, ichsmb, smbus_driver, smbus_devclass, 0, 0); 700