Message ID | 20200306151318.17422-11-rrichter@marvell.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | EDAC/ghes: Cleanup, rework and improvement of memory reporting | expand |
On Fri, Mar 06, 2020 at 04:13:17PM +0100, Robert Richter wrote: > Each edac mc must have a unique device for identification (see > add_mc_to_global_list()). This 1:1 mapping between parent device and > mci is a limitation for supporting multiple instances created by the > ghes driver. Solve this by creating an own device in between of the > ghes parent and the mci struct, this allows a 1:n mapping between > both. > > Implement this using a platform device as this is the least possible > effort to create and free a device. It shows up nicely in sysfs: > > # find /sys/ -name ghes_mc* > /sys/devices/platform/GHES.0/ghes_mc.1 > /sys/devices/platform/GHES.0/ghes_mc.0 > /sys/bus/platform/devices/ghes_mc.1 > /sys/bus/platform/devices/ghes_mc.0 > > Signed-off-by: Robert Richter <rrichter@marvell.com> > --- > drivers/edac/ghes_edac.c | 26 +++++++++++++++++++++++--- > 1 file changed, 23 insertions(+), 3 deletions(-) > > diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c > index cd61b8ae49f6..64220397296e 100644 > --- a/drivers/edac/ghes_edac.c > +++ b/drivers/edac/ghes_edac.c > @@ -539,6 +539,8 @@ static struct acpi_platform_list plat_list[] = { > static struct mem_ctl_info *ghes_mc_create(struct device *dev, int mc_idx, > int num_dimm) > { > + struct platform_device_info pdevinfo; > + struct platform_device *pdev; > struct edac_mc_layer layers[1]; > struct mem_ctl_info *mci; > struct ghes_mci *pvt; > @@ -547,13 +549,23 @@ static struct mem_ctl_info *ghes_mc_create(struct device *dev, int mc_idx, > layers[0].size = num_dimm; > layers[0].is_virt_csrow = true; > > + pdevinfo = (struct platform_device_info){ > + .parent = dev, > + .name = "ghes_mc", > + .id = mc_idx, > + }; You can statically allocate that one once at the top of the file and assign ->parent and ->id each time before calling the function below. > + > + pdev = platform_device_register_full(&pdevinfo); > + if (IS_ERR(pdev)) > + goto fail; > +
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index cd61b8ae49f6..64220397296e 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -539,6 +539,8 @@ static struct acpi_platform_list plat_list[] = { static struct mem_ctl_info *ghes_mc_create(struct device *dev, int mc_idx, int num_dimm) { + struct platform_device_info pdevinfo; + struct platform_device *pdev; struct edac_mc_layer layers[1]; struct mem_ctl_info *mci; struct ghes_mci *pvt; @@ -547,13 +549,23 @@ static struct mem_ctl_info *ghes_mc_create(struct device *dev, int mc_idx, layers[0].size = num_dimm; layers[0].is_virt_csrow = true; + pdevinfo = (struct platform_device_info){ + .parent = dev, + .name = "ghes_mc", + .id = mc_idx, + }; + + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) + goto fail; + mci = edac_mc_alloc(mc_idx, ARRAY_SIZE(layers), layers, sizeof(*pvt)); if (!mci) - return NULL; + goto fail; pvt = mci->pvt_info; - mci->pdev = dev; + mci->pdev = &pdev->dev; mci->mtype_cap = MEM_FLAG_EMPTY; mci->edac_ctl_cap = EDAC_FLAG_NONE; mci->edac_cap = EDAC_FLAG_NONE; @@ -562,6 +574,11 @@ static struct mem_ctl_info *ghes_mc_create(struct device *dev, int mc_idx, mci->dev_name = "ghes"; return mci; + +fail: + platform_device_unregister(pdev); + + return NULL; } static int ghes_mc_add_or_free(struct mem_ctl_info *mci, @@ -573,6 +590,7 @@ static int ghes_mc_add_or_free(struct mem_ctl_info *mci, rc = edac_mc_add_mc(mci); if (rc < 0) { ghes_dimm_release(dimms); + platform_device_unregister(to_platform_device(mci->pdev)); edac_mc_free(mci); return rc; } @@ -609,8 +627,10 @@ static void ghes_mc_free(void) return; mci = edac_mc_del_mc(mci->pdev); - if (mci) + if (mci) { + platform_device_unregister(to_platform_device(mci->pdev)); edac_mc_free(mci); + } } static int ghes_edac_register_fake(struct device *dev)
Each edac mc must have a unique device for identification (see add_mc_to_global_list()). This 1:1 mapping between parent device and mci is a limitation for supporting multiple instances created by the ghes driver. Solve this by creating an own device in between of the ghes parent and the mci struct, this allows a 1:n mapping between both. Implement this using a platform device as this is the least possible effort to create and free a device. It shows up nicely in sysfs: # find /sys/ -name ghes_mc* /sys/devices/platform/GHES.0/ghes_mc.1 /sys/devices/platform/GHES.0/ghes_mc.0 /sys/bus/platform/devices/ghes_mc.1 /sys/bus/platform/devices/ghes_mc.0 Signed-off-by: Robert Richter <rrichter@marvell.com> --- drivers/edac/ghes_edac.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-)