FAILED: patch "[PATCH] ipmi_si: Fix crash when using hard-coded device" failed to apply to 4.19-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.19-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 41b766d661bf94a364960862cfc248a78313dbd3 Mon Sep 17 00:00:00 2001
From: Corey Minyard <[email protected]>
Date: Thu, 21 Feb 2019 12:10:07 -0600
Subject: [PATCH] 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.
drivers/char/ipmi/ipmi_si.h +3 -1
@@ -25,7 +25,9 @@ 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); -int ipmi_si_hardcode_find_bmc (void ); +void ipmi_hardcode_init (void ); +void ipmi_si_hardcode_exit (void ); +int ipmi_si_hardcode_match (int addr_type,unsigned long addr);void ipmi_si_platform_init (void );void ipmi_si_platform_shutdown (void );
drivers/char/ipmi/ipmi_si_hardcode.c +174 -62
269 lines not on this page · raw message
drivers/char/ipmi/ipmi_si_intf.c +17 -6
@@ -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);
drivers/char/ipmi/ipmi_si_platform.c +22 -7
@@ -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 = {