From bdb57b7bc16252599cbcb826dfdf7e394dd2af4b Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 21 Feb 2019 17:21:50 -0600 Subject: [PATCH] ipmi_si: Remove hotmod devices on removal and exit When a hotmod-added device is removed or when the module is removed, remove the platform devices that was created for it. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si.h | 5 +++-- drivers/char/ipmi/ipmi_si_hotmod.c | 32 +++++++++++++++++++++++++++++++- drivers/char/ipmi/ipmi_si_intf.c | 12 +++++++++--- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index 49b211b..2ae9ebd 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -21,10 +21,11 @@ void ipmi_irq_start_cleanup(struct si_sm_io *io); int ipmi_std_irq_setup(struct si_sm_io *io); void ipmi_irq_finish_setup(struct si_sm_io *io); int ipmi_si_remove_by_dev(struct device *dev); -void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, - unsigned long addr); +struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, + unsigned long addr); void ipmi_hardcode_init(void); void ipmi_si_hardcode_exit(void); +void ipmi_si_hotmod_exit(void); int ipmi_si_hardcode_match(int addr_space, unsigned long addr); void ipmi_si_platform_init(void); void ipmi_si_platform_shutdown(void); diff --git a/drivers/char/ipmi/ipmi_si_hotmod.c b/drivers/char/ipmi/ipmi_si_hotmod.c index f0728be..230b10e 100644 --- a/drivers/char/ipmi/ipmi_si_hotmod.c +++ b/drivers/char/ipmi/ipmi_si_hotmod.c @@ -219,7 +219,18 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp) atomic_inc_return(&hotmod_nr), &h); } else { - ipmi_si_remove_by_data(h.space, h.type, h.addr); + struct device *dev; + + dev = ipmi_si_remove_by_data(h.space, h.type, h.addr); + if (dev && dev_is_platform(dev)) { + struct platform_device *pdev; + + pdev = to_platform_device(dev); + if (strcmp(pdev->name, "hotmod-ipmi-si") == 0) + platform_device_unregister(pdev); + } + if (dev) + put_device(dev); } } rv = len; @@ -227,3 +238,22 @@ out: kfree(str); return rv; } + +static int pdev_match_name(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + + return strcmp(pdev->name, "hotmod-ipmi-si") == 0; +} + +void ipmi_si_hotmod_exit(void) +{ + struct device *dev; + + while ((dev = bus_find_device(&platform_bus_type, NULL, NULL, + pdev_match_name))) { + struct platform_device *pdev = to_platform_device(dev); + + platform_device_unregister(pdev); + } +} diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index c8af06d..9b3a272 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2281,11 +2281,12 @@ int ipmi_si_remove_by_dev(struct device *dev) return rv; } -void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, - unsigned long addr) +struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, + unsigned long addr) { /* remove */ struct smi_info *e, *tmp_e; + struct device *dev = NULL; mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { @@ -2293,10 +2294,14 @@ void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, continue; if (e->io.si_type != si_type) continue; - if (e->io.addr_data == addr) + if (e->io.addr_data == addr) { + dev = get_device(e->io.dev); cleanup_one_si(e); + } } mutex_unlock(&smi_infos_lock); + + return dev; } static void cleanup_ipmi_si(void) @@ -2318,6 +2323,7 @@ static void cleanup_ipmi_si(void) mutex_unlock(&smi_infos_lock); ipmi_si_hardcode_exit(); + ipmi_si_hotmod_exit(); } module_exit(cleanup_ipmi_si); -- 2.7.4