ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/sys/dev/jedec_dimm/jedec_dimm.c
Revision: 12233
Committed: Fri Aug 9 00:04:09 2019 UTC (4 years, 9 months ago) by laffer1
Content type: text/plain
File size: 29117 byte(s)
Log Message:
fix a bug where some devices lie about support

File Contents

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

Properties

Name Value
svn:eol-style native
svn:keywords MidnightBSD=%H
svn:mime-type text/plain