mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
Reference in New Issue
Block a user