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/jedec_dimm/jedec_dimm.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: Ravi Pokala (rpokala@freebsd.org), Andriy Gapon (avg@FreeBSD.org)
    5  *
    6  * Copyright (c) 2016 Andriy Gapon <avg@FreeBSD.org>
    7  * Copyright (c) 2018 Panasas
    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$
   31  */
   32 
   33 /* 
   34  * This driver is a super-set of the now-deleted jedec_ts(4), and most of the
   35  * code for reading and reporting the temperature is either based on that driver,
   36  * or copied from it verbatim.
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/kernel.h>
   41 #include <sys/bus.h>
   42 #include <sys/endian.h>
   43 #include <sys/malloc.h>
   44 #include <sys/module.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/systm.h>
   47 
   48 #include <dev/jedec_dimm/jedec_dimm.h>
   49 #include <dev/smbus/smbconf.h>
   50 #include <dev/smbus/smbus.h>
   51 
   52 #include "smbus_if.h"
   53 
   54 struct jedec_dimm_softc {
   55         device_t dev;
   56         device_t smbus;
   57         uint8_t spd_addr;       /* SMBus address of the SPD EEPROM. */
   58         uint8_t tsod_addr;      /* Address of the Thermal Sensor On DIMM */
   59         uint32_t capacity_mb;
   60         char type_str[5];
   61         char part_str[21]; /* 18 (DDR3) or 20 (DDR4) chars, plus terminator */
   62         char serial_str[9]; /* 4 bytes = 8 nybble characters, plus terminator */
   63         char *slotid_str; /* Optional DIMM slot identifier (silkscreen) */
   64 };
   65 
   66 /* General Thermal Sensor on DIMM (TSOD) identification notes.
   67  *
   68  * The JEDEC TSE2004av specification defines the device ID that all compliant
   69  * devices should use, but very few do in practice. Maybe that's because the
   70  * earlier TSE2002av specification was rather vague about that.
   71  * Rare examples are IDT TSE2004GB2B0 and Atmel AT30TSE004A, not sure if
   72  * they are TSE2004av compliant by design or by accident.
   73  * Also, the specification mandates that PCI SIG manufacturer IDs are to be
   74  * used, but in practice the JEDEC manufacturer IDs are often used.
   75  */
   76 const struct jedec_dimm_tsod_dev {
   77         uint16_t        vendor_id;
   78         uint8_t         device_id;
   79         const char      *description;
   80 } known_tsod_devices[] = {
   81         /* Analog Devices ADT7408.
   82          * http://www.analog.com/media/en/technical-documentation/data-sheets/ADT7408.pdf
   83          */
   84         { 0x11d4, 0x08, "Analog Devices TSOD" },
   85 
   86         /* Atmel AT30TSE002B, AT30TSE004A.
   87          * http://www.atmel.com/images/doc8711.pdf
   88          * http://www.atmel.com/images/atmel-8868-dts-at30tse004a-datasheet.pdf
   89          * Note how one chip uses the JEDEC Manufacturer ID while the other
   90          * uses the PCI SIG one.
   91          */
   92         { 0x001f, 0x82, "Atmel TSOD" },
   93         { 0x1114, 0x22, "Atmel TSOD" },
   94 
   95         /* Integrated Device Technology (IDT) TS3000B3A, TSE2002B3C,
   96          * TSE2004GB2B0 chips and their variants.
   97          * http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf
   98          * http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf
   99          * https://www.idt.com/document/dst/tse2004gb2b0-datasheet
  100          */
  101         { 0x00b3, 0x29, "IDT TSOD" },
  102         { 0x00b3, 0x22, "IDT TSOD" },
  103 
  104         /* Maxim Integrated MAX6604.
  105          * Different document revisions specify different Device IDs.
  106          * Document 19-3837; Rev 0; 10/05 has 0x3e00 while
  107          * 19-3837; Rev 3; 10/11 has 0x5400.
  108          * http://datasheets.maximintegrated.com/en/ds/MAX6604.pdf
  109          */
  110         { 0x004d, 0x3e, "Maxim Integrated TSOD" },
  111         { 0x004d, 0x54, "Maxim Integrated TSOD" },
  112 
  113         /* Microchip Technology MCP9805, MCP9843, MCP98242, MCP98243
  114          * and their variants.
  115          * http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
  116          * Microchip Technology EMC1501.
  117          * http://ww1.microchip.com/downloads/en/DeviceDoc/00001605A.pdf
  118          */
  119         { 0x0054, 0x00, "Microchip TSOD" },
  120         { 0x0054, 0x20, "Microchip TSOD" },
  121         { 0x0054, 0x21, "Microchip TSOD" },
  122         { 0x1055, 0x08, "Microchip TSOD" },
  123 
  124         /* NXP Semiconductors SE97 and SE98.
  125          * http://www.nxp.com/docs/en/data-sheet/SE97B.pdf
  126          */
  127         { 0x1131, 0xa1, "NXP TSOD" },
  128         { 0x1131, 0xa2, "NXP TSOD" },
  129 
  130         /* ON Semiconductor CAT34TS02 revisions B and C, CAT6095 and compatible.
  131          * https://www.onsemi.com/pub/Collateral/CAT34TS02-D.PDF
  132          * http://www.onsemi.com/pub/Collateral/CAT6095-D.PDF
  133          */
  134         { 0x1b09, 0x08, "ON Semiconductor TSOD" },
  135         { 0x1b09, 0x0a, "ON Semiconductor TSOD" },
  136 
  137         /* ST[Microelectronics] STTS424E02, STTS2002 and others.
  138          * http://www.st.com/resource/en/datasheet/cd00157558.pdf
  139          * http://www.st.com/resource/en/datasheet/stts2002.pdf
  140          */
  141         { 0x104a, 0x00, "ST Microelectronics TSOD" },
  142         { 0x104a, 0x03, "ST Microelectronics TSOD" },
  143 };
  144 
  145 static int jedec_dimm_attach(device_t dev);
  146 
  147 static int jedec_dimm_capacity(struct jedec_dimm_softc *sc, enum dram_type type,
  148     uint32_t *capacity_mb);
  149 
  150 static int jedec_dimm_detach(device_t dev);
  151 
  152 static int jedec_dimm_dump(struct jedec_dimm_softc *sc, enum dram_type type);
  153 
  154 static int jedec_dimm_field_to_str(struct jedec_dimm_softc *sc, char *dst,
  155     size_t dstsz, uint16_t offset, uint16_t len, bool ascii);
  156 
  157 static int jedec_dimm_probe(device_t dev);
  158 
  159 static int jedec_dimm_readw_be(struct jedec_dimm_softc *sc, uint8_t reg,
  160     uint16_t *val);
  161 
  162 static int jedec_dimm_temp_sysctl(SYSCTL_HANDLER_ARGS);
  163 
  164 static const char *jedec_dimm_tsod_match(uint16_t vid, uint16_t did);
  165 
  166 
  167 /**
  168  * device_attach() method. Read the DRAM type, use that to determine the offsets
  169  * and lengths of the asset string fields. Calculate the capacity. If a TSOD is
  170  * present, figure out exactly what it is, and update the device description.
  171  * If all of that was successful, create the sysctls for the DIMM. If an
  172  * optional slotid has been hinted, create a sysctl for that too.
  173  *
  174  * @author rpokala
  175  *
  176  * @param[in,out] dev
  177  *      Device being attached.
  178  */
  179 static int
  180 jedec_dimm_attach(device_t dev)
  181 {
  182         uint8_t byte;
  183         uint16_t devid;
  184         uint16_t partnum_len;
  185         uint16_t partnum_offset;
  186         uint16_t serial_len;
  187         uint16_t serial_offset;
  188         uint16_t tsod_present_offset;
  189         uint16_t vendorid;
  190         bool tsod_present;
  191         int rc;
  192         int new_desc_len;
  193         enum dram_type type;
  194         struct jedec_dimm_softc *sc;
  195         struct sysctl_ctx_list *ctx;
  196         struct sysctl_oid *oid;
  197         struct sysctl_oid_list *children;
  198         const char *tsod_match;
  199         const char *slotid_str;
  200         char *new_desc;
  201 
  202         sc = device_get_softc(dev);
  203         ctx = device_get_sysctl_ctx(dev);
  204         oid = device_get_sysctl_tree(dev);
  205         children = SYSCTL_CHILDREN(oid);
  206 
  207         bzero(sc, sizeof(*sc));
  208         sc->dev = dev;
  209         sc->smbus = device_get_parent(dev);
  210         sc->spd_addr = smbus_get_addr(dev);
  211 
  212         /* The TSOD address has a different DTI from the SPD address, but shares
  213          * the LSA bits.
  214          */
  215         sc->tsod_addr = JEDEC_DTI_TSOD | (sc->spd_addr & 0x0f);
  216 
  217         /* Read the DRAM type, and set the various offsets and lengths. */
  218         rc = smbus_readb(sc->smbus, sc->spd_addr, SPD_OFFSET_DRAM_TYPE, &byte);
  219         if (rc != 0) {
  220                 device_printf(dev, "failed to read dram_type: %d\n", rc);
  221                 goto out;
  222         }
  223         type = (enum dram_type) byte;
  224         switch (type) {
  225         case DRAM_TYPE_DDR3_SDRAM:
  226                 (void) snprintf(sc->type_str, sizeof(sc->type_str), "DDR3");
  227                 partnum_len = SPD_LEN_DDR3_PARTNUM;
  228                 partnum_offset = SPD_OFFSET_DDR3_PARTNUM;
  229                 serial_len = SPD_LEN_DDR3_SERIAL;
  230                 serial_offset = SPD_OFFSET_DDR3_SERIAL;
  231                 tsod_present_offset = SPD_OFFSET_DDR3_TSOD_PRESENT;
  232                 break;
  233         case DRAM_TYPE_DDR4_SDRAM:
  234                 (void) snprintf(sc->type_str, sizeof(sc->type_str), "DDR4");
  235                 partnum_len = SPD_LEN_DDR4_PARTNUM;
  236                 partnum_offset = SPD_OFFSET_DDR4_PARTNUM;
  237                 serial_len = SPD_LEN_DDR4_SERIAL;
  238                 serial_offset = SPD_OFFSET_DDR4_SERIAL;
  239                 tsod_present_offset = SPD_OFFSET_DDR4_TSOD_PRESENT;
  240                 break;
  241         default:
  242                 device_printf(dev, "unsupported dram_type 0x%02x\n", type);
  243                 rc = EINVAL;
  244                 goto out;
  245         }
  246 
  247         if (bootverbose) {
  248                 /* bootverbose debuggery is best-effort, so ignore the rc. */
  249                 (void) jedec_dimm_dump(sc, type);
  250         }
  251 
  252         /* Read all the required info from the SPD. If any of it fails, error
  253          * out without creating the sysctls.
  254          */
  255         rc = jedec_dimm_capacity(sc, type, &sc->capacity_mb);
  256         if (rc != 0) {
  257                 goto out;
  258         }
  259 
  260         rc = jedec_dimm_field_to_str(sc, sc->part_str, sizeof(sc->part_str),
  261             partnum_offset, partnum_len, true);
  262         if (rc != 0) {
  263                 goto out;
  264         }
  265 
  266         rc = jedec_dimm_field_to_str(sc, sc->serial_str, sizeof(sc->serial_str),
  267             serial_offset, serial_len, false);
  268         if (rc != 0) {
  269                 goto out;
  270         }
  271 
  272         /* The MSBit of the TSOD-presence byte reports whether or not the TSOD
  273          * is in fact present. (While DDR3 and DDR4 don't explicitly require a
  274          * TSOD, essentially all DDR3 and DDR4 DIMMs include one.) But, as
  275          * discussed in [PR 235944], it turns out that some DIMMs claim to have
  276          * a TSOD when they actually don't. (Or maybe the firmware blocks it?)
  277          * <sigh>
  278          * If the SPD data says the TSOD is present, try to read manufacturer
  279          * and device info from it to confirm that it's a valid TSOD device.
  280          * If the data is unreadable, just continue as if the TSOD isn't there.
  281          * If the data was read successfully, see if it is a known TSOD device;
  282          * it's okay if it isn't (tsod_match == NULL).
  283          */
  284         rc = smbus_readb(sc->smbus, sc->spd_addr, tsod_present_offset, &byte);
  285         if (rc != 0) {
  286                 device_printf(dev, "failed to read TSOD-present byte: %d\n",
  287                     rc);
  288                 goto out;
  289         }
  290         if (byte & 0x80) {
  291                 tsod_present = true;
  292                 rc = jedec_dimm_readw_be(sc, TSOD_REG_MANUFACTURER, &vendorid);
  293                 if (rc != 0) {
  294                         device_printf(dev,
  295                             "failed to read TSOD Manufacturer ID\n");
  296                         rc = 0;
  297                         goto no_tsod;
  298                 }
  299                 rc = jedec_dimm_readw_be(sc, TSOD_REG_DEV_REV, &devid);
  300                 if (rc != 0) {
  301                         device_printf(dev, "failed to read TSOD Device ID\n");
  302                         rc = 0;
  303                         goto no_tsod;
  304                 }
  305 
  306                 tsod_match = jedec_dimm_tsod_match(vendorid, devid);
  307                 if (bootverbose) {
  308                         if (tsod_match == NULL) {
  309                                 device_printf(dev,
  310                                     "Unknown TSOD Manufacturer and Device IDs,"
  311                                     " 0x%x and 0x%x\n", vendorid, devid);
  312                         } else {
  313                                 device_printf(dev,
  314                                     "TSOD: %s\n", tsod_match);
  315                         }
  316                 }
  317         } else {
  318 no_tsod:
  319                 tsod_match = NULL;
  320                 tsod_present = false;
  321         }
  322 
  323         SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "type",
  324             CTLFLAG_RD | CTLFLAG_MPSAFE, sc->type_str, 0,
  325             "DIMM type");
  326 
  327         SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "capacity",
  328             CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, sc->capacity_mb,
  329             "DIMM capacity (MB)");
  330 
  331         SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "part",
  332             CTLFLAG_RD | CTLFLAG_MPSAFE, sc->part_str, 0,
  333             "DIMM Part Number");
  334 
  335         SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "serial",
  336             CTLFLAG_RD | CTLFLAG_MPSAFE, sc->serial_str, 0,
  337             "DIMM Serial Number");
  338 
  339         /* Create the temperature sysctl IFF the TSOD is present and valid */
  340         if (tsod_present && (tsod_match != NULL)) {
  341                 SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temp",
  342                     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0,
  343                     jedec_dimm_temp_sysctl, "IK", "DIMM temperature (deg C)");
  344         }
  345 
  346         /* If a "slotid" was hinted, add the sysctl for it. */
  347         if (resource_string_value(device_get_name(dev), device_get_unit(dev),
  348             "slotid", &slotid_str) == 0) {
  349                 if (slotid_str != NULL) {
  350                         sc->slotid_str = strdup(slotid_str, M_DEVBUF);
  351                         SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "slotid",
  352                             CTLFLAG_RD | CTLFLAG_MPSAFE, sc->slotid_str, 0,
  353                             "DIMM Slot Identifier");
  354                 }
  355         }
  356 
  357         /* If a TSOD type string or a slotid are present, add them to the
  358          * device description.
  359          */
  360         if ((tsod_match != NULL) || (sc->slotid_str != NULL)) {
  361                 new_desc_len = strlen(device_get_desc(dev));
  362                 if (tsod_match != NULL) {
  363                         new_desc_len += strlen(tsod_match);
  364                         new_desc_len += 4; /* " w/ " */
  365                 }
  366                 if (sc->slotid_str != NULL) {
  367                         new_desc_len += strlen(sc->slotid_str);
  368                         new_desc_len += 3; /* space + parens */
  369                 }
  370                 new_desc_len++; /* terminator */
  371                 new_desc = malloc(new_desc_len, M_TEMP, (M_WAITOK | M_ZERO));
  372                 (void) snprintf(new_desc, new_desc_len, "%s%s%s%s%s%s",
  373                     device_get_desc(dev),
  374                     (tsod_match ? " w/ " : ""),
  375                     (tsod_match ? tsod_match : ""),
  376                     (sc->slotid_str ? " (" : ""),
  377                     (sc->slotid_str ? sc->slotid_str : ""),
  378                     (sc->slotid_str ? ")" : ""));
  379                 device_set_desc_copy(dev, new_desc);
  380                 free(new_desc, M_TEMP);
  381         }
  382 
  383 out:
  384         return (rc);
  385 }
  386 
  387 /**
  388  * Calculate the capacity of a DIMM. Both DDR3 and DDR4 encode "geometry"
  389  * information in various SPD bytes. The standards documents codify everything
  390  * in look-up tables, but it's trivial to reverse-engineer the the formulas for
  391  * most of them. Unless otherwise noted, the same formulas apply for both DDR3
  392  * and DDR4. The SPD offsets of where the data comes from are different between
  393  * the two types, because having them be the same would be too easy.
  394  *
  395  * @author rpokala
  396  *
  397  * @param[in] sc
  398  *      Instance-specific context data
  399  *
  400  * @param[in] dram_type
  401  *      The locations of the data used to calculate the capacity depends on the
  402  *      type of the DIMM.
  403  *
  404  * @param[out] capacity_mb
  405  *      The calculated capacity, in MB
  406  */
  407 static int
  408 jedec_dimm_capacity(struct jedec_dimm_softc *sc, enum dram_type type,
  409     uint32_t *capacity_mb)
  410 {
  411         uint8_t bus_width_byte;
  412         uint8_t bus_width_offset;
  413         uint8_t dimm_ranks_byte;
  414         uint8_t dimm_ranks_offset;
  415         uint8_t sdram_capacity_byte;
  416         uint8_t sdram_capacity_offset;
  417         uint8_t sdram_pkg_type_byte;
  418         uint8_t sdram_pkg_type_offset;
  419         uint8_t sdram_width_byte;
  420         uint8_t sdram_width_offset;
  421         uint32_t bus_width;
  422         uint32_t dimm_ranks;
  423         uint32_t sdram_capacity;
  424         uint32_t sdram_pkg_type;
  425         uint32_t sdram_width;
  426         int rc;
  427 
  428         switch (type) {
  429         case DRAM_TYPE_DDR3_SDRAM:
  430                 bus_width_offset = SPD_OFFSET_DDR3_BUS_WIDTH;
  431                 dimm_ranks_offset = SPD_OFFSET_DDR3_DIMM_RANKS;
  432                 sdram_capacity_offset = SPD_OFFSET_DDR3_SDRAM_CAPACITY;
  433                 sdram_width_offset = SPD_OFFSET_DDR3_SDRAM_WIDTH;
  434                 break;
  435         case DRAM_TYPE_DDR4_SDRAM:
  436                 bus_width_offset = SPD_OFFSET_DDR4_BUS_WIDTH;
  437                 dimm_ranks_offset = SPD_OFFSET_DDR4_DIMM_RANKS;
  438                 sdram_capacity_offset = SPD_OFFSET_DDR4_SDRAM_CAPACITY;
  439                 sdram_pkg_type_offset = SPD_OFFSET_DDR4_SDRAM_PKG_TYPE;
  440                 sdram_width_offset = SPD_OFFSET_DDR4_SDRAM_WIDTH;
  441                 break;
  442         default:
  443                 device_printf(sc->dev, "unsupported dram_type 0x%02x\n", type);
  444                 rc = EINVAL;
  445                 goto out;
  446         }
  447 
  448         rc = smbus_readb(sc->smbus, sc->spd_addr, bus_width_offset,
  449             &bus_width_byte);
  450         if (rc != 0) {
  451                 device_printf(sc->dev, "failed to read bus_width: %d\n", rc);
  452                 goto out;
  453         }
  454 
  455         rc = smbus_readb(sc->smbus, sc->spd_addr, dimm_ranks_offset,
  456             &dimm_ranks_byte);
  457         if (rc != 0) {
  458                 device_printf(sc->dev, "failed to read dimm_ranks: %d\n", rc);
  459                 goto out;
  460         }
  461 
  462         rc = smbus_readb(sc->smbus, sc->spd_addr, sdram_capacity_offset,
  463             &sdram_capacity_byte);
  464         if (rc != 0) {
  465                 device_printf(sc->dev, "failed to read sdram_capacity: %d\n",
  466                     rc);
  467                 goto out;
  468         }
  469 
  470         rc = smbus_readb(sc->smbus, sc->spd_addr, sdram_width_offset,
  471             &sdram_width_byte);
  472         if (rc != 0) {
  473                 device_printf(sc->dev, "failed to read sdram_width: %d\n", rc);
  474                 goto out;
  475         }
  476 
  477         /* The "SDRAM Package Type" is only needed for DDR4 DIMMs. */
  478         if (type == DRAM_TYPE_DDR4_SDRAM) {
  479                 rc = smbus_readb(sc->smbus, sc->spd_addr, sdram_pkg_type_offset,
  480                     &sdram_pkg_type_byte);
  481                 if (rc != 0) {
  482                         device_printf(sc->dev,
  483                             "failed to read sdram_pkg_type: %d\n", rc);
  484                         goto out;
  485                 }
  486         }
  487 
  488         /* "Primary bus width, in bits" is in bits [2:0]. */
  489         bus_width_byte &= 0x07;
  490         if (bus_width_byte <= 3) {
  491                 bus_width = 1 << bus_width_byte;
  492                 bus_width *= 8;
  493         } else {
  494                 device_printf(sc->dev, "invalid bus width info\n");
  495                 rc = EINVAL;
  496                 goto out;
  497         }
  498 
  499         /* "Number of ranks per DIMM" is in bits [5:3]. Values 4-7 are only
  500          * valid for DDR4.
  501          */
  502         dimm_ranks_byte >>= 3;
  503         dimm_ranks_byte &= 0x07;
  504         if (dimm_ranks_byte <= 7) {
  505                 dimm_ranks = dimm_ranks_byte + 1;
  506         } else {
  507                 device_printf(sc->dev, "invalid DIMM Rank info\n");
  508                 rc = EINVAL;
  509                 goto out;
  510         }
  511         if ((dimm_ranks_byte >= 4) && (type != DRAM_TYPE_DDR4_SDRAM)) {
  512                 device_printf(sc->dev, "invalid DIMM Rank info\n");
  513                 rc = EINVAL;
  514                 goto out;
  515         }
  516 
  517         /* "Total SDRAM capacity per die, in Mb" is in bits [3:0]. There are two
  518          * different formulas, for values 0-7 and for values 8-9. Also, values
  519          * 7-9 are only valid for DDR4.
  520          */
  521         sdram_capacity_byte &= 0x0f;
  522         if (sdram_capacity_byte <= 7) {
  523                 sdram_capacity = 1 << sdram_capacity_byte;
  524                 sdram_capacity *= 256;
  525         } else if (sdram_capacity_byte <= 9) {
  526                 sdram_capacity = 12 << (sdram_capacity_byte - 8);
  527                 sdram_capacity *= 1024;
  528         } else {
  529                 device_printf(sc->dev, "invalid SDRAM capacity info\n");
  530                 rc = EINVAL;
  531                 goto out;
  532         }
  533         if ((sdram_capacity_byte >= 7) && (type != DRAM_TYPE_DDR4_SDRAM)) {
  534                 device_printf(sc->dev, "invalid SDRAM capacity info\n");
  535                 rc = EINVAL;
  536                 goto out;
  537         }
  538 
  539         /* "SDRAM device width" is in bits [2:0]. */
  540         sdram_width_byte &= 0x7;
  541         if (sdram_width_byte <= 3) {
  542                 sdram_width = 1 << sdram_width_byte;
  543                 sdram_width *= 4;
  544         } else {
  545                 device_printf(sc->dev, "invalid SDRAM width info\n");
  546                 rc = EINVAL;
  547                 goto out;
  548         }
  549 
  550         /* DDR4 has something called "3DS", which is indicated by [1:0] = 2;
  551          * when that is the case, the die count is encoded in [6:4], and
  552          * dimm_ranks is multiplied by it.
  553          */
  554         if ((type == DRAM_TYPE_DDR4_SDRAM) &&
  555             ((sdram_pkg_type_byte & 0x3) == 2)) {
  556                 sdram_pkg_type_byte >>= 4;
  557                 sdram_pkg_type_byte &= 0x07;
  558                 sdram_pkg_type = sdram_pkg_type_byte + 1;
  559                 dimm_ranks *= sdram_pkg_type;
  560         }
  561 
  562         /* Finally, assemble the actual capacity. The formula is the same for
  563          * both DDR3 and DDR4.
  564          */
  565         *capacity_mb = sdram_capacity / 8 * bus_width / sdram_width *
  566             dimm_ranks;
  567 
  568 out:
  569         return (rc);
  570 }
  571 
  572 /**
  573  * device_detach() method. If we allocated sc->slotid_str, free it. Even if we
  574  *      didn't allocate, free it anyway; free(NULL) is safe.
  575  *
  576  * @author rpokala
  577  *
  578  * @param[in,out] dev
  579  *      Device being detached.
  580  */
  581 static int
  582 jedec_dimm_detach(device_t dev)
  583 {
  584         struct jedec_dimm_softc *sc;
  585 
  586         sc = device_get_softc(dev);
  587         free(sc->slotid_str, M_DEVBUF);
  588 
  589         return (0);
  590 }
  591 
  592 /**
  593  * Read and dump the entire SPD contents.
  594  *
  595  * @author rpokala
  596  *
  597  * @param[in] sc
  598  *      Instance-specific context data
  599  *
  600  * @param[in] dram_type
  601  *      The length of data which needs to be read and dumped differs based on
  602  *      the type of the DIMM.
  603  */
  604 static int
  605 jedec_dimm_dump(struct jedec_dimm_softc *sc, enum dram_type type)
  606 {
  607         int i;
  608         int rc;
  609         bool page_changed;
  610         uint8_t bytes[512];
  611 
  612         page_changed = false;
  613 
  614         for (i = 0; i < 256; i++) {
  615                 rc = smbus_readb(sc->smbus, sc->spd_addr, i, &bytes[i]);
  616                 if (rc != 0) {
  617                         device_printf(sc->dev,
  618                             "unable to read page0:0x%02x: %d\n", i, rc);
  619                         goto out;
  620                 }
  621         }
  622 
  623         /* The DDR4 SPD is 512 bytes, but SMBus only allows for 8-bit offsets.
  624          * JEDEC gets around this by defining the "PAGE" DTI and LSAs.
  625          */
  626         if (type == DRAM_TYPE_DDR4_SDRAM) {
  627                 page_changed = true;
  628                 rc = smbus_writeb(sc->smbus,
  629                     (JEDEC_DTI_PAGE | JEDEC_LSA_PAGE_SET1), 0, 0);
  630                 if (rc != 0) {
  631                         /* Some SPD devices (or SMBus controllers?) claim the
  632                          * page-change command failed when it actually
  633                          * succeeded. Log a message but soldier on.
  634                          */
  635                         device_printf(sc->dev, "unable to change page: %d\n",
  636                             rc);
  637                 }
  638                 /* Add 256 to the store location, because we're in the second
  639                  * page.
  640                  */
  641                 for (i = 0; i < 256; i++) {
  642                         rc = smbus_readb(sc->smbus, sc->spd_addr, i,
  643                             &bytes[256 + i]);
  644                         if (rc != 0) {
  645                                 device_printf(sc->dev,
  646                                     "unable to read page1:0x%02x: %d\n", i, rc);
  647                                 goto out;
  648                         }
  649                 }
  650         }
  651 
  652         /* Display the data in a nice hexdump format, with byte offsets. */
  653         hexdump(bytes, (page_changed ? 512 : 256), NULL, 0);
  654 
  655 out:
  656         if (page_changed) {
  657                 int rc2;
  658                 /* Switch back to page0 before returning. */
  659                 rc2 = smbus_writeb(sc->smbus,
  660                     (JEDEC_DTI_PAGE | JEDEC_LSA_PAGE_SET0), 0, 0);
  661                 if (rc2 != 0) {
  662                         device_printf(sc->dev, "unable to restore page: %d\n",
  663                             rc2);
  664                 }
  665         }
  666         return (rc);
  667 }
  668 
  669 /**
  670  * Read a specified range of bytes from the SPD, convert them to a string, and
  671  * store them in the provided buffer. Some SPD fields are space-padded ASCII,
  672  * and some are just a string of bits that we want to convert to a hex string.
  673  *
  674  * @author rpokala
  675  *
  676  * @param[in] sc
  677  *      Instance-specific context data
  678  *
  679  * @param[out] dst
  680  *      The output buffer to populate
  681  *
  682  * @param[in] dstsz
  683  *      The size of the output buffer
  684  *
  685  * @param[in] offset
  686  *      The starting offset of the field within the SPD
  687  *
  688  * @param[in] len
  689  *      The length in bytes of the field within the SPD
  690  *
  691  * @param[in] ascii
  692  *      Is the field a sequence of ASCII characters? If not, it is binary data
  693  *      which should be converted to characters.
  694  */
  695 static int
  696 jedec_dimm_field_to_str(struct jedec_dimm_softc *sc, char *dst, size_t dstsz,
  697     uint16_t offset, uint16_t len, bool ascii)
  698 {
  699         uint8_t byte;
  700         int i;
  701         int rc;
  702         bool page_changed;
  703 
  704         /* Change to the proper page. Offsets [0, 255] are in page0; offsets
  705          * [256, 512] are in page1.
  706          *
  707          * *The page must be reset to page0 before returning.*
  708          *
  709          * For the page-change operation, only the DTI and LSA matter; the
  710          * offset and write-value are ignored, so use just 0.
  711          *
  712          * Mercifully, JEDEC defined the fields such that none of them cross
  713          * pages, so we don't need to worry about that complication.
  714          */
  715         if (offset < JEDEC_SPD_PAGE_SIZE) {
  716                 page_changed = false;
  717         } else if (offset < (2 * JEDEC_SPD_PAGE_SIZE)) {
  718                 page_changed = true;
  719                 rc = smbus_writeb(sc->smbus,
  720                     (JEDEC_DTI_PAGE | JEDEC_LSA_PAGE_SET1), 0, 0);
  721                 if (rc != 0) {
  722                         device_printf(sc->dev,
  723                             "unable to change page for offset 0x%04x: %d\n",
  724                             offset, rc);
  725                 }
  726                 /* Adjust the offset to account for the page change. */
  727                 offset -= JEDEC_SPD_PAGE_SIZE;
  728         } else {
  729                 page_changed = false;
  730                 rc = EINVAL;
  731                 device_printf(sc->dev, "invalid offset 0x%04x\n", offset);
  732                 goto out;
  733         }
  734 
  735         /* Sanity-check (adjusted) offset and length; everything must be within
  736          * the same page.
  737          */
  738         if (offset >= JEDEC_SPD_PAGE_SIZE) {
  739                 rc = EINVAL;
  740                 device_printf(sc->dev, "invalid offset 0x%04x\n", offset);
  741                 goto out;
  742         }
  743         if ((offset + len) >= JEDEC_SPD_PAGE_SIZE) {
  744                 rc = EINVAL;
  745                 device_printf(sc->dev,
  746                     "(offset + len) would cross page (0x%04x + 0x%04x)\n",
  747                     offset, len);
  748                 goto out;
  749         }
  750 
  751         /* Sanity-check the destination string length. If we're dealing with
  752          * ASCII chars, then the destination must be at least the same length;
  753          * otherwise, it must be *twice* the length, because each byte must
  754          * be converted into two nybble characters.
  755          *
  756          * And, of course, there needs to be an extra byte for the terminator.
  757          */
  758         if (ascii) {
  759                 if (dstsz < (len + 1)) {
  760                         rc = EINVAL;
  761                         device_printf(sc->dev,
  762                             "destination too short (%u < %u)\n",
  763                             (uint16_t) dstsz, (len + 1));
  764                         goto out;
  765                 }
  766         } else {
  767                 if (dstsz < ((2 * len) + 1)) {
  768                         rc = EINVAL;
  769                         device_printf(sc->dev,
  770                             "destination too short (%u < %u)\n",
  771                             (uint16_t) dstsz, ((2 * len) + 1));
  772                         goto out;
  773                 }
  774         }
  775 
  776         /* Read a byte at a time. */
  777         for (i = 0; i < len; i++) {
  778                 rc = smbus_readb(sc->smbus, sc->spd_addr, (offset + i), &byte);
  779                 if (rc != 0) {
  780                         device_printf(sc->dev,
  781                             "failed to read byte at 0x%02x: %d\n",
  782                             (offset + i), rc);
  783                         goto out;
  784                 }
  785                 if (ascii) {
  786                         /* chars can be copied directly. */
  787                         dst[i] = byte;
  788                 } else {
  789                         /* Raw bytes need to be converted to a two-byte hex
  790                          * string, plus the terminator.
  791                          */
  792                         (void) snprintf(&dst[(2 * i)], 3, "%02x", byte);
  793                 }
  794         }
  795 
  796         /* If we're dealing with ASCII, convert trailing spaces to NULs. */
  797         if (ascii) {
  798                 for (i = dstsz - 1; i > 0; i--) {
  799                         if (dst[i] == ' ') {
  800                                 dst[i] = 0;
  801                         } else if (dst[i] == 0) {
  802                                 continue;
  803                         } else {
  804                                 break;
  805                         }
  806                 }
  807         }
  808 
  809 out:
  810         if (page_changed) {
  811                 int rc2;
  812                 /* Switch back to page0 before returning. */
  813                 rc2 = smbus_writeb(sc->smbus,
  814                     (JEDEC_DTI_PAGE | JEDEC_LSA_PAGE_SET0), 0, 0);
  815                 if (rc2 != 0) {
  816                         device_printf(sc->dev,
  817                             "unable to restore page for offset 0x%04x: %d\n",
  818                             offset, rc2);
  819                 }
  820         }
  821 
  822         return (rc);
  823 }
  824 
  825 /**
  826  * device_probe() method. Validate the address that was given as a hint, and
  827  * display an error if it's bogus. Make sure that we're dealing with one of the
  828  * SPD versions that we can handle.
  829  *
  830  * @author rpokala
  831  *
  832  * @param[in] dev
  833  *      Device being probed.
  834  */
  835 static int
  836 jedec_dimm_probe(device_t dev)
  837 {
  838         uint8_t addr;
  839         uint8_t byte;
  840         int rc;
  841         enum dram_type type;
  842         device_t smbus;
  843 
  844         smbus = device_get_parent(dev);
  845         addr = smbus_get_addr(dev);
  846 
  847         /* Don't bother if this isn't an SPD address, or if the LSBit is set. */
  848         if (((addr & 0xf0) != JEDEC_DTI_SPD) ||
  849             ((addr & 0x01) != 0)) {
  850                 device_printf(dev,
  851                     "invalid \"addr\" hint; address must start with \"0x%x\","
  852                     " and the least-significant bit must be 0\n",
  853                     JEDEC_DTI_SPD);
  854                 rc = ENXIO;
  855                 goto out;
  856         }
  857 
  858         /* Try to read the DRAM_TYPE from the SPD. */
  859         rc = smbus_readb(smbus, addr, SPD_OFFSET_DRAM_TYPE, &byte);
  860         if (rc != 0) {
  861                 device_printf(dev, "failed to read dram_type\n");
  862                 goto out;
  863         }
  864 
  865         /* This driver currently only supports DDR3 and DDR4 SPDs. */
  866         type = (enum dram_type) byte;
  867         switch (type) {
  868         case DRAM_TYPE_DDR3_SDRAM:
  869                 rc = BUS_PROBE_DEFAULT;
  870                 device_set_desc(dev, "DDR3 DIMM");
  871                 break;
  872         case DRAM_TYPE_DDR4_SDRAM:
  873                 rc = BUS_PROBE_DEFAULT;
  874                 device_set_desc(dev, "DDR4 DIMM");
  875                 break;
  876         default:
  877                 rc = ENXIO;
  878                 break;
  879         }
  880 
  881 out:
  882         return (rc);
  883 }
  884 
  885 /**
  886  * SMBus specifies little-endian byte order, but it looks like the TSODs use
  887  * big-endian. Read and convert.
  888  *
  889  * @author avg
  890  *
  891  * @param[in] sc
  892  *      Instance-specific context data
  893  *
  894  * @param[in] reg
  895  *      The register number to read.
  896  *
  897  * @param[out] val
  898  *      Pointer to populate with the value read.
  899  */
  900 static int
  901 jedec_dimm_readw_be(struct jedec_dimm_softc *sc, uint8_t reg, uint16_t *val)
  902 {
  903         int rc;
  904 
  905         rc = smbus_readw(sc->smbus, sc->tsod_addr, reg, val);
  906         if (rc != 0) {
  907                 goto out;
  908         }
  909         *val = be16toh(*val);
  910 
  911 out:
  912         return (rc);
  913 }
  914 
  915 /**
  916  * Read the temperature data from the TSOD and convert it to the deciKelvin
  917  * value that the sysctl expects.
  918  *
  919  * @author avg
  920  */
  921 static int
  922 jedec_dimm_temp_sysctl(SYSCTL_HANDLER_ARGS)
  923 {
  924         uint16_t val;
  925         int rc;
  926         int temp;
  927         device_t dev = arg1;
  928         struct jedec_dimm_softc *sc;
  929 
  930         sc = device_get_softc(dev);
  931 
  932         rc = jedec_dimm_readw_be(sc, TSOD_REG_TEMPERATURE, &val);
  933         if (rc != 0) {
  934                 goto out;
  935         }
  936 
  937         /* The three MSBits are flags, and the next bit is a sign bit. */
  938         temp = val & 0xfff;
  939         if ((val & 0x1000) != 0)
  940                 temp = -temp;
  941         /* Each step is 0.0625 degrees, so convert to 1000ths of a degree C. */
  942         temp *= 625;
  943         /* ... and then convert to 1000ths of a Kelvin */
  944         temp += 2731500;
  945         /* As a practical matter, few (if any) TSODs are more accurate than
  946          * about a tenth of a degree, so round accordingly. This correlates with
  947          * the "IK" formatting used for this sysctl.
  948          */
  949         temp = (temp + 500) / 1000;
  950 
  951         rc = sysctl_handle_int(oidp, &temp, 0, req);
  952 
  953 out:
  954         return (rc);
  955 }
  956 
  957 /**
  958  * Check the TSOD's Vendor ID and Device ID against the list of known TSOD
  959  * devices. Return the description, or NULL if this doesn't look like a valid
  960  * TSOD.
  961  *
  962  * @author avg
  963  *
  964  * @param[in] vid
  965  *      The Vendor ID of the TSOD device
  966  *
  967  * @param[in] did
  968  *      The Device ID of the TSOD device
  969  *
  970  * @return
  971  *      The description string, or NULL for a failure to match.
  972  */
  973 static const char *
  974 jedec_dimm_tsod_match(uint16_t vid, uint16_t did)
  975 {
  976         const struct jedec_dimm_tsod_dev *d;
  977         int i;
  978 
  979         for (i = 0; i < nitems(known_tsod_devices); i++) {
  980                 d = &known_tsod_devices[i];
  981                 if ((vid == d->vendor_id) && ((did >> 8) == d->device_id)) {
  982                         return (d->description);
  983                 }
  984         }
  985 
  986         /* If no matches for a specific device, then check for a generic
  987          * TSE2004av-compliant device.
  988          */
  989         if ((did >> 8) == 0x22) {
  990                 return ("TSE2004av compliant TSOD");
  991         }
  992 
  993         return (NULL);
  994 }
  995 
  996 static device_method_t jedec_dimm_methods[] = {
  997         /* Methods from the device interface */
  998         DEVMETHOD(device_probe,         jedec_dimm_probe),
  999         DEVMETHOD(device_attach,        jedec_dimm_attach),
 1000         DEVMETHOD(device_detach,        jedec_dimm_detach),
 1001         DEVMETHOD_END
 1002 };
 1003 
 1004 static driver_t jedec_dimm_driver = {
 1005         .name = "jedec_dimm",
 1006         .methods = jedec_dimm_methods,
 1007         .size = sizeof(struct jedec_dimm_softc),
 1008 };
 1009 
 1010 DRIVER_MODULE(jedec_dimm, smbus, jedec_dimm_driver, 0, 0);
 1011 MODULE_DEPEND(jedec_dimm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
 1012 MODULE_VERSION(jedec_dimm, 1);
 1013 
 1014 /* vi: set ts=8 sw=4 sts=8 noet: */

Cache object: 7677062779366a0a97885cfc4f2e3c68


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