2022-02-02 15:16:01

by Yazen Ghannam

[permalink] [raw]
Subject: [PATCH v4 1/2] EDAC/amd64: Set memory type per DIMM

Current AMD systems allow mixing of DIMM types within a system. However,
DIMMs within a channel, i.e. managed by a single Unified Memory
Controller (UMC), must be of the same type.

Handle this possible configuration by checking and setting the memory
type for each individual "UMC" structure.

Signed-off-by: Yazen Ghannam <[email protected]>
---
Link:
https://lore.kernel.org/r/[email protected]

v3->v4:
* Cache dram_type in struct umc.

v2->v3:
* Change patch to properly handle systems with different DIMM types.

v1->v2:
* Was patch 3 in v1.
* Update commit message.

drivers/edac/amd64_edac.c | 47 +++++++++++++++++++++++++++++----------
drivers/edac/amd64_edac.h | 3 +++
2 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index fba609ada0e6..49e384207ce0 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1429,7 +1429,7 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt)
edac_dbg(1, "UMC%d x16 DIMMs present: %s\n",
i, (umc->dimm_cfg & BIT(7)) ? "yes" : "no");

- if (pvt->dram_type == MEM_LRDDR4) {
+ if (umc->dram_type == MEM_LRDDR4) {
amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ADDR_CFG, &tmp);
edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n",
i, 1 << ((tmp >> 4) & 0x3));
@@ -1616,19 +1616,40 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
}
}

+static void _determine_memory_type_df(struct amd64_umc *umc)
+{
+ if (!(umc->sdp_ctrl & UMC_SDP_INIT)) {
+ umc->dram_type = MEM_EMPTY;
+ return;
+ }
+
+ if (umc->dimm_cfg & BIT(5))
+ umc->dram_type = MEM_LRDDR4;
+ else if (umc->dimm_cfg & BIT(4))
+ umc->dram_type = MEM_RDDR4;
+ else
+ umc->dram_type = MEM_DDR4;
+}
+
+static void determine_memory_type_df(struct amd64_pvt *pvt)
+{
+ struct amd64_umc *umc;
+ u32 i;
+
+ for_each_umc(i) {
+ umc = &pvt->umc[i];
+
+ _determine_memory_type_df(umc);
+ edac_dbg(1, " UMC%d DIMM type: %s\n", i, edac_mem_types[umc->dram_type]);
+ }
+}
+
static void determine_memory_type(struct amd64_pvt *pvt)
{
u32 dram_ctrl, dcsm;

- if (pvt->umc) {
- if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
- pvt->dram_type = MEM_LRDDR4;
- else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
- pvt->dram_type = MEM_RDDR4;
- else
- pvt->dram_type = MEM_DDR4;
- return;
- }
+ if (pvt->umc)
+ return determine_memory_type_df(pvt);

switch (pvt->fam) {
case 0xf:
@@ -3452,7 +3473,9 @@ static void read_mc_regs(struct amd64_pvt *pvt)
read_dct_base_mask(pvt);

determine_memory_type(pvt);
- edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);
+
+ if (!pvt->umc)
+ edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);

determine_ecc_sym_sz(pvt);
}
@@ -3548,7 +3571,7 @@ static int init_csrows_df(struct mem_ctl_info *mci)
pvt->mc_node_id, cs);

dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs);
- dimm->mtype = pvt->dram_type;
+ dimm->mtype = pvt->umc[umc].dram_type;
dimm->edac_mode = edac_mode;
dimm->dtype = dev_type;
dimm->grain = 64;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 352bda9803f6..09ad28299c57 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -344,6 +344,9 @@ struct amd64_umc {
u32 sdp_ctrl; /* SDP Control reg */
u32 ecc_ctrl; /* DRAM ECC Control reg */
u32 umc_cap_hi; /* Capabilities High reg */
+
+ /* cache the dram_type */
+ enum mem_type dram_type;
};

