1a9656fbcSSascha Wildner /*- 2a9656fbcSSascha Wildner * Copyright (c) 1998, 1999 Takanori Watanabe 3a9656fbcSSascha Wildner * All rights reserved. 4a9656fbcSSascha Wildner * 5a9656fbcSSascha Wildner * Redistribution and use in source and binary forms, with or without 6a9656fbcSSascha Wildner * modification, are permitted provided that the following conditions 7a9656fbcSSascha Wildner * are met: 8a9656fbcSSascha Wildner * 1. Redistributions of source code must retain the above copyright 9a9656fbcSSascha Wildner * notice, this list of conditions and the following disclaimer. 10a9656fbcSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 11a9656fbcSSascha Wildner * notice, this list of conditions and the following disclaimer in the 12a9656fbcSSascha Wildner * documentation and/or other materials provided with the distribution. 13a9656fbcSSascha Wildner * 14a9656fbcSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a9656fbcSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a9656fbcSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a9656fbcSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a9656fbcSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a9656fbcSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a9656fbcSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a9656fbcSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a9656fbcSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a9656fbcSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a9656fbcSSascha Wildner * SUCH DAMAGE. 25a9656fbcSSascha Wildner * 26a9656fbcSSascha Wildner * $FreeBSD: src/sys/pci/intpm.c,v 1.45 2009/09/19 08:56:28 avg Exp $ 27a9656fbcSSascha Wildner */ 28a9656fbcSSascha Wildner 29a9656fbcSSascha Wildner #include <sys/param.h> 30a9656fbcSSascha Wildner #include <sys/systm.h> 31a9656fbcSSascha Wildner #include <sys/bus.h> 32a9656fbcSSascha Wildner #include <sys/globaldata.h> 33a9656fbcSSascha Wildner #include <sys/kernel.h> 34a9656fbcSSascha Wildner #include <sys/lock.h> 35a9656fbcSSascha Wildner #include <sys/module.h> 36a9656fbcSSascha Wildner #include <sys/mutex.h> 37a9656fbcSSascha Wildner #include <sys/rman.h> 38a9656fbcSSascha Wildner #include <bus/smbus/smbconf.h> 39a9656fbcSSascha Wildner 40a9656fbcSSascha Wildner #include "smbus_if.h" 41a9656fbcSSascha Wildner 42a9656fbcSSascha Wildner #include <bus/pci/pcireg.h> 43a9656fbcSSascha Wildner #include <bus/pci/pcivar.h> 44a9656fbcSSascha Wildner #include <dev/powermng/intpm/intpmreg.h> 45a9656fbcSSascha Wildner 46a9656fbcSSascha Wildner #include "opt_intpm.h" 47a9656fbcSSascha Wildner 48a9656fbcSSascha Wildner struct intsmb_softc { 49a9656fbcSSascha Wildner device_t dev; 50a9656fbcSSascha Wildner struct resource *io_res; 51a9656fbcSSascha Wildner struct resource *irq_res; 52a9656fbcSSascha Wildner void *irq_hand; 53a9656fbcSSascha Wildner device_t smbus; 54a9656fbcSSascha Wildner int isbusy; 55a9656fbcSSascha Wildner int cfg_irq9; 56a9656fbcSSascha Wildner int poll; 57a9656fbcSSascha Wildner struct lock lock; 58a9656fbcSSascha Wildner }; 59a9656fbcSSascha Wildner 60a9656fbcSSascha Wildner #define INTSMB_LOCK(sc) lockmgr(&(sc)->lock, LK_EXCLUSIVE) 61a9656fbcSSascha Wildner #define INTSMB_UNLOCK(sc) lockmgr(&(sc)->lock, LK_RELEASE) 62a9656fbcSSascha Wildner #define INTSMB_LOCK_ASSERT(sc) KKASSERT(lockstatus(&(sc)->lock, curthread) != 0) 63a9656fbcSSascha Wildner 64a9656fbcSSascha Wildner static int intsmb_probe(device_t); 65a9656fbcSSascha Wildner static int intsmb_attach(device_t); 66a9656fbcSSascha Wildner static int intsmb_detach(device_t); 67a9656fbcSSascha Wildner static int intsmb_intr(struct intsmb_softc *sc); 68a9656fbcSSascha Wildner static int intsmb_slvintr(struct intsmb_softc *sc); 69a9656fbcSSascha Wildner static void intsmb_alrintr(struct intsmb_softc *sc); 70a9656fbcSSascha Wildner static int intsmb_callback(device_t dev, int index, void *data); 71a9656fbcSSascha Wildner static int intsmb_quick(device_t dev, u_char slave, int how); 72a9656fbcSSascha Wildner static int intsmb_sendb(device_t dev, u_char slave, char byte); 73a9656fbcSSascha Wildner static int intsmb_recvb(device_t dev, u_char slave, char *byte); 74a9656fbcSSascha Wildner static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 75a9656fbcSSascha Wildner static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 76a9656fbcSSascha Wildner static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 77a9656fbcSSascha Wildner static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 78a9656fbcSSascha Wildner static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 79a9656fbcSSascha Wildner static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 80a9656fbcSSascha Wildner static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf); 81a9656fbcSSascha Wildner static void intsmb_start(struct intsmb_softc *sc, u_char cmd, int nointr); 82a9656fbcSSascha Wildner static int intsmb_stop(struct intsmb_softc *sc); 83a9656fbcSSascha Wildner static int intsmb_stop_poll(struct intsmb_softc *sc); 84a9656fbcSSascha Wildner static int intsmb_free(struct intsmb_softc *sc); 85a9656fbcSSascha Wildner static void intsmb_rawintr(void *arg); 86a9656fbcSSascha Wildner 87a9656fbcSSascha Wildner static int 88a9656fbcSSascha Wildner intsmb_probe(device_t dev) 89a9656fbcSSascha Wildner { 90a9656fbcSSascha Wildner 91a9656fbcSSascha Wildner switch (pci_get_devid(dev)) { 92a9656fbcSSascha Wildner case 0x71138086: /* Intel 82371AB */ 93a9656fbcSSascha Wildner case 0x719b8086: /* Intel 82443MX */ 94a9656fbcSSascha Wildner #if 0 95a9656fbcSSascha Wildner /* Not a good idea yet, this stops isab0 functioning */ 96a9656fbcSSascha Wildner case 0x02001166: /* ServerWorks OSB4 */ 97a9656fbcSSascha Wildner #endif 98a9656fbcSSascha Wildner device_set_desc(dev, "Intel PIIX4 SMBUS Interface"); 99a9656fbcSSascha Wildner break; 100a9656fbcSSascha Wildner case 0x43851002: 101a9656fbcSSascha Wildner device_set_desc(dev, "AMD SB600/700/710/750 SMBus Controller"); 102a9656fbcSSascha Wildner /* XXX Maybe force polling right here? */ 103a9656fbcSSascha Wildner break; 104a9656fbcSSascha Wildner default: 105a9656fbcSSascha Wildner return (ENXIO); 106a9656fbcSSascha Wildner } 107a9656fbcSSascha Wildner 108a9656fbcSSascha Wildner return (BUS_PROBE_DEFAULT); 109a9656fbcSSascha Wildner } 110a9656fbcSSascha Wildner 111a9656fbcSSascha Wildner static int 112a9656fbcSSascha Wildner intsmb_attach(device_t dev) 113a9656fbcSSascha Wildner { 114a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 115a9656fbcSSascha Wildner int error, rid, value; 116a9656fbcSSascha Wildner int intr; 117a9656fbcSSascha Wildner char *str; 118a9656fbcSSascha Wildner 119a9656fbcSSascha Wildner sc->dev = dev; 120a9656fbcSSascha Wildner 121a9656fbcSSascha Wildner lockinit(&sc->lock, "intsmb", 0, LK_CANRECURSE); 122a9656fbcSSascha Wildner 123a9656fbcSSascha Wildner sc->cfg_irq9 = 0; 124a9656fbcSSascha Wildner #ifndef NO_CHANGE_PCICONF 125a9656fbcSSascha Wildner switch (pci_get_devid(dev)) { 126a9656fbcSSascha Wildner case 0x71138086: /* Intel 82371AB */ 127a9656fbcSSascha Wildner case 0x719b8086: /* Intel 82443MX */ 128a9656fbcSSascha Wildner /* Changing configuration is allowed. */ 129a9656fbcSSascha Wildner sc->cfg_irq9 = 1; 130a9656fbcSSascha Wildner break; 131a9656fbcSSascha Wildner } 132a9656fbcSSascha Wildner #endif 133a9656fbcSSascha Wildner 134a9656fbcSSascha Wildner rid = PCI_BASE_ADDR_SMB; 135a9656fbcSSascha Wildner sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 136a9656fbcSSascha Wildner RF_ACTIVE); 137a9656fbcSSascha Wildner if (sc->io_res == NULL) { 138a9656fbcSSascha Wildner device_printf(dev, "Could not allocate I/O space\n"); 139a9656fbcSSascha Wildner error = ENXIO; 140a9656fbcSSascha Wildner goto fail; 141a9656fbcSSascha Wildner } 142a9656fbcSSascha Wildner 143a9656fbcSSascha Wildner if (sc->cfg_irq9) { 144a9656fbcSSascha Wildner pci_write_config(dev, PCIR_INTLINE, 0x9, 1); 145a9656fbcSSascha Wildner pci_write_config(dev, PCI_HST_CFG_SMB, 146a9656fbcSSascha Wildner PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1); 147a9656fbcSSascha Wildner } 148a9656fbcSSascha Wildner value = pci_read_config(dev, PCI_HST_CFG_SMB, 1); 149a9656fbcSSascha Wildner sc->poll = (value & PCI_INTR_SMB_ENABLE) == 0; 150a9656fbcSSascha Wildner intr = value & PCI_INTR_SMB_MASK; 151a9656fbcSSascha Wildner switch (intr) { 152a9656fbcSSascha Wildner case PCI_INTR_SMB_SMI: 153a9656fbcSSascha Wildner str = "SMI"; 154a9656fbcSSascha Wildner break; 155a9656fbcSSascha Wildner case PCI_INTR_SMB_IRQ9: 156a9656fbcSSascha Wildner str = "IRQ 9"; 157a9656fbcSSascha Wildner break; 158a9656fbcSSascha Wildner case PCI_INTR_SMB_IRQ_PCI: 159a9656fbcSSascha Wildner str = "PCI IRQ"; 160a9656fbcSSascha Wildner break; 161a9656fbcSSascha Wildner default: 162a9656fbcSSascha Wildner str = "BOGUS"; 163a9656fbcSSascha Wildner } 164a9656fbcSSascha Wildner 165a9656fbcSSascha Wildner device_printf(dev, "intr %s %s ", str, 166a9656fbcSSascha Wildner sc->poll == 0 ? "enabled" : "disabled"); 167a9656fbcSSascha Wildner kprintf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1)); 168a9656fbcSSascha Wildner 169a9656fbcSSascha Wildner if (!sc->poll && intr == PCI_INTR_SMB_SMI) { 170a9656fbcSSascha Wildner device_printf(dev, 171a9656fbcSSascha Wildner "using polling mode when configured interrupt is SMI\n"); 172a9656fbcSSascha Wildner sc->poll = 1; 173a9656fbcSSascha Wildner } 174a9656fbcSSascha Wildner 175a9656fbcSSascha Wildner if (sc->poll) 176a9656fbcSSascha Wildner goto no_intr; 177a9656fbcSSascha Wildner 178a9656fbcSSascha Wildner if (intr != PCI_INTR_SMB_IRQ9 && intr != PCI_INTR_SMB_IRQ_PCI) { 179a9656fbcSSascha Wildner device_printf(dev, "Unsupported interrupt mode\n"); 180a9656fbcSSascha Wildner error = ENXIO; 181a9656fbcSSascha Wildner goto fail; 182a9656fbcSSascha Wildner } 183a9656fbcSSascha Wildner 184a9656fbcSSascha Wildner /* Force IRQ 9. */ 185a9656fbcSSascha Wildner rid = 0; 186a9656fbcSSascha Wildner if (sc->cfg_irq9) 187a9656fbcSSascha Wildner bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1); 188a9656fbcSSascha Wildner 189a9656fbcSSascha Wildner sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 190a9656fbcSSascha Wildner RF_SHAREABLE | RF_ACTIVE); 191a9656fbcSSascha Wildner if (sc->irq_res == NULL) { 192a9656fbcSSascha Wildner device_printf(dev, "Could not allocate irq\n"); 193a9656fbcSSascha Wildner error = ENXIO; 194a9656fbcSSascha Wildner goto fail; 195a9656fbcSSascha Wildner } 196a9656fbcSSascha Wildner 197a9656fbcSSascha Wildner error = bus_setup_intr(dev, sc->irq_res, 0, 198a9656fbcSSascha Wildner intsmb_rawintr, sc, &sc->irq_hand, NULL); 199a9656fbcSSascha Wildner if (error) { 200a9656fbcSSascha Wildner device_printf(dev, "Failed to map intr\n"); 201a9656fbcSSascha Wildner goto fail; 202a9656fbcSSascha Wildner } 203a9656fbcSSascha Wildner 204a9656fbcSSascha Wildner no_intr: 205a9656fbcSSascha Wildner sc->isbusy = 0; 206a9656fbcSSascha Wildner sc->smbus = device_add_child(dev, "smbus", -1); 207a9656fbcSSascha Wildner if (sc->smbus == NULL) { 208a9656fbcSSascha Wildner error = ENXIO; 209a9656fbcSSascha Wildner goto fail; 210a9656fbcSSascha Wildner } 211a9656fbcSSascha Wildner error = device_probe_and_attach(sc->smbus); 212a9656fbcSSascha Wildner if (error) 213a9656fbcSSascha Wildner goto fail; 214a9656fbcSSascha Wildner 215a9656fbcSSascha Wildner #ifdef ENABLE_ALART 216a9656fbcSSascha Wildner /* Enable Arart */ 217a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN); 218a9656fbcSSascha Wildner #endif 219a9656fbcSSascha Wildner return (0); 220a9656fbcSSascha Wildner 221a9656fbcSSascha Wildner fail: 222a9656fbcSSascha Wildner intsmb_detach(dev); 223a9656fbcSSascha Wildner return (error); 224a9656fbcSSascha Wildner } 225a9656fbcSSascha Wildner 226a9656fbcSSascha Wildner static int 227a9656fbcSSascha Wildner intsmb_detach(device_t dev) 228a9656fbcSSascha Wildner { 229a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 230a9656fbcSSascha Wildner int error; 231a9656fbcSSascha Wildner 232a9656fbcSSascha Wildner error = bus_generic_detach(dev); 233a9656fbcSSascha Wildner if (error) 234a9656fbcSSascha Wildner return (error); 235a9656fbcSSascha Wildner 236a9656fbcSSascha Wildner if (sc->smbus) 237a9656fbcSSascha Wildner device_delete_child(dev, sc->smbus); 238a9656fbcSSascha Wildner if (sc->irq_hand) 239a9656fbcSSascha Wildner bus_teardown_intr(dev, sc->irq_res, sc->irq_hand); 240a9656fbcSSascha Wildner if (sc->irq_res) 241a9656fbcSSascha Wildner bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 242a9656fbcSSascha Wildner if (sc->io_res) 243a9656fbcSSascha Wildner bus_release_resource(dev, SYS_RES_IOPORT, PCI_BASE_ADDR_SMB, 244a9656fbcSSascha Wildner sc->io_res); 245a9656fbcSSascha Wildner lockuninit(&sc->lock); 246a9656fbcSSascha Wildner return (0); 247a9656fbcSSascha Wildner } 248a9656fbcSSascha Wildner 249a9656fbcSSascha Wildner static void 250a9656fbcSSascha Wildner intsmb_rawintr(void *arg) 251a9656fbcSSascha Wildner { 252a9656fbcSSascha Wildner struct intsmb_softc *sc = arg; 253a9656fbcSSascha Wildner 254a9656fbcSSascha Wildner INTSMB_LOCK(sc); 255a9656fbcSSascha Wildner intsmb_intr(sc); 256a9656fbcSSascha Wildner intsmb_slvintr(sc); 257a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 258a9656fbcSSascha Wildner } 259a9656fbcSSascha Wildner 260a9656fbcSSascha Wildner static int 261a9656fbcSSascha Wildner intsmb_callback(device_t dev, int index, void *data) 262a9656fbcSSascha Wildner { 263a9656fbcSSascha Wildner int error = 0; 264a9656fbcSSascha Wildner 265a9656fbcSSascha Wildner switch (index) { 266a9656fbcSSascha Wildner case SMB_REQUEST_BUS: 267a9656fbcSSascha Wildner break; 268a9656fbcSSascha Wildner case SMB_RELEASE_BUS: 269a9656fbcSSascha Wildner break; 270a9656fbcSSascha Wildner default: 271a9656fbcSSascha Wildner error = EINVAL; 272a9656fbcSSascha Wildner } 273a9656fbcSSascha Wildner 274a9656fbcSSascha Wildner return (error); 275a9656fbcSSascha Wildner } 276a9656fbcSSascha Wildner 277a9656fbcSSascha Wildner /* Counterpart of smbtx_smb_free(). */ 278a9656fbcSSascha Wildner static int 279a9656fbcSSascha Wildner intsmb_free(struct intsmb_softc *sc) 280a9656fbcSSascha Wildner { 281a9656fbcSSascha Wildner 282a9656fbcSSascha Wildner INTSMB_LOCK_ASSERT(sc); 283a9656fbcSSascha Wildner if ((bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & PIIX4_SMBHSTSTAT_BUSY) || 284a9656fbcSSascha Wildner #ifdef ENABLE_ALART 285a9656fbcSSascha Wildner (bus_read_1(sc->io_res, PIIX4_SMBSLVSTS) & PIIX4_SMBSLVSTS_BUSY) || 286a9656fbcSSascha Wildner #endif 287a9656fbcSSascha Wildner sc->isbusy) 288a9656fbcSSascha Wildner return (SMB_EBUSY); 289a9656fbcSSascha Wildner 290a9656fbcSSascha Wildner sc->isbusy = 1; 291a9656fbcSSascha Wildner /* Disable Interrupt in slave part. */ 292a9656fbcSSascha Wildner #ifndef ENABLE_ALART 293a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 0); 294a9656fbcSSascha Wildner #endif 295a9656fbcSSascha Wildner /* Reset INTR Flag to prepare INTR. */ 296a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTSTS, 297a9656fbcSSascha Wildner PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR | 298a9656fbcSSascha Wildner PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL); 299a9656fbcSSascha Wildner return (0); 300a9656fbcSSascha Wildner } 301a9656fbcSSascha Wildner 302a9656fbcSSascha Wildner static int 303a9656fbcSSascha Wildner intsmb_intr(struct intsmb_softc *sc) 304a9656fbcSSascha Wildner { 305a9656fbcSSascha Wildner int status, tmp; 306a9656fbcSSascha Wildner 307a9656fbcSSascha Wildner status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); 308a9656fbcSSascha Wildner if (status & PIIX4_SMBHSTSTAT_BUSY) 309a9656fbcSSascha Wildner return (1); 310a9656fbcSSascha Wildner 311a9656fbcSSascha Wildner if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR | 312a9656fbcSSascha Wildner PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) { 313a9656fbcSSascha Wildner 314a9656fbcSSascha Wildner tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 315a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, 316a9656fbcSSascha Wildner tmp & ~PIIX4_SMBHSTCNT_INTREN); 317a9656fbcSSascha Wildner if (sc->isbusy) { 318a9656fbcSSascha Wildner sc->isbusy = 0; 319a9656fbcSSascha Wildner wakeup(sc); 320a9656fbcSSascha Wildner } 321a9656fbcSSascha Wildner return (0); 322a9656fbcSSascha Wildner } 323a9656fbcSSascha Wildner return (1); /* Not Completed */ 324a9656fbcSSascha Wildner } 325a9656fbcSSascha Wildner 326a9656fbcSSascha Wildner static int 327a9656fbcSSascha Wildner intsmb_slvintr(struct intsmb_softc *sc) 328a9656fbcSSascha Wildner { 329a9656fbcSSascha Wildner int status; 330a9656fbcSSascha Wildner 331a9656fbcSSascha Wildner status = bus_read_1(sc->io_res, PIIX4_SMBSLVSTS); 332a9656fbcSSascha Wildner if (status & PIIX4_SMBSLVSTS_BUSY) 333a9656fbcSSascha Wildner return (1); 334a9656fbcSSascha Wildner if (status & PIIX4_SMBSLVSTS_ALART) 335a9656fbcSSascha Wildner intsmb_alrintr(sc); 336a9656fbcSSascha Wildner else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 337a9656fbcSSascha Wildner | PIIX4_SMBSLVSTS_SDW1)) { 338a9656fbcSSascha Wildner } 339a9656fbcSSascha Wildner 340a9656fbcSSascha Wildner /* Reset Status Register */ 341a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBSLVSTS, 342a9656fbcSSascha Wildner PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 | 343a9656fbcSSascha Wildner PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV); 344a9656fbcSSascha Wildner return (0); 345a9656fbcSSascha Wildner } 346a9656fbcSSascha Wildner 347a9656fbcSSascha Wildner static void 348a9656fbcSSascha Wildner intsmb_alrintr(struct intsmb_softc *sc) 349a9656fbcSSascha Wildner { 350a9656fbcSSascha Wildner int slvcnt; 351a9656fbcSSascha Wildner #ifdef ENABLE_ALART 352a9656fbcSSascha Wildner int error; 353a9656fbcSSascha Wildner uint8_t addr; 354a9656fbcSSascha Wildner #endif 355a9656fbcSSascha Wildner 356a9656fbcSSascha Wildner /* Stop generating INTR from ALART. */ 357a9656fbcSSascha Wildner slvcnt = bus_read_1(sc->io_res, PIIX4_SMBSLVCNT); 358a9656fbcSSascha Wildner #ifdef ENABLE_ALART 359a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 360a9656fbcSSascha Wildner slvcnt & ~PIIX4_SMBSLVCNT_ALTEN); 361a9656fbcSSascha Wildner #endif 362a9656fbcSSascha Wildner DELAY(5); 363a9656fbcSSascha Wildner 364a9656fbcSSascha Wildner /* Ask bus who asserted it and then ask it what's the matter. */ 365a9656fbcSSascha Wildner #ifdef ENABLE_ALART 366a9656fbcSSascha Wildner error = intsmb_free(sc); 367a9656fbcSSascha Wildner if (error) 368a9656fbcSSascha Wildner return; 369a9656fbcSSascha Wildner 370a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, SMBALTRESP | LSB); 371a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 1); 372a9656fbcSSascha Wildner error = intsmb_stop_poll(sc); 373a9656fbcSSascha Wildner if (error) 374a9656fbcSSascha Wildner device_printf(sc->dev, "ALART: ERROR\n"); 375a9656fbcSSascha Wildner else { 376a9656fbcSSascha Wildner addr = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 377a9656fbcSSascha Wildner device_printf(sc->dev, "ALART_RESPONSE: 0x%x\n", addr); 378a9656fbcSSascha Wildner } 379a9656fbcSSascha Wildner 380a9656fbcSSascha Wildner /* Re-enable INTR from ALART. */ 381a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 382a9656fbcSSascha Wildner slvcnt | PIIX4_SMBSLVCNT_ALTEN); 383a9656fbcSSascha Wildner DELAY(5); 384a9656fbcSSascha Wildner #endif 385a9656fbcSSascha Wildner } 386a9656fbcSSascha Wildner 387a9656fbcSSascha Wildner static void 388a9656fbcSSascha Wildner intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr) 389a9656fbcSSascha Wildner { 390a9656fbcSSascha Wildner unsigned char tmp; 391a9656fbcSSascha Wildner 392a9656fbcSSascha Wildner INTSMB_LOCK_ASSERT(sc); 393a9656fbcSSascha Wildner tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 394a9656fbcSSascha Wildner tmp &= 0xe0; 395a9656fbcSSascha Wildner tmp |= cmd; 396a9656fbcSSascha Wildner tmp |= PIIX4_SMBHSTCNT_START; 397a9656fbcSSascha Wildner 398a9656fbcSSascha Wildner /* While not in autoconfiguration enable interrupts. */ 399a9656fbcSSascha Wildner if (!sc->poll && !cold && !nointr) 400a9656fbcSSascha Wildner tmp |= PIIX4_SMBHSTCNT_INTREN; 401a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp); 402a9656fbcSSascha Wildner } 403a9656fbcSSascha Wildner 404a9656fbcSSascha Wildner static int 405a9656fbcSSascha Wildner intsmb_error(device_t dev, int status) 406a9656fbcSSascha Wildner { 407a9656fbcSSascha Wildner int error = 0; 408a9656fbcSSascha Wildner 409a9656fbcSSascha Wildner if (status & PIIX4_SMBHSTSTAT_ERR) 410a9656fbcSSascha Wildner error |= SMB_EBUSERR; 411a9656fbcSSascha Wildner if (status & PIIX4_SMBHSTSTAT_BUSC) 412a9656fbcSSascha Wildner error |= SMB_ECOLLI; 413a9656fbcSSascha Wildner if (status & PIIX4_SMBHSTSTAT_FAIL) 414a9656fbcSSascha Wildner error |= SMB_ENOACK; 415a9656fbcSSascha Wildner 416a9656fbcSSascha Wildner if (error != 0 && bootverbose) 417a9656fbcSSascha Wildner device_printf(dev, "error = %d, status = %#x\n", error, status); 418a9656fbcSSascha Wildner 419a9656fbcSSascha Wildner return (error); 420a9656fbcSSascha Wildner } 421a9656fbcSSascha Wildner 422a9656fbcSSascha Wildner /* 423a9656fbcSSascha Wildner * Polling Code. 424a9656fbcSSascha Wildner * 425a9656fbcSSascha Wildner * Polling is not encouraged because it requires waiting for the 426a9656fbcSSascha Wildner * device if it is busy. 427a9656fbcSSascha Wildner * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use 428a9656fbcSSascha Wildner * polling code then. 429a9656fbcSSascha Wildner */ 430a9656fbcSSascha Wildner static int 431a9656fbcSSascha Wildner intsmb_stop_poll(struct intsmb_softc *sc) 432a9656fbcSSascha Wildner { 433a9656fbcSSascha Wildner int error, i, status, tmp; 434a9656fbcSSascha Wildner 435a9656fbcSSascha Wildner INTSMB_LOCK_ASSERT(sc); 436a9656fbcSSascha Wildner 437a9656fbcSSascha Wildner /* First, wait for busy to be set. */ 438a9656fbcSSascha Wildner for (i = 0; i < 0x7fff; i++) 439a9656fbcSSascha Wildner if (bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & 440a9656fbcSSascha Wildner PIIX4_SMBHSTSTAT_BUSY) 441a9656fbcSSascha Wildner break; 442a9656fbcSSascha Wildner 443a9656fbcSSascha Wildner /* Wait for busy to clear. */ 444a9656fbcSSascha Wildner for (i = 0; i < 0x7fff; i++) { 445a9656fbcSSascha Wildner status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); 446a9656fbcSSascha Wildner if (!(status & PIIX4_SMBHSTSTAT_BUSY)) { 447a9656fbcSSascha Wildner sc->isbusy = 0; 448a9656fbcSSascha Wildner error = intsmb_error(sc->dev, status); 449a9656fbcSSascha Wildner return (error); 450a9656fbcSSascha Wildner } 451a9656fbcSSascha Wildner } 452a9656fbcSSascha Wildner 453a9656fbcSSascha Wildner /* Timed out waiting for busy to clear. */ 454a9656fbcSSascha Wildner sc->isbusy = 0; 455a9656fbcSSascha Wildner tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 456a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp & ~PIIX4_SMBHSTCNT_INTREN); 457a9656fbcSSascha Wildner return (SMB_ETIMEOUT); 458a9656fbcSSascha Wildner } 459a9656fbcSSascha Wildner 460a9656fbcSSascha Wildner /* 461a9656fbcSSascha Wildner * Wait for completion and return result. 462a9656fbcSSascha Wildner */ 463a9656fbcSSascha Wildner static int 464a9656fbcSSascha Wildner intsmb_stop(struct intsmb_softc *sc) 465a9656fbcSSascha Wildner { 466a9656fbcSSascha Wildner int error, status; 467a9656fbcSSascha Wildner 468a9656fbcSSascha Wildner INTSMB_LOCK_ASSERT(sc); 469a9656fbcSSascha Wildner 470a9656fbcSSascha Wildner if (sc->poll || cold) 471a9656fbcSSascha Wildner /* So that it can use device during device probe on SMBus. */ 472a9656fbcSSascha Wildner return (intsmb_stop_poll(sc)); 473a9656fbcSSascha Wildner 474a9656fbcSSascha Wildner error = lksleep(sc, &sc->lock, PCATCH, "SMBWAI", hz / 8); 475a9656fbcSSascha Wildner if (error == 0) { 476a9656fbcSSascha Wildner status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); 477a9656fbcSSascha Wildner if (!(status & PIIX4_SMBHSTSTAT_BUSY)) { 478a9656fbcSSascha Wildner error = intsmb_error(sc->dev, status); 479a9656fbcSSascha Wildner if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR)) 480a9656fbcSSascha Wildner device_printf(sc->dev, "unknown cause why?\n"); 481a9656fbcSSascha Wildner #ifdef ENABLE_ALART 482a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 483a9656fbcSSascha Wildner PIIX4_SMBSLVCNT_ALTEN); 484a9656fbcSSascha Wildner #endif 485a9656fbcSSascha Wildner return (error); 486a9656fbcSSascha Wildner } 487a9656fbcSSascha Wildner } 488a9656fbcSSascha Wildner 489a9656fbcSSascha Wildner /* Timeout Procedure. */ 490a9656fbcSSascha Wildner sc->isbusy = 0; 491a9656fbcSSascha Wildner 492a9656fbcSSascha Wildner /* Re-enable supressed interrupt from slave part. */ 493a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN); 494a9656fbcSSascha Wildner if (error == EWOULDBLOCK) 495a9656fbcSSascha Wildner return (SMB_ETIMEOUT); 496a9656fbcSSascha Wildner else 497a9656fbcSSascha Wildner return (SMB_EABORT); 498a9656fbcSSascha Wildner } 499a9656fbcSSascha Wildner 500a9656fbcSSascha Wildner static int 501a9656fbcSSascha Wildner intsmb_quick(device_t dev, u_char slave, int how) 502a9656fbcSSascha Wildner { 503a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 504a9656fbcSSascha Wildner int error; 505a9656fbcSSascha Wildner u_char data; 506a9656fbcSSascha Wildner 507a9656fbcSSascha Wildner data = slave; 508a9656fbcSSascha Wildner 509a9656fbcSSascha Wildner /* Quick command is part of Address, I think. */ 510a9656fbcSSascha Wildner switch(how) { 511a9656fbcSSascha Wildner case SMB_QWRITE: 512a9656fbcSSascha Wildner data &= ~LSB; 513a9656fbcSSascha Wildner break; 514a9656fbcSSascha Wildner case SMB_QREAD: 515a9656fbcSSascha Wildner data |= LSB; 516a9656fbcSSascha Wildner break; 517a9656fbcSSascha Wildner default: 518a9656fbcSSascha Wildner return (EINVAL); 519a9656fbcSSascha Wildner } 520a9656fbcSSascha Wildner 521a9656fbcSSascha Wildner INTSMB_LOCK(sc); 522a9656fbcSSascha Wildner error = intsmb_free(sc); 523a9656fbcSSascha Wildner if (error) { 524a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 525a9656fbcSSascha Wildner return (error); 526a9656fbcSSascha Wildner } 527a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, data); 528a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_QUICK, 0); 529a9656fbcSSascha Wildner error = intsmb_stop(sc); 530a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 531a9656fbcSSascha Wildner return (error); 532a9656fbcSSascha Wildner } 533a9656fbcSSascha Wildner 534a9656fbcSSascha Wildner static int 535a9656fbcSSascha Wildner intsmb_sendb(device_t dev, u_char slave, char byte) 536a9656fbcSSascha Wildner { 537a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 538a9656fbcSSascha Wildner int error; 539a9656fbcSSascha Wildner 540a9656fbcSSascha Wildner INTSMB_LOCK(sc); 541a9656fbcSSascha Wildner error = intsmb_free(sc); 542a9656fbcSSascha Wildner if (error) { 543a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 544a9656fbcSSascha Wildner return (error); 545a9656fbcSSascha Wildner } 546a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 547a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, byte); 548a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0); 549a9656fbcSSascha Wildner error = intsmb_stop(sc); 550a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 551a9656fbcSSascha Wildner return (error); 552a9656fbcSSascha Wildner } 553a9656fbcSSascha Wildner 554a9656fbcSSascha Wildner static int 555a9656fbcSSascha Wildner intsmb_recvb(device_t dev, u_char slave, char *byte) 556a9656fbcSSascha Wildner { 557a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 558a9656fbcSSascha Wildner int error; 559a9656fbcSSascha Wildner 560a9656fbcSSascha Wildner INTSMB_LOCK(sc); 561a9656fbcSSascha Wildner error = intsmb_free(sc); 562a9656fbcSSascha Wildner if (error) { 563a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 564a9656fbcSSascha Wildner return (error); 565a9656fbcSSascha Wildner } 566a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 567a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0); 568a9656fbcSSascha Wildner error = intsmb_stop(sc); 569a9656fbcSSascha Wildner if (error == 0) { 570a9656fbcSSascha Wildner #ifdef RECV_IS_IN_CMD 571a9656fbcSSascha Wildner /* 572a9656fbcSSascha Wildner * Linux SMBus stuff also troubles 573a9656fbcSSascha Wildner * Because Intel's datasheet does not make clear. 574a9656fbcSSascha Wildner */ 575a9656fbcSSascha Wildner *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTCMD); 576a9656fbcSSascha Wildner #else 577a9656fbcSSascha Wildner *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 578a9656fbcSSascha Wildner #endif 579a9656fbcSSascha Wildner } 580a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 581a9656fbcSSascha Wildner return (error); 582a9656fbcSSascha Wildner } 583a9656fbcSSascha Wildner 584a9656fbcSSascha Wildner static int 585a9656fbcSSascha Wildner intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 586a9656fbcSSascha Wildner { 587a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 588a9656fbcSSascha Wildner int error; 589a9656fbcSSascha Wildner 590a9656fbcSSascha Wildner INTSMB_LOCK(sc); 591a9656fbcSSascha Wildner error = intsmb_free(sc); 592a9656fbcSSascha Wildner if (error) { 593a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 594a9656fbcSSascha Wildner return (error); 595a9656fbcSSascha Wildner } 596a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 597a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 598a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, byte); 599a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0); 600a9656fbcSSascha Wildner error = intsmb_stop(sc); 601a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 602a9656fbcSSascha Wildner return (error); 603a9656fbcSSascha Wildner } 604a9656fbcSSascha Wildner 605a9656fbcSSascha Wildner static int 606a9656fbcSSascha Wildner intsmb_writew(device_t dev, u_char slave, char cmd, short word) 607a9656fbcSSascha Wildner { 608a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 609a9656fbcSSascha Wildner int error; 610a9656fbcSSascha Wildner 611a9656fbcSSascha Wildner INTSMB_LOCK(sc); 612a9656fbcSSascha Wildner error = intsmb_free(sc); 613a9656fbcSSascha Wildner if (error) { 614a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 615a9656fbcSSascha Wildner return (error); 616a9656fbcSSascha Wildner } 617a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 618a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 619a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, word & 0xff); 620a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (word >> 8) & 0xff); 621a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); 622a9656fbcSSascha Wildner error = intsmb_stop(sc); 623a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 624a9656fbcSSascha Wildner return (error); 625a9656fbcSSascha Wildner } 626a9656fbcSSascha Wildner 627a9656fbcSSascha Wildner static int 628a9656fbcSSascha Wildner intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 629a9656fbcSSascha Wildner { 630a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 631a9656fbcSSascha Wildner int error; 632a9656fbcSSascha Wildner 633a9656fbcSSascha Wildner INTSMB_LOCK(sc); 634a9656fbcSSascha Wildner error = intsmb_free(sc); 635a9656fbcSSascha Wildner if (error) { 636a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 637a9656fbcSSascha Wildner return (error); 638a9656fbcSSascha Wildner } 639a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 640a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 641a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0); 642a9656fbcSSascha Wildner error = intsmb_stop(sc); 643a9656fbcSSascha Wildner if (error == 0) 644a9656fbcSSascha Wildner *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 645a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 646a9656fbcSSascha Wildner return (error); 647a9656fbcSSascha Wildner } 648a9656fbcSSascha Wildner 649a9656fbcSSascha Wildner static int 650a9656fbcSSascha Wildner intsmb_readw(device_t dev, u_char slave, char cmd, short *word) 651a9656fbcSSascha Wildner { 652a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 653a9656fbcSSascha Wildner int error; 654a9656fbcSSascha Wildner 655a9656fbcSSascha Wildner INTSMB_LOCK(sc); 656a9656fbcSSascha Wildner error = intsmb_free(sc); 657a9656fbcSSascha Wildner if (error) { 658a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 659a9656fbcSSascha Wildner return (error); 660a9656fbcSSascha Wildner } 661a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 662a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 663a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); 664a9656fbcSSascha Wildner error = intsmb_stop(sc); 665a9656fbcSSascha Wildner if (error == 0) { 666a9656fbcSSascha Wildner *word = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 667a9656fbcSSascha Wildner *word |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8; 668a9656fbcSSascha Wildner } 669a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 670a9656fbcSSascha Wildner return (error); 671a9656fbcSSascha Wildner } 672a9656fbcSSascha Wildner 673a9656fbcSSascha Wildner /* 674a9656fbcSSascha Wildner * Data sheet claims that it implements all function, but also claims 675a9656fbcSSascha Wildner * that it implements 7 function and not mention PCALL. So I don't know 676a9656fbcSSascha Wildner * whether it will work. 677a9656fbcSSascha Wildner */ 678a9656fbcSSascha Wildner static int 679a9656fbcSSascha Wildner intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 680a9656fbcSSascha Wildner { 681a9656fbcSSascha Wildner #ifdef PROCCALL_TEST 682a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 683a9656fbcSSascha Wildner int error; 684a9656fbcSSascha Wildner 685a9656fbcSSascha Wildner INTSMB_LOCK(sc); 686a9656fbcSSascha Wildner error = intsmb_free(sc); 687a9656fbcSSascha Wildner if (error) { 688a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 689a9656fbcSSascha Wildner return (error); 690a9656fbcSSascha Wildner } 691a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 692a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 693a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, sdata & 0xff); 694a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (sdata & 0xff) >> 8); 695a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); 696a9656fbcSSascha Wildner error = intsmb_stop(sc); 697a9656fbcSSascha Wildner if (error == 0) { 698a9656fbcSSascha Wildner *rdata = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 699a9656fbcSSascha Wildner *rdata |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8; 700a9656fbcSSascha Wildner } 701a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 702a9656fbcSSascha Wildner return (error); 703a9656fbcSSascha Wildner #else 704a9656fbcSSascha Wildner return (SMB_ENOTSUPP); 705a9656fbcSSascha Wildner #endif 706a9656fbcSSascha Wildner } 707a9656fbcSSascha Wildner 708a9656fbcSSascha Wildner static int 709a9656fbcSSascha Wildner intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 710a9656fbcSSascha Wildner { 711a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 712a9656fbcSSascha Wildner int error, i; 713a9656fbcSSascha Wildner 714a9656fbcSSascha Wildner if (count > SMBBLOCKTRANS_MAX || count == 0) 715a9656fbcSSascha Wildner return (SMB_EINVAL); 716a9656fbcSSascha Wildner 717a9656fbcSSascha Wildner INTSMB_LOCK(sc); 718a9656fbcSSascha Wildner error = intsmb_free(sc); 719a9656fbcSSascha Wildner if (error) { 720a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 721a9656fbcSSascha Wildner return (error); 722a9656fbcSSascha Wildner } 723a9656fbcSSascha Wildner 724a9656fbcSSascha Wildner /* Reset internal array index. */ 725a9656fbcSSascha Wildner bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 726a9656fbcSSascha Wildner 727a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 728a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 729a9656fbcSSascha Wildner for (i = 0; i < count; i++) 730a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBBLKDAT, buf[i]); 731a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, count); 732a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0); 733a9656fbcSSascha Wildner error = intsmb_stop(sc); 734a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 735a9656fbcSSascha Wildner return (error); 736a9656fbcSSascha Wildner } 737a9656fbcSSascha Wildner 738a9656fbcSSascha Wildner static int 739a9656fbcSSascha Wildner intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 740a9656fbcSSascha Wildner { 741a9656fbcSSascha Wildner struct intsmb_softc *sc = device_get_softc(dev); 742a9656fbcSSascha Wildner int error, i; 743a9656fbcSSascha Wildner u_char data, nread; 744a9656fbcSSascha Wildner 745a9656fbcSSascha Wildner if (*count > SMBBLOCKTRANS_MAX || *count == 0) 746a9656fbcSSascha Wildner return (SMB_EINVAL); 747a9656fbcSSascha Wildner 748a9656fbcSSascha Wildner INTSMB_LOCK(sc); 749a9656fbcSSascha Wildner error = intsmb_free(sc); 750a9656fbcSSascha Wildner if (error) { 751a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 752a9656fbcSSascha Wildner return (error); 753a9656fbcSSascha Wildner } 754a9656fbcSSascha Wildner 755a9656fbcSSascha Wildner /* Reset internal array index. */ 756a9656fbcSSascha Wildner bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 757a9656fbcSSascha Wildner 758a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 759a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 760a9656fbcSSascha Wildner bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, *count); 761a9656fbcSSascha Wildner intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0); 762a9656fbcSSascha Wildner error = intsmb_stop(sc); 763a9656fbcSSascha Wildner if (error == 0) { 764a9656fbcSSascha Wildner nread = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 765a9656fbcSSascha Wildner if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) { 766a9656fbcSSascha Wildner for (i = 0; i < nread; i++) { 767a9656fbcSSascha Wildner data = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT); 768a9656fbcSSascha Wildner if (i < *count) 769a9656fbcSSascha Wildner buf[i] = data; 770a9656fbcSSascha Wildner } 771a9656fbcSSascha Wildner *count = nread; 772a9656fbcSSascha Wildner } else 773a9656fbcSSascha Wildner error = EIO; 774a9656fbcSSascha Wildner } 775a9656fbcSSascha Wildner INTSMB_UNLOCK(sc); 776a9656fbcSSascha Wildner return (error); 777a9656fbcSSascha Wildner } 778a9656fbcSSascha Wildner 779a9656fbcSSascha Wildner static devclass_t intsmb_devclass; 780a9656fbcSSascha Wildner 781a9656fbcSSascha Wildner static device_method_t intsmb_methods[] = { 782a9656fbcSSascha Wildner /* Device interface */ 783a9656fbcSSascha Wildner DEVMETHOD(device_probe, intsmb_probe), 784a9656fbcSSascha Wildner DEVMETHOD(device_attach, intsmb_attach), 785a9656fbcSSascha Wildner DEVMETHOD(device_detach, intsmb_detach), 786a9656fbcSSascha Wildner 787a9656fbcSSascha Wildner /* Bus interface */ 788a9656fbcSSascha Wildner DEVMETHOD(bus_print_child, bus_generic_print_child), 789a9656fbcSSascha Wildner 790a9656fbcSSascha Wildner /* SMBus interface */ 791a9656fbcSSascha Wildner DEVMETHOD(smbus_callback, intsmb_callback), 792a9656fbcSSascha Wildner DEVMETHOD(smbus_quick, intsmb_quick), 793a9656fbcSSascha Wildner DEVMETHOD(smbus_sendb, intsmb_sendb), 794a9656fbcSSascha Wildner DEVMETHOD(smbus_recvb, intsmb_recvb), 795a9656fbcSSascha Wildner DEVMETHOD(smbus_writeb, intsmb_writeb), 796a9656fbcSSascha Wildner DEVMETHOD(smbus_writew, intsmb_writew), 797a9656fbcSSascha Wildner DEVMETHOD(smbus_readb, intsmb_readb), 798a9656fbcSSascha Wildner DEVMETHOD(smbus_readw, intsmb_readw), 799a9656fbcSSascha Wildner DEVMETHOD(smbus_pcall, intsmb_pcall), 800a9656fbcSSascha Wildner DEVMETHOD(smbus_bwrite, intsmb_bwrite), 801a9656fbcSSascha Wildner DEVMETHOD(smbus_bread, intsmb_bread), 802a9656fbcSSascha Wildner 803a9656fbcSSascha Wildner { 0, 0 } 804a9656fbcSSascha Wildner }; 805a9656fbcSSascha Wildner 806a9656fbcSSascha Wildner static driver_t intsmb_driver = { 807a9656fbcSSascha Wildner "intsmb", 808a9656fbcSSascha Wildner intsmb_methods, 809a9656fbcSSascha Wildner sizeof(struct intsmb_softc), 810a9656fbcSSascha Wildner }; 811a9656fbcSSascha Wildner 812*aa2b9d05SSascha Wildner DRIVER_MODULE(intsmb, pci, intsmb_driver, intsmb_devclass, NULL, NULL); 813*aa2b9d05SSascha Wildner DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, NULL, NULL); 814a9656fbcSSascha Wildner MODULE_DEPEND(intsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 815a9656fbcSSascha Wildner MODULE_VERSION(intsmb, 1); 816