summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel/io/amdzen/zen_umc.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/intel/io/amdzen/zen_umc.c')
-rw-r--r--usr/src/uts/intel/io/amdzen/zen_umc.c110
1 files changed, 68 insertions, 42 deletions
diff --git a/usr/src/uts/intel/io/amdzen/zen_umc.c b/usr/src/uts/intel/io/amdzen/zen_umc.c
index ed10a1e50b..947c17b4ff 100644
--- a/usr/src/uts/intel/io/amdzen/zen_umc.c
+++ b/usr/src/uts/intel/io/amdzen/zen_umc.c
@@ -1840,6 +1840,71 @@ zen_umc_fill_ccm_cb(const uint_t dfno, const uint32_t fabid,
}
/*
+ * This is used to fill in the common properties about a DIMM. This should occur
+ * after the rank information has been filled out. The information used is the
+ * same between DDR4 and DDR5 DIMMs. The only major difference is the register
+ * offset.
+ */
+static boolean_t
+zen_umc_fill_dimm_common(zen_umc_t *umc, zen_umc_df_t *df, zen_umc_chan_t *chan,
+ const uint_t dimmno, boolean_t ddr4)
+{
+ umc_dimm_t *dimm;
+ int ret;
+ smn_reg_t reg;
+ uint32_t val;
+ const uint32_t id = chan->chan_logid;
+
+ dimm = &chan->chan_dimms[dimmno];
+ dimm->ud_dimmno = dimmno;
+
+ if (ddr4) {
+ reg = UMC_DIMMCFG_DDR4(id, dimmno);
+ } else {
+ reg = UMC_DIMMCFG_DDR5(id, dimmno);
+ }
+ if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
+ dev_err(umc->umc_dip, CE_WARN, "failed to read DIMM "
+ "configuration register %x: %d", SMN_REG_ADDR(reg), ret);
+ return (B_FALSE);
+ }
+ dimm->ud_dimmcfg_raw = val;
+
+ if (UMC_DIMMCFG_GET_X16(val) != 0) {
+ dimm->ud_width = UMC_DIMM_W_X16;
+ } else if (UMC_DIMMCFG_GET_X4(val) != 0) {
+ dimm->ud_width = UMC_DIMM_W_X4;
+ } else {
+ dimm->ud_width = UMC_DIMM_W_X8;
+ }
+
+ if (UMC_DIMMCFG_GET_3DS(val) != 0) {
+ dimm->ud_kind = UMC_DIMM_K_3DS_RDIMM;
+ } else if (UMC_DIMMCFG_GET_LRDIMM(val) != 0) {
+ dimm->ud_kind = UMC_DIMM_K_LRDIMM;
+ } else if (UMC_DIMMCFG_GET_RDIMM(val) != 0) {
+ dimm->ud_kind = UMC_DIMM_K_RDIMM;
+ } else {
+ dimm->ud_kind = UMC_DIMM_K_UDIMM;
+ }
+
+ /*
+ * DIMM information in a UMC can be somewhat confusing. There are quite
+ * a number of non-zero reset values that are here. Flag whether or not
+ * we think this entry should be usable based on enabled chip-selects.
+ */
+ for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_BASE; i++) {
+ if (dimm->ud_cs[i].ucs_base.udb_valid ||
+ dimm->ud_cs[i].ucs_sec.udb_valid) {
+ dimm->ud_flags |= UMC_DIMM_F_VALID;
+ break;
+ }
+ }
+
+ return (B_TRUE);
+}
+
+/*
* Fill all the information about a DDR4 DIMM. In the DDR4 UMC, some of this
* information is on a per-chip select basis while at other times it is on a
* per-DIMM basis. In general, chip-selects 0/1 correspond to DIMM 0, and
@@ -1861,7 +1926,6 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
ASSERT3U(dimmno, <, ZEN_UMC_MAX_DIMMS);
dimm = &chan->chan_dimms[dimmno];
- dimm->ud_dimmno = dimmno;
cs0 = &dimm->ud_cs[0];
cs1 = &dimm->ud_cs[1];
@@ -2049,46 +2113,7 @@ zen_umc_fill_chan_dimm_ddr4(zen_umc_t *umc, zen_umc_df_t *df,
bcopy(cs0->ucs_rm_bits_sec, cs1->ucs_rm_bits_sec,
sizeof (cs0->ucs_rm_bits_sec));
- reg = UMC_DIMMCFG_DDR4(id, dimmno);
- if ((ret = amdzen_c_smn_read32(df->zud_dfno, reg, &val)) != 0) {
- dev_err(umc->umc_dip, CE_WARN, "failed to read DIMM "
- "configuration register %x: %d", SMN_REG_ADDR(reg), ret);
- return (B_FALSE);
- }
- dimm->ud_dimmcfg_raw = val;
-
- if (UMC_DIMMCFG_GET_X16(val) != 0) {
- dimm->ud_width = UMC_DIMM_W_X16;
- } else if (UMC_DIMMCFG_GET_X4(val) != 0) {
- dimm->ud_width = UMC_DIMM_W_X4;
- } else {
- dimm->ud_width = UMC_DIMM_W_X8;
- }
-
- if (UMC_DIMMCFG_GET_3DS(val) != 0) {
- dimm->ud_kind = UMC_DIMM_K_3DS_RDIMM;
- } else if (UMC_DIMMCFG_GET_LRDIMM(val) != 0) {
- dimm->ud_kind = UMC_DIMM_K_LRDIMM;
- } else if (UMC_DIMMCFG_GET_RDIMM(val) != 0) {
- dimm->ud_kind = UMC_DIMM_K_RDIMM;
- } else {
- dimm->ud_kind = UMC_DIMM_K_UDIMM;
- }
-
- /*
- * DIMM information in a UMC can be somewhat confusing. There are quite
- * a number of non-zero reset values that are here. Flag whether or not
- * we think this entry should be usable based on enabled chip-selects.
- */
- for (uint_t i = 0; i < ZEN_UMC_MAX_CHAN_BASE; i++) {
- if (dimm->ud_cs[i].ucs_base.udb_valid ||
- dimm->ud_cs[i].ucs_sec.udb_valid) {
- dimm->ud_flags |= UMC_DIMM_F_VALID;
- break;
- }
- }
-
- return (B_TRUE);
+ return (zen_umc_fill_dimm_common(umc, df, chan, dimmno, B_TRUE));
}
/*
@@ -2309,9 +2334,10 @@ zen_umc_fill_chan_rank_ddr5(zen_umc_t *umc, zen_umc_df_t *df,
bcopy(cs->ucs_rm_bits, cs->ucs_rm_bits_sec,
sizeof (cs->ucs_rm_bits));
- return (B_TRUE);
+ return (zen_umc_fill_dimm_common(umc, df, chan, dimmno, B_FALSE));
}
+
static void
zen_umc_fill_ddr_type(zen_umc_chan_t *chan, boolean_t ddr4)
{