git: 861fdb46300b - stable/13 - jedec_dimm(4): Add manufacturing year and week.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 05 May 2023 00:30:01 UTC
The branch stable/13 has been updated by rpokala: URL: https://cgit.FreeBSD.org/src/commit/?id=861fdb46300bd16808ca443ecc222f10db02d53d commit 861fdb46300bd16808ca443ecc222f10db02d53d Author: Ravi Pokala <rpokala@FreeBSD.org> AuthorDate: 2023-04-25 06:07:39 +0000 Commit: Ravi Pokala <rpokala@FreeBSD.org> CommitDate: 2023-05-05 00:27:55 +0000 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 (cherry picked from commit de57e0ef5a15c75231191e643d4d1949ddbca92d) --- share/man/man4/jedec_dimm.4 | 10 ++- sys/dev/jedec_dimm/jedec_dimm.c | 131 +++++++++++++++++++++++++++++++++++++++- sys/dev/jedec_dimm/jedec_dimm.h | 6 +- 3 files changed, 144 insertions(+), 3 deletions(-) diff --git a/share/man/man4/jedec_dimm.4 b/share/man/man4/jedec_dimm.4 index ea4183fafc1a..6c13da1a450e 100644 --- a/share/man/man4/jedec_dimm.4 +++ b/share/man/man4/jedec_dimm.4 @@ -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 diff --git a/sys/dev/jedec_dimm/jedec_dimm.c b/sys/dev/jedec_dimm/jedec_dimm.c index 884da8b51061..73ea10c5c5e1 100644 --- a/sys/dev/jedec_dimm/jedec_dimm.c +++ b/sys/dev/jedec_dimm/jedec_dimm.c @@ -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 @@ no_tsod: 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 @@ out: 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 diff --git a/sys/dev/jedec_dimm/jedec_dimm.h b/sys/dev/jedec_dimm/jedec_dimm.h index 3b330251efc5..00a9b3d521b6 100644 --- a/sys/dev/jedec_dimm/jedec_dimm.h +++ b/sys/dev/jedec_dimm/jedec_dimm.h @@ -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