struct amd64_pvt {
--
2.25.1


2022-02-03 15:39:41

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] EDAC/amd64: Set memory type per DIMM

On Thu, Feb 03, 2022 at 02:19:19PM +0100, William Roche wrote:
> As we are moving the dram_type cached date from pvt to umc for family >=
> 0x17, should we also add a small comment for the dram_type field in the
> amd64_pvt structure to indicate that ?

Who would be that comment for? People who are looking at the code, so
that they know which is which?

> Something like that for example:
>
> @@ -385,7 +385,7 @@
>      /* place to store error injection parameters prior to issue */
>      struct error_injection injection;
>
> -    /* cache the dram_type */
> +    /* cache the dram_type for family<0x17 */
>      enum mem_type dram_type;
>
>      struct amd64_umc *umc;    /* UMC registers */
>
>
> Just a suggestion.
> The code looks good to me.
>
> Reviewed-by: William Roche <[email protected]>
>
> W.

Btw, I'd appreciate it if you do not top-post.

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-02-03 17:15:16

by William Roche

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] EDAC/amd64: Set memory type per DIMM

On 03/02/2022 15:09, Borislav Petkov wrote:

> On Thu, Feb 03, 2022 at 02:19:19PM +0100, William Roche wrote:
>> As we are moving the dram_type cached date from pvt to umc for family >=
>> 0x17, should we also add a small comment for the dram_type field in the
>> amd64_pvt structure to indicate that ?
> Who would be that comment for? People who are looking at the code, so
> that they know which is which?

Yes, it could be a hint about the use case of this field.
Of course we could be more complete and also comment the umc field use
in this same structure that depends on the family higher or lower than
17 too.
But I had the impression that the creation of a new dram_type cache
field would be clarified by a comment on the old location, that's it.
It's up to Yazen and you to include or not  this small addition about
dram_type.

>
>> Something like that for example:
>>
>> @@ -385,7 +385,7 @@
>>      /* place to store error injection parameters prior to issue */
>>      struct error_injection injection;
>>
>> -    /* cache the dram_type */
>> +    /* cache the dram_type for family<0x17 */
>>      enum mem_type dram_type;
>>
>>      struct amd64_umc *umc;    /* UMC registers */
>>
>>
>> Just a suggestion.
>> The code looks good to me.
>>
>> Reviewed-by: William Roche <[email protected]>
>>
>> W.
> Btw, I'd appreciate it if you do not top-post.
>
> Thx.

Sure, sorry.

2022-02-05 18:55:16

by Yazen Ghannam

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] EDAC/amd64: Set memory type per DIMM

On Thu, Feb 03, 2022 at 04:46:44PM +0100, William Roche wrote:
> On 03/02/2022 15:09, Borislav Petkov wrote:
>
> > On Thu, Feb 03, 2022 at 02:19:19PM +0100, William Roche wrote:
> > > As we are moving the dram_type cached date from pvt to umc for family >=
> > > 0x17, should we also add a small comment for the dram_type field in the
> > > amd64_pvt structure to indicate that ?
> > Who would be that comment for? People who are looking at the code, so
> > that they know which is which?
>
> Yes, it could be a hint about the use case of this field.
> Of course we could be more complete and also comment the umc field use in
> this same structure that depends on the family higher or lower than 17 too.
> But I had the impression that the creation of a new dram_type cache field
> would be clarified by a comment on the old location, that's it.
> It's up to Yazen and you to include or not? this small addition about
> dram_type.
>

Thanks William for the review.

I think this is a good suggestion. I think it could be a bit more verbose.
Please see below.

Thanks,
Yazen

---

From 028207619fb01008a2defc65183cbd30f98c021f Mon Sep 17 00:00:00 2001
From: Yazen Ghannam <[email protected]>
Date: Fri, 4 Feb 2022 15:10:52 +0000
Subject: [PATCH] EDAC/amd64: Comment on which dram_type to use

A copy of enum mem_type was added to struct amd64_umc so that memory
type can be properly identified on each independent Unified Memory
Controller.

