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/10.4/sys/pci/intpm.c 310076 2016-12-14 16:35:17Z avg $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/lock.h>
   35 #include <sys/module.h>
   36 #include <sys/mutex.h>
   37 #include <sys/rman.h>
   38 #include <machine/bus.h>
   39 #include <dev/smbus/smbconf.h>
   40 
   41 #include "smbus_if.h"
   42 
   43 #include <dev/pci/pcireg.h>
   44 #include <dev/pci/pcivar.h>
   45 #include <pci/intpmreg.h>
   46 #include <dev/amdsbwd/amd_chipset.h>
   47 
   48 #include "opt_intpm.h"
   49 
   50 struct intsmb_softc {
   51         device_t                dev;
   52         struct resource         *io_res;
   53         struct resource         *irq_res;
   54         void                    *irq_hand;
   55         device_t                smbus;
   56         int                     io_rid;
   57         int                     isbusy;
   58         int                     cfg_irq9;
   59         int                     sb8xx;
   60         int                     poll;
   61         struct mtx              lock;
   62 };
   63 
   64 #define INTSMB_LOCK(sc)         mtx_lock(&(sc)->lock)
   65 #define INTSMB_UNLOCK(sc)       mtx_unlock(&(sc)->lock)
   66 #define INTSMB_LOCK_ASSERT(sc)  mtx_assert(&(sc)->lock, MA_OWNED)
   67 
   68 static int intsmb_probe(device_t);
   69 static int intsmb_attach(device_t);
   70 static int intsmb_detach(device_t);
   71 static int intsmb_intr(struct intsmb_softc *sc);
   72 static int intsmb_slvintr(struct intsmb_softc *sc);
   73 static void intsmb_alrintr(struct intsmb_softc *sc);
   74 static int intsmb_callback(device_t dev, int index, void *data);
   75 static int intsmb_quick(device_t dev, u_char slave, int how);
   76 static int intsmb_sendb(device_t dev, u_char slave, char byte);
   77 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
   78 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   79 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
   80 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   81 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   82 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
   83 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   84 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
   85 static void intsmb_start(struct intsmb_softc *sc, u_char cmd, int nointr);
   86 static int intsmb_stop(struct intsmb_softc *sc);
   87 static int intsmb_stop_poll(struct intsmb_softc *sc);
   88 static int intsmb_free(struct intsmb_softc *sc);
   89 static void intsmb_rawintr(void *arg);
   90 
   91 static int
   92 intsmb_probe(device_t dev)
   93 {
   94 
   95         switch (pci_get_devid(dev)) {
   96         case 0x71138086:        /* Intel 82371AB */
   97         case 0x719b8086:        /* Intel 82443MX */
   98 #if 0
   99         /* Not a good idea yet, this stops isab0 functioning */
  100         case 0x02001166:        /* ServerWorks OSB4 */
  101 #endif
  102                 device_set_desc(dev, "Intel PIIX4 SMBUS Interface");
  103                 break;
  104         case 0x43721002:
  105                 device_set_desc(dev, "ATI IXP400 SMBus Controller");
  106                 break;
  107         case AMDSB_SMBUS_DEVID:
  108                 device_set_desc(dev, "AMD SB600/7xx/8xx/9xx SMBus Controller");
  109                 break;
  110         case AMDFCH_SMBUS_DEVID:        /* AMD FCH */
  111         case AMDCZ_SMBUS_DEVID:         /* AMD Carizzo FCH */
  112                 device_set_desc(dev, "AMD FCH SMBus Controller");
  113                 break;
  114         default:
  115                 return (ENXIO);
  116         }
  117 
  118         return (BUS_PROBE_DEFAULT);
  119 }
  120 
  121 static uint8_t
  122 amd_pmio_read(struct resource *res, uint8_t reg)
  123 {
  124         bus_write_1(res, 0, reg);       /* Index */
  125         return (bus_read_1(res, 1));    /* Data */
  126 }
  127 
  128 static int
  129 sb8xx_attach(device_t dev)
  130 {
  131         static const int        AMDSB_SMBIO_WIDTH = 0x14;
  132         struct intsmb_softc     *sc;
  133         struct resource         *res;
  134         uint32_t                devid;
  135         uint8_t                 revid;
  136         uint16_t                addr;
  137         int                     rid;
  138         int                     rc;
  139         bool                    enabled;
  140 
  141         sc = device_get_softc(dev);
  142         rid = 0;
  143         rc = bus_set_resource(dev, SYS_RES_IOPORT, rid, AMDSB_PMIO_INDEX,
  144             AMDSB_PMIO_WIDTH);
  145         if (rc != 0) {
  146                 device_printf(dev, "bus_set_resource for PM IO failed\n");
  147                 return (ENXIO);
  148         }
  149         res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  150             RF_ACTIVE);
  151         if (res == NULL) {
  152                 device_printf(dev, "bus_alloc_resource for PM IO failed\n");
  153                 return (ENXIO);
  154         }
  155 
  156         devid = pci_get_devid(dev);
  157         revid = pci_get_revid(dev);
  158         if (devid == AMDSB_SMBUS_DEVID ||
  159             (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) ||
  160             (devid == AMDCZ_SMBUS_DEVID  && revid < AMDCZ49_SMBUS_REVID)) {
  161                 addr = amd_pmio_read(res, AMDSB8_PM_SMBUS_EN + 1);
  162                 addr <<= 8;
  163                 addr |= amd_pmio_read(res, AMDSB8_PM_SMBUS_EN);
  164                 enabled = (addr & AMDSB8_SMBUS_EN) != 0;
  165                 addr &= AMDSB8_SMBUS_ADDR_MASK;
  166         } else {
  167                 addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN0);
  168                 enabled = (addr & AMDFCH41_SMBUS_EN) != 0;
  169                 addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN1);
  170                 addr <<= 8;
  171         }
  172 
  173         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
  174         bus_delete_resource(dev, SYS_RES_IOPORT, rid);
  175 
  176         if (!enabled) {
  177                 device_printf(dev, "SB8xx/SB9xx/FCH SMBus not enabled\n");
  178                 return (ENXIO);
  179         }
  180 
  181         sc->io_rid = 0;
  182         rc = bus_set_resource(dev, SYS_RES_IOPORT, sc->io_rid, addr,
  183             AMDSB_SMBIO_WIDTH);
  184         if (rc != 0) {
  185                 device_printf(dev, "bus_set_resource for SMBus IO failed\n");
  186                 return (ENXIO);
  187         }
  188         if (res == NULL) {
  189                 device_printf(dev, "bus_alloc_resource for SMBus IO failed\n");
  190                 return (ENXIO);
  191         }
  192         sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
  193             RF_ACTIVE);
  194         sc->poll = 1;
  195         return (0);
  196 }
  197 
  198 static void
  199 intsmb_release_resources(device_t dev)
  200 {
  201         struct intsmb_softc *sc = device_get_softc(dev);
  202 
  203         if (sc->smbus)
  204                 device_delete_child(dev, sc->smbus);
  205         if (sc->irq_hand)
  206                 bus_teardown_intr(dev, sc->irq_res, sc->irq_hand);
  207         if (sc->irq_res)
  208                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  209         if (sc->io_res)
  210                 bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid,
  211                     sc->io_res);
  212         mtx_destroy(&sc->lock);
  213 }
  214 
  215 static int
  216 intsmb_attach(device_t dev)
  217 {
  218         struct intsmb_softc *sc = device_get_softc(dev);
  219         int error, rid, value;
  220         int intr;
  221         char *str;
  222 
  223         sc->dev = dev;
  224 
  225         mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);
  226 
  227         sc->cfg_irq9 = 0;
  228         switch (pci_get_devid(dev)) {
  229 #ifndef NO_CHANGE_PCICONF
  230         case 0x71138086:        /* Intel 82371AB */
  231         case 0x719b8086:        /* Intel 82443MX */
  232                 /* Changing configuration is allowed. */
  233                 sc->cfg_irq9 = 1;
  234                 break;
  235 #endif
  236         case AMDSB_SMBUS_DEVID:
  237                 if (pci_get_revid(dev) >= AMDSB8_SMBUS_REVID)
  238                         sc->sb8xx = 1;
  239                 break;
  240         case AMDFCH_SMBUS_DEVID:
  241         case AMDCZ_SMBUS_DEVID:
  242                 sc->sb8xx = 1;
  243                 break;
  244         }
  245 
  246         if (sc->sb8xx) {
  247                 error = sb8xx_attach(dev);
  248                 if (error != 0)
  249                         goto fail;
  250                 else
  251                         goto no_intr;
  252         }
  253 
  254         sc->io_rid = PCI_BASE_ADDR_SMB;
  255         sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
  256             RF_ACTIVE);
  257         if (sc->io_res == NULL) {
  258                 device_printf(dev, "Could not allocate I/O space\n");
  259                 error = ENXIO;
  260                 goto fail;
  261         }
  262 
  263         if (sc->cfg_irq9) {
  264                 pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
  265                 pci_write_config(dev, PCI_HST_CFG_SMB,
  266                     PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
  267         }
  268         value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
  269         sc->poll = (value & PCI_INTR_SMB_ENABLE) == 0;
  270         intr = value & PCI_INTR_SMB_MASK;
  271         switch (intr) {
  272         case PCI_INTR_SMB_SMI:
  273                 str = "SMI";
  274                 break;
  275         case PCI_INTR_SMB_IRQ9:
  276                 str = "IRQ 9";
  277                 break;
  278         case PCI_INTR_SMB_IRQ_PCI:
  279                 str = "PCI IRQ";
  280                 break;
  281         default:
  282                 str = "BOGUS";
  283         }
  284 
  285         device_printf(dev, "intr %s %s ", str,
  286             sc->poll == 0 ? "enabled" : "disabled");
  287         printf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1));
  288 
  289         if (!sc->poll && intr == PCI_INTR_SMB_SMI) {
  290                 device_printf(dev,
  291                     "using polling mode when configured interrupt is SMI\n");
  292                 sc->poll = 1;
  293         }
  294 
  295         if (sc->poll)
  296             goto no_intr;
  297 
  298         if (intr != PCI_INTR_SMB_IRQ9 && intr != PCI_INTR_SMB_IRQ_PCI) {
  299                 device_printf(dev, "Unsupported interrupt mode\n");
  300                 error = ENXIO;
  301                 goto fail;
  302         }
  303 
  304         /* Force IRQ 9. */
  305         rid = 0;
  306         if (sc->cfg_irq9)
  307                 bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
  308 
  309         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  310             RF_SHAREABLE | RF_ACTIVE);
  311         if (sc->irq_res == NULL) {
  312                 device_printf(dev, "Could not allocate irq\n");
  313                 error = ENXIO;
  314                 goto fail;
  315         }
  316 
  317         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  318             NULL, intsmb_rawintr, sc, &sc->irq_hand);
  319         if (error) {
  320                 device_printf(dev, "Failed to map intr\n");
  321                 goto fail;
  322         }
  323 
  324 no_intr:
  325         sc->isbusy = 0;
  326         sc->smbus = device_add_child(dev, "smbus", -1);
  327         if (sc->smbus == NULL) {
  328                 device_printf(dev, "failed to add smbus child\n");
  329                 error = ENXIO;
  330                 goto fail;
  331         }
  332         error = device_probe_and_attach(sc->smbus);
  333         if (error) {
  334                 device_printf(dev, "failed to probe+attach smbus child\n");
  335                 goto fail;
  336         }
  337 
  338 #ifdef ENABLE_ALART
  339         /* Enable Arart */
  340         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
  341 #endif
  342         return (0);
  343 
  344 fail:
  345         intsmb_release_resources(dev);
  346         return (error);
  347 }
  348 
  349 static int
  350 intsmb_detach(device_t dev)
  351 {
  352         int error;
  353 
  354         error = bus_generic_detach(dev);
  355         if (error) {
  356                 device_printf(dev, "bus detach failed\n");
  357                 return (error);
  358         }
  359 
  360         intsmb_release_resources(dev);
  361         return (0);
  362 }
  363 
  364 static void
  365 intsmb_rawintr(void *arg)
  366 {
  367         struct intsmb_softc *sc = arg;
  368 
  369         INTSMB_LOCK(sc);
  370         intsmb_intr(sc);
  371         intsmb_slvintr(sc);
  372         INTSMB_UNLOCK(sc);
  373 }
  374 
  375 static int
  376 intsmb_callback(device_t dev, int index, void *data)
  377 {
  378         int error = 0;
  379 
  380         switch (index) {
  381         case SMB_REQUEST_BUS:
  382                 break;
  383         case SMB_RELEASE_BUS:
  384                 break;
  385         default:
  386                 error = SMB_EINVAL;
  387         }
  388 
  389         return (error);
  390 }
  391 
  392 /* Counterpart of smbtx_smb_free(). */
  393 static int
  394 intsmb_free(struct intsmb_softc *sc)
  395 {
  396 
  397         INTSMB_LOCK_ASSERT(sc);
  398         if ((bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & PIIX4_SMBHSTSTAT_BUSY) ||
  399 #ifdef ENABLE_ALART
  400             (bus_read_1(sc->io_res, PIIX4_SMBSLVSTS) & PIIX4_SMBSLVSTS_BUSY) ||
  401 #endif
  402             sc->isbusy)
  403                 return (SMB_EBUSY);
  404 
  405         sc->isbusy = 1;
  406         /* Disable Interrupt in slave part. */
  407 #ifndef ENABLE_ALART
  408         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 0);
  409 #endif
  410         /* Reset INTR Flag to prepare INTR. */
  411         bus_write_1(sc->io_res, PIIX4_SMBHSTSTS,
  412             PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  413             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL);
  414         return (0);
  415 }
  416 
  417 static int
  418 intsmb_intr(struct intsmb_softc *sc)
  419 {
  420         int status, tmp;
  421 
  422         status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  423         if (status & PIIX4_SMBHSTSTAT_BUSY)
  424                 return (1);
  425 
  426         if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  427             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) {
  428 
  429                 tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  430                 bus_write_1(sc->io_res, PIIX4_SMBHSTCNT,
  431                     tmp & ~PIIX4_SMBHSTCNT_INTREN);
  432                 if (sc->isbusy) {
  433                         sc->isbusy = 0;
  434                         wakeup(sc);
  435                 }
  436                 return (0);
  437         }
  438         return (1); /* Not Completed */
  439 }
  440 
  441 static int
  442 intsmb_slvintr(struct intsmb_softc *sc)
  443 {
  444         int status;
  445 
  446         status = bus_read_1(sc->io_res, PIIX4_SMBSLVSTS);
  447         if (status & PIIX4_SMBSLVSTS_BUSY)
  448                 return (1);
  449         if (status & PIIX4_SMBSLVSTS_ALART)
  450                 intsmb_alrintr(sc);
  451         else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2
  452                 | PIIX4_SMBSLVSTS_SDW1)) {
  453         }
  454 
  455         /* Reset Status Register */
  456         bus_write_1(sc->io_res, PIIX4_SMBSLVSTS,
  457             PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 |
  458             PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV);
  459         return (0);
  460 }
  461 
  462 static void
  463 intsmb_alrintr(struct intsmb_softc *sc)
  464 {
  465         int slvcnt;
  466 #ifdef ENABLE_ALART
  467         int error;
  468         uint8_t addr;
  469 #endif
  470 
  471         /* Stop generating INTR from ALART. */
  472         slvcnt = bus_read_1(sc->io_res, PIIX4_SMBSLVCNT);
  473 #ifdef ENABLE_ALART
  474         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  475             slvcnt & ~PIIX4_SMBSLVCNT_ALTEN);
  476 #endif
  477         DELAY(5);
  478 
  479         /* Ask bus who asserted it and then ask it what's the matter. */
  480 #ifdef ENABLE_ALART
  481         error = intsmb_free(sc);
  482         if (error)
  483                 return;
  484 
  485         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, SMBALTRESP | LSB);
  486         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 1);
  487         error = intsmb_stop_poll(sc);
  488         if (error)
  489                 device_printf(sc->dev, "ALART: ERROR\n");
  490         else {
  491                 addr = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  492                 device_printf(sc->dev, "ALART_RESPONSE: 0x%x\n", addr);
  493         }
  494 
  495         /* Re-enable INTR from ALART. */
  496         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  497             slvcnt | PIIX4_SMBSLVCNT_ALTEN);
  498         DELAY(5);
  499 #endif
  500 }
  501 
  502 static void
  503 intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr)
  504 {
  505         unsigned char tmp;
  506 
  507         INTSMB_LOCK_ASSERT(sc);
  508         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  509         tmp &= 0xe0;
  510         tmp |= cmd;
  511         tmp |= PIIX4_SMBHSTCNT_START;
  512 
  513         /* While not in autoconfiguration enable interrupts. */
  514         if (!sc->poll && !cold && !nointr)
  515                 tmp |= PIIX4_SMBHSTCNT_INTREN;
  516         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp);
  517 }
  518 
  519 static int
  520 intsmb_error(device_t dev, int status)
  521 {
  522         int error = 0;
  523 
  524         if (status & PIIX4_SMBHSTSTAT_ERR)
  525                 error |= SMB_EBUSERR;
  526         if (status & PIIX4_SMBHSTSTAT_BUSC)
  527                 error |= SMB_ECOLLI;
  528         if (status & PIIX4_SMBHSTSTAT_FAIL)
  529                 error |= SMB_ENOACK;
  530 
  531         if (error != 0 && bootverbose)
  532                 device_printf(dev, "error = %d, status = %#x\n", error, status);
  533 
  534         return (error);
  535 }
  536 
  537 /*
  538  * Polling Code.
  539  *
  540  * Polling is not encouraged because it requires waiting for the
  541  * device if it is busy.
  542  * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use
  543  * polling code then.
  544  */
  545 static int
  546 intsmb_stop_poll(struct intsmb_softc *sc)
  547 {
  548         int error, i, status, tmp;
  549 
  550         INTSMB_LOCK_ASSERT(sc);
  551 
  552         /* First, wait for busy to be set. */
  553         for (i = 0; i < 0x7fff; i++)
  554                 if (bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) &
  555                     PIIX4_SMBHSTSTAT_BUSY)
  556                         break;
  557 
  558         /* Wait for busy to clear. */
  559         for (i = 0; i < 0x7fff; i++) {
  560                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  561                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  562                         sc->isbusy = 0;
  563                         error = intsmb_error(sc->dev, status);
  564                         return (error);
  565                 }
  566         }
  567 
  568         /* Timed out waiting for busy to clear. */
  569         sc->isbusy = 0;
  570         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  571         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp & ~PIIX4_SMBHSTCNT_INTREN);
  572         return (SMB_ETIMEOUT);
  573 }
  574 
  575 /*
  576  * Wait for completion and return result.
  577  */
  578 static int
  579 intsmb_stop(struct intsmb_softc *sc)
  580 {
  581         int error, status;
  582 
  583         INTSMB_LOCK_ASSERT(sc);
  584 
  585         if (sc->poll || cold)
  586                 /* So that it can use device during device probe on SMBus. */
  587                 return (intsmb_stop_poll(sc));
  588 
  589         error = msleep(sc, &sc->lock, PWAIT | PCATCH, "SMBWAI", hz / 8);
  590         if (error == 0) {
  591                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  592                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  593                         error = intsmb_error(sc->dev, status);
  594                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
  595                                 device_printf(sc->dev, "unknown cause why?\n");
  596 #ifdef ENABLE_ALART
  597                         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  598                             PIIX4_SMBSLVCNT_ALTEN);
  599 #endif
  600                         return (error);
  601                 }
  602         }
  603 
  604         /* Timeout Procedure. */
  605         sc->isbusy = 0;
  606 
  607         /* Re-enable supressed interrupt from slave part. */
  608         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
  609         if (error == EWOULDBLOCK)
  610                 return (SMB_ETIMEOUT);
  611         else
  612                 return (SMB_EABORT);
  613 }
  614 
  615 static int
  616 intsmb_quick(device_t dev, u_char slave, int how)
  617 {
  618         struct intsmb_softc *sc = device_get_softc(dev);
  619         int error;
  620         u_char data;
  621 
  622         data = slave;
  623 
  624         /* Quick command is part of Address, I think. */
  625         switch(how) {
  626         case SMB_QWRITE:
  627                 data &= ~LSB;
  628                 break;
  629         case SMB_QREAD:
  630                 data |= LSB;
  631                 break;
  632         default:
  633                 return (SMB_EINVAL);
  634         }
  635 
  636         INTSMB_LOCK(sc);
  637         error = intsmb_free(sc);
  638         if (error) {
  639                 INTSMB_UNLOCK(sc);
  640                 return (error);
  641         }
  642         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, data);
  643         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_QUICK, 0);
  644         error = intsmb_stop(sc);
  645         INTSMB_UNLOCK(sc);
  646         return (error);
  647 }
  648 
  649 static int
  650 intsmb_sendb(device_t dev, u_char slave, char byte)
  651 {
  652         struct intsmb_softc *sc = device_get_softc(dev);
  653         int error;
  654 
  655         INTSMB_LOCK(sc);
  656         error = intsmb_free(sc);
  657         if (error) {
  658                 INTSMB_UNLOCK(sc);
  659                 return (error);
  660         }
  661         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  662         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, byte);
  663         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  664         error = intsmb_stop(sc);
  665         INTSMB_UNLOCK(sc);
  666         return (error);
  667 }
  668 
  669 static int
  670 intsmb_recvb(device_t dev, u_char slave, char *byte)
  671 {
  672         struct intsmb_softc *sc = device_get_softc(dev);
  673         int error;
  674 
  675         INTSMB_LOCK(sc);
  676         error = intsmb_free(sc);
  677         if (error) {
  678                 INTSMB_UNLOCK(sc);
  679                 return (error);
  680         }
  681         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  682         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  683         error = intsmb_stop(sc);
  684         if (error == 0) {
  685 #ifdef RECV_IS_IN_CMD
  686                 /*
  687                  * Linux SMBus stuff also troubles
  688                  * Because Intel's datasheet does not make clear.
  689                  */
  690                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTCMD);
  691 #else
  692                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  693 #endif
  694         }
  695         INTSMB_UNLOCK(sc);
  696         return (error);
  697 }
  698 
  699 static int
  700 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  701 {
  702         struct intsmb_softc *sc = device_get_softc(dev);
  703         int error;
  704 
  705         INTSMB_LOCK(sc);
  706         error = intsmb_free(sc);
  707         if (error) {
  708                 INTSMB_UNLOCK(sc);
  709                 return (error);
  710         }
  711         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  712         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  713         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, byte);
  714         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  715         error = intsmb_stop(sc);
  716         INTSMB_UNLOCK(sc);
  717         return (error);
  718 }
  719 
  720 static int
  721 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
  722 {
  723         struct intsmb_softc *sc = device_get_softc(dev);
  724         int error;
  725 
  726         INTSMB_LOCK(sc);
  727         error = intsmb_free(sc);
  728         if (error) {
  729                 INTSMB_UNLOCK(sc);
  730                 return (error);
  731         }
  732         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  733         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  734         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, word & 0xff);
  735         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (word >> 8) & 0xff);
  736         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  737         error = intsmb_stop(sc);
  738         INTSMB_UNLOCK(sc);
  739         return (error);
  740 }
  741 
  742 static int
  743 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  744 {
  745         struct intsmb_softc *sc = device_get_softc(dev);
  746         int error;
  747 
  748         INTSMB_LOCK(sc);
  749         error = intsmb_free(sc);
  750         if (error) {
  751                 INTSMB_UNLOCK(sc);
  752                 return (error);
  753         }
  754         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  755         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  756         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  757         error = intsmb_stop(sc);
  758         if (error == 0)
  759                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  760         INTSMB_UNLOCK(sc);
  761         return (error);
  762 }
  763 
  764 static int
  765 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  766 {
  767         struct intsmb_softc *sc = device_get_softc(dev);
  768         int error;
  769 
  770         INTSMB_LOCK(sc);
  771         error = intsmb_free(sc);
  772         if (error) {
  773                 INTSMB_UNLOCK(sc);
  774                 return (error);
  775         }
  776         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  777         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  778         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  779         error = intsmb_stop(sc);
  780         if (error == 0) {
  781                 *word = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  782                 *word |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8;
  783         }
  784         INTSMB_UNLOCK(sc);
  785         return (error);
  786 }
  787 
  788 static int
  789 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  790 {
  791 
  792         return (SMB_ENOTSUPP);
  793 }
  794 
  795 static int
  796 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  797 {
  798         struct intsmb_softc *sc = device_get_softc(dev);
  799         int error, i;
  800 
  801         if (count > SMBBLOCKTRANS_MAX || count == 0)
  802                 return (SMB_EINVAL);
  803 
  804         INTSMB_LOCK(sc);
  805         error = intsmb_free(sc);
  806         if (error) {
  807                 INTSMB_UNLOCK(sc);
  808                 return (error);
  809         }
  810 
  811         /* Reset internal array index. */
  812         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  813 
  814         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  815         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  816         for (i = 0; i < count; i++)
  817                 bus_write_1(sc->io_res, PIIX4_SMBBLKDAT, buf[i]);
  818         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, count);
  819         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  820         error = intsmb_stop(sc);
  821         INTSMB_UNLOCK(sc);
  822         return (error);
  823 }
  824 
  825 static int
  826 intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  827 {
  828         struct intsmb_softc *sc = device_get_softc(dev);
  829         int error, i;
  830         u_char data, nread;
  831 
  832         INTSMB_LOCK(sc);
  833         error = intsmb_free(sc);
  834         if (error) {
  835                 INTSMB_UNLOCK(sc);
  836                 return (error);
  837         }
  838 
  839         /* Reset internal array index. */
  840         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  841 
  842         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  843         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  844         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  845         error = intsmb_stop(sc);
  846         if (error == 0) {
  847                 nread = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  848                 if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) {
  849                         *count = nread;
  850                         for (i = 0; i < nread; i++)
  851                                 data = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT);
  852                 } else
  853                         error = SMB_EBUSERR;
  854         }
  855         INTSMB_UNLOCK(sc);
  856         return (error);
  857 }
  858 
  859 static devclass_t intsmb_devclass;
  860 
  861 static device_method_t intsmb_methods[] = {
  862         /* Device interface */
  863         DEVMETHOD(device_probe,         intsmb_probe),
  864         DEVMETHOD(device_attach,        intsmb_attach),
  865         DEVMETHOD(device_detach,        intsmb_detach),
  866 
  867         /* SMBus interface */
  868         DEVMETHOD(smbus_callback,       intsmb_callback),
  869         DEVMETHOD(smbus_quick,          intsmb_quick),
  870         DEVMETHOD(smbus_sendb,          intsmb_sendb),
  871         DEVMETHOD(smbus_recvb,          intsmb_recvb),
  872         DEVMETHOD(smbus_writeb,         intsmb_writeb),
  873         DEVMETHOD(smbus_writew,         intsmb_writew),
  874         DEVMETHOD(smbus_readb,          intsmb_readb),
  875         DEVMETHOD(smbus_readw,          intsmb_readw),
  876         DEVMETHOD(smbus_pcall,          intsmb_pcall),
  877         DEVMETHOD(smbus_bwrite,         intsmb_bwrite),
  878         DEVMETHOD(smbus_bread,          intsmb_bread),
  879 
  880         DEVMETHOD_END
  881 };
  882 
  883 static driver_t intsmb_driver = {
  884         "intsmb",
  885         intsmb_methods,
  886         sizeof(struct intsmb_softc),
  887 };
  888 
  889 DRIVER_MODULE_ORDERED(intsmb, pci, intsmb_driver, intsmb_devclass, 0, 0,
  890     SI_ORDER_ANY);
  891 DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0);
  892 MODULE_DEPEND(intsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  893 MODULE_VERSION(intsmb, 1);

Cache object: 3d7ae3bb7671be8302e9a26b0f439e6f


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