jedec_dimm(4): Add manufacturing year and week.
DDR3 and DDR4 encode the week and year that the DIMM was manufactured, as a pair of two-digit binary-coded decimal values. Read the values, and report them as (uint8_t)s. Reviewed by: imp, jhb MFC after: 1 week Sponsored by: Panasas Differential Revision: https://reviews.freebsd.org/D39795
This commit is contained in:
parent
e315351fc7
commit
de57e0ef5a
@ -26,7 +26,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 31, 2018
|
||||
.Dd April 25, 2023
|
||||
.Dt JEDEC_DIMM 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -76,6 +76,10 @@ interface; all values are read-only:
|
||||
a string description of the DIMM, including TSOD and slotid info if present.
|
||||
.It Va dev.jedec_dimm.X.capacity
|
||||
the DIMM's memory capacity, in megabytes
|
||||
.It Va dev.jedec_dimm.X.mfg_week
|
||||
the week within the year in which the DIMM was manufactured
|
||||
.It Va dev.jedec_dimm.X.mfg_year
|
||||
the year in which the DIMM was manufactured
|
||||
.It Va dev.jedec_dimm.X.part
|
||||
the manufacturer's part number of the DIMM
|
||||
.It Va dev.jedec_dimm.X.serial
|
||||
@ -144,6 +148,8 @@ dev.jedec_dimm.0.%location: addr=0xa0
|
||||
dev.jedec_dimm.0.%parent: smbus0
|
||||
dev.jedec_dimm.0.%pnpinfo:
|
||||
dev.jedec_dimm.0.capacity: 16384
|
||||
dev.jedec_dimm.0.mfg_week: 30
|
||||
dev.jedec_dimm.0.mfg_year: 17
|
||||
dev.jedec_dimm.0.part: 36ASF2G72PZ-2G1A2
|
||||
dev.jedec_dimm.0.serial: 0ea815de
|
||||
dev.jedec_dimm.0.slotid: A1
|
||||
@ -156,6 +162,8 @@ dev.jedec_dimm.6.%location: addr=0xa8
|
||||
dev.jedec_dimm.6.%parent: smbus1
|
||||
dev.jedec_dimm.6.%pnpinfo:
|
||||
dev.jedec_dimm.6.capacity: 8192
|
||||
dev.jedec_dimm.6.mfg_week: 13
|
||||
dev.jedec_dimm.6.mfg_year: 19
|
||||
dev.jedec_dimm.6.part: VRA9MR8B2H1603
|
||||
dev.jedec_dimm.6.serial: 0c4c46ad
|
||||
dev.jedec_dimm.6.temp: 43.1C
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Authors: Ravi Pokala (rpokala@freebsd.org), Andriy Gapon (avg@FreeBSD.org)
|
||||
*
|
||||
* Copyright (c) 2016 Andriy Gapon <avg@FreeBSD.org>
|
||||
* Copyright (c) 2018 Panasas
|
||||
* Copyright (c) 2018-2023 Panasas
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -56,6 +56,8 @@ struct jedec_dimm_softc {
|
||||
device_t smbus;
|
||||
uint8_t spd_addr; /* SMBus address of the SPD EEPROM. */
|
||||
uint8_t tsod_addr; /* Address of the Thermal Sensor On DIMM */
|
||||
uint8_t mfg_year;
|
||||
uint8_t mfg_week;
|
||||
uint32_t capacity_mb;
|
||||
char type_str[5];
|
||||
char part_str[21]; /* 18 (DDR3) or 20 (DDR4) chars, plus terminator */
|
||||
@ -154,6 +156,9 @@ static int jedec_dimm_dump(struct jedec_dimm_softc *sc, enum dram_type type);
|
||||
static int jedec_dimm_field_to_str(struct jedec_dimm_softc *sc, char *dst,
|
||||
size_t dstsz, uint16_t offset, uint16_t len, bool ascii);
|
||||
|
||||
static int jedec_dimm_mfg_date(struct jedec_dimm_softc *sc, enum dram_type type,
|
||||
uint8_t *year, uint8_t *week);
|
||||
|
||||
static int jedec_dimm_probe(device_t dev);
|
||||
|
||||
static int jedec_dimm_readw_be(struct jedec_dimm_softc *sc, uint8_t reg,
|
||||
@ -257,6 +262,11 @@ jedec_dimm_attach(device_t dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = jedec_dimm_mfg_date(sc, type, &sc->mfg_year, &sc->mfg_week);
|
||||
if (rc != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = jedec_dimm_field_to_str(sc, sc->part_str, sizeof(sc->part_str),
|
||||
partnum_offset, partnum_len, true);
|
||||
if (rc != 0) {
|
||||
@ -336,6 +346,14 @@ jedec_dimm_attach(device_t dev)
|
||||
CTLFLAG_RD | CTLFLAG_MPSAFE, sc->serial_str, 0,
|
||||
"DIMM Serial Number");
|
||||
|
||||
SYSCTL_ADD_U8(ctx, children, OID_AUTO, "mfg_year",
|
||||
CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, sc->mfg_year,
|
||||
"DIMM manufacturing year (20xx)");
|
||||
|
||||
SYSCTL_ADD_U8(ctx, children, OID_AUTO, "mfg_week",
|
||||
CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, sc->mfg_week,
|
||||
"DIMM manufacturing week");
|
||||
|
||||
/* Create the temperature sysctl IFF the TSOD is present and valid */
|
||||
if (tsod_present && (tsod_match != NULL)) {
|
||||
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temp",
|
||||
@ -822,6 +840,117 @@ jedec_dimm_field_to_str(struct jedec_dimm_softc *sc, char *dst, size_t dstsz,
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Both DDR3 and DDR4 encode manufacturing date as a one-byte BCD-encoded
|
||||
* year (offset from 2000) and a one-byte BCD-encoded week within that year.
|
||||
* The SPD offsets are different between the two types.
|
||||
*
|
||||
* @author rpokala
|
||||
*
|
||||
* @param[in] sc
|
||||
* Instance-specific context data
|
||||
*
|
||||
* @param[in] dram_type
|
||||
* The locations of the manufacturing date depends on the type of the DIMM.
|
||||
*
|
||||
* @param[out] year
|
||||
* The manufacturing year, offset from 2000
|
||||
*
|
||||
* @param[out] week
|
||||
* The manufacturing week within the year
|
||||
*/
|
||||
static int
|
||||
jedec_dimm_mfg_date(struct jedec_dimm_softc *sc, enum dram_type type,
|
||||
uint8_t *year, uint8_t *week)
|
||||
{
|
||||
uint8_t year_bcd;
|
||||
uint8_t week_bcd;
|
||||
uint16_t year_offset;
|
||||
uint16_t week_offset;
|
||||
bool page_changed;
|
||||
int rc;
|
||||
|
||||
switch (type) {
|
||||
case DRAM_TYPE_DDR3_SDRAM:
|
||||
year_offset = SPD_OFFSET_DDR3_MOD_MFG_YEAR;
|
||||
week_offset = SPD_OFFSET_DDR3_MOD_MFG_WEEK;
|
||||
break;
|
||||
case DRAM_TYPE_DDR4_SDRAM:
|
||||
year_offset = SPD_OFFSET_DDR4_MOD_MFG_YEAR;
|
||||
week_offset = SPD_OFFSET_DDR4_MOD_MFG_WEEK;
|
||||
break;
|
||||
default:
|
||||
device_printf(sc->dev, "unsupported dram_type 0x%02x\n", type);
|
||||
rc = EINVAL;
|
||||
page_changed = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Change to the proper page. Offsets [0, 255] are in page0; offsets
|
||||
* [256, 512] are in page1.
|
||||
*
|
||||
* *The page must be reset to page0 before returning.*
|
||||
*
|
||||
* For the page-change operation, only the DTI and LSA matter; the
|
||||
* offset and write-value are ignored, so use just 0.
|
||||
*
|
||||
* Mercifully, JEDEC defined the fields such that all of the
|
||||
* manufacturing-related ones are on the same page, so we don't need to
|
||||
* worry about that complication.
|
||||
*/
|
||||
if (year_offset < JEDEC_SPD_PAGE_SIZE) {
|
||||
page_changed = false;
|
||||
} else if (year_offset < (2 * JEDEC_SPD_PAGE_SIZE)) {
|
||||
page_changed = true;
|
||||
rc = smbus_writeb(sc->smbus,
|
||||
(JEDEC_DTI_PAGE | JEDEC_LSA_PAGE_SET1), 0, 0);
|
||||
if (rc != 0) {
|
||||
device_printf(sc->dev,
|
||||
"unable to change page for offset 0x%04x: %d\n",
|
||||
year_offset, rc);
|
||||
}
|
||||
/* Adjust the offset to account for the page change. */
|
||||
year_offset -= JEDEC_SPD_PAGE_SIZE;
|
||||
week_offset -= JEDEC_SPD_PAGE_SIZE;
|
||||
} else {
|
||||
device_printf(sc->dev, "invalid offset 0x%04x\n", year_offset);
|
||||
rc = EINVAL;
|
||||
page_changed = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = smbus_readb(sc->smbus, sc->spd_addr, year_offset, &year_bcd);
|
||||
if (rc != 0) {
|
||||
device_printf(sc->dev, "failed to read mfg year: %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = smbus_readb(sc->smbus, sc->spd_addr, week_offset, &week_bcd);
|
||||
if (rc != 0) {
|
||||
device_printf(sc->dev, "failed to read mfg week: %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Convert from one-byte BCD to one-byte integer. */
|
||||
*year = (((year_bcd & 0xf0) >> 4) * 10) + (year_bcd & 0x0f);
|
||||
*week = (((week_bcd & 0xf0) >> 4) * 10) + (week_bcd & 0x0f);
|
||||
|
||||
out:
|
||||
if (page_changed) {
|
||||
int rc2;
|
||||
/* Switch back to page0 before returning. */
|
||||
rc2 = smbus_writeb(sc->smbus,
|
||||
(JEDEC_DTI_PAGE | JEDEC_LSA_PAGE_SET0), 0, 0);
|
||||
if (rc2 != 0) {
|
||||
device_printf(sc->dev,
|
||||
"unable to restore page for offset 0x%04x: %d\n",
|
||||
year_offset, rc2);
|
||||
}
|
||||
}
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* device_probe() method. Validate the address that was given as a hint, and
|
||||
* display an error if it's bogus. Make sure that we're dealing with one of the
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Authors: Ravi Pokala (rpokala@freebsd.org)
|
||||
*
|
||||
* Copyright (c) 2018 Panasas
|
||||
* Copyright (c) 2018-2023 Panasas
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -90,6 +90,8 @@
|
||||
#define SPD_OFFSET_DDR3_SDRAM_WIDTH 7
|
||||
#define SPD_OFFSET_DDR3_BUS_WIDTH 8
|
||||
#define SPD_OFFSET_DDR3_TSOD_PRESENT 32
|
||||
#define SPD_OFFSET_DDR3_MOD_MFG_YEAR 120
|
||||
#define SPD_OFFSET_DDR3_MOD_MFG_WEEK 121
|
||||
#define SPD_OFFSET_DDR3_SERIAL 122
|
||||
#define SPD_LEN_DDR3_SERIAL 4
|
||||
#define SPD_OFFSET_DDR3_PARTNUM 128
|
||||
@ -100,6 +102,8 @@
|
||||
#define SPD_OFFSET_DDR4_SDRAM_WIDTH 12
|
||||
#define SPD_OFFSET_DDR4_BUS_WIDTH 13
|
||||
#define SPD_OFFSET_DDR4_TSOD_PRESENT 14
|
||||
#define SPD_OFFSET_DDR4_MOD_MFG_YEAR 323
|
||||
#define SPD_OFFSET_DDR4_MOD_MFG_WEEK 324
|
||||
#define SPD_OFFSET_DDR4_SERIAL 325
|
||||
#define SPD_LEN_DDR4_SERIAL 4
|
||||
#define SPD_OFFSET_DDR4_PARTNUM 329
|
||||
|
Loading…
Reference in New Issue
Block a user