Add a comment to the original struct amd64_pvt variable to indicate it
shouldn't be used on newer systems.

Signed-off-by: Yazen Ghannam <[email protected]>
---
drivers/edac/amd64_edac.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 6f8147abfa71..38e5ad95d010 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -397,7 +397,12 @@ struct amd64_pvt {
/* place to store error injection parameters prior to issue */
struct error_injection injection;

- /* cache the dram_type */
+ /*
+ * cache the dram_type
+ *
+ * NOTE: Don't use this for Family 17h and later.
+ * Use dram_type in struct amd64_umc instead.
+ */
enum mem_type dram_type;

struct amd64_umc *umc; /* UMC registers */
--
2.25.1


2022-02-07 08:46:00

by William Roche

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] EDAC/amd64: Set memory type per DIMM

On 04/02/2022 16:51, Yazen Ghannam wrote:

>
> diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
> index 6f8147abfa71..38e5ad95d010 100644
> --- a/drivers/edac/amd64_edac.h
> +++ b/drivers/edac/amd64_edac.h
> @@ -397,7 +397,12 @@ struct amd64_pvt {
> /* place to store error injection parameters prior to issue */
> struct error_injection injection;
>
> - /* cache the dram_type */
> + /*
> + * cache the dram_type
> + *
> + * NOTE: Don't use this for Family 17h and later.
> + * Use dram_type in struct amd64_umc instead.
> + */
> enum mem_type dram_type;
>
> struct amd64_umc *umc; /* UMC registers */

It works for me Yazen.
Thanks!


2022-02-24 01:51:38

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] EDAC/amd64: Set memory type per DIMM

On Wed, Feb 02, 2022 at 02:43:06PM +0000, Yazen Ghannam wrote:
> +static void _determine_memory_type_df(struct amd64_umc *umc)

You don't need this function, right?

IOW, here's what I've applied:

---
From: Yazen Ghannam <[email protected]>
Date: Wed, 2 Feb 2022 14:43:06 +0000
Subject: [PATCH] EDAC/amd64: Set memory type per DIMM

Current AMD systems allow mixing of DIMM types within a system. However,
DIMMs within a channel, i.e. managed by a single Unified Memory
Controller (UMC), must be of the same type.

Handle this possible configuration by checking and setting the memory
type for each individual "UMC" structure.

Signed-off-by: Yazen Ghannam <[email protected]>
Signed-off-by: Borislav Petkov <[email protected]>
Reviewed-by: William Roche <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/edac/amd64_edac.c | 43 ++++++++++++++++++++++++++++-----------
drivers/edac/amd64_edac.h | 10 ++++++++-
2 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index fba609ada0e6..388b072daa94 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1429,7 +1429,7 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt)
edac_dbg(1, "UMC%d x16 DIMMs present: %s\n",
i, (umc->dimm_cfg & BIT(7)) ? "yes" : "no");

- if (pvt->dram_type == MEM_LRDDR4) {
+ if (umc->dram_type == MEM_LRDDR4) {
amd_smn_read(pvt->mc_node_id, umc_base + UMCCH_ADDR_CFG, &tmp);
edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n",
i, 1 << ((tmp >> 4) & 0x3));
@@ -1616,19 +1616,36 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
}
}

