diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/pci/intpm.c | 789 | ||||
-rw-r--r-- | sys/pci/intpmreg.h | 77 |
2 files changed, 866 insertions, 0 deletions
diff --git a/sys/pci/intpm.c b/sys/pci/intpm.c new file mode 100644 index 0000000..9d3eccc --- /dev/null +++ b/sys/pci/intpm.c @@ -0,0 +1,789 @@ +/*- + * Copyright (c) 1998, 1999 Takanori Watanabe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include "pci.h" +#include "intpm.h" + +#if NPCI > 0 +#if NINTPM >0 +/* I don't think the chip is used in other architecture. :-)*/ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> + +#include <machine/clock.h> +#include <sys/uio.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/malloc.h> +#include <sys/buf.h> + +#include <dev/smbus/smbconf.h> + +#include "smbus_if.h" + +/*This should be removed if force_pci_map_int supported*/ +#include <sys/interrupt.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> +#include <pci/intpmreg.h> + +#include "opt_intpm.h" + +static struct _pcsid +{ + pcidi_t type; + char *desc; +} pci_ids[] = +{ + { 0x71138086,"Intel 82371AB Power management controller"}, + + { 0x00000000, NULL } +}; +static int intsmb_probe(device_t); +static int intsmb_attach(device_t); +static void intsmb_print_child(device_t, device_t); + +static int intsmb_intr(device_t dev); +static int intsmb_slvintr(device_t dev); +static void intsmb_alrintr(device_t dev); +static int intsmb_callback(device_t dev, int index, caddr_t data); +static int intsmb_quick(device_t dev, u_char slave, int how); +static int intsmb_sendb(device_t dev, u_char slave, char byte); +static int intsmb_recvb(device_t dev, u_char slave, char *byte); +static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); +static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); +static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); +static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); +static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); +static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); +static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); +static void intsmb_start(device_t dev,u_char cmd,int nointr); +static int intsmb_stop(device_t dev); +static int intsmb_stop_poll(device_t dev); +static int intsmb_free(device_t dev); +static struct intpm_pci_softc *intpm_alloc(int unit); +static const char* intpm_probe __P((pcici_t tag, pcidi_t type)); +static void intpm_attach __P((pcici_t config_id, int unit)); +static devclass_t intsmb_devclass; + +static device_method_t intpm_methods[]={ + DEVMETHOD(device_probe,intsmb_probe), + DEVMETHOD(device_attach,intsmb_attach), + + DEVMETHOD(bus_print_child, intsmb_print_child), + + DEVMETHOD(smbus_callback,intsmb_callback), + DEVMETHOD(smbus_quick,intsmb_quick), + DEVMETHOD(smbus_sendb,intsmb_sendb), + DEVMETHOD(smbus_recvb,intsmb_recvb), + DEVMETHOD(smbus_writeb,intsmb_writeb), + DEVMETHOD(smbus_writew,intsmb_writew), + DEVMETHOD(smbus_readb,intsmb_readb), + DEVMETHOD(smbus_readw,intsmb_readw), + DEVMETHOD(smbus_pcall,intsmb_pcall), + DEVMETHOD(smbus_bwrite,intsmb_bwrite), + DEVMETHOD(smbus_bread,intsmb_bread), + {0,0} +}; + +static struct intpm_pci_softc{ + bus_space_tag_t smbst; + bus_space_handle_t smbsh; + bus_space_tag_t pmst; + bus_space_handle_t pmsh; + pcici_t cfg; + device_t smbus; +}intpm_pci[NINTPM]; + + +struct intsmb_softc{ + struct intpm_pci_softc *pci_sc; + bus_space_tag_t st; + bus_space_handle_t sh; + device_t smbus; + int isbusy; +}; +static driver_t intpm_driver = { + "intsmb", + intpm_methods, + DRIVER_TYPE_MISC, + sizeof(struct intsmb_softc), +}; +static u_long intpm_count ; + +static struct pci_device intpm_device = { + "intpm", + intpm_probe, + intpm_attach, + &intpm_count +}; + +DATA_SET (pcidevice_set, intpm_device); + +static int +intsmb_probe(device_t dev) +{ + struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); + sc->smbus=smbus_alloc_bus(dev); + if (!sc->smbus) + return (EINVAL); /* XXX don't know what to return else */ + device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); + + return (0); /* XXX don't know what to return else */ +} +static int +intsmb_attach(device_t dev) +{ + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + sc->pci_sc=&intpm_pci[device_get_unit(dev)]; + sc->isbusy=0; + sc->sh=sc->pci_sc->smbsh; + sc->st=sc->pci_sc->smbst; + sc->pci_sc->smbus=dev; + device_probe_and_attach(sc->smbus); +#ifdef ENABLE_ALART + /*Enable Arart*/ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, + PIIX4_SMBSLVCNT_ALTEN); +#endif + return (0); +} + +static void +intsmb_print_child(device_t bus, device_t dev) +{ + printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); + return; +} +static int +intsmb_callback(device_t dev, int index, caddr_t data) +{ + int error = 0; + intrmask_t s; + s=splnet(); + switch (index) { + case SMB_REQUEST_BUS: + break; + case SMB_RELEASE_BUS: + break; + default: + error = EINVAL; + } + splx(s); + return (error); +} +/*counterpart of smbtx_smb_free*/ +static int +intsmb_free(device_t dev){ + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& + PIIX4_SMBHSTSTAT_BUSY) +#ifdef ENABLE_ALART + ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& + PIIX4_SMBSLVSTS_BUSY) +#endif + || sc->isbusy) + return EBUSY; + sc->isbusy=1; + /*Disable Intrrupt in slave part*/ +#ifndef ENABLE_ALART + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); +#endif + /*Reset INTR Flag to prepare INTR*/ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, + (PIIX4_SMBHSTSTAT_INTR| + PIIX4_SMBHSTSTAT_ERR| + PIIX4_SMBHSTSTAT_BUSC| + PIIX4_SMBHSTSTAT_FAIL) + ); + return 0; +} + +static int +intsmb_intr(device_t dev) +{ + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + int status; + intrmask_t s; + status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); + if(status&PIIX4_SMBHSTSTAT_BUSY){ + return 1; + + } + s=splhigh(); + if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR| + PIIX4_SMBHSTSTAT_ERR| + PIIX4_SMBHSTSTAT_BUSC| + PIIX4_SMBHSTSTAT_FAIL))){ + int tmp; + sc->isbusy=0; + tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, + tmp&~PIIX4_SMBHSTCNT_INTREN); + splx(s); + wakeup(sc); + return 0; + } + splx(s); + return 1;/* Not Completed*/ +} +static int +intsmb_slvintr(device_t dev) +{ + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + int status,retval; + retval=1; + status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); + if(status&PIIX4_SMBSLVSTS_BUSY) + return retval; + if(status&PIIX4_SMBSLVSTS_ALART){ + intsmb_alrintr(dev); + retval=0; + }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 + |PIIX4_SMBSLVSTS_SDW1)){ + retval=0; + } + /*Reset Status Register*/ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| + PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| + PIIX4_SMBSLVSTS_SLV); + return retval; +} + +static void intsmb_alrintr(device_t dev) +{ + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + int slvcnt; + /*stop generating INTR from ALART*/ + slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); +#ifdef ENABLE_ALART + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, + slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; +#endif + DELAY(5); + /*ask bus who assert it and then ask it what's the matter. */ +#ifdef ENABLE_ALART + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP + |LSB); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); + if(!(error=intsmb_stop_poll(dev))){ + addr=bus_space_read_1(sc->st,sc->sh, + PIIX4_SMBHSTDAT0); + printf("ALART_RESPONSE: %x\n",(int) addr); + } + }else{ + printf("ERROR\n"); + } + + /*Re-enable INTR from ALART*/ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, + slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; + DELAY(5); +#endif + + return; +} +static void +intsmb_start(device_t dev,unsigned char cmd,int nointr) +{ + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + unsigned char tmp; + tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); + tmp&= 0xe0; + tmp |= cmd; + tmp |=PIIX4_SMBHSTCNT_START; + /*While not in autoconfiguration Intrrupt Enabled*/ + if(!cold||!nointr) + tmp |=PIIX4_SMBHSTCNT_INTREN; + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); +} + +/*Polling Code. Polling is not encouraged + * because It is required to wait for the device get busy. + *(29063505.pdf from Intel) + * But during boot,intrrupt cannot be used. + * so use polling code while in autoconfiguration. + */ + +static int +intsmb_stop_poll(device_t dev){ + int error,i; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + /* + * In smbtx driver ,Simply waiting. + * This loops 100-200 times. + */ + for(i=0;i<0x7fff;i++){ + if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) + &PIIX4_SMBHSTSTAT_BUSY)){ + break; + } + } + for(i=0;i<0x7fff;i++){ + int status; + status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); + if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ + sc->isbusy=0; + error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : + (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: + (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; + if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ + printf("unknown cause why?"); + } + return error; + } + } + sc->isbusy=0; + return EIO; +} +/* + *wait for completion and return result. + */ +static int +intsmb_stop(device_t dev){ + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + if(cold){ + /*So that it can use device during probing device on SMBus.*/ + error=intsmb_stop_poll(dev); + return error; + }else{ + if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ + int status; + status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); + if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ + error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : + (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: + (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; + if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ + printf("intsmb%d:unknown cause why?\n", + device_get_unit(dev)); + } +#ifdef ENABLE_ALART + bus_space_write_1(sc->st,sc->sh, + PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); +#endif + return error; + } + } + } + /*Timeout Procedure*/ + sc->isbusy=0; + /*Re-enable supressed intrrupt from slave part*/ + bus_space_write_1(sc->st,sc->sh, + PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); + return EIO; +} + +static int +intsmb_quick(device_t dev, u_char slave, int how) +{ + int error=0; + u_char data; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + data=slave; + /*Quick command is part of Address, I think*/ + switch(how){ + case SMB_QWRITE: + data&=~LSB; + break; + case SMB_QREAD: + data|=LSB; + break; + default: + error=EINVAL; + } + if(!error){ + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh, + PIIX4_SMBHSTADD,data); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); + error=intsmb_stop(dev); + } + } + + return (error); +} + +static int +intsmb_sendb(device_t dev, u_char slave, char byte) +{ + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); + error=intsmb_stop(dev); + } + return (error); +} +static int +intsmb_recvb(device_t dev, u_char slave, char *byte) +{ + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave + |LSB); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); + if(!(error=intsmb_stop(dev))){ +#ifdef RECV_IS_IN_CMD + /*Linux SMBus stuff also troubles + Because Intel's datasheet will not make clear. + */ + *byte=bus_space_read_1(sc->st,sc->sh, + PIIX4_SMBHSTCMD); +#else + *byte=bus_space_read_1(sc->st,sc->sh, + PIIX4_SMBHSTDAT0); +#endif + } + } + return (error); +} +static int +intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) +{ + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); + error=intsmb_stop(dev); + } + return (error); +} +static int +intsmb_writew(device_t dev, u_char slave, char cmd, short word) +{ + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, + word&0xff); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, + (word>>8)&0xff); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); + error=intsmb_stop(dev); + } + return (error); +} + +static int +intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) +{ + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); + if(!(error=intsmb_stop(dev))){ + *byte=bus_space_read_1(sc->st,sc->sh, + PIIX4_SMBHSTDAT0); + } + } + return (error); +} +static int +intsmb_readw(device_t dev, u_char slave, char cmd, short *word) +{ + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); + if(!(error=intsmb_stop(dev))){ + *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; + *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; + } + } + return (error); +} +/* + * Data sheet claims that it implements all function, but also claims + * that it implements 7 function and not mention PCALL. So I don't know + * whether it will work. + */ +static int +intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) +{ +#ifdef PROCCALL_TEST + int error; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(!error){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); + } + if(!(error=intsmb_stop(dev))){ + *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; + *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; + } + return error; +#else + return 0; +#endif +} +static int +intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) +{ + int error,i; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(count>SMBBLOCKTRANS_MAX||count==0) + error=EINVAL; + if(!error){ + /*Reset internal array index*/ + bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); + + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); + for(i=0;i<count;i++){ + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]); + } + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); + error=intsmb_stop(dev); + } + return (error); +} + +static int +intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) +{ + int error,i; + struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); + error=intsmb_free(dev); + if(count>SMBBLOCKTRANS_MAX||count==0) + error=EINVAL; + if(!error){ + /*Reset internal array index*/ + bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); + + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); + bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); + intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); + error=intsmb_stop(dev); + if(!error){ + bzero(buf,count);/*Is it needed?*/ + count= bus_space_read_1(sc->st,sc->sh, + PIIX4_SMBHSTDAT0); + if(count!=0&&count<=SMBBLOCKTRANS_MAX){ + for(i=0;i<count;i++){ + buf[i]=bus_space_read_1(sc->st, + sc->sh, + PIIX4_SMBBLKDAT); + } + } + else{ + error=EIO; + } + } + } + return (error); +} + +DRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0); + + +static void intpm_intr __P((void *arg)); + +static const char* +intpm_probe (pcici_t tag, pcidi_t type) +{ + struct _pcsid *ep =pci_ids; + while (ep->type && ep->type != type) + ++ep; + return (ep->desc); +} + +static struct intpm_pci_softc *intpm_alloc(int unit){ + if(unit<NINTPM) + return &intpm_pci[unit]; + else + return NULL; +} + +/*Same as pci_map_int but this ignores INTPIN*/ +static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr) +{ + int error; +#ifdef APIC_IO + int nextpin, muxcnt; +#endif + /* Spec sheet claims that it use IRQ 9*/ + int irq = 9; + void *dev_instance = (void *)-1; /* XXX use cfg->devdata */ + void *idesc; + + idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0); + error = intr_connect(idesc); + if (error != 0) + return 0; +#ifdef APIC_IO + nextpin = next_apic_irq(irq); + + if (nextpin < 0) + return 1; + + /* + * Attempt handling of some broken mp tables. + * + * It's OK to yell (since the mp tables are broken). + * + * Hanging in the boot is not OK + */ + + muxcnt = 2; + nextpin = next_apic_irq(nextpin); + while (muxcnt < 5 && nextpin >= 0) { + muxcnt++; + nextpin = next_apic_irq(nextpin); + } + if (muxcnt >= 5) { + printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n"); + return 0; + } + + printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt); + + nextpin = next_apic_irq(irq); + while (nextpin >= 0) { + idesc = intr_create(dev_instance, nextpin, func, arg, + maskptr, 0); + error = intr_connect(idesc); + if (error != 0) + return 0; + printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq); + nextpin = next_apic_irq(nextpin); + } +#endif + return 1; +} +static void +intpm_attach(config_id, unit) + pcici_t config_id; + int unit; +{ + int value; + + char * str; + { + struct intpm_pci_softc *sciic; + device_t smbinterface; + value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4); + sciic=intpm_alloc(unit); + if(sciic==NULL){ + return; + } + + sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM; + + /*Calling pci_map_port is better.But bus_space_handle_t != + * pci_port_t, so I don't call support routine while + * bus_space_??? support routine will be appear. + */ + sciic->smbsh=value&(~1); + if(sciic->smbsh==I386_BUS_SPACE_MEM){ + /*According to the spec, this will not occur*/ + int dummy; + pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy); + } + printf("intpm%d: %s %x ",unit, + (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory", + sciic->smbsh); +#ifndef NO_CHANGE_PCICONF + pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1); + pci_cfgwrite(config_id,PCI_HST_CFG_SMB, + PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); +#endif + config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1); + printf("ALLOCED IRQ %d ",config_id->intline); + value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1); + switch(value&0xe){ + case PCI_INTR_SMB_SMI: + str="SMI"; + break; + case PCI_INTR_SMB_IRQ9: + str="IRQ 9"; + break; + default: + str="BOGUS"; + } + printf("intr %s %s ",str,((value&1)? "enabled":"disabled")); + value=pci_cfgread(config_id,PCI_REVID_SMB,1); + printf("revision %d\n",value); + /* + * Install intr HANDLER here + */ + if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){ + printf("intpm%d: Failed to map intr\n",unit); + } + smbinterface=device_add_child(root_bus,"intsmb",unit,NULL); + device_probe_and_attach(smbinterface); + } + value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4); + printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); + return; +} +static void intpm_intr(void *arg) +{ + struct intpm_pci_softc *sc; + sc=(struct intpm_pci_softc *)arg; + intsmb_intr(sc->smbus); + intsmb_slvintr(sc->smbus); +} +#endif /* NPCI > 0 */ +#endif diff --git a/sys/pci/intpmreg.h b/sys/pci/intpmreg.h new file mode 100644 index 0000000..fdadef0 --- /dev/null +++ b/sys/pci/intpmreg.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1998, 1999 Takanori Watanabe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +/*Register Difinition for Intel Chipset with ACPI Support*/ +#define PCI_BASE_ADDR_SMB 0x90 /*Where to MAP IO*/ +#define PCI_BASE_ADDR_PM 0x40 +#define PCI_HST_CFG_SMB 0xd2 /*Host Configuration*/ +#define PCI_INTR_SMB_SMI 0 +#define PCI_INTR_SMB_IRQ9 8 +#define PCI_INTR_SMB_ENABLE 1 +#define PCI_SLV_CMD_SMB 0xd3 /*SLAVE COMMAND*/ +#define PCI_SLV_SDW_SMB_1 0xd4 /*SLAVE SHADOW PORT 1*/ +#define PCI_SLV_SDW_SMB_2 0xd5 /*SLAVE SHADOW PORT 2*/ +#define PCI_REVID_SMB 0xd6 +#define LSB 0x1 +#define PIIX4_SMBHSTSTS 0x00 +#define PIIX4_SMBHSTSTAT_BUSY (1<<0) +#define PIIX4_SMBHSTSTAT_INTR (1<<1) +#define PIIX4_SMBHSTSTAT_ERR (1<<2) +#define PIIX4_SMBHSTSTAT_BUSC (1<<3) +#define PIIX4_SMBHSTSTAT_FAIL (1<<4) +#define PIIX4_SMBSLVSTS 0x01 +#define PIIX4_SMBSLVSTS_ALART (1<<5) +#define PIIX4_SMBSLVSTS_SDW2 (1<<4) +#define PIIX4_SMBSLVSTS_SDW1 (1<<3) +#define PIIX4_SMBSLVSTS_SLV (1<<2) +#define PIIX4_SMBSLVSTS_BUSY (1<<0) +#define PIIX4_SMBHSTCNT 0x02 +#define PIIX4_SMBHSTCNT_START (1<<6) +#define PIIX4_SMBHSTCNT_PROT_QUICK 0 +#define PIIX4_SMBHSTCNT_PROT_BYTE (1<<2) +#define PIIX4_SMBHSTCNT_PROT_BDATA (2<<2) +#define PIIX4_SMBHSTCNT_PROT_WDATA (3<<2) +#define PIIX4_SMBHSTCNT_PROT_BLOCK (5<<2) +#define SMBBLOCKTRANS_MAX 32 +#define PIIX4_SMBHSTCNT_KILL (1<<1) +#define PIIX4_SMBHSTCNT_INTREN (1) +#define PIIX4_SMBHSTCMD 0x03 +#define PIIX4_SMBHSTADD 0x04 +#define PIIX4_SMBHSTDAT0 0x05 +#define PIIX4_SMBHSTDAT1 0x06 +#define PIIX4_SMBBLKDAT 0x07 +#define PIIX4_SMBSLVCNT 0x08 +#define PIIX4_SMBSLVCNT_ALTEN (1<<3) +#define PIIX4_SMBSLVCNT_SD2EN (1<<2) +#define PIIX4_SMBSLVCNT_SD1EN (1<<1) +#define PIIX4_SMBSLVCNT_SLVEN (1) +#define PIIX4_SMBSLVCMD 0x09 +#define PIIX4_SMBSLVEVT 0x0a +#define PIIX4_SMBSLVDAT 0x0c +/*This is SMBus alart response address*/ +#define SMBALTRESP 0x18 |