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