The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pci/intpm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1998, 1999 Takanori Watanabe
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *        notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *        notice, this list of conditions and the following disclaimer in the
   12  *        documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  *      $FreeBSD$
   27  */
   28 
   29 #include "pci.h"
   30 #include "intpm.h"
   31 
   32 #if NPCI > 0
   33 #if NINTPM >0
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <machine/bus_pio.h>
   38 #include <machine/bus_memio.h>
   39 #include <machine/bus.h>
   40 
   41 #include <machine/clock.h>
   42 #include <sys/uio.h>
   43 #include <sys/module.h>
   44 #include <sys/bus.h>
   45 #include <sys/conf.h>
   46 #include <sys/malloc.h>
   47 #include <sys/buf.h>
   48 
   49 #include <dev/smbus/smbconf.h>
   50 
   51 #include "smbus_if.h"
   52 
   53 /*This should be removed if force_pci_map_int supported*/
   54 #include <sys/interrupt.h>
   55 
   56 #include <pci/pcireg.h>
   57 #include <pci/pcivar.h>
   58 #include <pci/intpmreg.h>
   59 
   60 #include "opt_intpm.h"
   61 
   62 static struct _pcsid
   63 {
   64         pcidi_t type;
   65         char    *desc;
   66 } pci_ids[] =
   67 {
   68         { 0x71138086,"Intel 82371AB Power management controller"},
   69         
   70         { 0x00000000,   NULL                                    }
   71 };
   72 static int intsmb_probe(device_t);
   73 static int intsmb_attach(device_t);
   74 static void intsmb_print_child(device_t, device_t);
   75 
   76 static int intsmb_intr(device_t dev);
   77 static int intsmb_slvintr(device_t dev);
   78 static void  intsmb_alrintr(device_t dev);
   79 static int intsmb_callback(device_t dev, int index, caddr_t data);
   80 static int intsmb_quick(device_t dev, u_char slave, int how);
   81 static int intsmb_sendb(device_t dev, u_char slave, char byte);
   82 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
   83 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   84 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
   85 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   86 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   87 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
   88 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   89 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   90 static void intsmb_start(device_t dev,u_char cmd,int nointr);
   91 static int intsmb_stop(device_t dev);
   92 static int intsmb_stop_poll(device_t dev);
   93 static int intsmb_free(device_t dev);
   94 static struct intpm_pci_softc *intpm_alloc(int unit);
   95 static const char* intpm_probe __P((pcici_t tag, pcidi_t type));
   96 static void intpm_attach __P((pcici_t config_id, int unit));
   97 static devclass_t intsmb_devclass;
   98 
   99 static device_method_t intpm_methods[]={
  100         DEVMETHOD(device_probe,intsmb_probe),
  101         DEVMETHOD(device_attach,intsmb_attach),
  102 
  103         DEVMETHOD(bus_print_child, intsmb_print_child),
  104         
  105         DEVMETHOD(smbus_callback,intsmb_callback),
  106         DEVMETHOD(smbus_quick,intsmb_quick),
  107         DEVMETHOD(smbus_sendb,intsmb_sendb),
  108         DEVMETHOD(smbus_recvb,intsmb_recvb),
  109         DEVMETHOD(smbus_writeb,intsmb_writeb),
  110         DEVMETHOD(smbus_writew,intsmb_writew),
  111         DEVMETHOD(smbus_readb,intsmb_readb),
  112         DEVMETHOD(smbus_readw,intsmb_readw),
  113         DEVMETHOD(smbus_pcall,intsmb_pcall),
  114         DEVMETHOD(smbus_bwrite,intsmb_bwrite),
  115         DEVMETHOD(smbus_bread,intsmb_bread),
  116         {0,0}
  117 };
  118 
  119 static struct intpm_pci_softc{
  120         bus_space_tag_t smbst;
  121         bus_space_handle_t smbsh;
  122         bus_space_tag_t pmst;
  123         bus_space_handle_t pmsh;
  124         pcici_t cfg;
  125         device_t  smbus;
  126 }intpm_pci[NINTPM];
  127 
  128 
  129 struct intsmb_softc{
  130         struct intpm_pci_softc *pci_sc;
  131         bus_space_tag_t st;
  132         bus_space_handle_t sh;
  133         device_t smbus;
  134         int isbusy;
  135 };
  136 static driver_t intpm_driver = {
  137         "intsmb",
  138         intpm_methods,
  139         DRIVER_TYPE_MISC,
  140         sizeof(struct intsmb_softc),
  141 };
  142 static u_long intpm_count ;
  143 
  144 static struct   pci_device intpm_device = {
  145         "intpm",
  146         intpm_probe,
  147         intpm_attach,
  148         &intpm_count
  149 };
  150 
  151 DATA_SET (pcidevice_set, intpm_device);
  152 
  153 static int 
  154 intsmb_probe(device_t dev)
  155 {
  156         struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
  157         sc->smbus=smbus_alloc_bus(dev);
  158         if (!sc->smbus)
  159                 return (EINVAL);    /* XXX don't know what to return else */
  160         device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
  161         
  162         return (0);          /* XXX don't know what to return else */
  163 }
  164 static int
  165 intsmb_attach(device_t dev)
  166 {
  167         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  168         sc->pci_sc=&intpm_pci[device_get_unit(dev)];
  169         sc->isbusy=0;
  170         sc->sh=sc->pci_sc->smbsh;
  171         sc->st=sc->pci_sc->smbst;
  172         sc->pci_sc->smbus=dev;
  173         device_probe_and_attach(sc->smbus);
  174 #ifdef ENABLE_ALART
  175         /*Enable Arart*/
  176         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
  177                           PIIX4_SMBSLVCNT_ALTEN);
  178 #endif 
  179         return (0);
  180 }
  181 
  182 static void
  183 intsmb_print_child(device_t bus, device_t dev)
  184 {
  185         printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
  186         return;
  187 }
  188 static int 
  189 intsmb_callback(device_t dev, int index, caddr_t data)
  190 {
  191         int error = 0;
  192         intrmask_t s;
  193         s=splnet();
  194         switch (index) {
  195         case SMB_REQUEST_BUS:
  196                 break;
  197         case SMB_RELEASE_BUS:
  198                 break;
  199         default:
  200                 error = EINVAL;
  201         }
  202         splx(s);
  203         return (error);
  204 }
  205 /*counterpart of smbtx_smb_free*/
  206 static        int
  207 intsmb_free(device_t dev){
  208         intrmask_t s;
  209         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  210         if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
  211             PIIX4_SMBHSTSTAT_BUSY)
  212 #ifdef ENABLE_ALART
  213            ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
  214               PIIX4_SMBSLVSTS_BUSY)
  215 #endif
  216            || sc->isbusy)
  217                 return EBUSY;
  218         s=splhigh();
  219         sc->isbusy=1;
  220         /*Disable Intrrupt in slave part*/
  221 #ifndef ENABLE_ALART
  222         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
  223 #endif
  224         /*Reset INTR Flag to prepare INTR*/
  225         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
  226                           (PIIX4_SMBHSTSTAT_INTR|
  227                            PIIX4_SMBHSTSTAT_ERR|
  228                            PIIX4_SMBHSTSTAT_BUSC|
  229                            PIIX4_SMBHSTSTAT_FAIL)
  230                 );
  231         splx(s);
  232         return 0;
  233 }
  234 
  235 static int
  236 intsmb_intr(device_t dev)
  237 {
  238         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  239         int status;
  240         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
  241         if(status&PIIX4_SMBHSTSTAT_BUSY){
  242                 return 1;
  243                 
  244         }
  245         if(status&(PIIX4_SMBHSTSTAT_INTR|
  246                                 PIIX4_SMBHSTSTAT_ERR|
  247                                 PIIX4_SMBHSTSTAT_BUSC|
  248                                 PIIX4_SMBHSTSTAT_FAIL)){
  249                 int tmp;
  250                 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  251                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
  252                                   tmp&~PIIX4_SMBHSTCNT_INTREN);
  253                 if(sc->isbusy){
  254                   sc->isbusy=0;
  255                   wakeup(sc);
  256                 }
  257                 return 0;
  258         }
  259         return 1;/* Not Completed*/
  260 }
  261 static int
  262 intsmb_slvintr(device_t dev)
  263 {
  264         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  265         int status,retval;
  266         retval=1;
  267         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
  268         if(status&PIIX4_SMBSLVSTS_BUSY)
  269                 return retval;
  270         if(status&PIIX4_SMBSLVSTS_ALART){
  271                 intsmb_alrintr(dev);
  272                 retval=0;
  273         }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
  274                           |PIIX4_SMBSLVSTS_SDW1)){
  275                 retval=0;
  276         }
  277         /*Reset Status Register*/
  278         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
  279                           PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
  280                           PIIX4_SMBSLVSTS_SLV);
  281         return retval;
  282 }
  283 
  284 static void intsmb_alrintr(device_t dev)
  285 {
  286         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  287         int slvcnt;
  288 #ifdef ENABLE_ALART
  289         int error;
  290 #endif
  291 
  292         /*stop generating INTR from ALART*/
  293         slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
  294 #ifdef ENABLE_ALART
  295         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
  296                           slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
  297 #endif
  298         DELAY(5);
  299         /*ask bus who assert it and then ask it what's the matter. */   
  300 #ifdef ENABLE_ALART
  301         error=intsmb_free(dev);
  302         if(!error){
  303                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
  304                                   |LSB);
  305                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
  306                 if(!(error=intsmb_stop_poll(dev))){
  307                         volatile u_int8_t *addr;
  308                         addr=bus_space_read_1(sc->st,sc->sh,
  309                                               PIIX4_SMBHSTDAT0);
  310                         printf("ALART_RESPONSE: %p\n", addr);
  311                 }
  312         }else{
  313                 printf("ERROR\n");
  314         }
  315 
  316         /*Re-enable INTR from ALART*/
  317         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
  318                           slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
  319         DELAY(5);
  320 #endif
  321 
  322         return;
  323 }
  324 static void
  325 intsmb_start(device_t dev,unsigned char cmd,int nointr)
  326 {
  327         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  328         unsigned char tmp;
  329         tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  330         tmp&= 0xe0;
  331         tmp |= cmd;
  332         tmp |=PIIX4_SMBHSTCNT_START;
  333         /*While not in autoconfiguration Intrrupt Enabled*/
  334         if(!cold||!nointr)
  335                 tmp |=PIIX4_SMBHSTCNT_INTREN;
  336         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
  337 }
  338 
  339 /*Polling Code. Polling is not encouraged 
  340  * because It is required to wait for the device get busy.
  341  *(29063505.pdf from Intel)
  342  * But during boot,intrrupt cannot be used.
  343  * so use polling code while in autoconfiguration.
  344  */
  345 
  346 static        int
  347 intsmb_stop_poll(device_t dev){
  348         int error,i;
  349         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  350         
  351         /*
  352          *  In smbtx driver ,Simply waiting.
  353          *  This loops 100-200 times.
  354          */
  355         for(i=0;i<0x7fff;i++){
  356                 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
  357                     &PIIX4_SMBHSTSTAT_BUSY)){
  358                         break;
  359                 }
  360         }
  361         for(i=0;i<0x7fff;i++){
  362                 int status;
  363                 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
  364                 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
  365                         sc->isbusy=0;
  366                         error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
  367                                 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
  368                                 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
  369                         if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
  370                                 printf("unknown cause why?");
  371                         }
  372                         return error;
  373                 }
  374         }
  375         {
  376           int tmp;
  377           sc->isbusy=0;
  378           tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  379           bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
  380                             tmp&~PIIX4_SMBHSTCNT_INTREN);
  381         }
  382         return EIO;
  383 }
  384 /*
  385  *wait for completion and return result.
  386  */
  387 static        int
  388 intsmb_stop(device_t dev){
  389         int error;
  390         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  391         intrmask_t s;
  392         if(cold){
  393                 /*So that it can use device during probing device on SMBus.*/
  394                 error=intsmb_stop_poll(dev);
  395                 return error;
  396         }else{
  397                 if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
  398                         int status;
  399                         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
  400                         if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
  401                                 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
  402                                         (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
  403                                         (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
  404                                 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
  405                                         printf("intsmb%d:unknown cause why?\n",
  406                                                device_get_unit(dev));
  407                                 }
  408 #ifdef ENABLE_ALART
  409                                 bus_space_write_1(sc->st,sc->sh,
  410                                                   PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
  411 #endif
  412                                 return error;
  413                         }
  414                 }
  415         }
  416         /*Timeout Procedure*/
  417         s=splhigh();
  418         sc->isbusy=0;
  419         /*Re-enable supressed intrrupt from slave part*/
  420         bus_space_write_1(sc->st,sc->sh,
  421                           PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
  422         splx(s);
  423         return EIO;
  424 }
  425 
  426 static int
  427 intsmb_quick(device_t dev, u_char slave, int how)
  428 {
  429         int error=0;
  430         u_char data;
  431         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  432         data=slave;
  433         /*Quick command is part of Address, I think*/
  434         switch(how){
  435         case SMB_QWRITE:
  436                 data&=~LSB;
  437                 break;
  438         case SMB_QREAD:
  439                 data|=LSB;
  440                 break;
  441         default:
  442                 error=EINVAL;
  443         }
  444         if(!error){
  445                 error=intsmb_free(dev);
  446                 if(!error){
  447                         bus_space_write_1(sc->st,sc->sh,
  448                                           PIIX4_SMBHSTADD,data);
  449                         intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
  450                         error=intsmb_stop(dev);
  451                 }
  452         }
  453 
  454         return (error);
  455 }
  456 
  457 static int
  458 intsmb_sendb(device_t dev, u_char slave, char byte)
  459 {
  460         int error;
  461         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  462         error=intsmb_free(dev);
  463         if(!error){
  464                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  465                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
  466                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
  467                 error=intsmb_stop(dev);
  468         }
  469         return (error);
  470 }
  471 static int
  472 intsmb_recvb(device_t dev, u_char slave, char *byte)
  473 {
  474         int error;
  475         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  476         error=intsmb_free(dev);
  477         if(!error){
  478                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
  479                                   |LSB);
  480                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
  481                 if(!(error=intsmb_stop(dev))){
  482 #ifdef RECV_IS_IN_CMD
  483                         /*Linux SMBus stuff also troubles
  484                           Because Intel's datasheet will not make clear.
  485                          */
  486                         *byte=bus_space_read_1(sc->st,sc->sh,
  487                                                PIIX4_SMBHSTCMD);
  488 #else
  489                         *byte=bus_space_read_1(sc->st,sc->sh,
  490                                                PIIX4_SMBHSTDAT0);
  491 #endif
  492                 }
  493         }
  494         return (error);
  495 }
  496 static int
  497 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  498 {
  499         int error;
  500         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  501         error=intsmb_free(dev);
  502         if(!error){
  503                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  504                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  505                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
  506                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
  507                 error=intsmb_stop(dev);
  508         }
  509         return (error);
  510 }
  511 static int
  512 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
  513 {
  514         int error;
  515         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  516         error=intsmb_free(dev);
  517         if(!error){
  518                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  519                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  520                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
  521                                   word&0xff);
  522                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
  523                                   (word>>8)&0xff);
  524                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
  525                 error=intsmb_stop(dev);
  526         }
  527         return (error);
  528 }
  529 
  530 static int
  531 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  532 {
  533         int error;
  534         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  535         error=intsmb_free(dev);
  536         if(!error){
  537                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
  538                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  539                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
  540                 if(!(error=intsmb_stop(dev))){
  541                         *byte=bus_space_read_1(sc->st,sc->sh,
  542                                                PIIX4_SMBHSTDAT0);
  543                 }
  544         }
  545         return (error);
  546 }
  547 static int
  548 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  549 {
  550         int error;
  551         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  552         error=intsmb_free(dev);
  553         if(!error){
  554                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
  555                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  556                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
  557                 if(!(error=intsmb_stop(dev))){
  558                         *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
  559                         *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
  560                 }
  561         }
  562         return (error);
  563 }
  564 /*
  565  * Data sheet claims that it implements all function, but also claims
  566  * that it implements 7 function and not mention PCALL. So I don't know
  567  * whether it will work.
  568  */
  569 static int
  570 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  571 {
  572 #ifdef PROCCALL_TEST
  573         int error;
  574         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  575         error=intsmb_free(dev);
  576         if(!error){
  577                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  578                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  579                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
  580                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
  581                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
  582         }
  583         if(!(error=intsmb_stop(dev))){
  584                 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
  585                 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
  586         }
  587         return error;
  588 #else
  589         return 0;
  590 #endif
  591 }
  592 static int
  593 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  594 {
  595         int error,i;
  596         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  597         error=intsmb_free(dev);
  598         if(count>SMBBLOCKTRANS_MAX||count==0)
  599                 error=EINVAL;
  600         if(!error){
  601                 /*Reset internal array index*/
  602                 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  603                 
  604                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  605                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  606                 for(i=0;i<count;i++){
  607                         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
  608                 }
  609                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
  610                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
  611                 error=intsmb_stop(dev);
  612         }
  613         return (error);
  614 }
  615 
  616 static int
  617 intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  618 {
  619         int error,i;
  620         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  621         error=intsmb_free(dev);
  622         if(count>SMBBLOCKTRANS_MAX||count==0)
  623                 error=EINVAL;
  624         if(!error){
  625                 /*Reset internal array index*/
  626                 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  627                 
  628                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
  629                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  630                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
  631                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
  632                 error=intsmb_stop(dev);
  633                 if(!error){
  634                         bzero(buf,count);/*Is it needed?*/
  635                         count= bus_space_read_1(sc->st,sc->sh,
  636                                                 PIIX4_SMBHSTDAT0);
  637                         if(count!=0&&count<=SMBBLOCKTRANS_MAX){
  638                                 for(i=0;i<count;i++){
  639                                         buf[i]=bus_space_read_1(sc->st,
  640                                                                 sc->sh,
  641                                                                 PIIX4_SMBBLKDAT);
  642                                 }
  643                         }
  644                         else{
  645                                 error=EIO;
  646                         }
  647                 }
  648         }
  649         return (error);
  650 }
  651 
  652 DRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0);
  653 
  654 
  655 static void intpm_intr __P((void *arg));
  656 
  657 static const char*
  658 intpm_probe (pcici_t tag, pcidi_t type)
  659 {
  660         struct _pcsid   *ep =pci_ids;
  661         while (ep->type && ep->type != type)
  662                 ++ep;
  663         return (ep->desc);
  664 }
  665 
  666 static struct intpm_pci_softc *intpm_alloc(int unit){
  667         if(unit<NINTPM)
  668                 return &intpm_pci[unit];
  669         else
  670                 return NULL;
  671 }
  672 
  673 /*Same as pci_map_int but this ignores INTPIN*/
  674 static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr)
  675 {
  676         int error;
  677 #ifdef APIC_IO
  678         int nextpin, muxcnt;
  679 #endif
  680         /* Spec sheet claims that it use IRQ 9*/
  681         int irq = 9;
  682         void *dev_instance = (void *)-1; /* XXX use cfg->devdata        */
  683         void *idesc;
  684         
  685         idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0);
  686         error = intr_connect(idesc);
  687         if (error != 0)
  688                 return 0;
  689 #ifdef APIC_IO
  690         nextpin = next_apic_irq(irq);
  691         
  692         if (nextpin < 0)
  693                 return 1;
  694         
  695         /* 
  696          * Attempt handling of some broken mp tables.
  697          *
  698          * It's OK to yell (since the mp tables are broken).
  699          * 
  700          * Hanging in the boot is not OK
  701          */
  702         
  703         muxcnt = 2;
  704         nextpin = next_apic_irq(nextpin);
  705         while (muxcnt < 5 && nextpin >= 0) {
  706                 muxcnt++;
  707                 nextpin = next_apic_irq(nextpin);
  708         }
  709         if (muxcnt >= 5) {
  710                 printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n");
  711                 return 0;
  712         }
  713         
  714         printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt);
  715         
  716         nextpin = next_apic_irq(irq);
  717         while (nextpin >= 0) {
  718                 idesc = intr_create(dev_instance, nextpin, func, arg,
  719                                     maskptr, 0);
  720                 error = intr_connect(idesc);
  721                 if (error != 0)
  722                         return 0;
  723                 printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq);
  724                 nextpin = next_apic_irq(nextpin);
  725         }
  726 #endif
  727         return 1;
  728 }
  729 static void
  730 intpm_attach(config_id, unit)
  731      pcici_t config_id;
  732      int        unit;
  733 {
  734         int value;
  735         
  736         char * str;
  737         {
  738                 struct intpm_pci_softc *sciic;
  739                 device_t smbinterface;
  740                 value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4);
  741                 sciic=intpm_alloc(unit);
  742                 if(sciic==NULL){
  743                         return;
  744                 }
  745 
  746                 sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM;
  747 
  748                 /*Calling pci_map_port is better.But bus_space_handle_t != 
  749                  * pci_port_t, so I don't call support routine while 
  750                  * bus_space_??? support routine will be appear.
  751                  */
  752                 sciic->smbsh=value&(~1);
  753                 if(sciic->smbsh==I386_BUS_SPACE_MEM){
  754                        /*According to the spec, this will not occur*/
  755                        int dummy;
  756                        pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy);
  757                 }
  758                 printf("intpm%d: %s %x ",unit,
  759                        (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory",
  760                        sciic->smbsh);
  761 #ifndef NO_CHANGE_PCICONF
  762                 pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1);
  763                 pci_cfgwrite(config_id,PCI_HST_CFG_SMB, 
  764                              PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
  765 #endif
  766                 config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1);
  767                 printf("ALLOCED IRQ %d ",config_id->intline);
  768                 value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1);
  769                 switch(value&0xe){
  770                 case PCI_INTR_SMB_SMI:
  771                         str="SMI";
  772                         break;
  773                 case PCI_INTR_SMB_IRQ9:
  774                         str="IRQ 9";
  775                         break;
  776                 default:
  777                         str="BOGUS";
  778                 }
  779                 printf("intr %s %s ",str,((value&1)? "enabled":"disabled"));
  780                 value=pci_cfgread(config_id,PCI_REVID_SMB,1);
  781                 printf("revision %d\n",value);                
  782                 /*
  783                  * Install intr HANDLER here
  784                  */
  785                 if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){
  786                         printf("intpm%d: Failed to map intr\n",unit);
  787                 }
  788                 smbinterface=device_add_child(root_bus,"intsmb",unit,NULL);
  789                 device_probe_and_attach(smbinterface);
  790         }
  791         value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4);
  792         printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
  793         return;
  794 }
  795 static void intpm_intr(void *arg)
  796 {
  797         struct intpm_pci_softc *sc;
  798         sc=(struct intpm_pci_softc *)arg;
  799         intsmb_intr(sc->smbus);
  800         intsmb_slvintr(sc->smbus);
  801         
  802 }
  803 #endif /* NPCI > 0 */
  804 #endif

Cache object: 55bd922a045406dadd3c2e451b6774f3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.