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> 543a50ed55SArchie Cobbs #include <sys/mutex.h> 553c5656bfSArchie Cobbs #include <sys/syslog.h> 563c5656bfSArchie Cobbs #include <sys/bus.h> 573c5656bfSArchie Cobbs 583c5656bfSArchie Cobbs #include <machine/bus.h> 593c5656bfSArchie Cobbs #include <sys/rman.h> 603c5656bfSArchie Cobbs #include <machine/resource.h> 613c5656bfSArchie Cobbs 623c5656bfSArchie Cobbs #include <dev/smbus/smbconf.h> 633c5656bfSArchie Cobbs 643c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_var.h> 653c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_reg.h> 663c5656bfSArchie Cobbs 673c5656bfSArchie Cobbs /* 683c5656bfSArchie Cobbs * Enable debugging by defining ICHSMB_DEBUG to a non-zero value. 693c5656bfSArchie Cobbs */ 703c5656bfSArchie Cobbs #define ICHSMB_DEBUG 0 71a5f50ef9SJoerg Wunsch #if ICHSMB_DEBUG != 0 && defined(__CC_SUPPORTS___FUNC__) 723c5656bfSArchie Cobbs #define DBG(fmt, args...) \ 736e551fb6SDavid E. O'Brien do { log(LOG_DEBUG, "%s: " fmt, __func__ , ## args); } while (0) 743c5656bfSArchie Cobbs #else 753c5656bfSArchie Cobbs #define DBG(fmt, args...) do { } while (0) 763c5656bfSArchie Cobbs #endif 773c5656bfSArchie Cobbs 783c5656bfSArchie Cobbs /* 793c5656bfSArchie Cobbs * Our child device driver name 803c5656bfSArchie Cobbs */ 813c5656bfSArchie Cobbs #define DRIVER_SMBUS "smbus" 823c5656bfSArchie Cobbs 833c5656bfSArchie Cobbs /* 843c5656bfSArchie Cobbs * Internal functions 853c5656bfSArchie Cobbs */ 863c5656bfSArchie Cobbs static int ichsmb_wait(sc_p sc); 873c5656bfSArchie Cobbs 883c5656bfSArchie Cobbs /******************************************************************** 893c5656bfSArchie Cobbs BUS-INDEPENDENT BUS METHODS 903c5656bfSArchie Cobbs ********************************************************************/ 913c5656bfSArchie Cobbs 923c5656bfSArchie Cobbs /* 933c5656bfSArchie Cobbs * Handle probe-time duties that are independent of the bus 943c5656bfSArchie Cobbs * our device lives on. 953c5656bfSArchie Cobbs */ 963c5656bfSArchie Cobbs int 973c5656bfSArchie Cobbs ichsmb_probe(device_t dev) 983c5656bfSArchie Cobbs { 99b77e575eSWarner Losh return (BUS_PROBE_DEFAULT); 1003c5656bfSArchie Cobbs } 1013c5656bfSArchie Cobbs 1023c5656bfSArchie Cobbs /* 1033c5656bfSArchie Cobbs * Handle attach-time duties that are independent of the bus 1043c5656bfSArchie Cobbs * our device lives on. 1053c5656bfSArchie Cobbs */ 1063c5656bfSArchie Cobbs int 1073c5656bfSArchie Cobbs ichsmb_attach(device_t dev) 1083c5656bfSArchie Cobbs { 1093c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1103c5656bfSArchie Cobbs int error; 1112e6e32daSTakanori Watanabe device_t smb; 1122e6e32daSTakanori Watanabe 1132e6e32daSTakanori Watanabe /* Add child: an instance of the "smbus" device */ 1142e6e32daSTakanori Watanabe if ((smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) { 1152e6e32daSTakanori Watanabe log(LOG_ERR, "%s: no \"%s\" child found\n", 1162e6e32daSTakanori Watanabe device_get_nameunit(dev), DRIVER_SMBUS); 1172e6e32daSTakanori Watanabe return (ENXIO); 1182e6e32daSTakanori Watanabe } 1193c5656bfSArchie Cobbs 1203c5656bfSArchie Cobbs /* Clear interrupt conditions */ 1213c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, 0xff); 1223c5656bfSArchie Cobbs 1233c5656bfSArchie Cobbs /* Add "smbus" child */ 1243c5656bfSArchie Cobbs if ((error = bus_generic_attach(dev)) != 0) { 1253c5656bfSArchie Cobbs log(LOG_ERR, "%s: failed to attach child: %d\n", 1263c5656bfSArchie Cobbs device_get_nameunit(dev), error); 1273a50ed55SArchie Cobbs return (ENXIO); 1283c5656bfSArchie Cobbs } 1293c5656bfSArchie Cobbs 1303a50ed55SArchie Cobbs /* Create mutex */ 1316008862bSJohn Baldwin mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF); 1323a50ed55SArchie Cobbs return (0); 1333c5656bfSArchie Cobbs } 1343c5656bfSArchie Cobbs 1353c5656bfSArchie Cobbs /******************************************************************** 1363c5656bfSArchie Cobbs SMBUS METHODS 1373c5656bfSArchie Cobbs ********************************************************************/ 1383c5656bfSArchie Cobbs 1393c5656bfSArchie Cobbs int 1403c5656bfSArchie Cobbs ichsmb_callback(device_t dev, int index, caddr_t data) 1413c5656bfSArchie Cobbs { 1423c5656bfSArchie Cobbs int smb_error = 0; 1433c5656bfSArchie Cobbs 1443c5656bfSArchie Cobbs DBG("index=%d how=%d\n", index, data ? *(int *)data : -1); 1453c5656bfSArchie Cobbs switch (index) { 1463c5656bfSArchie Cobbs case SMB_REQUEST_BUS: 1473c5656bfSArchie Cobbs break; 1483c5656bfSArchie Cobbs case SMB_RELEASE_BUS: 1493c5656bfSArchie Cobbs break; 1503c5656bfSArchie Cobbs default: 1513c5656bfSArchie Cobbs smb_error = SMB_EABORT; /* XXX */ 1523c5656bfSArchie Cobbs break; 1533c5656bfSArchie Cobbs } 1543c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1553c5656bfSArchie Cobbs return (smb_error); 1563c5656bfSArchie Cobbs } 1573c5656bfSArchie Cobbs 1583c5656bfSArchie Cobbs int 1593c5656bfSArchie Cobbs ichsmb_quick(device_t dev, u_char slave, int how) 1603c5656bfSArchie Cobbs { 1613c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1623c5656bfSArchie Cobbs int smb_error; 1633c5656bfSArchie Cobbs 1643c5656bfSArchie Cobbs DBG("slave=0x%02x how=%d\n", slave, how); 1653c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 1666e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 1673c5656bfSArchie Cobbs switch (how) { 1683c5656bfSArchie Cobbs case SMB_QREAD: 1693c5656bfSArchie Cobbs case SMB_QWRITE: 1709ed346baSBosko Milekic mtx_lock(&sc->mutex); 1713c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK; 1723c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 1733c5656bfSArchie Cobbs (slave << 1) | (how == SMB_QREAD ? 1743c5656bfSArchie Cobbs ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE)); 1753c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 1763c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 1773c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 1789ed346baSBosko Milekic mtx_unlock(&sc->mutex); 1793c5656bfSArchie Cobbs break; 1803c5656bfSArchie Cobbs default: 1813c5656bfSArchie Cobbs smb_error = SMB_ENOTSUPP; 1823c5656bfSArchie Cobbs } 1833c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1843c5656bfSArchie Cobbs return (smb_error); 1853c5656bfSArchie Cobbs } 1863c5656bfSArchie Cobbs 1873c5656bfSArchie Cobbs int 1883c5656bfSArchie Cobbs ichsmb_sendb(device_t dev, u_char slave, char byte) 1893c5656bfSArchie Cobbs { 1903c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1913c5656bfSArchie Cobbs int smb_error; 1923c5656bfSArchie Cobbs 1933c5656bfSArchie Cobbs DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte); 1943c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 1956e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 1969ed346baSBosko Milekic mtx_lock(&sc->mutex); 1973c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 1983c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 1993c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2003c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, byte); 2013c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2023c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2033c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2049ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2053c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2063c5656bfSArchie Cobbs return (smb_error); 2073c5656bfSArchie Cobbs } 2083c5656bfSArchie Cobbs 2093c5656bfSArchie Cobbs int 2103c5656bfSArchie Cobbs ichsmb_recvb(device_t dev, u_char slave, char *byte) 2113c5656bfSArchie Cobbs { 2123c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2133c5656bfSArchie Cobbs int smb_error; 2143c5656bfSArchie Cobbs 2153c5656bfSArchie Cobbs DBG("slave=0x%02x\n", slave); 2163c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2176e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2189ed346baSBosko Milekic mtx_lock(&sc->mutex); 2193c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 2203c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2213c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 2223c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2233c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2243c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 2253c5656bfSArchie Cobbs *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 2269ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2273c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 2283c5656bfSArchie Cobbs return (smb_error); 2293c5656bfSArchie Cobbs } 2303c5656bfSArchie Cobbs 2313c5656bfSArchie Cobbs int 2323c5656bfSArchie Cobbs ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 2333c5656bfSArchie Cobbs { 2343c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2353c5656bfSArchie Cobbs int smb_error; 2363c5656bfSArchie Cobbs 2373c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n", 2383c5656bfSArchie Cobbs slave, (u_char)cmd, (u_char)byte); 2393c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2406e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2419ed346baSBosko Milekic mtx_lock(&sc->mutex); 2423c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 2433c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2443c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2453c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2463c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, byte); 2473c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2483c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2493c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2509ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2513c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2523c5656bfSArchie Cobbs return (smb_error); 2533c5656bfSArchie Cobbs } 2543c5656bfSArchie Cobbs 2553c5656bfSArchie Cobbs int 2563c5656bfSArchie Cobbs ichsmb_writew(device_t dev, u_char slave, char cmd, short word) 2573c5656bfSArchie Cobbs { 2583c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2593c5656bfSArchie Cobbs int smb_error; 2603c5656bfSArchie Cobbs 2613c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n", 2623c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)word); 2633c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2646e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2659ed346baSBosko Milekic mtx_lock(&sc->mutex); 2663c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 2673c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2683c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2693c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2703c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, word & 0xff); 2713c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, word >> 8); 2723c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2733c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2743c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2759ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2763c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2773c5656bfSArchie Cobbs return (smb_error); 2783c5656bfSArchie Cobbs } 2793c5656bfSArchie Cobbs 2803c5656bfSArchie Cobbs int 2813c5656bfSArchie Cobbs ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 2823c5656bfSArchie Cobbs { 2833c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2843c5656bfSArchie Cobbs int smb_error; 2853c5656bfSArchie Cobbs 2863c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 2873c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2886e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2899ed346baSBosko Milekic mtx_lock(&sc->mutex); 2903c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 2913c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2923c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 2933c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2943c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2953c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2963c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 2973c5656bfSArchie Cobbs *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 2989ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2993c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 3003c5656bfSArchie Cobbs return (smb_error); 3013c5656bfSArchie Cobbs } 3023c5656bfSArchie Cobbs 3033c5656bfSArchie Cobbs int 3043c5656bfSArchie Cobbs ichsmb_readw(device_t dev, u_char slave, char cmd, short *word) 3053c5656bfSArchie Cobbs { 3063c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3073c5656bfSArchie Cobbs int smb_error; 3083c5656bfSArchie Cobbs 3093c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 3103c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3116e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3129ed346baSBosko Milekic mtx_lock(&sc->mutex); 3133c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 3143c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3153c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 3163c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3173c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3183c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3193c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 3203c5656bfSArchie Cobbs *word = (bus_space_read_1(sc->io_bst, 3213c5656bfSArchie Cobbs sc->io_bsh, ICH_D0) & 0xff) 3223c5656bfSArchie Cobbs | (bus_space_read_1(sc->io_bst, 3233c5656bfSArchie Cobbs sc->io_bsh, ICH_D1) << 8); 3243c5656bfSArchie Cobbs } 3259ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3263c5656bfSArchie Cobbs DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word); 3273c5656bfSArchie Cobbs return (smb_error); 3283c5656bfSArchie Cobbs } 3293c5656bfSArchie Cobbs 3303c5656bfSArchie Cobbs int 3313c5656bfSArchie Cobbs ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 3323c5656bfSArchie Cobbs { 3333c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3343c5656bfSArchie Cobbs int smb_error; 3353c5656bfSArchie Cobbs 3363c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n", 3373c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)sdata); 3383c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3396e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3409ed346baSBosko Milekic mtx_lock(&sc->mutex); 3413c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL; 3423c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3433c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 3443c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3453c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, sdata & 0xff); 3463c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, sdata >> 8); 3473c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3483c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3493c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 3503c5656bfSArchie Cobbs *rdata = (bus_space_read_1(sc->io_bst, 3513c5656bfSArchie Cobbs sc->io_bsh, ICH_D0) & 0xff) 3523c5656bfSArchie Cobbs | (bus_space_read_1(sc->io_bst, 3533c5656bfSArchie Cobbs sc->io_bsh, ICH_D1) << 8); 3543c5656bfSArchie Cobbs } 3559ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3563c5656bfSArchie Cobbs DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata); 3573c5656bfSArchie Cobbs return (smb_error); 3583c5656bfSArchie Cobbs } 3593c5656bfSArchie Cobbs 3603c5656bfSArchie Cobbs int 3613c5656bfSArchie Cobbs ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 3623c5656bfSArchie Cobbs { 3633c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3643c5656bfSArchie Cobbs int smb_error; 3653c5656bfSArchie Cobbs 3663c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 3673c5656bfSArchie Cobbs #if ICHSMB_DEBUG 3683c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 3693c5656bfSArchie Cobbs { 3703c5656bfSArchie Cobbs u_char *p; 3713c5656bfSArchie Cobbs 3723c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 3733c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 3743c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 3753c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 3763c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 3773c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 3783c5656bfSArchie Cobbs } 3793c5656bfSArchie Cobbs } 3803c5656bfSArchie Cobbs #undef DISP 3813c5656bfSArchie Cobbs #endif 3823c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3836e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3843c5656bfSArchie Cobbs if (count < 1 || count > 32) 3853c5656bfSArchie Cobbs return (EINVAL); 3863c5656bfSArchie Cobbs bcopy(buf, sc->block_data, count); 3873c5656bfSArchie Cobbs sc->block_count = count; 3883c5656bfSArchie Cobbs sc->block_index = 1; 3893c5656bfSArchie Cobbs sc->block_write = 1; 3903c5656bfSArchie Cobbs 3919ed346baSBosko Milekic mtx_lock(&sc->mutex); 3923c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 3933c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3943c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 3953c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3963c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); 3973c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_BLOCK_DB, buf[0]); 3983c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3993c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4003c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 4019ed346baSBosko Milekic mtx_unlock(&sc->mutex); 4023c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4033c5656bfSArchie Cobbs return (smb_error); 4043c5656bfSArchie Cobbs } 4053c5656bfSArchie Cobbs 4063c5656bfSArchie Cobbs int 4073c5656bfSArchie Cobbs ichsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 4083c5656bfSArchie Cobbs { 4093c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 4103c5656bfSArchie Cobbs int smb_error; 4113c5656bfSArchie Cobbs 4123c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 4133c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 4146e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 4153c5656bfSArchie Cobbs if (count < 1 || count > 32) 4163c5656bfSArchie Cobbs return (EINVAL); 4173c5656bfSArchie Cobbs bzero(sc->block_data, sizeof(sc->block_data)); 4183c5656bfSArchie Cobbs sc->block_count = count; 4193c5656bfSArchie Cobbs sc->block_index = 0; 4203c5656bfSArchie Cobbs sc->block_write = 0; 4213c5656bfSArchie Cobbs 4229ed346baSBosko Milekic mtx_lock(&sc->mutex); 4233c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 4243c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 4253c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 4263c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 4273c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); /* XXX? */ 4283c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 4293c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4303c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 4313c5656bfSArchie Cobbs bcopy(sc->block_data, buf, sc->block_count); 4329ed346baSBosko Milekic mtx_unlock(&sc->mutex); 4333c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4343c5656bfSArchie Cobbs #if ICHSMB_DEBUG 4353c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 4363c5656bfSArchie Cobbs { 4373c5656bfSArchie Cobbs u_char *p; 4383c5656bfSArchie Cobbs 4393c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 4403c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 4413c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 4423c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 4433c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 4443c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 4453c5656bfSArchie Cobbs } 4463c5656bfSArchie Cobbs } 4473c5656bfSArchie Cobbs #undef DISP 4483c5656bfSArchie Cobbs #endif 4493c5656bfSArchie Cobbs return (smb_error); 4503c5656bfSArchie Cobbs } 4513c5656bfSArchie Cobbs 4523c5656bfSArchie Cobbs /******************************************************************** 4533c5656bfSArchie Cobbs OTHER FUNCTIONS 4543c5656bfSArchie Cobbs ********************************************************************/ 4553c5656bfSArchie Cobbs 4563c5656bfSArchie Cobbs /* 4573c5656bfSArchie Cobbs * This table describes what interrupts we should ever expect to 4583c5656bfSArchie Cobbs * see after each ICH command, not including the SMBALERT interrupt. 4593c5656bfSArchie Cobbs */ 4603c5656bfSArchie Cobbs static const u_int8_t ichsmb_state_irqs[] = { 4613c5656bfSArchie Cobbs /* quick */ 4623c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4633c5656bfSArchie Cobbs /* byte */ 4643c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4653c5656bfSArchie Cobbs /* byte data */ 4663c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4673c5656bfSArchie Cobbs /* word data */ 4683c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4693c5656bfSArchie Cobbs /* process call */ 4703c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4713c5656bfSArchie Cobbs /* block */ 4723c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 4733c5656bfSArchie Cobbs | ICH_HST_STA_BYTE_DONE_STS), 4743c5656bfSArchie Cobbs /* i2c read (not used) */ 4753c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 4763c5656bfSArchie Cobbs | ICH_HST_STA_BYTE_DONE_STS) 4773c5656bfSArchie Cobbs }; 4783c5656bfSArchie Cobbs 4793c5656bfSArchie Cobbs /* 4803c5656bfSArchie Cobbs * Interrupt handler. This handler is bus-independent. Note that our 4813c5656bfSArchie Cobbs * interrupt may be shared, so we must handle "false" interrupts. 4823c5656bfSArchie Cobbs */ 4833c5656bfSArchie Cobbs void 4843c5656bfSArchie Cobbs ichsmb_device_intr(void *cookie) 4853c5656bfSArchie Cobbs { 4863c5656bfSArchie Cobbs const sc_p sc = cookie; 4873c5656bfSArchie Cobbs const device_t dev = sc->dev; 4883c5656bfSArchie Cobbs const int maxloops = 16; 4893c5656bfSArchie Cobbs u_int8_t status; 4903c5656bfSArchie Cobbs u_int8_t ok_bits; 4913c5656bfSArchie Cobbs int cmd_index; 4923c5656bfSArchie Cobbs int count; 4933c5656bfSArchie Cobbs 4949ed346baSBosko Milekic mtx_lock(&sc->mutex); 4953c5656bfSArchie Cobbs for (count = 0; count < maxloops; count++) { 4963c5656bfSArchie Cobbs 4973c5656bfSArchie Cobbs /* Get and reset status bits */ 4983c5656bfSArchie Cobbs status = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA); 4993c5656bfSArchie Cobbs #if ICHSMB_DEBUG 5003c5656bfSArchie Cobbs if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY)) 5013c5656bfSArchie Cobbs || count > 0) { 5023c5656bfSArchie Cobbs DBG("%d stat=0x%02x\n", count, status); 5033c5656bfSArchie Cobbs } 5043c5656bfSArchie Cobbs #endif 5053c5656bfSArchie Cobbs status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY); 5063c5656bfSArchie Cobbs if (status == 0) 5073c5656bfSArchie Cobbs break; 5083c5656bfSArchie Cobbs 5093c5656bfSArchie Cobbs /* Check for unexpected interrupt */ 5103c5656bfSArchie Cobbs ok_bits = ICH_HST_STA_SMBALERT_STS; 5113c5656bfSArchie Cobbs cmd_index = sc->ich_cmd >> 2; 5123c5656bfSArchie Cobbs if (sc->ich_cmd != -1) { 5133c5656bfSArchie Cobbs KASSERT(cmd_index < sizeof(ichsmb_state_irqs), 5143c5656bfSArchie Cobbs ("%s: ich_cmd=%d", device_get_nameunit(dev), 5153c5656bfSArchie Cobbs sc->ich_cmd)); 5163c5656bfSArchie Cobbs ok_bits |= ichsmb_state_irqs[cmd_index]; 5173c5656bfSArchie Cobbs } 5183c5656bfSArchie Cobbs if ((status & ~ok_bits) != 0) { 5193c5656bfSArchie Cobbs log(LOG_ERR, "%s: irq 0x%02x during %d\n", 5203c5656bfSArchie Cobbs device_get_nameunit(dev), status, cmd_index); 5213c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, 5223c5656bfSArchie Cobbs ICH_HST_STA, (status & ~ok_bits)); 5233c5656bfSArchie Cobbs continue; 5243c5656bfSArchie Cobbs } 5253c5656bfSArchie Cobbs 5263c5656bfSArchie Cobbs /* Handle SMBALERT interrupt */ 5273c5656bfSArchie Cobbs if (status & ICH_HST_STA_SMBALERT_STS) { 5283c5656bfSArchie Cobbs static int smbalert_count = 16; 5293c5656bfSArchie Cobbs if (smbalert_count > 0) { 5303c5656bfSArchie Cobbs log(LOG_WARNING, "%s: SMBALERT# rec'd\n", 5313c5656bfSArchie Cobbs device_get_nameunit(dev)); 5323c5656bfSArchie Cobbs if (--smbalert_count == 0) { 5333c5656bfSArchie Cobbs log(LOG_WARNING, 5343c5656bfSArchie Cobbs "%s: not logging anymore\n", 5353c5656bfSArchie Cobbs device_get_nameunit(dev)); 5363c5656bfSArchie Cobbs } 5373c5656bfSArchie Cobbs } 5383c5656bfSArchie Cobbs } 5393c5656bfSArchie Cobbs 5403c5656bfSArchie Cobbs /* Check for bus error */ 5413c5656bfSArchie Cobbs if (status & ICH_HST_STA_BUS_ERR) { 5423c5656bfSArchie Cobbs sc->smb_error = SMB_ECOLLI; /* XXX SMB_EBUSERR? */ 5433c5656bfSArchie Cobbs goto finished; 5443c5656bfSArchie Cobbs } 5453c5656bfSArchie Cobbs 5463c5656bfSArchie Cobbs /* Check for device error */ 5473c5656bfSArchie Cobbs if (status & ICH_HST_STA_DEV_ERR) { 5483c5656bfSArchie Cobbs sc->smb_error = SMB_ENOACK; /* or SMB_ETIMEOUT? */ 5493c5656bfSArchie Cobbs goto finished; 5503c5656bfSArchie Cobbs } 5513c5656bfSArchie Cobbs 5523c5656bfSArchie Cobbs /* Check for byte completion in block transfer */ 5533c5656bfSArchie Cobbs if (status & ICH_HST_STA_BYTE_DONE_STS) { 5543c5656bfSArchie Cobbs if (sc->block_write) { 5553c5656bfSArchie Cobbs if (sc->block_index < sc->block_count) { 5563c5656bfSArchie Cobbs 5573c5656bfSArchie Cobbs /* Write next byte */ 5583c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, 5593c5656bfSArchie Cobbs sc->io_bsh, ICH_BLOCK_DB, 5603c5656bfSArchie Cobbs sc->block_data[sc->block_index++]); 5613c5656bfSArchie Cobbs } 5623c5656bfSArchie Cobbs } else { 5633c5656bfSArchie Cobbs 5643c5656bfSArchie Cobbs /* First interrupt, get the count also */ 5653c5656bfSArchie Cobbs if (sc->block_index == 0) { 5663c5656bfSArchie Cobbs sc->block_count = bus_space_read_1( 5673c5656bfSArchie Cobbs sc->io_bst, sc->io_bsh, ICH_D0); 5683c5656bfSArchie Cobbs } 5693c5656bfSArchie Cobbs 5703c5656bfSArchie Cobbs /* Get next byte, if any */ 5713c5656bfSArchie Cobbs if (sc->block_index < sc->block_count) { 5723c5656bfSArchie Cobbs 5733c5656bfSArchie Cobbs /* Read next byte */ 5743c5656bfSArchie Cobbs sc->block_data[sc->block_index++] = 5753c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, 5763c5656bfSArchie Cobbs sc->io_bsh, ICH_BLOCK_DB); 5773c5656bfSArchie Cobbs 5783c5656bfSArchie Cobbs /* Set "LAST_BYTE" bit before reading 5793c5656bfSArchie Cobbs the last byte of block data */ 5803c5656bfSArchie Cobbs if (sc->block_index 5813c5656bfSArchie Cobbs >= sc->block_count - 1) { 5823c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, 5833c5656bfSArchie Cobbs sc->io_bsh, ICH_HST_CNT, 5843c5656bfSArchie Cobbs ICH_HST_CNT_LAST_BYTE 5853c5656bfSArchie Cobbs | ICH_HST_CNT_INTREN 5863c5656bfSArchie Cobbs | sc->ich_cmd); 5873c5656bfSArchie Cobbs } 5883c5656bfSArchie Cobbs } 5893c5656bfSArchie Cobbs } 5903c5656bfSArchie Cobbs } 5913c5656bfSArchie Cobbs 5923c5656bfSArchie Cobbs /* Check command completion */ 5933c5656bfSArchie Cobbs if (status & ICH_HST_STA_INTR) { 5943c5656bfSArchie Cobbs sc->smb_error = SMB_ENOERR; 5953c5656bfSArchie Cobbs finished: 5963c5656bfSArchie Cobbs sc->ich_cmd = -1; 5973c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, 5983c5656bfSArchie Cobbs ICH_HST_STA, status); 5993c5656bfSArchie Cobbs wakeup(sc); 6003c5656bfSArchie Cobbs break; 6013c5656bfSArchie Cobbs } 6023c5656bfSArchie Cobbs 6033c5656bfSArchie Cobbs /* Clear status bits and try again */ 6043c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, status); 6053c5656bfSArchie Cobbs } 6069ed346baSBosko Milekic mtx_unlock(&sc->mutex); 6073c5656bfSArchie Cobbs 6083c5656bfSArchie Cobbs /* Too many loops? */ 6093c5656bfSArchie Cobbs if (count == maxloops) { 6103c5656bfSArchie Cobbs log(LOG_ERR, "%s: interrupt loop, status=0x%02x\n", 6113c5656bfSArchie Cobbs device_get_nameunit(dev), 6123c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 6133c5656bfSArchie Cobbs } 6143c5656bfSArchie Cobbs } 6153c5656bfSArchie Cobbs 6163c5656bfSArchie Cobbs /* 6173a50ed55SArchie Cobbs * Wait for command completion. Assumes mutex is held. 6183c5656bfSArchie Cobbs * Returns an SMB_* error code. 6193c5656bfSArchie Cobbs */ 6203c5656bfSArchie Cobbs static int 6213c5656bfSArchie Cobbs ichsmb_wait(sc_p sc) 6223c5656bfSArchie Cobbs { 6233c5656bfSArchie Cobbs const device_t dev = sc->dev; 6243c5656bfSArchie Cobbs int error, smb_error; 6253c5656bfSArchie Cobbs 6263c5656bfSArchie Cobbs KASSERT(sc->ich_cmd != -1, 6276e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 6283a50ed55SArchie Cobbs mtx_assert(&sc->mutex, MA_OWNED); 6293c5656bfSArchie Cobbs sleep: 6303a50ed55SArchie Cobbs error = msleep(sc, &sc->mutex, PZERO | PCATCH, "ichsmb", hz / 4); 6313a50ed55SArchie Cobbs DBG("msleep -> %d\n", error); 6323c5656bfSArchie Cobbs switch (error) { 6333c5656bfSArchie Cobbs case ERESTART: 6343c5656bfSArchie Cobbs if (sc->ich_cmd != -1) 6353c5656bfSArchie Cobbs goto sleep; 6363c5656bfSArchie Cobbs /* FALLTHROUGH */ 6373c5656bfSArchie Cobbs case 0: 6383c5656bfSArchie Cobbs smb_error = sc->smb_error; 6393c5656bfSArchie Cobbs break; 6403c5656bfSArchie Cobbs case EWOULDBLOCK: 6413c5656bfSArchie Cobbs log(LOG_ERR, "%s: device timeout, status=0x%02x\n", 6423c5656bfSArchie Cobbs device_get_nameunit(dev), 6433c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 6443c5656bfSArchie Cobbs sc->ich_cmd = -1; 6453c5656bfSArchie Cobbs smb_error = SMB_ETIMEOUT; 6463c5656bfSArchie Cobbs break; 6473c5656bfSArchie Cobbs default: 6483c5656bfSArchie Cobbs smb_error = SMB_EABORT; 6493c5656bfSArchie Cobbs break; 6503c5656bfSArchie Cobbs } 6513c5656bfSArchie Cobbs return (smb_error); 6523c5656bfSArchie Cobbs } 6533c5656bfSArchie Cobbs 6543c5656bfSArchie Cobbs /* 6553c5656bfSArchie Cobbs * Release resources associated with device. 6563c5656bfSArchie Cobbs */ 6573c5656bfSArchie Cobbs void 6583c5656bfSArchie Cobbs ichsmb_release_resources(sc_p sc) 6593c5656bfSArchie Cobbs { 6603c5656bfSArchie Cobbs const device_t dev = sc->dev; 6613c5656bfSArchie Cobbs 6623c5656bfSArchie Cobbs if (sc->irq_handle != NULL) { 6633c5656bfSArchie Cobbs bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 6643c5656bfSArchie Cobbs sc->irq_handle = NULL; 6653c5656bfSArchie Cobbs } 6663c5656bfSArchie Cobbs if (sc->irq_res != NULL) { 6673c5656bfSArchie Cobbs bus_release_resource(dev, 6683c5656bfSArchie Cobbs SYS_RES_IRQ, sc->irq_rid, sc->irq_res); 6693c5656bfSArchie Cobbs sc->irq_res = NULL; 6703c5656bfSArchie Cobbs } 6713c5656bfSArchie Cobbs if (sc->io_res != NULL) { 6723c5656bfSArchie Cobbs bus_release_resource(dev, 6733c5656bfSArchie Cobbs SYS_RES_IOPORT, sc->io_rid, sc->io_res); 6743c5656bfSArchie Cobbs sc->io_res = NULL; 6753c5656bfSArchie Cobbs } 6763c5656bfSArchie Cobbs } 6773c5656bfSArchie Cobbs 6782e6e32daSTakanori Watanabe int ichsmb_detach(device_t dev) 6792e6e32daSTakanori Watanabe { 6802e6e32daSTakanori Watanabe #if 0 6812e6e32daSTakanori Watanabe const sc_p sc = device_get_softc(dev); 6822e6e32daSTakanori Watanabe bus_generic_detach(dev); 6832e6e32daSTakanori Watanabe device_delete_child(dev, sc->smb); 6842e6e32daSTakanori Watanabe ichsmb_release_resources(sc); 6852e6e32daSTakanori Watanabe 6862e6e32daSTakanori Watanabe return 0; 6872e6e32daSTakanori Watanabe #else 6882e6e32daSTakanori Watanabe /*smbus drivers don't handle detach child properly*/ 6892e6e32daSTakanori Watanabe return EBUSY; 6902e6e32daSTakanori Watanabe #endif 6912e6e32daSTakanori Watanabe } 692