diff options
author | Corey Minyard <cminyard@mvista.com> | 2019-02-21 12:10:07 -0600 |
---|---|---|
committer | Corey Minyard <cminyard@mvista.com> | 2019-02-22 07:12:41 -0600 |
commit | 41b766d661bf94a364960862cfc248a78313dbd3 (patch) | |
tree | e623d8249e3d353e59d0cd6a09b333c3c069bb6f /drivers/char/ipmi/ipmi_si_platform.c | |
parent | f32043901a389ee8b5417c0cec547a84a2f9b38a (diff) | |
download | linux-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.c | 29 |
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", ®size); + if (!rv) + io.regsize = regsize; + + io.regshift = 0; + rv = device_property_read_u8(&pdev->dev, "reg-shift", ®shift); + 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 = { |