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