summaryrefslogtreecommitdiff
path: root/drivers/char/ipmi/ipmi_si_intf.c
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2019-02-21 21:10:07 +0300
committerCorey Minyard <cminyard@mvista.com>2019-02-22 16:12:41 +0300
commit41b766d661bf94a364960862cfc248a78313dbd3 (patch)
treee623d8249e3d353e59d0cd6a09b333c3c069bb6f /drivers/char/ipmi/ipmi_si_intf.c
parentf32043901a389ee8b5417c0cec547a84a2f9b38a (diff)
downloadlinux-41b766d661bf94a364960862cfc248a78313dbd3.tar.xz
ipmi_si: Fix crash when using hard-coded device
When excuting a command like: modprobe ipmi_si ports=0xffc0e3 type=bt The system would get an oops. The trouble here is that ipmi_si_hardcode_find_bmc() is called before ipmi_si_platform_init(), but initialization of the hard-coded device creates an IPMI platform device, which won't be initialized yet. The real trouble is that hard-coded devices aren't created with any device, and the fixup is done later. So do it right, create the hard-coded devices as normal platform devices. This required adding some new resource types to the IPMI platform code for passing information required by the hard-coded device and adding some code to remove the hard-coded platform devices on module removal. To enforce the "hard-coded devices passed by the user take priority over firmware devices" rule, some special code was added to check and see if a hard-coded device already exists. Reported-by: Yang Yingliang <yangyingliang@huawei.com> Cc: stable@vger.kernel.org # v4.15+ Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: Yang Yingliang <yangyingliang@huawei.com>
Diffstat (limited to 'drivers/char/ipmi/ipmi_si_intf.c')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index ae99d6a14789..abbd526626d5 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1865,6 +1865,18 @@ int ipmi_si_add_smi(struct si_sm_io *io)
int rv = 0;
struct smi_info *new_smi, *dup;
+ /*
+ * If the user gave us a hard-coded device at the same
+ * address, they presumably want us to use it and not what is
+ * in the firmware.
+ */
+ if (io->addr_source != SI_HARDCODED &&
+ ipmi_si_hardcode_match(io->addr_type, io->addr_data)) {
+ dev_info(io->dev,
+ "Hard-coded device at this address already exists");
+ return -ENODEV;
+ }
+
if (!io->io_setup) {
if (io->addr_type == IPMI_IO_ADDR_SPACE) {
io->io_setup = ipmi_si_port_setup;
@@ -2097,7 +2109,7 @@ static int try_smi_init(struct smi_info *new_smi)
return rv;
}
-static int init_ipmi_si(void)
+static int __init init_ipmi_si(void)
{
struct smi_info *e;
enum ipmi_addr_src type = SI_INVALID;
@@ -2105,11 +2117,9 @@ static int init_ipmi_si(void)
if (initialized)
return 0;
- pr_info("IPMI System Interface driver\n");
+ ipmi_hardcode_init();
- /* If the user gave us a device, they presumably want us to use it */
- if (!ipmi_si_hardcode_find_bmc())
- goto do_scan;
+ pr_info("IPMI System Interface driver\n");
ipmi_si_platform_init();
@@ -2121,7 +2131,6 @@ static int init_ipmi_si(void)
with multiple BMCs we assume that there will be several instances
of a given type so if we succeed in registering a type then also
try to register everything else of the same type */
-do_scan:
mutex_lock(&smi_infos_lock);
list_for_each_entry(e, &smi_infos, link) {
/* Try to register a device if it has an IRQ and we either
@@ -2307,6 +2316,8 @@ static void cleanup_ipmi_si(void)
list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
cleanup_one_si(e);
mutex_unlock(&smi_infos_lock);
+
+ ipmi_si_hardcode_exit();
}
module_exit(cleanup_ipmi_si);