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

Cache object: 1edad6b93c998348fd71da79ad4f483e


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