1.\" 2.\" This file and its contents are supplied under the terms of the 3.\" Common Development and Distribution License ("CDDL"), version 1.0. 4.\" You may only use this file in accordance with the terms of version 5.\" 1.0 of the CDDL. 6.\" 7.\" A full copy of the text of the CDDL should have accompanied this 8.\" source. A copy of the CDDL is also available via the Internet at 9.\" http://www.illumos.org/license/CDDL. 10.\" 11.\" 12.\" Copyright 2023 Oxide Computer Company 13.\" 14.Dd September 22, 2023 15.Dt LIBJEDEC_SPD 3JEDEC 16.Os 17.Sh NAME 18.Nm libjedec_spd 19.Nd parse DIMM SPD data 20.Sh LIBRARY 21.Lb libjedec 22.Sh SYNOPSIS 23.In libjedec.h 24.Ft "nvlist_t *" 25.Fo libjedec_spd 26.Fa "const uint8_t *buf" 27.Fa "size_t buflen" 28.Fa "spd_error_t *errp 29.Fc 30.Sh DESCRIPTION 31The 32.Fn libjedec_spd 33function parses a binary payload of SPD 34.Pq serial presence detect 35data and transforms it into a 36.Vt nvlist_t 37that can be used by callers to inspect the data. 38.Pp 39SPD data is defined by JEDEC and used in various DDR DRAM standards. 40This information describes everything from the size and organization of 41the DIMM and its dies, 42timing information, electrical properties, manufacturing data, and more. 43A DRAM module 44.Pq the thing we plug into a computer 45is made up of a number of different components. 46For example, a DDR5 module 47.Pq which is plugged into a slot 48contains not only a number of different DRAM dies, but also power 49controllers, registers, clock drivers, and more. 50The SPD data describes all of this information. 51.Pp 52There are two major properties of SPD information that determine which 53keys are present in it: 54.Bl -enum -width Ds 55.It 56The DDR version that the device implements. 57Examples of the version information include DDR4, LPDDR5, DDR3, and many 58others. 59.It 60The module's type. 61Examples of this include whether it is an RDIMM 62.Pq registered DIMM , 63UDIMM 64.Pq unregistered DIMM , 65soldered down, etc. 66.El 67.Pp 68While each DDR version has different SPD information and the module's 69type may further modify parts of it, the 70.Vt nvlist_t 71that is returned attempts to normalize this information as much as 72possible. 73Each key that is returned is defined in 74.In libjedec.h 75as a macro. 76The key space is dot 77.Pq Sq \&. 78delineated. 79The following key spaces are currently used: 80.Bl -tag -width Ds 81.It Dq meta 82This contains information about the SPD ROM itself, the encoding 83revision, the DRAM standard in use, the type of module, etc. 84This section also contains all of the CRC values and information that 85affects how the rest of data is parsed 86.Pq such as whether or not the package is monolithic . 87.It Dq dram 88This section contains information that is specific to the SDRAM dies 89that are present. 90This includes addressing information such as the number of rows, 91columns, banks, and bank groups that are on each die. 92It also includes information such as the supported voltages of the dies 93themselves and then describes a lot of the different timing properties 94such as the minimum times that a controller must wait between certain 95actions. 96.It Dq ddr4 , Dq ddr5 97This section contains information that is specific to a given DDR 98standard and cannot otherwise share a common definition. 99This section has a few additional subdivisions of information to cover 100items related to the module's type or are otherwise logically grouped 101together such as refresh management. 102For example, the library uses namespaces such as 103.Dq ddr4.rdimm 104and 105.Dq ddr5.lrdimm 106for properties that would be specific to DDR4 RDIMMs and DDR5 LRDIMMs 107respectively. 108.It Dq module 109This section relates to information about the physical module which 110includes information such as its physical dimensions, the types of 111components that are present on it, signal mapping, and related. 112.It Dq mfg 113This section contains information about the module manufacturing. 114This is where things like the module's serial number, the manufacturer, 115the part number, and related can be found. 116Generally this information is found in a different part of the SPD ROM 117and therefore may not always be present. 118.It Dq errors 119This section is an embedded 120.Vt nvlist_t 121that contains keys for each value that couldn't be parsed. 122For more information, see the 123.Sx Parsing Errors 124section for more information. 125.El 126.Ss Data Types 127The library attempts to use a fixed number of data types when performing 128conversions and follows the following guidelines: 129.Bl -bullet 130.It 131By default, integer values use a 132.Vt uint32_t 133to try and make things more uniform where possible and to allow for 134future changes. 135A 136.Vt uint64_t 137is used when the types contain data that could naturally overflow a 138.Vt uint32_t 139such as when counting the number of bits, bytes, or measuring time 140.Pq which is normalized to picoseconds . 141.Pp 142All integers are denoted as such explicitly with their size: either 143.Sq uint32_t 144or 145.Sq uint64_t . 146Some banks of keys all have the same type and are denoted as such in the 147introductory block comment. 148Use 149.Xr nvlist_lookup_uint32 3NVPAIR 150or 151.Xr nvlist_lookup_uint64 3NVPAIR 152to retrieve these keys. 153.It 154Strings, which are stored as traditional 155.Vt char * 156values should only contain printable characters. 157.Pp 158All strings are denoted as such by using the comment 159.Sq string . 160Use 161.Xr nvlist_lookup_string 3NVPAIR 162to retrieve these keys. 163.It 164There are many values which represent enumerations. 165The raw type is stored as a 166.Vt uint32_t . 167In general, these enumerations, unless otherwise indicated should not be 168assumed to have the identical values of a given specification. 169This is done because the values are not always uniform from 170specification to specification, except in rare cases. 171Not all DDR specifications can result in the same set of enumeration 172values. 173.Pp 174For example, consider the 175.Vt spd_temp_type_t 176which is an enumeration that describes the kind of temperature 177monitoring device present. 178The enumeration contains values from DDR3, DDR4, and DDR5; however, each 179standard has its own defined type of SPD temperature sensor. 180.Pp 181All enumerations are denoted as such by using the comment 182.Sq uint32_t Pq enum . 183Use 184.Xr nvlist_lookup_uint32 3NVPAIR 185to retrieve these keys. 186.It 187Several items are used to indicate a fact, but do not have any actual 188data associated with them. 189Their mere presence is sufficient to indicate a unique property of the 190DIMM. 191Examples of this include if the package is non-monolithic, the DIMM has 192asymmetrical ranks, etc. 193.Pp 194All such items are denoted as such by using the comment 195.Sq key . 196Use 197.Xr nvlist_lookup_boolean 3NVPAIR 198to retrieve these keys. 199.It 200A few types use arrays of 201.Vt uint32_t 202values to denote information. 203Some of the keys have a fixed number of entries that are expected, while 204others are variable and will depend on the parsed data. 205For example, a JEDEC ID is always encoded as two 206.Vt uint32_t 207values, the continuation and the underlying ID itself. 208Other values, such as the number of supported voltages or CAS latencies 209will vary. 210.Pp 211All fixed size arrays denote their size by using the comment 212.Sq uint32_t [4] , 213where the number four is replaced with the actual size. 214All variable sized arrays elide the number and are denoted by the 215comment 216.Sq uint32_t [] . 217Use 218.Xr nvlist_lookup_uint32_array 3NVPAIR 219to retrieve these keys. 220.El 221.Ss Parsing Errors 222There are a number of different issues that can arise when trying to 223parse the SPD data that a device returns. 224The library attempts to parse as much as it can and breaks errors into 225two large categories: 226.Bl -enum -width Ds 227.It 228Errors which prevent us from doing anything at all, which are noted in 229the 230.Sx ERRORS 231section. 232The main items that relate to data 233.Pq as opposed to issues like running out of memory 234include when we encounter a DDR specification that we don't support or 235that the data has an encoding version we don't understand. 236This can also occur if there's not enough data for us to figure out what 237kind of SPD information is encoded. 238.It 239Errors that mean we cannot parse a specific piece of SPD data. 240This is by far the most common form of error that we encounter and these 241are the entries that make up the 242.Dq errors 243section of the returned 244.Vt nvlist_t 245that was mentioned earlier. 246.El 247.Pp 248The 249.Dq errors 250section is a nested 251.Vt nvlist_t 252that can be retrieved by using the 253.Dv SPD_KEY_ERRS 254key. 255This keys in this nvlist use the same name as the normal data keys. 256For example, if we were unable to properly parse the manufacturer's 257JEDEC ID, then the key 258.Dv SPD_KEY_MFG_MOD_MFG_ID 259.Pq Dq mfg.module-mfg-id 260would not be present in the top-level 261.Vt nvlist_t 262and would instead be in the error 263.Vt nvlist_t . 264.Pp 265Each item present in the error 266.Vt nvlist_t 267is itself a 268.Vt nvlist_t 269which contains the following keys: 270.Bl -tag -width Ds 271.It Dv SPD_KEY_ERRS_CODE 272The error code, a 273.Vt uint32_t, 274indicates a class of issue that occurred and its values are defined by 275the 276.Vt spd_error_kind_t 277enumeration. 278The following errors are defined: 279.Bl -tag -width Ds 280.It SPD_ERROR_NO_XLATE 281This indicates that the library did not know how to interpret a specific 282binary value. 283For example, if a given particular field was using what we believed to 284be a reserved value then we would set this error. 285.It SPD_ERROR_UNPRINT 286This indicates that we encountered a non-ASCII or otherwise unprintable 287character that was not allowed in the SPD string character set. 288.It SPD_ERROR_NO_DATA 289This indicates that there was no data for a given key. 290For example, this would be a string that consisted solely of space 291characters which are used to represent padding. 292.It SPD_ERROR_INTERNAL 293This indicates that something went wrong inside the library that was 294unexpected. 295.It SPD_ERROR_BAD_DATA 296This indicates that we've encountered something strange about the data 297in question. 298For example, this would be used for an invalid CRC or if the combination 299of values would cause an underflow in a calculation. 300.El 301.It Dv SPD_KEY_ERRS_MSG 302This is an error message that is intended for a person to understand and 303contains more specific information than the code above. 304.El 305.Pp 306Finally, there is one last top-level key that we will set if we find 307that the set of data that we had was incomplete. 308Rather than tag every single item in the 309.Dq errors 310.Vt nvlist_t , 311we instead insert the key 312.Dv SPD_KEY_INCOMPLETE 313on the top-level nvlist. 314The key is a 315.Vt uint32_t 316that contains the starting offset of the 317.Sy key 318that we were unable to parse, which may be less than the total amount of 319data that was provided. 320For example, if we had 100 bytes of data, but there was a 20 byte key 321starting at byte 90, the this key would have a value of 90 as that's 322what we were unable to parse. 323.Sh RETURN VALUES 324Upon successful completion, the 325.Fn libjedec_spd 326function returns an allocated 327.Vt nvlist_t 328that contains the parsed SPD data. 329There may be individual SPD fields that were unparsable which will be 330found in the 331.Dv SPD_KEY_ERRS 332field of the nvlist still. 333Otherwise 334.Dv NULL 335is returned 336and 337.Fa errp 338is set with a value that indicates why the function was unable to parse 339any data. 340.Sh EXAMPLES 341.Sy Example 1 342Printing SPD DRAM and Module Type 343.Pp 344The following example shows how to parse the SPD information and print 345out the type of DRAM and module's type. 346This example assumes that one has already obtained the raw SPD file from 347somewhere and just prints the raw values. 348.Bd -literal -offset 2 349#include <stdio.h> 350#include <stdint.h> 351#include <libjedec.h> 352 353void 354dump_dram_module_type(const uint8_t *buf, size_t len) 355{ 356 nvlist_t *nvl; 357 spd_error_t err; 358 uint32_t ddr, mod; 359 360 nvl = libjedec_spd(buf, len, &err); 361 if (nvl == NULL) { 362 (void) fprintf(stderr, "failed to parse SPD data: 0x%x\en", 363 err); 364 return; 365 } 366 367 if (nvlist_lookup_pairs(nvl, 0, 368 SPD_KEY_DRAM_TYPE, DATA_TYPE_UINT32, &ddr, 369 SPD_KEY_MOD_TYPE, DATA_TYPE_UINT32, &mod, 370 NULL) != 0) { 371 nvlist_free(nvl); 372 (void) fprintf(stderr, "failed to look up keys\en"); 373 return; 374 } 375 376 nvlist_free(nvl); 377 (void) printf("Found DDR type 0x%x, module type 0x%x\en", ddr, 378 mod); 379} 380.Ed 381.Sh ERRORS 382Upon returning from the 383.Fn libjedec_spd 384function, the 385.Fa errp 386pointer will be set to one of the following values: 387.Bl -tag -width Dv 388.It Er LIBJEDEC_SPD_OK 389This indicates that the system was able to parse SPD data into a valid 390.Vt nvlist_t 391and return it to the caller. 392This code should never appear when the function fails and returns 393.Dv NULL . 394Callers must still cehck the contents of the 395.Dv SPD_KEY_ERRS 396nvlist. 397.It Dv LIBJEDEC_SPD_NOMEM 398This indicates that the system ran out of memory while trying to 399construct the 400.Vt nvlist_t 401to return. 402.It Dv LIBJEDEC_SPD_TOOSHORT 403This indicates that not enough SPD data was present as indicated by 404.Fa buf 405and 406.Fa buflen 407for the given type of SPD information and therefore we were unable to 408successfully parse basic information. 409.It Dv LIBJEDEC_SPD_UNSUP_TYPE 410This indicates that the type of SPD data present, e.g. DDR4 SDRAM, 411LPDDR3, etc., that was found is not currently supported by the library. 412.It Dv LIBJEDEC_SPD_UNSUP_REV 413This indicates that while the library is familiar with the specific type 414of SPD data present, the encoding level of the data 415.Pq similar to a major version 416is unsupported by the library. 417.El 418.Sh INTERFACE STABILITY 419.Sy Uncommitted 420.Sh MT-LEVEL 421.Sy MT-Safe 422.Sh SEE ALSO 423.Xr libjedec 3LIB , 424.Xr nvlist_lookup_boolean 3NVPAIR , 425.Xr nvlist_lookup_string 3NVPAIR , 426.Xr nvlist_lookup_uint32 3NVPAIR , 427.Xr nvlist_lookup_uint32_array 3NVPAIR , 428.Xr nvlist_lookup_uint64 3NVPAIR 429.Pp 430.Rs 431.%Q JEDEC Solid State Technology Association 432.%T Serial Presence Detect (SPD), General Standard 433.%N 21-C 434.Re 435.Rs 436.%Q JEDEC Solid State Technology Association 437.%T DDR5 Serial Presence Detect (SPD) Contents 438.%N JESD400-5A.01 439.%D January 2023 440.Re 441