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 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/6.3/sys/pci/intpm.c 173886 2007-11-24 19:45:58Z cvs2svn $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <machine/bus.h>
   34 
   35 #include <sys/uio.h>
   36 #include <sys/module.h>
   37 #include <sys/bus.h>
   38 #include <sys/rman.h>
   39 #include <machine/resource.h>
   40 #include <dev/smbus/smbconf.h>
   41 
   42 #include "smbus_if.h"
   43 
   44 /*This should be removed if force_pci_map_int supported*/
   45 #include <sys/interrupt.h>
   46 
   47 #include <dev/pci/pcireg.h>
   48 #include <dev/pci/pcivar.h>
   49 #include <pci/intpmreg.h>
   50 
   51 #include "opt_intpm.h"
   52 
   53 static struct _pcsid
   54 {
   55         u_int32_t type;
   56         char    *desc;
   57 } pci_ids[] = {
   58         { 0x71138086, "Intel 82371AB Power management controller" },
   59         { 0x719b8086, "Intel 82443MX Power management controller" },
   60 #if 0
   61         /* Not a good idea yet, this stops isab0 functioning */
   62         { 0x02001166, "ServerWorks OSB4 PCI to ISA Bridge" },
   63 #endif
   64 
   65         { 0x00000000, NULL }
   66 };
   67 
   68 static int intsmb_probe(device_t);
   69 static int intsmb_attach(device_t);
   70 static int intsmb_intr(device_t dev);
   71 static int intsmb_slvintr(device_t dev);
   72 static void  intsmb_alrintr(device_t dev);
   73 static int intsmb_callback(device_t dev, int index, void *data);
   74 static int intsmb_quick(device_t dev, u_char slave, int how);
   75 static int intsmb_sendb(device_t dev, u_char slave, char byte);
   76 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
   77 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   78 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
   79 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   80 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   81 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
   82 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   83 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
   84 static void intsmb_start(device_t dev, u_char cmd, int nointr);
   85 static int intsmb_stop(device_t dev);
   86 static int intsmb_stop_poll(device_t dev);
   87 static int intsmb_free(device_t dev);
   88 static int intpm_probe (device_t dev);
   89 static int intpm_attach (device_t dev);
   90 static void intpm_intr(void *arg);
   91 
   92 static devclass_t intsmb_devclass;
   93 
   94 static device_method_t intpm_methods[] = {
   95         /* Device interface */
   96         DEVMETHOD(device_probe,         intsmb_probe),
   97         DEVMETHOD(device_attach,        intsmb_attach),
   98 
   99         /* Bus interface */
  100         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  101 
  102         /* SMBus interface */
  103         DEVMETHOD(smbus_callback,       intsmb_callback),
  104         DEVMETHOD(smbus_quick,          intsmb_quick),
  105         DEVMETHOD(smbus_sendb,          intsmb_sendb),
  106         DEVMETHOD(smbus_recvb,          intsmb_recvb),
  107         DEVMETHOD(smbus_writeb,         intsmb_writeb),
  108         DEVMETHOD(smbus_writew,         intsmb_writew),
  109         DEVMETHOD(smbus_readb,          intsmb_readb),
  110         DEVMETHOD(smbus_readw,          intsmb_readw),
  111         DEVMETHOD(smbus_pcall,          intsmb_pcall),
  112         DEVMETHOD(smbus_bwrite,         intsmb_bwrite),
  113         DEVMETHOD(smbus_bread,          intsmb_bread),
  114 
  115         { 0, 0 }
  116 };
  117 
  118 struct intpm_pci_softc {
  119         bus_space_tag_t         smbst;
  120         bus_space_handle_t      smbsh;
  121         bus_space_tag_t         pmst;
  122         bus_space_handle_t      pmsh;
  123         device_t                smbus;
  124 };
  125 
  126 
  127 struct intsmb_softc {
  128         struct intpm_pci_softc  *pci_sc;
  129         bus_space_tag_t         st;
  130         bus_space_handle_t      sh;
  131         device_t                smbus;
  132         int                     isbusy;
  133 };
  134 
  135 static driver_t intpm_driver = {
  136         "intsmb",
  137         intpm_methods,
  138         sizeof(struct intsmb_softc),
  139 };
  140 
  141 static devclass_t intpm_devclass;
  142 
  143 static device_method_t intpm_pci_methods[] = {
  144         DEVMETHOD(device_probe,         intpm_probe),
  145         DEVMETHOD(device_attach,        intpm_attach),
  146 
  147         { 0, 0 }
  148 };
  149 
  150 static driver_t intpm_pci_driver = {
  151         "intpm",
  152         intpm_pci_methods,
  153         sizeof(struct intpm_pci_softc)
  154 };
  155 
  156 static int
  157 intsmb_probe(device_t dev)
  158 {
  159         struct intsmb_softc *sc = device_get_softc(dev);
  160 
  161         sc->smbus = device_add_child(dev, "smbus", -1);
  162         if (!sc->smbus)
  163                 return (EINVAL);    /* XXX don't know what to return else */
  164         device_set_desc(dev, "Intel PIIX4 SMBUS Interface");
  165 
  166         return (BUS_PROBE_DEFAULT); /* XXX don't know what to return else */
  167 }
  168 static int
  169 intsmb_attach(device_t dev)
  170 {
  171         struct intsmb_softc *sc = device_get_softc(dev);
  172 
  173         sc->pci_sc = device_get_softc(device_get_parent(dev));
  174         sc->isbusy = 0;
  175         sc->sh = sc->pci_sc->smbsh;
  176         sc->st = sc->pci_sc->smbst;
  177         sc->pci_sc->smbus = dev;
  178         device_probe_and_attach(sc->smbus);
  179 #ifdef ENABLE_ALART
  180         /*Enable Arart*/
  181         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
  182             PIIX4_SMBSLVCNT_ALTEN);
  183 #endif
  184         return (0);
  185 }
  186 
  187 static int
  188 intsmb_callback(device_t dev, int index, void *data)
  189 {
  190         int error = 0;
  191         intrmask_t s;
  192 
  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 
  204         return (error);
  205 }
  206 
  207 /* Counterpart of smbtx_smb_free(). */
  208 static int
  209 intsmb_free(device_t dev)
  210 {
  211         struct intsmb_softc *sc = device_get_softc(dev);
  212         intrmask_t s;
  213 
  214         if ((bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS) &
  215             PIIX4_SMBHSTSTAT_BUSY) ||
  216 #ifdef ENABLE_ALART
  217             (bus_space_read_1(sc->st, sc->sh, PIIX4_SMBSLVSTS) & 
  218             PIIX4_SMBSLVSTS_BUSY) ||
  219 #endif
  220             sc->isbusy)
  221                 return (EBUSY);
  222         s = splhigh();
  223         sc->isbusy = 1;
  224         /* Disable Interrupt in slave part. */
  225 #ifndef ENABLE_ALART
  226         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT, 0);
  227 #endif
  228         /* Reset INTR Flag to prepare INTR. */
  229         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTSTS,
  230             (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  231             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL));
  232         splx(s);
  233         return (0);
  234 }
  235 
  236 static int
  237 intsmb_intr(device_t dev)
  238 {
  239         struct intsmb_softc *sc = device_get_softc(dev);
  240         int status;
  241 
  242         status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS);
  243         if (status & PIIX4_SMBHSTSTAT_BUSY)
  244                 return (1);
  245 
  246         if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  247             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) {
  248                 int tmp;
  249 
  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 
  262 static int
  263 intsmb_slvintr(device_t dev)
  264 {
  265         struct intsmb_softc *sc = device_get_softc(dev);
  266         int status, retval;
  267 
  268         retval = 1;
  269         status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBSLVSTS);
  270         if (status & PIIX4_SMBSLVSTS_BUSY)
  271                 return (retval);
  272         if (status & PIIX4_SMBSLVSTS_ALART) {
  273                 intsmb_alrintr(dev);
  274                 retval = 0;
  275         } else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2
  276                 | PIIX4_SMBSLVSTS_SDW1)) {
  277                 retval = 0;
  278         }
  279 
  280         /* Reset Status Register */
  281         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVSTS,
  282             PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 |
  283             PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV);
  284         return (retval);
  285 }
  286 
  287 static void
  288 intsmb_alrintr(device_t dev)
  289 {
  290         struct intsmb_softc *sc = device_get_softc(dev);
  291         int slvcnt;
  292 #ifdef ENABLE_ALART
  293         int error;
  294 #endif
  295 
  296         /* Stop generating INTR from ALART. */
  297         slvcnt = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBSLVCNT);
  298 #ifdef ENABLE_ALART
  299         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
  300             slvcnt & ~PIIX4_SMBSLVCNT_ALTEN);
  301 #endif
  302         DELAY(5);
  303 
  304         /* Ask bus who asserted it and then ask it what's the matter. */
  305 #ifdef ENABLE_ALART
  306         error = intsmb_free(dev);
  307         if (!error) {
  308                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
  309                     SMBALTRESP | LSB);
  310                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BYTE, 1);
  311                 if (!(error = intsmb_stop_poll(dev))) {
  312                         u_int8_t addr;
  313 
  314                         addr = bus_space_read_1(sc->st, sc->sh,
  315                             PIIX4_SMBHSTDAT0);
  316                         printf("ALART_RESPONSE: 0x%x\n", addr);
  317                 }
  318         } else
  319                 printf("ERROR\n");
  320 
  321         /* Re-enable INTR from ALART. */
  322         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
  323             slvcnt | PIIX4_SMBSLVCNT_ALTEN);
  324         DELAY(5);
  325 #endif
  326 }
  327 
  328 static void
  329 intsmb_start(device_t dev, unsigned char cmd, int nointr)
  330 {
  331         struct intsmb_softc *sc = device_get_softc(dev);
  332         unsigned char tmp;
  333 
  334         tmp = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
  335         tmp &= 0xe0;
  336         tmp |= cmd;
  337         tmp |= PIIX4_SMBHSTCNT_START;
  338 
  339         /* While not in autoconfiguration enable interrupts. */
  340         if (!cold || !nointr)
  341                 tmp |= PIIX4_SMBHSTCNT_INTREN;
  342         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCNT, tmp);
  343 }
  344 
  345 /*
  346  * Polling Code.
  347  *
  348  * Polling is not encouraged because it requires waiting for the
  349  * device if it is busy.
  350  * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use
  351  * polling code then.
  352  */
  353 static int
  354 intsmb_stop_poll(device_t dev)
  355 {
  356         struct intsmb_softc *sc = device_get_softc(dev);
  357         int error, i;
  358         int tmp;
  359 
  360         /*
  361          *  In smbtx driver, Simply waiting.
  362          *  This loops 100-200 times.
  363          */
  364         for (i = 0; i < 0x7fff; i++)
  365                 if (bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS) &
  366                     PIIX4_SMBHSTSTAT_BUSY)
  367                         break;
  368 
  369         for (i = 0; i < 0x7fff; i++) {
  370                 int status;
  371 
  372                 status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS);
  373                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  374                         sc->isbusy = 0;
  375                         error = (status & PIIX4_SMBHSTSTAT_ERR) ? EIO :
  376                             (status & PIIX4_SMBHSTSTAT_BUSC) ? EBUSY : 
  377                             (status & PIIX4_SMBHSTSTAT_FAIL) ? EIO : 0;
  378                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
  379                                 printf("unknown cause why?");
  380                         return (error);
  381                 }
  382         }
  383 
  384         sc->isbusy = 0;
  385         tmp = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
  386         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCNT, 
  387             tmp & ~PIIX4_SMBHSTCNT_INTREN);
  388         return (EIO);
  389 }
  390 
  391 /*
  392  * Wait for completion and return result.
  393  */
  394 static int
  395 intsmb_stop(device_t dev)
  396 {
  397         struct intsmb_softc *sc = device_get_softc(dev);
  398         int error;
  399         intrmask_t s;
  400 
  401         if (cold) {
  402                 /* So that it can use device during device probe on SMBus. */
  403                 error = intsmb_stop_poll(dev);
  404                 return (error);
  405         }
  406 
  407         if (!tsleep(sc, (PWAIT) | PCATCH, "SMBWAI", hz/8)) {
  408                 int status;
  409 
  410                 status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS);
  411                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  412                         error = (status & PIIX4_SMBHSTSTAT_ERR) ? EIO :
  413                             (status & PIIX4_SMBHSTSTAT_BUSC) ? EBUSY : 
  414                             (status & PIIX4_SMBHSTSTAT_FAIL) ? EIO : 0;
  415                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
  416                                 printf("intsmb%d: unknown cause why?\n",
  417                                     device_get_unit(dev));
  418 #ifdef ENABLE_ALART
  419                         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
  420                             PIIX4_SMBSLVCNT_ALTEN);
  421 #endif
  422                         return (error);
  423                 }
  424         }
  425 
  426         /* Timeout Procedure. */
  427         s = splhigh();
  428         sc->isbusy = 0;
  429 
  430         /* Re-enable supressed interrupt from slave part. */
  431         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
  432             PIIX4_SMBSLVCNT_ALTEN);
  433         splx(s);
  434         return (EIO);
  435 }
  436 
  437 static int
  438 intsmb_quick(device_t dev, u_char slave, int how)
  439 {
  440         struct intsmb_softc *sc = device_get_softc(dev);
  441         int error = 0;
  442         u_char data;
  443 
  444         data = slave;
  445 
  446         /* Quick command is part of Address, I think. */
  447         switch(how) {
  448         case SMB_QWRITE:
  449                 data &= ~LSB;
  450                 break;
  451         case SMB_QREAD:
  452                 data |= LSB;
  453                 break;
  454         default:
  455                 error = EINVAL;
  456         }
  457         if (!error) {
  458                 error = intsmb_free(dev);
  459                 if (!error) {
  460                         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
  461                             data);
  462                         intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_QUICK, 0);
  463                         error = intsmb_stop(dev);
  464                 }
  465         }
  466 
  467         return (error);
  468 }
  469 
  470 static int
  471 intsmb_sendb(device_t dev, u_char slave, char byte)
  472 {
  473         struct intsmb_softc *sc = device_get_softc(dev);
  474         int error;
  475 
  476         error = intsmb_free(dev);
  477         if (!error) {
  478                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
  479                     slave & ~LSB);
  480                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, byte);
  481                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  482                 error = intsmb_stop(dev);
  483         }
  484         return (error);
  485 }
  486 
  487 static int
  488 intsmb_recvb(device_t dev, u_char slave, char *byte)
  489 {
  490         struct intsmb_softc *sc = device_get_softc(dev);
  491         int error;
  492 
  493         error = intsmb_free(dev);
  494         if (!error) {
  495                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
  496                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  497                 if (!(error = intsmb_stop(dev))) {
  498 #ifdef RECV_IS_IN_CMD
  499                         /*
  500                          * Linux SMBus stuff also troubles
  501                          * Because Intel's datasheet does not make clear.
  502                          */
  503                         *byte = bus_space_read_1(sc->st, sc->sh,
  504                             PIIX4_SMBHSTCMD);
  505 #else
  506                         *byte = bus_space_read_1(sc->st, sc->sh, 
  507                             PIIX4_SMBHSTDAT0);
  508 #endif
  509                 }
  510         }
  511         return (error);
  512 }
  513 
  514 static int
  515 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  516 {
  517         struct intsmb_softc *sc = device_get_softc(dev);
  518         int error;
  519 
  520         error = intsmb_free(dev);
  521         if (!error) {
  522                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
  523                     slave & ~LSB);
  524                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
  525                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, byte);
  526                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  527                 error = intsmb_stop(dev);
  528         }
  529         return (error);
  530 }
  531 
  532 static int
  533 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
  534 {
  535         struct intsmb_softc *sc = device_get_softc(dev);
  536         int error;
  537 
  538         error = intsmb_free(dev);
  539         if (!error) {
  540                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
  541                     slave & ~LSB);
  542                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
  543                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, 
  544                     word & 0xff);
  545                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT1, 
  546                     (word >> 8) & 0xff);
  547                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  548                 error = intsmb_stop(dev);
  549         }
  550         return (error);
  551 }
  552 
  553 static int
  554 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  555 {
  556         struct intsmb_softc *sc = device_get_softc(dev);
  557         int error;
  558 
  559         error = intsmb_free(dev);
  560         if (!error) {
  561                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
  562                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
  563                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  564                 if (!(error = intsmb_stop(dev)))
  565                         *byte = bus_space_read_1(sc->st, sc->sh,
  566                             PIIX4_SMBHSTDAT0);
  567         }
  568         return (error);
  569 }
  570 static int
  571 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  572 {
  573         struct intsmb_softc *sc = device_get_softc(dev);
  574         int error;
  575 
  576         error = intsmb_free(dev);
  577         if (!error) {
  578                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
  579                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
  580                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  581                 if (!(error = intsmb_stop(dev))) {
  582                         *word = bus_space_read_1(sc->st, sc->sh,
  583                             PIIX4_SMBHSTDAT0);
  584                         *word |= bus_space_read_1(sc->st, sc->sh,
  585                             PIIX4_SMBHSTDAT1) << 8;
  586                 }
  587         }
  588         return (error);
  589 }
  590 
  591 /*
  592  * Data sheet claims that it implements all function, but also claims
  593  * that it implements 7 function and not mention PCALL. So I don't know
  594  * whether it will work.
  595  */
  596 static int
  597 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  598 {
  599 #ifdef PROCCALL_TEST
  600         struct intsmb_softc *sc = device_get_softc(dev);
  601         int error;
  602 
  603         error = intsmb_free(dev);
  604         if (!error) {
  605                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
  606                     slave & ~LSB);
  607                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
  608                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0,
  609                     sdata & 0xff);
  610                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT1,
  611                     (sdata & 0xff) >> 8);
  612                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  613         }
  614         if (!(error = intsmb_stop(dev))) {
  615                 *rdata = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0);
  616                 *rdata |= bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTDAT1) <<
  617                     8;
  618         }
  619         return (error);
  620 #else
  621         return (0);
  622 #endif
  623 }
  624 
  625 static int
  626 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  627 {
  628         struct intsmb_softc *sc = device_get_softc(dev);
  629         int error, i;
  630 
  631         error = intsmb_free(dev);
  632         if (count > SMBBLOCKTRANS_MAX || count == 0)
  633                 error = SMB_EINVAL;
  634         if (!error) {
  635                 /* Reset internal array index. */
  636                 bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
  637 
  638                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
  639                     slave & ~LSB);
  640                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
  641                 for (i = 0; i < count; i++)
  642                         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBBLKDAT,
  643                             buf[i]);
  644                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, count);
  645                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  646                 error = intsmb_stop(dev);
  647         }
  648         return (error);
  649 }
  650 
  651 static int
  652 intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  653 {
  654         struct intsmb_softc *sc = device_get_softc(dev);
  655         int error, i;
  656         u_char data, nread;
  657 
  658         error = intsmb_free(dev);
  659         if (*count > SMBBLOCKTRANS_MAX || *count == 0)
  660                 error = SMB_EINVAL;
  661         if (!error) {
  662                 /* Reset internal array index. */
  663                 bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
  664 
  665                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
  666                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
  667                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, *count);
  668                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  669                 error = intsmb_stop(dev);
  670                 if (!error) {
  671                         nread= bus_space_read_1(sc->st, sc->sh,
  672                             PIIX4_SMBHSTDAT0);
  673                         if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) {
  674                                 for (i = 0; i < nread; i++) {
  675                                         data = bus_space_read_1(sc->st, sc->sh, 
  676                                             PIIX4_SMBBLKDAT);
  677                                         if (i < *count)
  678                                                 buf[i] = data;
  679                                 }
  680                                 *count = nread;
  681                         } else {
  682                                 error = EIO;
  683                         }
  684                 }
  685         }
  686         return (error);
  687 }
  688 
  689 DRIVER_MODULE(intsmb, intpm, intpm_driver, intsmb_devclass, 0, 0);
  690 
  691 static int
  692 intpm_attach(device_t dev)
  693 {
  694         struct intpm_pci_softc *sc;
  695         struct resource *res;
  696         device_t smbinterface;
  697         void *ih;
  698         char *str;
  699         int error, rid, value;
  700         int unit = device_get_unit(dev);
  701 
  702         sc = device_get_softc(dev);
  703         if (sc == NULL)
  704                 return (ENOMEM);
  705 
  706         rid = PCI_BASE_ADDR_SMB;
  707         res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
  708         if (res == NULL) {
  709                 device_printf(dev, "Could not allocate Bus space\n");
  710                 return (ENXIO);
  711         }
  712         sc->smbst = rman_get_bustag(res);
  713         sc->smbsh = rman_get_bushandle(res);
  714 
  715 #ifdef __i386__
  716         device_printf(dev, "%s %lx\n", (sc->smbst == I386_BUS_SPACE_IO) ?
  717             "I/O mapped" : "Memory", rman_get_start(res));
  718 #endif
  719 
  720 #ifndef NO_CHANGE_PCICONF
  721         pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
  722         pci_write_config(dev, PCI_HST_CFG_SMB,
  723             PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
  724 #endif
  725         value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
  726         switch (value & 0xe) {
  727         case PCI_INTR_SMB_SMI:
  728                 str = "SMI";
  729                 break;
  730         case PCI_INTR_SMB_IRQ9:
  731                 str = "IRQ 9";
  732                 break;
  733         default:
  734                 str = "BOGUS";
  735         }
  736         device_printf(dev, "intr %s %s ", str,
  737             (value & 1) ? "enabled" : "disabled");
  738         value = pci_read_config(dev, PCI_REVID_SMB, 1);
  739         printf("revision %d\n", value);
  740 
  741         /* Install interrupt handler. */
  742         rid = 0;
  743         res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 9, 9, 1,
  744             RF_SHAREABLE | RF_ACTIVE);
  745         if (res == NULL) {
  746                 device_printf(dev, "could not allocate irq");
  747                 return (ENOMEM);
  748         }
  749         error = bus_setup_intr(dev, res, INTR_TYPE_MISC, intpm_intr, sc, &ih);
  750         if (error) {
  751                 device_printf(dev, "Failed to map intr\n");
  752                 return (error);
  753         }
  754         smbinterface = device_add_child(dev, "intsmb", unit);
  755         if (!smbinterface)
  756                 printf("intsmb%d: could not add SMBus device\n", unit);
  757         device_probe_and_attach(smbinterface);
  758 
  759         value = pci_read_config(dev, PCI_BASE_ADDR_PM, 4);
  760         printf("intpm%d: PM %s %x \n", unit,
  761             (value & 1) ? "I/O mapped" : "Memory", value & 0xfffe);
  762         return (0);
  763 }
  764 
  765 static int
  766 intpm_probe(device_t dev)
  767 {
  768         struct _pcsid *ep = pci_ids;
  769         uint32_t device_id = pci_get_devid(dev);
  770 
  771         while (ep->type && ep->type != device_id)
  772                 ++ep;
  773         if (ep->desc != NULL) {
  774                 device_set_desc(dev, ep->desc);
  775                 bus_set_resource(dev, SYS_RES_IRQ, 0, 9, 1); /* XXX setup intr resource */
  776                 return (BUS_PROBE_DEFAULT);
  777         } else {
  778                 return (ENXIO);
  779         }
  780 }
  781 
  782 static void
  783 intpm_intr(void *arg)
  784 {
  785         struct intpm_pci_softc *sc = arg;
  786 
  787         intsmb_intr(sc->smbus);
  788         intsmb_slvintr(sc->smbus);
  789 }
  790 
  791 DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
  792 DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0);
  793 MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  794 MODULE_VERSION(intpm, 1);

Cache object: e0e9487298d9e087c08114255efb8df2


[ 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.