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/dev/ismt/ismt.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) 2014 Intel Corporation
    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  * 3. Neither the name of Intel Corporation nor the names of its
   14  *    contributors may be used to endorse or promote products derived from
   15  *    this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/errno.h>
   37 #include <sys/kernel.h>
   38 #include <sys/lock.h>
   39 #include <sys/module.h>
   40 #include <sys/priority.h>
   41 #include <sys/proc.h>
   42 #include <sys/syslog.h>
   43 
   44 #include <machine/bus.h>
   45 #include <sys/rman.h>
   46 #include <machine/resource.h>
   47 
   48 #include <dev/pci/pcireg.h>
   49 #include <dev/pci/pcivar.h>
   50 #include <dev/smbus/smbconf.h>
   51 
   52 #include "smbus_if.h"
   53 
   54 #define ISMT_DESC_ENTRIES       32
   55 
   56 /* Hardware Descriptor Constants - Control Field */
   57 #define ISMT_DESC_CWRL  0x01    /* Command/Write Length */
   58 #define ISMT_DESC_BLK   0X04    /* Perform Block Transaction */
   59 #define ISMT_DESC_FAIR  0x08    /* Set fairness flag upon successful arbit. */
   60 #define ISMT_DESC_PEC   0x10    /* Packet Error Code */
   61 #define ISMT_DESC_I2C   0x20    /* I2C Enable */
   62 #define ISMT_DESC_INT   0x40    /* Interrupt */
   63 #define ISMT_DESC_SOE   0x80    /* Stop On Error */
   64 
   65 /* Hardware Descriptor Constants - Status Field */
   66 #define ISMT_DESC_SCS   0x01    /* Success */
   67 #define ISMT_DESC_DLTO  0x04    /* Data Low Time Out */
   68 #define ISMT_DESC_NAK   0x08    /* NAK Received */
   69 #define ISMT_DESC_CRC   0x10    /* CRC Error */
   70 #define ISMT_DESC_CLTO  0x20    /* Clock Low Time Out */
   71 #define ISMT_DESC_COL   0x40    /* Collisions */
   72 #define ISMT_DESC_LPR   0x80    /* Large Packet Received */
   73 
   74 /* Macros */
   75 #define ISMT_DESC_ADDR_RW(addr, is_read) ((addr) | (is_read))
   76 
   77 /* iSMT General Register address offsets (SMBBAR + <addr>) */
   78 #define ISMT_GR_GCTRL           0x000   /* General Control */
   79 #define ISMT_GR_SMTICL          0x008   /* SMT Interrupt Cause Location */
   80 #define ISMT_GR_ERRINTMSK       0x010   /* Error Interrupt Mask */
   81 #define ISMT_GR_ERRAERMSK       0x014   /* Error AER Mask */
   82 #define ISMT_GR_ERRSTS          0x018   /* Error Status */
   83 #define ISMT_GR_ERRINFO         0x01c   /* Error Information */
   84 
   85 /* iSMT Master Registers */
   86 #define ISMT_MSTR_MDBA          0x100   /* Master Descriptor Base Address */
   87 #define ISMT_MSTR_MCTRL         0x108   /* Master Control */
   88 #define ISMT_MSTR_MSTS          0x10c   /* Master Status */
   89 #define ISMT_MSTR_MDS           0x110   /* Master Descriptor Size */
   90 #define ISMT_MSTR_RPOLICY       0x114   /* Retry Policy */
   91 
   92 /* iSMT Miscellaneous Registers */
   93 #define ISMT_SPGT       0x300   /* SMBus PHY Global Timing */
   94 
   95 /* General Control Register (GCTRL) bit definitions */
   96 #define ISMT_GCTRL_TRST 0x04    /* Target Reset */
   97 #define ISMT_GCTRL_KILL 0x08    /* Kill */
   98 #define ISMT_GCTRL_SRST 0x40    /* Soft Reset */
   99 
  100 /* Master Control Register (MCTRL) bit definitions */
  101 #define ISMT_MCTRL_SS   0x01            /* Start/Stop */
  102 #define ISMT_MCTRL_MEIE 0x10            /* Master Error Interrupt Enable */
  103 #define ISMT_MCTRL_FMHP 0x00ff0000      /* Firmware Master Head Ptr (FMHP) */
  104 
  105 /* Master Status Register (MSTS) bit definitions */
  106 #define ISMT_MSTS_HMTP  0xff0000        /* HW Master Tail Pointer (HMTP) */
  107 #define ISMT_MSTS_MIS   0x20            /* Master Interrupt Status (MIS) */
  108 #define ISMT_MSTS_MEIS  0x10            /* Master Error Int Status (MEIS) */
  109 #define ISMT_MSTS_IP    0x01            /* In Progress */
  110 
  111 /* Master Descriptor Size (MDS) bit definitions */
  112 #define ISMT_MDS_MASK   0xff    /* Master Descriptor Size mask (MDS) */
  113 
  114 /* SMBus PHY Global Timing Register (SPGT) bit definitions */
  115 #define ISMT_SPGT_SPD_MASK      0xc0000000      /* SMBus Speed mask */
  116 #define ISMT_SPGT_SPD_80K       0x00            /* 80 kHz */
  117 #define ISMT_SPGT_SPD_100K      (0x1 << 30)     /* 100 kHz */
  118 #define ISMT_SPGT_SPD_400K      (0x2 << 30)     /* 400 kHz */
  119 #define ISMT_SPGT_SPD_1M        (0x3 << 30)     /* 1 MHz */
  120 
  121 /* MSI Control Register (MSICTL) bit definitions */
  122 #define ISMT_MSICTL_MSIE        0x01    /* MSI Enable */
  123 
  124 #define ISMT_MAX_BLOCK_SIZE     32 /* per SMBus spec */
  125 
  126 //#define ISMT_DEBUG    device_printf
  127 #ifndef ISMT_DEBUG
  128 #define ISMT_DEBUG(...)
  129 #endif
  130 
  131 /* iSMT Hardware Descriptor */
  132 struct ismt_desc {
  133         uint8_t tgtaddr_rw;     /* target address & r/w bit */
  134         uint8_t wr_len_cmd;     /* write length in bytes or a command */
  135         uint8_t rd_len;         /* read length */
  136         uint8_t control;        /* control bits */
  137         uint8_t status;         /* status bits */
  138         uint8_t retry;          /* collision retry and retry count */
  139         uint8_t rxbytes;        /* received bytes */
  140         uint8_t txbytes;        /* transmitted bytes */
  141         uint32_t dptr_low;      /* lower 32 bit of the data pointer */
  142         uint32_t dptr_high;     /* upper 32 bit of the data pointer */
  143 } __packed;
  144 
  145 #define DESC_SIZE       (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc))
  146 
  147 #define DMA_BUFFER_SIZE 64
  148 
  149 struct ismt_softc {
  150         device_t                pcidev;
  151         device_t                smbdev;
  152 
  153         struct thread           *bus_reserved;
  154 
  155         int                     intr_rid;
  156         struct resource         *intr_res;
  157         void                    *intr_handle;
  158 
  159         bus_space_tag_t         mmio_tag;
  160         bus_space_handle_t      mmio_handle;
  161         int                     mmio_rid;
  162         struct resource         *mmio_res;
  163 
  164         uint8_t                 head;
  165 
  166         struct ismt_desc        *desc;
  167         bus_dma_tag_t           desc_dma_tag;
  168         bus_dmamap_t            desc_dma_map;
  169         uint64_t                desc_bus_addr;
  170 
  171         uint8_t                 *dma_buffer;
  172         bus_dma_tag_t           dma_buffer_dma_tag;
  173         bus_dmamap_t            dma_buffer_dma_map;
  174         uint64_t                dma_buffer_bus_addr;
  175 
  176         uint8_t                 using_msi;
  177 };
  178 
  179 static void
  180 ismt_intr(void *arg)
  181 {
  182         struct ismt_softc *sc = arg;
  183         uint32_t val;
  184 
  185         val = bus_read_4(sc->mmio_res, ISMT_MSTR_MSTS);
  186         ISMT_DEBUG(sc->pcidev, "%s MSTS=0x%x\n", __func__, val);
  187 
  188         val |= (ISMT_MSTS_MIS | ISMT_MSTS_MEIS);
  189         bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, val);
  190 
  191         wakeup(sc);
  192 }
  193 
  194 static int 
  195 ismt_callback(device_t dev, int index, void *data)
  196 {
  197         struct ismt_softc       *sc;
  198         int                     acquired, err;
  199 
  200         sc = device_get_softc(dev);
  201 
  202         switch (index) {
  203         case SMB_REQUEST_BUS:
  204                 acquired = atomic_cmpset_ptr(
  205                     (uintptr_t *)&sc->bus_reserved,
  206                     (uintptr_t)NULL, (uintptr_t)curthread);
  207                 ISMT_DEBUG(dev, "SMB_REQUEST_BUS acquired=%d\n", acquired);
  208                 if (acquired)
  209                         err = 0;
  210                 else
  211                         err = EWOULDBLOCK;
  212                 break;
  213         case SMB_RELEASE_BUS:
  214                 KASSERT(sc->bus_reserved == curthread,
  215                     ("SMB_RELEASE_BUS called by wrong thread\n"));
  216                 ISMT_DEBUG(dev, "SMB_RELEASE_BUS\n");
  217                 atomic_store_rel_ptr((uintptr_t *)&sc->bus_reserved,
  218                     (uintptr_t)NULL);
  219                 err = 0;
  220                 break;
  221         default:
  222                 err = SMB_EABORT;
  223                 break;
  224         }
  225 
  226         return (err);
  227 }
  228 
  229 static struct ismt_desc *
  230 ismt_alloc_desc(struct ismt_softc *sc)
  231 {
  232         struct ismt_desc *desc;
  233 
  234         KASSERT(sc->bus_reserved == curthread,
  235             ("curthread %p did not request bus (%p has reserved)\n",
  236             curthread, sc->bus_reserved));
  237 
  238         desc = &sc->desc[sc->head++];
  239         if (sc->head == ISMT_DESC_ENTRIES)
  240                 sc->head = 0;
  241 
  242         memset(desc, 0, sizeof(*desc));
  243 
  244         return (desc);
  245 }
  246 
  247 static int
  248 ismt_submit(struct ismt_softc *sc, struct ismt_desc *desc, uint8_t slave,
  249     uint8_t is_read)
  250 {
  251         uint32_t err, fmhp, val;
  252 
  253         desc->control |= ISMT_DESC_FAIR;
  254         if (sc->using_msi)
  255                 desc->control |= ISMT_DESC_INT;
  256 
  257         desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(slave, is_read);
  258         desc->dptr_low = (sc->dma_buffer_bus_addr & 0xFFFFFFFFLL);
  259         desc->dptr_high = (sc->dma_buffer_bus_addr >> 32);
  260 
  261         wmb();
  262 
  263         fmhp = sc->head << 16;
  264         val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
  265         val &= ~ISMT_MCTRL_FMHP;
  266         val |= fmhp;
  267         bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
  268 
  269         /* set the start bit */
  270         val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
  271         val |= ISMT_MCTRL_SS;
  272         bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
  273 
  274         err = tsleep(sc, PWAIT, "ismt_wait", 5 * hz);
  275 
  276         if (err != 0) {
  277                 ISMT_DEBUG(sc->pcidev, "%s timeout\n", __func__);
  278                 return (SMB_ETIMEOUT);
  279         }
  280 
  281         ISMT_DEBUG(sc->pcidev, "%s status=0x%x\n", __func__, desc->status);
  282 
  283         if (desc->status & ISMT_DESC_SCS)
  284                 return (SMB_ENOERR);
  285 
  286         if (desc->status & ISMT_DESC_NAK)
  287                 return (SMB_ENOACK);
  288 
  289         if (desc->status & ISMT_DESC_CRC)
  290                 return (SMB_EBUSERR);
  291 
  292         if (desc->status & ISMT_DESC_COL)
  293                 return (SMB_ECOLLI);
  294 
  295         if (desc->status & ISMT_DESC_LPR)
  296                 return (SMB_EINVAL);
  297 
  298         if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO))
  299                 return (SMB_ETIMEOUT);
  300 
  301         return (SMB_EBUSERR);
  302 }
  303 
  304 
  305 static int
  306 ismt_quick(device_t dev, u_char slave, int how)
  307 {
  308         struct ismt_desc        *desc;
  309         struct ismt_softc       *sc;
  310         int                     is_read;
  311 
  312         ISMT_DEBUG(dev, "%s\n", __func__);
  313 
  314         if (how != SMB_QREAD && how != SMB_QWRITE) {
  315                 return (SMB_ENOTSUPP);
  316         }
  317 
  318         sc = device_get_softc(dev);
  319         desc = ismt_alloc_desc(sc);
  320         is_read = (how == SMB_QREAD ? 1 : 0);
  321         return (ismt_submit(sc, desc, slave, is_read));
  322 }
  323 
  324 static int
  325 ismt_sendb(device_t dev, u_char slave, char byte)
  326 {
  327         struct ismt_desc        *desc;
  328         struct ismt_softc       *sc;
  329 
  330         ISMT_DEBUG(dev, "%s\n", __func__);
  331 
  332         sc = device_get_softc(dev);
  333         desc = ismt_alloc_desc(sc);
  334         desc->control = ISMT_DESC_CWRL;
  335         desc->wr_len_cmd = byte;
  336 
  337         return (ismt_submit(sc, desc, slave, 0));
  338 }
  339 
  340 static int
  341 ismt_recvb(device_t dev, u_char slave, char *byte)
  342 {
  343         struct ismt_desc        *desc;
  344         struct ismt_softc       *sc;
  345         int                     err;
  346 
  347         ISMT_DEBUG(dev, "%s\n", __func__);
  348 
  349         sc = device_get_softc(dev);
  350         desc = ismt_alloc_desc(sc);
  351         desc->rd_len = 1;
  352 
  353         err = ismt_submit(sc, desc, slave, 1);
  354 
  355         if (err != SMB_ENOERR)
  356                 return (err);
  357 
  358         *byte = sc->dma_buffer[0];
  359 
  360         return (err);
  361 }
  362 
  363 static int
  364 ismt_writeb(device_t dev, u_char slave, char cmd, char byte)
  365 {
  366         struct ismt_desc        *desc;
  367         struct ismt_softc       *sc;
  368 
  369         ISMT_DEBUG(dev, "%s\n", __func__);
  370 
  371         sc = device_get_softc(dev);
  372         desc = ismt_alloc_desc(sc);
  373         desc->wr_len_cmd = 2;
  374         sc->dma_buffer[0] = cmd;
  375         sc->dma_buffer[1] = byte;
  376 
  377         return (ismt_submit(sc, desc, slave, 0));
  378 }
  379 
  380 static int
  381 ismt_writew(device_t dev, u_char slave, char cmd, short word)
  382 {
  383         struct ismt_desc        *desc;
  384         struct ismt_softc       *sc;
  385 
  386         ISMT_DEBUG(dev, "%s\n", __func__);
  387 
  388         sc = device_get_softc(dev);
  389         desc = ismt_alloc_desc(sc);
  390         desc->wr_len_cmd = 3;
  391         sc->dma_buffer[0] = cmd;
  392         sc->dma_buffer[1] = word & 0xFF;
  393         sc->dma_buffer[2] = word >> 8;
  394 
  395         return (ismt_submit(sc, desc, slave, 0));
  396 }
  397 
  398 static int
  399 ismt_readb(device_t dev, u_char slave, char cmd, char *byte)
  400 {
  401         struct ismt_desc        *desc;
  402         struct ismt_softc       *sc;
  403         int                     err;
  404 
  405         ISMT_DEBUG(dev, "%s\n", __func__);
  406 
  407         sc = device_get_softc(dev);
  408         desc = ismt_alloc_desc(sc);
  409         desc->control = ISMT_DESC_CWRL;
  410         desc->wr_len_cmd = cmd;
  411         desc->rd_len = 1;
  412 
  413         err = ismt_submit(sc, desc, slave, 1);
  414 
  415         if (err != SMB_ENOERR)
  416                 return (err);
  417 
  418         *byte = sc->dma_buffer[0];
  419 
  420         return (err);
  421 }
  422 
  423 static int
  424 ismt_readw(device_t dev, u_char slave, char cmd, short *word)
  425 {
  426         struct ismt_desc        *desc;
  427         struct ismt_softc       *sc;
  428         int                     err;
  429 
  430         ISMT_DEBUG(dev, "%s\n", __func__);
  431 
  432         sc = device_get_softc(dev);
  433         desc = ismt_alloc_desc(sc);
  434         desc->control = ISMT_DESC_CWRL;
  435         desc->wr_len_cmd = cmd;
  436         desc->rd_len = 2;
  437 
  438         err = ismt_submit(sc, desc, slave, 1);
  439 
  440         if (err != SMB_ENOERR)
  441                 return (err);
  442 
  443         *word = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
  444 
  445         return (err);
  446 }
  447 
  448 static int
  449 ismt_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  450 {
  451         struct ismt_desc        *desc;
  452         struct ismt_softc       *sc;
  453         int                     err;
  454 
  455         ISMT_DEBUG(dev, "%s\n", __func__);
  456 
  457         sc = device_get_softc(dev);
  458         desc = ismt_alloc_desc(sc);
  459         desc->wr_len_cmd = 3;
  460         desc->rd_len = 2;
  461         sc->dma_buffer[0] = cmd;
  462         sc->dma_buffer[1] = sdata & 0xff;
  463         sc->dma_buffer[2] = sdata >> 8;
  464 
  465         err = ismt_submit(sc, desc, slave, 0);
  466 
  467         if (err != SMB_ENOERR)
  468                 return (err);
  469 
  470         *rdata = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
  471 
  472         return (err);
  473 }
  474 
  475 static int
  476 ismt_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  477 {
  478         struct ismt_desc        *desc;
  479         struct ismt_softc       *sc;
  480 
  481         ISMT_DEBUG(dev, "%s\n", __func__);
  482 
  483         if (count == 0 || count > ISMT_MAX_BLOCK_SIZE)
  484                 return (SMB_EINVAL);
  485 
  486         sc = device_get_softc(dev);
  487         desc = ismt_alloc_desc(sc);
  488         desc->control = ISMT_DESC_I2C;
  489         desc->wr_len_cmd = count + 1;
  490         sc->dma_buffer[0] = cmd;
  491         memcpy(&sc->dma_buffer[1], buf, count);
  492 
  493         return (ismt_submit(sc, desc, slave, 0));
  494 }
  495 
  496 static int
  497 ismt_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  498 {
  499         struct ismt_desc        *desc;
  500         struct ismt_softc       *sc;
  501         int                     err;
  502 
  503         ISMT_DEBUG(dev, "%s\n", __func__);
  504 
  505         if (*count == 0 || *count > ISMT_MAX_BLOCK_SIZE)
  506                 return (SMB_EINVAL);
  507 
  508         sc = device_get_softc(dev);
  509         desc = ismt_alloc_desc(sc);
  510         desc->control = ISMT_DESC_I2C | ISMT_DESC_CWRL;
  511         desc->wr_len_cmd = cmd;
  512         desc->rd_len = *count;
  513 
  514         err = ismt_submit(sc, desc, slave, 0);
  515 
  516         if (err != SMB_ENOERR)
  517                 return (err);
  518 
  519         memcpy(buf, sc->dma_buffer, desc->rxbytes);
  520         *count = desc->rxbytes;
  521 
  522         return (err);
  523 }
  524 
  525 static int
  526 ismt_detach(device_t dev)
  527 {
  528         struct ismt_softc       *sc;
  529         int                     error;
  530 
  531         ISMT_DEBUG(dev, "%s\n", __func__);
  532         sc = device_get_softc(dev);
  533 
  534         error = bus_generic_detach(dev);
  535         if (error)
  536                 return (error);
  537 
  538         device_delete_child(dev, sc->smbdev);
  539 
  540         if (sc->intr_handle != NULL) {
  541                 bus_teardown_intr(dev, sc->intr_res, sc->intr_handle);
  542                 sc->intr_handle = NULL;
  543         }
  544         if (sc->intr_res != NULL) {
  545                 bus_release_resource(dev,
  546                     SYS_RES_IRQ, sc->intr_rid, sc->intr_res);
  547                 sc->intr_res = NULL;
  548         }
  549         if (sc->using_msi == 1)
  550                 pci_release_msi(dev);
  551 
  552         if (sc->mmio_res != NULL) {
  553                 bus_release_resource(dev,
  554                     SYS_RES_MEMORY, sc->mmio_rid, sc->mmio_res);
  555                 sc->mmio_res = NULL;
  556         }
  557 
  558         bus_dmamap_unload(sc->desc_dma_tag, sc->desc_dma_map);
  559         bus_dmamap_unload(sc->dma_buffer_dma_tag, sc->dma_buffer_dma_map);
  560 
  561         bus_dmamem_free(sc->desc_dma_tag, sc->desc,
  562             sc->desc_dma_map);
  563         bus_dmamem_free(sc->dma_buffer_dma_tag, sc->dma_buffer,
  564             sc->dma_buffer_dma_map);
  565 
  566         bus_dma_tag_destroy(sc->desc_dma_tag);
  567         bus_dma_tag_destroy(sc->dma_buffer_dma_tag);
  568 
  569         pci_disable_busmaster(dev);
  570 
  571         return 0;
  572 }
  573 
  574 static void
  575 ismt_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
  576 {
  577         uint64_t *bus_addr = (uint64_t *)arg;
  578 
  579         KASSERT(error == 0, ("%s: error=%d\n", __func__, error));
  580         KASSERT(nseg == 1, ("%s: nseg=%d\n", __func__, nseg));
  581 
  582         *bus_addr = seg[0].ds_addr;
  583 }
  584 
  585 static int
  586 ismt_attach(device_t dev)
  587 {
  588         struct ismt_softc *sc = device_get_softc(dev);
  589         int err, num_vectors, val;
  590 
  591         sc->pcidev = dev;
  592         pci_enable_busmaster(dev);
  593 
  594         if ((sc->smbdev = device_add_child(dev, "smbus", -1)) == NULL) {
  595                 device_printf(dev, "no smbus child found\n");
  596                 err = ENXIO;
  597                 goto fail;
  598         }
  599 
  600         sc->mmio_rid = PCIR_BAR(0);
  601         sc->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  602             &sc->mmio_rid, RF_ACTIVE);
  603         if (sc->mmio_res == NULL) {
  604                 device_printf(dev, "cannot allocate mmio region\n");
  605                 err = ENOMEM;
  606                 goto fail;
  607         }
  608 
  609         sc->mmio_tag = rman_get_bustag(sc->mmio_res);
  610         sc->mmio_handle = rman_get_bushandle(sc->mmio_res);
  611 
  612         /* Attach "smbus" child */
  613         if ((err = bus_generic_attach(dev)) != 0) {
  614                 device_printf(dev, "failed to attach child: %d\n", err);
  615                 err = ENXIO;
  616                 goto fail;
  617         }
  618 
  619         bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
  620             BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
  621             DESC_SIZE, 1, DESC_SIZE,
  622             0, NULL, NULL, &sc->desc_dma_tag);
  623 
  624         bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
  625             BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
  626             DMA_BUFFER_SIZE, 1, DMA_BUFFER_SIZE,
  627             0, NULL, NULL, &sc->dma_buffer_dma_tag);
  628 
  629         bus_dmamap_create(sc->desc_dma_tag, 0,
  630             &sc->desc_dma_map);
  631         bus_dmamap_create(sc->dma_buffer_dma_tag, 0,
  632             &sc->dma_buffer_dma_map);
  633 
  634         bus_dmamem_alloc(sc->desc_dma_tag,
  635             (void **)&sc->desc, BUS_DMA_WAITOK,
  636             &sc->desc_dma_map);
  637         bus_dmamem_alloc(sc->dma_buffer_dma_tag,
  638             (void **)&sc->dma_buffer, BUS_DMA_WAITOK,
  639             &sc->dma_buffer_dma_map);
  640 
  641         bus_dmamap_load(sc->desc_dma_tag,
  642             sc->desc_dma_map, sc->desc, DESC_SIZE,
  643             ismt_single_map, &sc->desc_bus_addr, 0);
  644         bus_dmamap_load(sc->dma_buffer_dma_tag,
  645             sc->dma_buffer_dma_map, sc->dma_buffer, DMA_BUFFER_SIZE,
  646             ismt_single_map, &sc->dma_buffer_bus_addr, 0);
  647 
  648         bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA,
  649             (sc->desc_bus_addr & 0xFFFFFFFFLL));
  650         bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA + 4,
  651             (sc->desc_bus_addr >> 32));
  652 
  653         /* initialize the Master Control Register (MCTRL) */
  654         bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, ISMT_MCTRL_MEIE);
  655 
  656         /* initialize the Master Status Register (MSTS) */
  657         bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, 0);
  658 
  659         /* initialize the Master Descriptor Size (MDS) */
  660         val = bus_read_4(sc->mmio_res, ISMT_MSTR_MDS);
  661         val &= ~ISMT_MDS_MASK;
  662         val |= (ISMT_DESC_ENTRIES - 1);
  663         bus_write_4(sc->mmio_res, ISMT_MSTR_MDS, val);
  664 
  665         sc->using_msi = 1;
  666 
  667         if (pci_msi_count(dev) == 0) {
  668                 sc->using_msi = 0;
  669                 goto intx;
  670         }
  671 
  672         num_vectors = 1;
  673         if (pci_alloc_msi(dev, &num_vectors) != 0) {
  674                 sc->using_msi = 0;
  675                 goto intx;
  676         }
  677 
  678         sc->intr_rid = 1;
  679         sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  680             &sc->intr_rid, RF_ACTIVE);
  681 
  682         if (sc->intr_res == NULL) {
  683                 sc->using_msi = 0;
  684                 pci_release_msi(dev);
  685         }
  686 
  687 intx:
  688         if (sc->using_msi == 0) {
  689                 sc->intr_rid = 0;
  690                 sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  691                     &sc->intr_rid, RF_SHAREABLE | RF_ACTIVE);
  692                 if (sc->intr_res == NULL) {
  693                         device_printf(dev, "cannot allocate irq\n");
  694                         err = ENXIO;
  695                         goto fail;
  696                 }
  697         }
  698 
  699         ISMT_DEBUG(dev, "using_msi = %d\n", sc->using_msi);
  700 
  701         err = bus_setup_intr(dev, sc->intr_res,
  702             INTR_TYPE_MISC | INTR_MPSAFE, NULL, ismt_intr, sc,
  703             &sc->intr_handle);
  704         if (err != 0) {
  705                 device_printf(dev, "cannot setup interrupt\n");
  706                 err = ENXIO;
  707                 goto fail;
  708         }
  709 
  710         return (0);
  711 
  712 fail:
  713         ismt_detach(dev);
  714         return (err);
  715 }
  716 
  717 #define ID_INTEL_S1200_SMT0             0x0c598086
  718 #define ID_INTEL_S1200_SMT1             0x0c5a8086
  719 #define ID_INTEL_C2000_SMT              0x1f158086
  720 #define ID_INTEL_C3000_SMT              0x19ac8086
  721 
  722 static int
  723 ismt_probe(device_t dev)
  724 {
  725         const char *desc;
  726 
  727         switch (pci_get_devid(dev)) {
  728         case ID_INTEL_S1200_SMT0:
  729                 desc = "Atom Processor S1200 SMBus 2.0 Controller 0";
  730                 break;
  731         case ID_INTEL_S1200_SMT1:
  732                 desc = "Atom Processor S1200 SMBus 2.0 Controller 1";
  733                 break;
  734         case ID_INTEL_C2000_SMT:
  735                 desc = "Atom Processor C2000 SMBus 2.0";
  736                 break;
  737         case ID_INTEL_C3000_SMT:
  738                 desc = "Atom Processor C3000 SMBus 2.0";
  739                 break;
  740         default:
  741                 return (ENXIO);
  742         }
  743 
  744         device_set_desc(dev, desc);
  745         return (BUS_PROBE_DEFAULT);
  746 }
  747 
  748 /* Device methods */
  749 static device_method_t ismt_pci_methods[] = {
  750         DEVMETHOD(device_probe,         ismt_probe),
  751         DEVMETHOD(device_attach,        ismt_attach),
  752         DEVMETHOD(device_detach,        ismt_detach),
  753 
  754         DEVMETHOD(smbus_callback,       ismt_callback),
  755         DEVMETHOD(smbus_quick,          ismt_quick),
  756         DEVMETHOD(smbus_sendb,          ismt_sendb),
  757         DEVMETHOD(smbus_recvb,          ismt_recvb),
  758         DEVMETHOD(smbus_writeb,         ismt_writeb),
  759         DEVMETHOD(smbus_writew,         ismt_writew),
  760         DEVMETHOD(smbus_readb,          ismt_readb),
  761         DEVMETHOD(smbus_readw,          ismt_readw),
  762         DEVMETHOD(smbus_pcall,          ismt_pcall),
  763         DEVMETHOD(smbus_bwrite,         ismt_bwrite),
  764         DEVMETHOD(smbus_bread,          ismt_bread),
  765 
  766         DEVMETHOD_END
  767 };
  768 
  769 static driver_t ismt_pci_driver = {
  770         "ismt",
  771         ismt_pci_methods,
  772         sizeof(struct ismt_softc)
  773 };
  774 
  775 DRIVER_MODULE(ismt, pci, ismt_pci_driver, 0, 0);
  776 DRIVER_MODULE(smbus, ismt, smbus_driver, 0, 0);
  777 
  778 MODULE_DEPEND(ismt, pci, 1, 1, 1);
  779 MODULE_DEPEND(ismt, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  780 MODULE_VERSION(ismt, 1);

Cache object: fbbe6782aff6599e278e394faa8aac21


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