xref: /illumos-gate/usr/src/man/man3jedec/libjedec_spd.3jedec (revision bc0ee17c150fbf29e52c0ff365163e4e7b1c2f0a)
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 2024 Oxide Computer Company
13.\"
14.Dd September 2, 2024
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.Pp
109Similarly, there are subdivisions based on the device in question.
110For example,
111.Dq ddr3.mb
112and
113.Dq ddr4.rcd
114refer to properties of the DDR3 memory buffer and the DDR4 registering
115clock driver respectively.
116.It Dq lp
117This section describes information that is specific to low power
118devices that come from the LPDDR standards.
119.It Dq channel
120This section describes properties that are specific to the
121implementation of a channel.
122DDR3 and DDR4 DIMMs have a single channel.
123DDR5 DIMMs have a single channel that is broken into two sub-channels.
124A channel represents a specific data stream to the host.
125Most DDR channels are 64-bit channels with optional ECC.
126LPDDR devices have rather different channel widths and their soldered
127down form factor may have more than one channel present
128.Pq regardless of sub-channels .
129.It Dq module
130This section relates to information about the physical module which
131includes information such as its physical dimensions, the types of
132components that are present on it, signal mapping, and related.
133.It Dq mfg
134This section contains information about the module manufacturing.
135This is where things like the module's serial number, the manufacturer,
136the part number, and related can be found.
137Generally this information is found in a different part of the SPD ROM
138and therefore may not always be present.
139.It Dq errors
140This section is an embedded
141.Vt nvlist_t
142that contains keys for each value that couldn't be parsed.
143For more information, see the
144.Sx Parsing Errors
145section for more information.
146.El
147.Ss Data Types
148The library attempts to use a fixed number of data types when performing
149conversions and follows the following guidelines:
150.Bl -bullet
151.It
152By default, integer values use a
153.Vt uint32_t
154to try and make things more uniform where possible and to allow for
155future changes.
156A
157.Vt uint64_t
158is used when the types contain data that could naturally overflow a
159.Vt uint32_t
160such as when counting the number of bits, bytes, or measuring time
161.Pq which is normalized to picoseconds .
162.Pp
163All integers are denoted as such explicitly with their size: either
164.Sq uint32_t
165or
166.Sq uint64_t .
167Some banks of keys all have the same type and are denoted as such in the
168introductory block comment.
169Use
170.Xr nvlist_lookup_uint32 3NVPAIR
171or
172.Xr nvlist_lookup_uint64 3NVPAIR
173to retrieve these keys.
174.It
175Strings, which are stored as traditional
176.Vt char *
177values should only contain printable characters.
178.Pp
179All strings are denoted as such by using the comment
180.Sq string .
181Use
182.Xr nvlist_lookup_string 3NVPAIR
183to retrieve these keys.
184.It
185There are many values which represent enumerations.
186The raw type is stored as a
187.Vt uint32_t .
188In general, these enumerations, unless otherwise indicated should not be
189assumed to have the identical values of a given specification.
190This is done because the values are not always uniform from
191specification to specification, except in rare cases.
192Not all DDR specifications can result in the same set of enumeration
193values.
194.Pp
195For example, consider the
196.Vt spd_temp_type_t
197which is an enumeration that describes the kind of temperature
198monitoring device present.
199The enumeration contains values from DDR3, DDR4, and DDR5; however, each
200standard has its own defined type of SPD temperature sensor.
201.Pp
202All enumerations are denoted as such by using the comment
203.Sq uint32_t Pq enum .
204Use
205.Xr nvlist_lookup_uint32 3NVPAIR
206to retrieve these keys.
207.It
208Several items are used to indicate a fact, but do not have any actual
209data associated with them.
210Their mere presence is sufficient to indicate a unique property of the
211DIMM.
212Examples of this include if the package is non-monolithic, the DIMM has
213asymmetrical ranks, etc.
214.Pp
215All such items are denoted as such by using the comment
216.Sq key .
217Use
218.Xr nvlist_lookup_boolean 3NVPAIR
219to retrieve these keys.
220.It
221A few types use arrays of
222.Vt uint32_t
223values to denote information.
224Some of the keys have a fixed number of entries that are expected, while
225others are variable and will depend on the parsed data.
226For example, a JEDEC ID is always encoded as two
227.Vt uint32_t
228values, the continuation and the underlying ID itself.
229Other values, such as the number of supported voltages or CAS latencies
230will vary.
231.Pp
232All fixed size arrays denote their size by using the comment
233.Sq uint32_t [4] ,
234where the number four is replaced with the actual size.
235All variable sized arrays elide the number and are denoted by the
236comment
237.Sq uint32_t [] .
238Use
239.Xr nvlist_lookup_uint32_array 3NVPAIR
240to retrieve these keys.
241.Pp
242A few keys will use different sized integer arrays.
243For example, arrays that relate to timing parameters use arrays of
244.Vt uint64_t
245to match the broader pattern of using the
246.Vt uint64_t
247for timing.
248.El
249.Ss Parsing Errors
250There are a number of different issues that can arise when trying to
251parse the SPD data that a device returns.
252The library attempts to parse as much as it can and breaks errors into
253two large categories:
254.Bl -enum -width Ds
255.It
256Errors which prevent us from doing anything at all, which are noted in
257the
258.Sx ERRORS
259section.
260The main items that relate to data
261.Pq as opposed to issues like running out of memory
262include when we encounter a DDR specification that we don't support or
263that the data has an encoding version we don't understand.
264This can also occur if there's not enough data for us to figure out what
265kind of SPD information is encoded.
266.It
267Errors that mean we cannot parse a specific piece of SPD data.
268This is by far the most common form of error that we encounter and these
269are the entries that make up the
270.Dq errors
271section of the returned
272.Vt nvlist_t
273that was mentioned earlier.
274.El
275.Pp
276The
277.Dq errors
278section is a nested
279.Vt nvlist_t
280that can be retrieved by using the
281.Dv SPD_KEY_ERRS
282key.
283This keys in this nvlist use the same name as the normal data keys.
284For example, if we were unable to properly parse the manufacturer's
285JEDEC ID, then the key
286.Dv SPD_KEY_MFG_MOD_MFG_ID
287.Pq Dq mfg.module-mfg-id
288would not be present in the top-level
289.Vt nvlist_t
290and would instead be in the error
291.Vt nvlist_t .
292.Pp
293Each item present in the error
294.Vt nvlist_t
295is itself a
296.Vt nvlist_t
297which contains the following keys:
298.Bl -tag -width Ds
299.It Dv SPD_KEY_ERRS_CODE
300The error code, a
301.Vt uint32_t,
302indicates a class of issue that occurred and its values are defined by
303the
304.Vt spd_error_kind_t
305enumeration.
306The following errors are defined:
307.Bl -tag -width Ds
308.It SPD_ERROR_NO_XLATE
309This indicates that the library did not know how to interpret a specific
310binary value.
311For example, if a given particular field was using what we believed to
312be a reserved value then we would set this error.
313.It SPD_ERROR_UNPRINT
314This indicates that we encountered a non-ASCII or otherwise unprintable
315character that was not allowed in the SPD string character set.
316.It SPD_ERROR_NO_DATA
317This indicates that there was no data for a given key.
318For example, this would be a string that consisted solely of space
319characters which are used to represent padding.
320.It SPD_ERROR_INTERNAL
321This indicates that something went wrong inside the library that was
322unexpected.
323.It SPD_ERROR_BAD_DATA
324This indicates that we've encountered something strange about the data
325in question.
326For example, this would be used for an invalid CRC or if the combination
327of values would cause an underflow in a calculation.
328.El
329.It Dv SPD_KEY_ERRS_MSG
330This is an error message that is intended for a person to understand and
331contains more specific information than the code above.
332.El
333.Pp
334Finally, there is one last top-level key that we will set if we find
335that the set of data that we had was incomplete.
336Rather than tag every single item in the
337.Dq errors
338.Vt nvlist_t ,
339we instead insert the key
340.Dv SPD_KEY_INCOMPLETE
341on the top-level nvlist.
342The key is a
343.Vt uint32_t
344that contains the starting offset of the
345.Sy key
346that we were unable to parse, which may be less than the total amount of
347data that was provided.
348For example, if we had 100 bytes of data, but there was a 20 byte key
349starting at byte 90, the this key would have a value of 90 as that's
350what we were unable to parse.
351.Sh RETURN VALUES
352Upon successful completion, the
353.Fn libjedec_spd
354function returns an allocated
355.Vt nvlist_t
356that contains the parsed SPD data.
357There may be individual SPD fields that were unparsable which will be
358found in the
359.Dv SPD_KEY_ERRS
360field of the nvlist still.
361Otherwise
362.Dv NULL
363is returned
364and
365.Fa errp
366is set with a value that indicates why the function was unable to parse
367any data.
368.Sh EXAMPLES
369.Sy Example 1
370Printing SPD DRAM and Module Type
371.Pp
372The following example shows how to parse the SPD information and print
373out the type of DRAM and module's type.
374This example assumes that one has already obtained the raw SPD file from
375somewhere and just prints the raw values.
376.Bd -literal -offset 2
377#include <stdio.h>
378#include <stdint.h>
379#include <libjedec.h>
380
381void
382dump_dram_module_type(const uint8_t *buf, size_t len)
383{
384	nvlist_t *nvl;
385	spd_error_t err;
386	uint32_t ddr, mod;
387
388	nvl = libjedec_spd(buf, len, &err);
389	if (nvl == NULL) {
390		(void) fprintf(stderr, "failed to parse SPD data: 0x%x\en",
391		    err);
392		return;
393	}
394
395	if (nvlist_lookup_pairs(nvl, 0,
396	    SPD_KEY_DRAM_TYPE, DATA_TYPE_UINT32, &ddr,
397	    SPD_KEY_MOD_TYPE, DATA_TYPE_UINT32, &mod,
398	    NULL) != 0) {
399		nvlist_free(nvl);
400		(void) fprintf(stderr, "failed to look up keys\en");
401		return;
402	}
403
404	nvlist_free(nvl);
405	(void) printf("Found DDR type 0x%x, module type 0x%x\en", ddr,
406	    mod);
407}
408.Ed
409.Sh ERRORS
410Upon returning from the
411.Fn libjedec_spd
412function, the
413.Fa errp
414pointer will be set to one of the following values:
415.Bl  -tag -width Dv
416.It Er LIBJEDEC_SPD_OK
417This indicates that the system was able to parse SPD data into a valid
418.Vt nvlist_t
419and return it to the caller.
420This code should never appear when the function fails and returns
421.Dv NULL .
422Callers must still cehck the contents of the
423.Dv SPD_KEY_ERRS
424nvlist.
425.It Dv LIBJEDEC_SPD_NOMEM
426This indicates that the system ran out of memory while trying to
427construct the
428.Vt nvlist_t
429to return.
430.It Dv LIBJEDEC_SPD_TOOSHORT
431This indicates that not enough SPD data was present as indicated by
432.Fa buf
433and
434.Fa buflen
435for the given type of SPD information and therefore we were unable to
436successfully parse basic information.
437.It Dv LIBJEDEC_SPD_UNSUP_TYPE
438This indicates that the type of SPD data present, e.g. DDR4 SDRAM,
439LPDDR3, etc., that was found is not currently supported by the library.
440.It Dv LIBJEDEC_SPD_UNSUP_REV
441This indicates that while the library is familiar with the specific type
442of SPD data present, the encoding level of the data
443.Pq similar to a major version
444is unsupported by the library.
445.El
446.Sh INTERFACE STABILITY
447.Sy Uncommitted
448.Sh MT-LEVEL
449.Sy MT-Safe
450.Sh SEE ALSO
451.Xr libjedec 3LIB ,
452.Xr nvlist_lookup_boolean 3NVPAIR ,
453.Xr nvlist_lookup_string 3NVPAIR ,
454.Xr nvlist_lookup_uint32 3NVPAIR ,
455.Xr nvlist_lookup_uint32_array 3NVPAIR ,
456.Xr nvlist_lookup_uint64 3NVPAIR
457.Pp
458.Rs
459.%Q JEDEC Solid State Technology Association
460.%T Serial Presence Detect (SPD), General Standard
461.%N 21-C
462.Re
463.Rs
464.%Q JEDEC Solid State Technology Association
465.%T DDR5 Serial Presence Detect (SPD) Contents
466.%N JESD400-5B Document Release 1.2
467.%D October 2023
468.Re
469.Rs
470.%Q JEDEC Solid State Technology Association
471.%T LPDDR5/5X Serial Presence Detect (SPD) Contents
472.%N JESD406-5 Document Release 1.0
473.%D June 2024
474.Re
475