summaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi/ipmi_si_platform.c
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2019-02-21 12:10:07 -0600
committerCorey Minyard <cminyard@mvista.com>2019-02-22 07:12:41 -0600
commit41b766d661bf94a364960862cfc248a78313dbd3 (patch)
treee623d8249e3d353e59d0cd6a09b333c3c069bb6f /drivers/char/ipmi/ipmi_si_platform.c
parentf32043901a389ee8b5417c0cec547a84a2f9b38a (diff)
downloadlinux-stable-41b766d661bf94a364960862cfc248a78313dbd3.tar.gz
linux-stable-41b766d661bf94a364960862cfc248a78313dbd3.tar.bz2
linux-stable-41b766d661bf94a364960862cfc248a78313dbd3.zip
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_platform.c')
-rw-r--r--drivers/char/ipmi/ipmi_si_platform.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c
index 15cf819f884f..8158d03542f4 100644
--- a/drivers/char/ipmi/ipmi_si_platform.c
+++ b/drivers/char/ipmi/ipmi_si_platform.c
@@ -128,8 +128,6 @@ ipmi_get_info_from_resources(struct platform_device *pdev,
if (res_second->start > io->addr_data)
io->regspacing = res_second->start - io->addr_data;
}
- io->regsize = DEFAULT_REGSIZE;
- io->regshift = 0;
return res;
}
@@ -137,7 +135,7 @@ ipmi_get_info_from_resources(struct platform_device *pdev,
static int platform_ipmi_probe(struct platform_device *pdev)
{
struct si_sm_io io;
- u8 type, slave_addr, addr_source;
+ u8 type, slave_addr, addr_source, regsize, regshift;
int rv;
rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source);
@@ -149,7 +147,7 @@ static int platform_ipmi_probe(struct platform_device *pdev)
if (addr_source == SI_SMBIOS) {
if (!si_trydmi)
return -ENODEV;
- } else {
+ } else if (addr_source != SI_HARDCODED) {
if (!si_tryplatform)
return -ENODEV;
}
@@ -169,11 +167,23 @@ static int platform_ipmi_probe(struct platform_device *pdev)
case SI_BT:
io.si_type = type;
break;
+ case SI_TYPE_INVALID: /* User disabled this in hardcode. */
+ return -ENODEV;
default:
dev_err(&pdev->dev, "ipmi-type property is invalid\n");
return -EINVAL;
}
+ io.regsize = DEFAULT_REGSIZE;
+ rv = device_property_read_u8(&pdev->dev, "reg-size", &regsize);
+ if (!rv)
+ io.regsize = regsize;
+
+ io.regshift = 0;
+ rv = device_property_read_u8(&pdev->dev, "reg-shift", &regshift);
+ if (!rv)
+ io.regshift = regshift;
+
if (!ipmi_get_info_from_resources(pdev, &io))
return -EINVAL;
@@ -193,7 +203,8 @@ static int platform_ipmi_probe(struct platform_device *pdev)
io.dev = &pdev->dev;
- pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n",
+ pr_info("ipmi_si: %s: %s %#lx regsize %d spacing %d irq %d\n",
+ ipmi_addr_src_to_str(addr_source),
(io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
io.addr_data, io.regsize, io.regspacing, io.irq);
@@ -358,6 +369,9 @@ static int acpi_ipmi_probe(struct platform_device *pdev)
goto err_free;
}
+ io.regsize = DEFAULT_REGSIZE;
+ io.regshift = 0;
+
res = ipmi_get_info_from_resources(pdev, &io);
if (!res) {
rv = -EINVAL;
@@ -420,8 +434,9 @@ static int ipmi_remove(struct platform_device *pdev)
}
static const struct platform_device_id si_plat_ids[] = {
- { "dmi-ipmi-si", 0 },
- { }
+ { "dmi-ipmi-si", 0 },
+ { "hardcode-ipmi-si", 0 },
+ { }
};
struct platform_driver ipmi_platform_driver = {