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>
This commit is contained in:
Borislav Petkov (AMD)
2026-04-13 11:43:52 +02:00
5 changed files with 132 additions and 108 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
int rc;
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);
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;
}
if (dt == DEV_UNKNOWN)
continue;
/* 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;
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;
}
priv->mci[i] = mci;
priv->dwidth = dt;
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;
mci->pdev = dev;
platform_set_drvdata(pdev, priv);
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;
}
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;
}
if (dt == DEV_UNKNOWN)
return 0;
/* 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;
}
sprintf(name, "versal-net-ddrmc5-edac-%d", i);
dev->init_name = name;
dev->release = versal_edac_release;
rc = device_register(dev);
if (rc)
goto err_mc_free;
mci->pdev = 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_unreg;
}
priv->mci[i] = mci;
priv->dwidth = dt;
platform_set_drvdata(pdev, priv);
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);
}
edac_mc_free(mci);
}
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[] = {