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/imcsmb/imcsmb.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Authors: Joe Kloss; Ravi Pokala (rpokala@freebsd.org)
    5  *
    6  * Copyright (c) 2017-2018 Panasas
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   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  * $FreeBSD$
   30  */
   31 
   32 /* A detailed description of this device is present in imcsmb_pci.c */
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/endian.h>
   39 #include <sys/errno.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/syslog.h>
   43 #include <sys/bus.h>
   44 
   45 #include <machine/bus.h>
   46 #include <machine/atomic.h>
   47 
   48 #include <dev/pci/pcivar.h>
   49 #include <dev/pci/pcireg.h>
   50 
   51 #include <dev/smbus/smbconf.h>
   52 
   53 #include "imcsmb_reg.h"
   54 #include "imcsmb_var.h"
   55 
   56 /* Device methods */
   57 static int imcsmb_attach(device_t dev);
   58 static int imcsmb_detach(device_t dev);
   59 static int imcsmb_probe(device_t dev);
   60 
   61 /* SMBus methods */
   62 static int imcsmb_callback(device_t dev, int index, void *data);
   63 static int imcsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   64 static int imcsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   65 static int imcsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   66 static int imcsmb_writew(device_t dev, u_char slave, char cmd, short word);
   67 
   68 /* All the read/write methods wrap around this. */
   69 static int imcsmb_transfer(device_t dev, u_char slave, char cmd, void *data,
   70     int word_op, int write_op);
   71 
   72 /**
   73  * device_attach() method. Set up the softc, including getting the set of the
   74  * parent imcsmb_pci's registers that we will use. Create the smbus(4) device,
   75  * which any SMBus slave device drivers will connect to.
   76  *
   77  * @author rpokala
   78  *
   79  * @param[in,out] dev
   80  *      Device being attached.
   81  */
   82 static int
   83 imcsmb_attach(device_t dev)
   84 {
   85         struct imcsmb_softc *sc;
   86         int rc;
   87 
   88         /* Initialize private state */
   89         sc = device_get_softc(dev);
   90         sc->dev = dev;
   91         sc->imcsmb_pci = device_get_parent(dev);
   92         sc->regs = device_get_ivars(dev);
   93 
   94         /* Create the smbus child */
   95         sc->smbus = device_add_child(dev, "smbus", -1);
   96         if (sc->smbus == NULL) {
   97                 /* Nothing has been allocated, so there's no cleanup. */
   98                 device_printf(dev, "Child smbus not added\n");
   99                 rc = ENXIO;
  100                 goto out;
  101         }
  102 
  103         /* Attach the smbus child. */
  104         if ((rc = bus_generic_attach(dev)) != 0) {
  105                 device_printf(dev, "Failed to attach smbus: %d\n", rc);
  106         }
  107 
  108 out:
  109         return (rc);
  110 }
  111 
  112 /**
  113  * device_detach() method. attach() didn't do any allocations, so all that's
  114  * needed here is to free up any downstream drivers and children.
  115  *
  116  * @author Joe Kloss
  117  *
  118  * @param[in] dev
  119  *      Device being detached.
  120  */
  121 static int
  122 imcsmb_detach(device_t dev)
  123 {
  124         int rc;
  125 
  126         /* Detach any attached drivers */
  127         rc = bus_generic_detach(dev);
  128         if (rc == 0) {
  129                 /* Remove all children */
  130                 rc = device_delete_children(dev);
  131         }
  132 
  133         return (rc);
  134 }
  135 
  136 /**
  137  * device_probe() method. All the actual probing was done by the imcsmb_pci
  138  * parent, so just report success.
  139  *
  140  * @author Joe Kloss
  141  *
  142  * @param[in,out] dev
  143  *      Device being probed.
  144  */
  145 static int
  146 imcsmb_probe(device_t dev)
  147 {
  148 
  149         device_set_desc(dev, "iMC SMBus controller");
  150         return (BUS_PROBE_DEFAULT);
  151 }
  152 
  153 /**
  154  * smbus_callback() method. Call the parent imcsmb_pci's request or release
  155  * function to quiesce / restart firmware tasks which might use the SMBus.
  156  *
  157  * @author rpokala
  158  *
  159  * @param[in] dev
  160  *      Device being requested or released.
  161  *
  162  * @param[in] index
  163  *      Either SMB_REQUEST_BUS or SMB_RELEASE_BUS.
  164  *
  165  * @param[in] data
  166  *      Tell's the rest of the SMBus subsystem to allow or disallow waiting;
  167  *      this driver only works with SMB_DONTWAIT.
  168  */
  169 static int
  170 imcsmb_callback(device_t dev, int index, void *data)
  171 {
  172         struct imcsmb_softc *sc;
  173         int *how;
  174         int rc;
  175 
  176         sc = device_get_softc(dev);
  177         how = (int *) data;
  178 
  179         switch (index) {
  180         case SMB_REQUEST_BUS: {
  181                 if (*how != SMB_DONTWAIT) {
  182                         rc = EINVAL;
  183                         goto out;
  184                 }
  185                 rc = imcsmb_pci_request_bus(sc->imcsmb_pci);
  186                 break;
  187         }
  188         case SMB_RELEASE_BUS:
  189                 imcsmb_pci_release_bus(sc->imcsmb_pci);
  190                 rc = 0;
  191                 break;
  192         default:
  193                 rc = EINVAL;
  194                 break;
  195         }
  196 
  197 out:
  198         return (rc);
  199 }
  200 
  201 /**
  202  * smbus_readb() method. Thin wrapper around imcsmb_transfer().
  203  *
  204  * @author Joe Kloss
  205  *
  206  * @param[in] dev
  207  *
  208  * @param[in] slave
  209  *      The SMBus address of the target device.
  210  *
  211  * @param[in] cmd
  212  *      The SMBus command for the target device; this is the offset for SPDs,
  213  *      or the register number for TSODs.
  214  *
  215  * @param[out] byte
  216  *      The byte which was read.
  217  */
  218 static int
  219 imcsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  220 {
  221 
  222         return (imcsmb_transfer(dev, slave, cmd, byte, FALSE, FALSE));
  223 }
  224 
  225 /**
  226  * smbus_readw() method. Thin wrapper around imcsmb_transfer().
  227  *
  228  * @author Joe Kloss
  229  *
  230  * @param[in] dev
  231  *
  232  * @param[in] slave
  233  *      The SMBus address of the target device.
  234  *
  235  * @param[in] cmd
  236  *      The SMBus command for the target device; this is the offset for SPDs,
  237  *      or the register number for TSODs.
  238  *
  239  * @param[out] word
  240  *      The word which was read.
  241  */
  242 static int
  243 imcsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  244 {
  245 
  246         return (imcsmb_transfer(dev, slave, cmd, word, TRUE, FALSE));
  247 }
  248 
  249 /**
  250  * smbus_writeb() method. Thin wrapper around imcsmb_transfer().
  251  *
  252  * @author Joe Kloss
  253  *
  254  * @param[in] dev
  255  *
  256  * @param[in] slave
  257  *      The SMBus address of the target device.
  258  *
  259  * @param[in] cmd
  260  *      The SMBus command for the target device; this is the offset for SPDs,
  261  *      or the register number for TSODs.
  262  *
  263  * @param[in] byte
  264  *      The byte to write.
  265  */
  266 static int
  267 imcsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  268 {
  269 
  270         return (imcsmb_transfer(dev, slave, cmd, &byte, FALSE, TRUE));
  271 }
  272 
  273 /**
  274  * smbus_writew() method. Thin wrapper around imcsmb_transfer().
  275  *
  276  * @author Joe Kloss
  277  *
  278  * @param[in] dev
  279  *
  280  * @param[in] slave
  281  *      The SMBus address of the target device.
  282  *
  283  * @param[in] cmd
  284  *      The SMBus command for the target device; this is the offset for SPDs,
  285  *      or the register number for TSODs.
  286  *
  287  * @param[in] word
  288  *      The word to write.
  289  */
  290 static int
  291 imcsmb_writew(device_t dev, u_char slave, char cmd, short word)
  292 {
  293 
  294         return (imcsmb_transfer(dev, slave, cmd, &word, TRUE, TRUE));
  295 }
  296 
  297 /**
  298  * Manipulate the PCI control registers to read data from or write data to the
  299  * SMBus controller.
  300  *
  301  * @author Joe Kloss, rpokala
  302  *
  303  * @param[in] dev
  304  *
  305  * @param[in] slave
  306  *      The SMBus address of the target device.
  307  *
  308  * @param[in] cmd
  309  *      The SMBus command for the target device; this is the offset for SPDs,
  310  *      or the register number for TSODs.
  311  *
  312  * @param[in,out] data
  313  *      Pointer to either the value to be written, or where to place the value
  314  *      which was read.
  315  *
  316  * @param[in] word_op
  317  *      Bool: is this a word operation?
  318  *
  319  * @param[in] write_op
  320  *      Bool: is this a write operation?
  321  */
  322 static int
  323 imcsmb_transfer(device_t dev, u_char slave, char cmd, void *data, int word_op,
  324     int write_op)
  325 {
  326         struct imcsmb_softc *sc;
  327         int i;
  328         int rc;
  329         uint32_t cmd_val;
  330         uint32_t cntl_val;
  331         uint32_t orig_cntl_val;
  332         uint32_t stat_val;
  333         uint16_t *word;
  334         uint16_t lword;
  335         uint8_t *byte;
  336         uint8_t lbyte;
  337 
  338         sc = device_get_softc(dev);
  339         byte = data;
  340         word = data;
  341         lbyte = *byte;
  342         lword = *word;
  343 
  344         /* We modify the value of the control register; save the original, so
  345          * we can restore it later
  346          */
  347         orig_cntl_val = pci_read_config(sc->imcsmb_pci,
  348             sc->regs->smb_cntl, 4);
  349         cntl_val = orig_cntl_val;
  350 
  351         /*
  352          * Set up the SMBCNTL register
  353          */
  354 
  355         /* [31:28] Clear the existing value of the DTI bits, then set them to
  356          * the four high bits of the slave address.
  357          */
  358         cntl_val &= ~IMCSMB_CNTL_DTI_MASK;
  359         cntl_val |= ((uint32_t) slave & 0xf0) << 24;
  360 
  361         /* [27:27] Set the CLK_OVERRIDE bit, to enable normal operation */
  362         cntl_val |= IMCSMB_CNTL_CLK_OVERRIDE;
  363 
  364         /* [26:26] Clear the WRITE_DISABLE bit; the datasheet says this isn't
  365          * necessary, but empirically, it is.
  366          */
  367         cntl_val &= ~IMCSMB_CNTL_WRITE_DISABLE_BIT;
  368 
  369         /* [9:9] Clear the POLL_EN bit, to stop the hardware TSOD polling. */
  370         cntl_val &= ~IMCSMB_CNTL_POLL_EN;
  371 
  372         /*
  373          * Set up the SMBCMD register
  374          */
  375 
  376         /* [31:31] Set the TRIGGER bit; when this gets written, the controller
  377          * will issue the command.
  378          */
  379         cmd_val = IMCSMB_CMD_TRIGGER_BIT;
  380 
  381         /* [29:29] For word operations, set the WORD_ACCESS bit. */
  382         if (word_op) {
  383                 cmd_val |= IMCSMB_CMD_WORD_ACCESS;
  384         }
  385 
  386         /* [27:27] For write operations, set the WRITE bit. */
  387         if (write_op) {
  388                 cmd_val |= IMCSMB_CMD_WRITE_BIT;
  389         }
  390 
  391         /* [26:24] The three non-DTI, non-R/W bits of the slave address. */
  392         cmd_val |= (uint32_t) ((slave & 0xe) << 23);
  393 
  394         /* [23:16] The command (offset in the case of an EEPROM, or register in
  395          * the case of TSOD or NVDIMM controller).
  396          */
  397         cmd_val |= (uint32_t) ((uint8_t) cmd << 16);
  398 
  399         /* [15:0] The data to be written for a write operation. */
  400         if (write_op) {
  401                 if (word_op) {
  402                         /* The datasheet says the controller uses different
  403                          * endianness for word operations on I2C vs SMBus!
  404                          *      I2C: [15:8] = MSB; [7:0] = LSB
  405                          *      SMB: [15:8] = LSB; [7:0] = MSB
  406                          * As a practical matter, this controller is very
  407                          * specifically for use with DIMMs, the SPD (and
  408                          * NVDIMM controllers) are only accessed as bytes,
  409                          * the temperature sensor is only accessed as words, and
  410                          * the temperature sensors are I2C. Thus, byte-swap the
  411                          * word.
  412                          */
  413                         lword = htobe16(lword);
  414                 } else {
  415                         /* For byte operations, the data goes in the LSB, and
  416                          * the MSB is a don't care.
  417                          */
  418                         lword = (uint16_t) (lbyte & 0xff);
  419                 }
  420                 cmd_val |= lword;
  421         }
  422 
  423         /* Write the updated value to the control register first, to disable
  424          * the hardware TSOD polling.
  425          */
  426         pci_write_config(sc->imcsmb_pci, sc->regs->smb_cntl, cntl_val, 4);
  427 
  428         /* Poll on the BUSY bit in the status register until clear, or timeout.
  429          * We just cleared the auto-poll bit, so we need to make sure the device
  430          * is idle before issuing a command. We can safely timeout after 35 ms,
  431          * as this is the maximum time the SMBus spec allows for a transaction.
  432          */
  433         for (i = 4; i != 0; i--) {
  434                 stat_val = pci_read_config(sc->imcsmb_pci, sc->regs->smb_stat,
  435                     4);
  436                 if ((stat_val & IMCSMB_STATUS_BUSY_BIT) == 0) {
  437                         break;
  438                 }
  439                 pause("imcsmb", 10 * hz / 1000);
  440         }
  441 
  442         if (i == 0) {
  443                 device_printf(sc->dev,
  444                     "transfer: timeout waiting for device to settle\n");
  445         }
  446 
  447         /* Now that polling has stopped, we can write the command register. This
  448          * starts the SMBus command.
  449          */
  450         pci_write_config(sc->imcsmb_pci, sc->regs->smb_cmd, cmd_val, 4);
  451 
  452         /* Wait for WRITE_DATA_DONE/READ_DATA_VALID to be set, or timeout and
  453          * fail. We wait up to 35ms.
  454          */
  455         for (i = 35000; i != 0; i -= 10)
  456         {
  457                 DELAY(10);
  458                 stat_val = pci_read_config(sc->imcsmb_pci, sc->regs->smb_stat,
  459                     4);
  460                 /* For a write, the bits holding the data contain the data being
  461                  * written. You'd think that would cause the READ_DATA_VALID bit
  462                  * to be cleared, because the data bits no longer contain valid
  463                  * data from the most recent read operation. While that would be
  464                  * logical, that's not the case here: READ_DATA_VALID is only
  465                  * cleared when starting a read operation, and WRITE_DATA_DONE
  466                  * is only cleared when starting a write operation.
  467                  */
  468                 if (write_op) {
  469                         if ((stat_val & IMCSMB_STATUS_WRITE_DATA_DONE) != 0) {
  470                                 break;
  471                         }
  472                 } else {
  473                         if ((stat_val & IMCSMB_STATUS_READ_DATA_VALID) != 0) {
  474                                 break;
  475                         }
  476                 }
  477         }
  478         if (i == 0) {
  479                 rc = SMB_ETIMEOUT;
  480                 device_printf(dev, "transfer timeout\n");
  481                 goto out;
  482         }
  483 
  484         /* It is generally the case that this bit indicates non-ACK, but it
  485          * could also indicate other bus errors. There's no way to tell the
  486          * difference.
  487          */
  488         if ((stat_val & IMCSMB_STATUS_BUS_ERROR_BIT) != 0) {
  489                 /* While it is not documented, empirically, SPD page-change
  490                  * commands (writes with DTI = 0x60) always complete with the
  491                  * error bit set. So, ignore it in those cases.
  492                  */
  493                 if ((slave & 0xf0) != 0x60) {
  494                         rc = SMB_ENOACK;
  495                         goto out;
  496                 }
  497         }
  498 
  499         /* For a read operation, copy the data out */
  500         if (write_op == 0) {
  501                 if (word_op) {
  502                         /* The data is returned in bits [15:0]; as discussed
  503                          * above, byte-swap.
  504                          */
  505                         lword = (uint16_t) (stat_val & 0xffff);
  506                         lword = htobe16(lword);
  507                         *word = lword;
  508                 } else {
  509                         /* The data is returned in bits [7:0] */
  510                         lbyte = (uint8_t) (stat_val & 0xff);
  511                         *byte = lbyte;
  512                 }
  513         }
  514 
  515         /* A lack of an error is, de facto, success. */
  516         rc = SMB_ENOERR;
  517 
  518 out:
  519         /* Restore the original value of the control register. */
  520         pci_write_config(sc->imcsmb_pci, sc->regs->smb_cntl, orig_cntl_val, 4);
  521         return (rc);
  522 }
  523 
  524 /* Device methods */
  525 static device_method_t imcsmb_methods[] = {
  526         /* Device interface */
  527         DEVMETHOD(device_attach,        imcsmb_attach),
  528         DEVMETHOD(device_detach,        imcsmb_detach),
  529         DEVMETHOD(device_probe,         imcsmb_probe),
  530 
  531         /* smbus methods */
  532         DEVMETHOD(smbus_callback,       imcsmb_callback),
  533         DEVMETHOD(smbus_readb,          imcsmb_readb),
  534         DEVMETHOD(smbus_readw,          imcsmb_readw),
  535         DEVMETHOD(smbus_writeb,         imcsmb_writeb),
  536         DEVMETHOD(smbus_writew,         imcsmb_writew),
  537 
  538         DEVMETHOD_END
  539 };
  540 
  541 static driver_t imcsmb_driver = {
  542         .name = "imcsmb",
  543         .methods = imcsmb_methods,
  544         .size = sizeof(struct imcsmb_softc),
  545 };
  546 
  547 DRIVER_MODULE(imcsmb, imcsmb_pci, imcsmb_driver, 0, 0);
  548 MODULE_DEPEND(imcsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  549 MODULE_VERSION(imcsmb, 1);
  550 
  551 DRIVER_MODULE(smbus, imcsmb, smbus_driver, 0, 0);
  552 
  553 /* vi: set ts=8 sw=4 sts=8 noet: */

Cache object: 67f76ad51f4cfde3b1772ffd63fd071f


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