-static void determine_memory_type(struct amd64_pvt *pvt)
+static void determine_memory_type_df(struct amd64_pvt *pvt)
{
- u32 dram_ctrl, dcsm;
+ struct amd64_umc *umc;
+ u32 i;

- if (pvt->umc) {
- if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
- pvt->dram_type = MEM_LRDDR4;
- else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
- pvt->dram_type = MEM_RDDR4;
+ for_each_umc(i) {
+ umc = &pvt->umc[i];
+
+ if (!(umc->sdp_ctrl & UMC_SDP_INIT)) {
+ umc->dram_type = MEM_EMPTY;
+ continue;
+ }
+
+ if (umc->dimm_cfg & BIT(5))
+ umc->dram_type = MEM_LRDDR4;
+ else if (umc->dimm_cfg & BIT(4))
+ umc->dram_type = MEM_RDDR4;
else
- pvt->dram_type = MEM_DDR4;
- return;
+ umc->dram_type = MEM_DDR4;
+
+ edac_dbg(1, " UMC%d DIMM type: %s\n", i, edac_mem_types[umc->dram_type]);
}
+}
+
+static void determine_memory_type(struct amd64_pvt *pvt)
+{
+ u32 dram_ctrl, dcsm;
+
+ if (pvt->umc)
+ return determine_memory_type_df(pvt);

switch (pvt->fam) {
case 0xf:
@@ -3452,7 +3469,9 @@ static void read_mc_regs(struct amd64_pvt *pvt)
read_dct_base_mask(pvt);

determine_memory_type(pvt);
- edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);
+
+ if (!pvt->umc)
+ edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);

determine_ecc_sym_sz(pvt);
}
@@ -3548,7 +3567,7 @@ static int init_csrows_df(struct mem_ctl_info *mci)
pvt->mc_node_id, cs);

dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs);
- dimm->mtype = pvt->dram_type;
+ dimm->mtype = pvt->umc[umc].dram_type;
dimm->edac_mode = edac_mode;
dimm->dtype = dev_type;
dimm->grain = 64;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 352bda9803f6..6b8742369f9d 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -344,6 +344,9 @@ struct amd64_umc {
u32 sdp_ctrl; /* SDP Control reg */
u32 ecc_ctrl; /* DRAM ECC Control reg */
u32 umc_cap_hi; /* Capabilities High reg */
+
+ /* cache the dram_type */
+ enum mem_type dram_type;
};

struct amd64_pvt {
@@ -391,7 +394,12 @@ struct amd64_pvt {
/* place to store error injection parameters prior to issue */
struct error_injection injection;

- /* cache the dram_type */
+ /*
+ * cache the dram_type
+ *
+ * NOTE: Don't use this for Family 17h and later.
+ * Use dram_type in struct amd64_umc instead.
+ */
enum mem_type dram_type;

struct amd64_umc *umc; /* UMC registers */
--
2.29.2

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-02-24 19:23:51

by Yazen Ghannam

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] EDAC/amd64: Set memory type per DIMM

On Wed, Feb 23, 2022 at 09:55:08PM +0100, Borislav Petkov wrote:
> On Wed, Feb 02, 2022 at 02:43:06PM +0000, Yazen Ghannam wrote:
> > +static void _determine_memory_type_df(struct amd64_umc *umc)
>
> You don't need this function, right?
>
> IOW, here's what I've applied:
>

...

>
> -static void determine_memory_type(struct amd64_pvt *pvt)
> +static void determine_memory_type_df(struct amd64_pvt *pvt)
> {
> - u32 dram_ctrl, dcsm;
> + struct amd64_umc *umc;
> + u32 i;
>
> - if (pvt->umc) {
> - if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
> - pvt->dram_type = MEM_LRDDR4;
> - else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
> - pvt->dram_type = MEM_RDDR4;
> + for_each_umc(i) {
> + umc = &pvt->umc[i];
> +
> + if (!(umc->sdp_ctrl & UMC_SDP_INIT)) {
> + umc->dram_type = MEM_EMPTY;
> + continue;
> + }
> +
> + if (umc->dimm_cfg & BIT(5))
> + umc->dram_type = MEM_LRDDR4;
> + else if (umc->dimm_cfg & BIT(4))
> + umc->dram_type = MEM_RDDR4;
> else
> - pvt->dram_type = MEM_DDR4;
> - return;
> + umc->dram_type = MEM_DDR4;
> +
> + edac_dbg(1, " UMC%d DIMM type: %s\n", i, edac_mem_types[umc->dram_type]);
> }
> +}

Ah, I see. You got rid of the extra helper function. Makes sense and looks
okay to me.

Thanks,
Yazen