diff options
| author | Borislav Petkov (AMD) <bp@alien8.de> | 2026-04-13 11:43:52 +0200 |
|---|---|---|
| committer | Borislav Petkov (AMD) <bp@alien8.de> | 2026-04-13 11:43:52 +0200 |
| commit | 4db9a9841dc1060e8805a4c40bdd7e6058d45100 (patch) | |
| tree | 2bfb3c7030d0c61388caecd8be56ea8e39f60528 /drivers/edac | |
| parent | 62ba6d66b22356a6a78fd015c37fd108710dfc32 (diff) | |
| parent | 865867a6652adeae23b64a9735bb727b49eb92a0 (diff) | |
Merge remote-tracking branches 'ras/edac-misc' and 'ras/edac-drivers' into edac-updates
* ras/edac-misc:
EDAC/mc: Use kzalloc_flex()
EDAC/ie31200: Make rpl_s_cfg static
EDAC/mpc85xx: Constify device sysfs attributes
EDAC/device: Allow addition of const sysfs attributes
EDAC/pci_sysfs: Constify instance sysfs attributes
EDAC/device: Constify info sysfs attributes
EDAC/device: Drop unnecessary and dangerous casts of attributes
EDAC/device: Drop unused macro to_edacdev_attr()
EDAC/altera: Drop unused field eccmgr_sysfs_attr
* ras/edac-drivers:
EDAC/i10nm: Fix spelling mistake "readd" -> "read"
EDAC/versalnet: Fix device_node leak in mc_probe()
EDAC/versalnet: Fix memory leak in remove and probe error paths
EDAC/amd64: Add support for family 19h, models 40h-4fh
EDAC/i10nm: Add driver decoder for Granite Rapids server
EDAC/sb: Use kzalloc_flex()
EDAC/i7core: Use kzalloc_flex()
EDAC/versalnet: Refactor memory controller initialization and cleanup
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Diffstat (limited to 'drivers/edac')
| -rw-r--r-- | drivers/edac/amd64_edac.c | 3 | ||||
| -rw-r--r-- | drivers/edac/i10nm_base.c | 16 | ||||
| -rw-r--r-- | drivers/edac/i7core_edac.c | 15 | ||||
| -rw-r--r-- | drivers/edac/sb_edac.c | 14 | ||||
| -rw-r--r-- | drivers/edac/versalnet_edac.c | 180 |
5 files changed, 126 insertions, 102 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 8908ab881c85..c6aa69dbd9fb 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3863,6 +3863,9 @@ static int per_family_init(struct amd64_pvt *pvt) pvt->max_mcs = 8; } break; + case 0x40 ... 0x4f: + pvt->max_mcs = 4; + break; case 0x60 ... 0x6f: pvt->flags.zn_regs_v2 = 1; break; diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 89b3e8cc38b1..63df35444214 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -196,7 +196,7 @@ static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width) case 8: return I10NM_GET_REG64(imc, chan, offset); default: - i10nm_printk(KERN_ERR, "Invalid readd RRL 0x%x width %d\n", offset, width); + i10nm_printk(KERN_ERR, "Invalid read RRL 0x%x width %d\n", offset, width); return 0; } } @@ -580,6 +580,10 @@ static bool i10nm_mc_decode_available(struct mce *mce) if (bank < 13 || bank > 20) return false; break; + case GNR: + if (bank < 13 || bank > 24) + return false; + break; default: return false; } @@ -637,6 +641,16 @@ static bool i10nm_mc_decode(struct decoded_addr *res) res->rank = GET_BITFIELD(m->misc, 57, 57); res->dimm = GET_BITFIELD(m->misc, 58, 58); break; + case GNR: + res->imc = m->bank - 13; + res->channel = 0; + res->column = GET_BITFIELD(m->misc, 9, 18) << 2; + res->row = GET_BITFIELD(m->misc, 19, 36); + res->bank_group = GET_BITFIELD(m->misc, 39, 41); + res->bank_address = GET_BITFIELD(m->misc, 37, 38); + res->rank = GET_BITFIELD(m->misc, 55, 56); + res->dimm = GET_BITFIELD(m->misc, 57, 57); + break; default: return false; } diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0f783173d0ec..b87c4c6471ea 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -240,9 +240,9 @@ struct pci_id_table { struct i7core_dev { struct list_head list; u8 socket; - struct pci_dev **pdev; - int n_devs; struct mem_ctl_info *mci; + int n_devs; + struct pci_dev *pdev[] __counted_by(n_devs); }; struct i7core_pvt { @@ -455,18 +455,12 @@ static struct i7core_dev *alloc_i7core_dev(u8 socket, { struct i7core_dev *i7core_dev; - i7core_dev = kzalloc_obj(*i7core_dev); + i7core_dev = kzalloc_flex(*i7core_dev, pdev, table->n_devs); if (!i7core_dev) return NULL; - i7core_dev->pdev = kzalloc_objs(*i7core_dev->pdev, table->n_devs); - if (!i7core_dev->pdev) { - kfree(i7core_dev); - return NULL; - } - - i7core_dev->socket = socket; i7core_dev->n_devs = table->n_devs; + i7core_dev->socket = socket; list_add_tail(&i7core_dev->list, &i7core_edac_list); return i7core_dev; @@ -475,7 +469,6 @@ static struct i7core_dev *alloc_i7core_dev(u8 socket, static void free_i7core_dev(struct i7core_dev *i7core_dev) { list_del(&i7core_dev->list); - kfree(i7core_dev->pdev); kfree(i7core_dev); } diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 09d4e816404b..7b282dfd093f 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -364,11 +364,11 @@ struct sbridge_dev { int seg; u8 bus, mc; u8 node_id, source_id; - struct pci_dev **pdev; enum domain dom; int n_devs; int i_devs; struct mem_ctl_info *mci; + struct pci_dev *pdev[] __counted_by(n_devs); }; struct knl_pvt { @@ -771,21 +771,14 @@ static struct sbridge_dev *alloc_sbridge_dev(int seg, u8 bus, enum domain dom, { struct sbridge_dev *sbridge_dev; - sbridge_dev = kzalloc_obj(*sbridge_dev); + sbridge_dev = kzalloc_flex(*sbridge_dev, pdev, table->n_devs_per_imc); if (!sbridge_dev) return NULL; - sbridge_dev->pdev = kzalloc_objs(*sbridge_dev->pdev, - table->n_devs_per_imc); - if (!sbridge_dev->pdev) { - kfree(sbridge_dev); - return NULL; - } - + sbridge_dev->n_devs = table->n_devs_per_imc; sbridge_dev->seg = seg; sbridge_dev->bus = bus; sbridge_dev->dom = dom; - sbridge_dev->n_devs = table->n_devs_per_imc; list_add_tail(&sbridge_dev->list, &sbridge_edac_list); return sbridge_dev; @@ -794,7 +787,6 @@ static struct sbridge_dev *alloc_sbridge_dev(int seg, u8 bus, enum domain dom, static void free_sbridge_dev(struct sbridge_dev *sbridge_dev) { list_del(&sbridge_dev->list); - kfree(sbridge_dev->pdev); kfree(sbridge_dev); } diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index 2cbc13d9bd00..ec1315582414 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -70,6 +70,8 @@ #define XDDR5_BUS_WIDTH_32 1 #define XDDR5_BUS_WIDTH_16 2 +#define MC_NAME_LEN 32 + /** * struct ecc_error_info - ECC error log information. * @burstpos: Burst position. @@ -760,7 +762,17 @@ static void versal_edac_release(struct device *dev) kfree(dev); } -static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev) +static void remove_one_mc(struct mc_priv *priv, int i) +{ + struct mem_ctl_info *mci; + + mci = priv->mci[i]; + device_unregister(mci->pdev); + edac_mc_del_mc(mci->pdev); + edac_mc_free(mci); +} + +static int init_one_mc(struct mc_priv *priv, struct platform_device *pdev, int i) { u32 num_chans, rank, dwidth, config; struct edac_mc_layer layers[2]; @@ -768,112 +780,120 @@ static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev) struct device *dev; enum dev_type dt; char *name; - int rc, i; - - for (i = 0; i < NUM_CONTROLLERS; i++) { - config = priv->adec[CONF + i * ADEC_NUM]; - num_chans = FIELD_GET(MC5_NUM_CHANS_MASK, config); - rank = 1 << FIELD_GET(MC5_RANK_MASK, config); - dwidth = FIELD_GET(MC5_BUS_WIDTH_MASK, config); - - switch (dwidth) { - case XDDR5_BUS_WIDTH_16: - dt = DEV_X16; - break; - case XDDR5_BUS_WIDTH_32: - dt = DEV_X32; - break; - case XDDR5_BUS_WIDTH_64: - dt = DEV_X64; - break; - default: - dt = DEV_UNKNOWN; - } + int rc; - if (dt == DEV_UNKNOWN) - continue; + config = priv->adec[CONF + i * ADEC_NUM]; + num_chans = FIELD_GET(MC5_NUM_CHANS_MASK, config); + rank = 1 << FIELD_GET(MC5_RANK_MASK, config); + dwidth = FIELD_GET(MC5_BUS_WIDTH_MASK, config); + + switch (dwidth) { + case XDDR5_BUS_WIDTH_16: + dt = DEV_X16; + break; + case XDDR5_BUS_WIDTH_32: + dt = DEV_X32; + break; + case XDDR5_BUS_WIDTH_64: + dt = DEV_X64; + break; + default: + dt = DEV_UNKNOWN; + } - /* Find the first enabled device and register that one. */ - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = rank; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = num_chans; - layers[1].is_virt_csrow = false; + if (dt == DEV_UNKNOWN) + return 0; - rc = -ENOMEM; - mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, - sizeof(struct mc_priv)); - if (!mci) { - edac_printk(KERN_ERR, EDAC_MC, "Failed memory allocation for MC%d\n", i); - goto err_alloc; - } + /* Find the first enabled device and register that one. */ + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = rank; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = num_chans; + layers[1].is_virt_csrow = false; + + rc = -ENOMEM; + name = kzalloc(MC_NAME_LEN, GFP_KERNEL); + if (!name) + return rc; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + goto err_name_free; + + mci = edac_mc_alloc(i, ARRAY_SIZE(layers), layers, sizeof(struct mc_priv)); + if (!mci) { + edac_printk(KERN_ERR, EDAC_MC, "Failed memory allocation for MC%d\n", i); + goto err_dev_free; + } - priv->mci[i] = mci; - priv->dwidth = dt; + sprintf(name, "versal-net-ddrmc5-edac-%d", i); - dev = kzalloc_obj(*dev); - dev->release = versal_edac_release; - name = kmalloc(32, GFP_KERNEL); - sprintf(name, "versal-net-ddrmc5-edac-%d", i); - dev->init_name = name; - rc = device_register(dev); - if (rc) - goto err_alloc; + dev->init_name = name; + dev->release = versal_edac_release; - mci->pdev = dev; + rc = device_register(dev); + if (rc) + goto err_mc_free; - platform_set_drvdata(pdev, priv); + mci->pdev = dev; + mc_init(mci, dev); - mc_init(mci, dev); - rc = edac_mc_add_mc(mci); - if (rc) { - edac_printk(KERN_ERR, EDAC_MC, "Failed to register MC%d with EDAC core\n", i); - goto err_alloc; - } + rc = edac_mc_add_mc(mci); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, "Failed to register MC%d with EDAC core\n", i); + goto err_unreg; } - return 0; -err_alloc: - while (i--) { - mci = priv->mci[i]; - if (!mci) - continue; - - if (mci->pdev) { - device_unregister(mci->pdev); - edac_mc_del_mc(mci->pdev); - } + priv->mci[i] = mci; + priv->dwidth = dt; - edac_mc_free(mci); - } + platform_set_drvdata(pdev, priv); + + return 0; + +err_unreg: + device_unregister(mci->pdev); +err_mc_free: + edac_mc_free(mci); +err_dev_free: + kfree(dev); +err_name_free: + kfree(name); return rc; } -static void remove_versalnet(struct mc_priv *priv) +static int init_versalnet(struct mc_priv *priv, struct platform_device *pdev) { - struct mem_ctl_info *mci; - int i; + int rc, i; for (i = 0; i < NUM_CONTROLLERS; i++) { - device_unregister(priv->mci[i]->pdev); - mci = edac_mc_del_mc(priv->mci[i]->pdev); - if (!mci) - return; + rc = init_one_mc(priv, pdev, i); + if (rc) { + while (i--) + remove_one_mc(priv, i); - edac_mc_free(mci); + return rc; + } } + return 0; +} + +static void remove_versalnet(struct mc_priv *priv) +{ + for (int i = 0; i < NUM_CONTROLLERS; i++) + remove_one_mc(priv, i); } static int mc_probe(struct platform_device *pdev) { - struct device_node *r5_core_node; struct mc_priv *priv; struct rproc *rp; int rc; - r5_core_node = of_parse_phandle(pdev->dev.of_node, "amd,rproc", 0); + struct device_node *r5_core_node __free(device_node) = + of_parse_phandle(pdev->dev.of_node, "amd,rproc", 0); if (!r5_core_node) { dev_err(&pdev->dev, "amd,rproc: invalid phandle\n"); return -EINVAL; @@ -917,6 +937,7 @@ static int mc_probe(struct platform_device *pdev) err_init: cdx_mcdi_finish(priv->mcdi); + kfree(priv->mcdi); err_unreg: unregister_rpmsg_driver(&amd_rpmsg_driver); @@ -938,6 +959,7 @@ static void mc_remove(struct platform_device *pdev) remove_versalnet(priv); rproc_shutdown(priv->mcdi->r5_rproc); cdx_mcdi_finish(priv->mcdi); + kfree(priv->mcdi); } static const struct of_device_id amd_edac_match[] = { |
