--- /dev/null
+From 41b766d661bf94a364960862cfc248a78313dbd3 Mon Sep 17 00:00:00 2001
+From: Corey Minyard <cminyard@mvista.com>
+Date: Thu, 21 Feb 2019 12:10:07 -0600
+Subject: ipmi_si: Fix crash when using hard-coded device
+
+From: Corey Minyard <cminyard@mvista.com>
+
+commit 41b766d661bf94a364960862cfc248a78313dbd3 upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/ipmi/ipmi_si.h | 4
+ drivers/char/ipmi/ipmi_si_hardcode.c | 232 +++++++++++++++++++++++++----------
+ drivers/char/ipmi/ipmi_si_intf.c | 23 ++-
+ drivers/char/ipmi/ipmi_si_platform.c | 29 +++-
+ 4 files changed, 214 insertions(+), 74 deletions(-)
+
+--- a/drivers/char/ipmi/ipmi_si.h
++++ b/drivers/char/ipmi/ipmi_si.h
+@@ -25,7 +25,9 @@ void ipmi_irq_finish_setup(struct si_sm_
+ 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);
+
+--- a/drivers/char/ipmi/ipmi_si_hardcode.c
++++ b/drivers/char/ipmi/ipmi_si_hardcode.c
+@@ -3,6 +3,7 @@
+ #define pr_fmt(fmt) "ipmi_hardcode: " fmt
+
+ #include <linux/moduleparam.h>
++#include <linux/platform_device.h>
+ #include "ipmi_si.h"
+
+ /*
+@@ -12,23 +13,22 @@
+
+ #define SI_MAX_PARMS 4
+
+-static char *si_type[SI_MAX_PARMS];
+ #define MAX_SI_TYPE_STR 30
+-static char si_type_str[MAX_SI_TYPE_STR];
++static char si_type_str[MAX_SI_TYPE_STR] __initdata;
+ static unsigned long addrs[SI_MAX_PARMS];
+ static unsigned int num_addrs;
+ static unsigned int ports[SI_MAX_PARMS];
+ static unsigned int num_ports;
+-static int irqs[SI_MAX_PARMS];
+-static unsigned int num_irqs;
+-static int regspacings[SI_MAX_PARMS];
+-static unsigned int num_regspacings;
+-static int regsizes[SI_MAX_PARMS];
+-static unsigned int num_regsizes;
+-static int regshifts[SI_MAX_PARMS];
+-static unsigned int num_regshifts;
+-static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */
+-static unsigned int num_slave_addrs;
++static int irqs[SI_MAX_PARMS] __initdata;
++static unsigned int num_irqs __initdata;
++static int regspacings[SI_MAX_PARMS] __initdata;
++static unsigned int num_regspacings __initdata;
++static int regsizes[SI_MAX_PARMS] __initdata;
++static unsigned int num_regsizes __initdata;
++static int regshifts[SI_MAX_PARMS] __initdata;
++static unsigned int num_regshifts __initdata;
++static int slave_addrs[SI_MAX_PARMS] __initdata;
++static unsigned int num_slave_addrs __initdata;
+
+ module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0);
+ MODULE_PARM_DESC(type, "Defines the type of each interface, each"
+@@ -73,12 +73,133 @@ MODULE_PARM_DESC(slave_addrs, "Set the d
+ " overridden by this parm. This is an array indexed"
+ " by interface number.");
+
+-int ipmi_si_hardcode_find_bmc(void)
++static struct platform_device *ipmi_hc_pdevs[SI_MAX_PARMS];
++
++static void __init ipmi_hardcode_init_one(const char *si_type_str,
++ unsigned int i,
++ unsigned long addr,
++ unsigned int flags)
++{
++ struct platform_device *pdev;
++ unsigned int num_r = 1, size;
++ struct resource r[4];
++ struct property_entry p[6];
++ enum si_type si_type;
++ unsigned int regspacing, regsize;
++ int rv;
++
++ memset(p, 0, sizeof(p));
++ memset(r, 0, sizeof(r));
++
++ if (!si_type_str || !*si_type_str || strcmp(si_type_str, "kcs") == 0) {
++ size = 2;
++ si_type = SI_KCS;
++ } else if (strcmp(si_type_str, "smic") == 0) {
++ size = 2;
++ si_type = SI_SMIC;
++ } else if (strcmp(si_type_str, "bt") == 0) {
++ size = 3;
++ si_type = SI_BT;
++ } else if (strcmp(si_type_str, "invalid") == 0) {
++ /*
++ * Allow a firmware-specified interface to be
++ * disabled.
++ */
++ size = 1;
++ si_type = SI_TYPE_INVALID;
++ } else {
++ pr_warn("Interface type specified for interface %d, was invalid: %s\n",
++ i, si_type_str);
++ return;
++ }
++
++ regsize = regsizes[i];
++ if (regsize == 0)
++ regsize = DEFAULT_REGSIZE;
++
++ p[0] = PROPERTY_ENTRY_U8("ipmi-type", si_type);
++ p[1] = PROPERTY_ENTRY_U8("slave-addr", slave_addrs[i]);
++ p[2] = PROPERTY_ENTRY_U8("addr-source", SI_HARDCODED);
++ p[3] = PROPERTY_ENTRY_U8("reg-shift", regshifts[i]);
++ p[4] = PROPERTY_ENTRY_U8("reg-size", regsize);
++ /* Last entry must be left NULL to terminate it. */
++
++ /*
++ * Register spacing is derived from the resources in
++ * the IPMI platform code.
++ */
++ regspacing = regspacings[i];
++ if (regspacing == 0)
++ regspacing = regsize;
++
++ r[0].start = addr;
++ r[0].end = r[0].start + regsize - 1;
++ r[0].name = "IPMI Address 1";
++ r[0].flags = flags;
++
++ if (size > 1) {
++ r[1].start = r[0].start + regspacing;
++ r[1].end = r[1].start + regsize - 1;
++ r[1].name = "IPMI Address 2";
++ r[1].flags = flags;
++ num_r++;
++ }
++
++ if (size > 2) {
++ r[2].start = r[1].start + regspacing;
++ r[2].end = r[2].start + regsize - 1;
++ r[2].name = "IPMI Address 3";
++ r[2].flags = flags;
++ num_r++;
++ }
++
++ if (irqs[i]) {
++ r[num_r].start = irqs[i];
++ r[num_r].end = irqs[i];
++ r[num_r].name = "IPMI IRQ";
++ r[num_r].flags = IORESOURCE_IRQ;
++ num_r++;
++ }
++
++ pdev = platform_device_alloc("hardcode-ipmi-si", i);
++ if (!pdev) {
++ pr_err("Error allocating IPMI platform device %d\n", i);
++ return;
++ }
++
++ rv = platform_device_add_resources(pdev, r, num_r);
++ if (rv) {
++ dev_err(&pdev->dev,
++ "Unable to add hard-code resources: %d\n", rv);
++ goto err;
++ }
++
++ rv = platform_device_add_properties(pdev, p);
++ if (rv) {
++ dev_err(&pdev->dev,
++ "Unable to add hard-code properties: %d\n", rv);
++ goto err;
++ }
++
++ rv = platform_device_add(pdev);
++ if (rv) {
++ dev_err(&pdev->dev,
++ "Unable to add hard-code device: %d\n", rv);
++ goto err;
++ }
++
++ ipmi_hc_pdevs[i] = pdev;
++ return;
++
++err:
++ platform_device_put(pdev);
++}
++
++void __init ipmi_hardcode_init(void)
+ {
+- int ret = -ENODEV;
+- int i;
+- struct si_sm_io io;
++ unsigned int i;
+ char *str;
++ char *si_type[SI_MAX_PARMS];
+
+ /* Parse out the si_type string into its components. */
+ str = si_type_str;
+@@ -95,54 +216,45 @@ int ipmi_si_hardcode_find_bmc(void)
+ }
+ }
+
+- memset(&io, 0, sizeof(io));
+ for (i = 0; i < SI_MAX_PARMS; i++) {
+- if (!ports[i] && !addrs[i])
+- continue;
+-
+- io.addr_source = SI_HARDCODED;
+- pr_info("probing via hardcoded address\n");
++ if (i < num_ports && ports[i])
++ ipmi_hardcode_init_one(si_type[i], i, ports[i],
++ IORESOURCE_IO);
++ if (i < num_addrs && addrs[i])
++ ipmi_hardcode_init_one(si_type[i], i, addrs[i],
++ IORESOURCE_MEM);
++ }
++}
+
+- if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
+- io.si_type = SI_KCS;
+- } else if (strcmp(si_type[i], "smic") == 0) {
+- io.si_type = SI_SMIC;
+- } else if (strcmp(si_type[i], "bt") == 0) {
+- io.si_type = SI_BT;
+- } else {
+- pr_warn("Interface type specified for interface %d, was invalid: %s\n",
+- i, si_type[i]);
+- continue;
+- }
++void ipmi_si_hardcode_exit(void)
++{
++ unsigned int i;
+
+- if (ports[i]) {
+- /* An I/O port */
+- io.addr_data = ports[i];
+- io.addr_type = IPMI_IO_ADDR_SPACE;
+- } else if (addrs[i]) {
+- /* A memory port */
+- io.addr_data = addrs[i];
+- io.addr_type = IPMI_MEM_ADDR_SPACE;
+- } else {
+- pr_warn("Interface type specified for interface %d, but port and address were not set or set to zero\n",
+- i);
+- continue;
+- }
++ for (i = 0; i < SI_MAX_PARMS; i++) {
++ if (ipmi_hc_pdevs[i])
++ platform_device_unregister(ipmi_hc_pdevs[i]);
++ }
++}
+
+- io.addr = NULL;
+- io.regspacing = regspacings[i];
+- if (!io.regspacing)
+- io.regspacing = DEFAULT_REGSPACING;
+- io.regsize = regsizes[i];
+- if (!io.regsize)
+- io.regsize = DEFAULT_REGSIZE;
+- io.regshift = regshifts[i];
+- io.irq = irqs[i];
+- if (io.irq)
+- io.irq_setup = ipmi_std_irq_setup;
+- io.slave_addr = slave_addrs[i];
++/*
++ * Returns true of the given address exists as a hardcoded address,
++ * false if not.
++ */
++int ipmi_si_hardcode_match(int addr_type, unsigned long addr)
++{
++ unsigned int i;
+
+- ret = ipmi_si_add_smi(&io);
++ if (addr_type == IPMI_IO_ADDR_SPACE) {
++ for (i = 0; i < num_ports; i++) {
++ if (ports[i] == addr)
++ return 1;
++ }
++ } else {
++ for (i = 0; i < num_addrs; i++) {
++ if (addrs[i] == addr)
++ return 1;
++ }
+ }
+- return ret;
++
++ return 0;
+ }
+--- a/drivers/char/ipmi/ipmi_si_intf.c
++++ b/drivers/char/ipmi/ipmi_si_intf.c
+@@ -1862,6 +1862,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;
+@@ -2089,7 +2101,7 @@ static int try_smi_init(struct smi_info
+ 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;
+@@ -2097,11 +2109,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();
+
+@@ -2113,7 +2123,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
+@@ -2299,6 +2308,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);
+
+--- 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 plat
+ 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 plat
+ 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 pl
+ 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 pl
+ 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 pl
+
+ 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 platfo
+ 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_d
+ }
+
+ 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 = {
--- /dev/null
+From 401e7e88d4ef80188ffa07095ac00456f901b8c4 Mon Sep 17 00:00:00 2001
+From: Yang Yingliang <yangyingliang@huawei.com>
+Date: Mon, 28 Jan 2019 11:08:54 +0800
+Subject: ipmi_si: fix use-after-free of resource->name
+
+From: Yang Yingliang <yangyingliang@huawei.com>
+
+commit 401e7e88d4ef80188ffa07095ac00456f901b8c4 upstream.
+
+When we excute the following commands, we got oops
+rmmod ipmi_si
+cat /proc/ioports
+
+[ 1623.482380] Unable to handle kernel paging request at virtual address ffff00000901d478
+[ 1623.482382] Mem abort info:
+[ 1623.482383] ESR = 0x96000007
+[ 1623.482385] Exception class = DABT (current EL), IL = 32 bits
+[ 1623.482386] SET = 0, FnV = 0
+[ 1623.482387] EA = 0, S1PTW = 0
+[ 1623.482388] Data abort info:
+[ 1623.482389] ISV = 0, ISS = 0x00000007
+[ 1623.482390] CM = 0, WnR = 0
+[ 1623.482393] swapper pgtable: 4k pages, 48-bit VAs, pgdp = 00000000d7d94a66
+[ 1623.482395] [ffff00000901d478] pgd=000000dffbfff003, pud=000000dffbffe003, pmd=0000003f5d06e003, pte=0000000000000000
+[ 1623.482399] Internal error: Oops: 96000007 [#1] SMP
+[ 1623.487407] Modules linked in: ipmi_si(E) nls_utf8 isofs rpcrdma ib_iser ib_srpt target_core_mod ib_srp scsi_transport_srp ib_ipoib rdma_ucm ib_umad rdma_cm ib_cm dm_mirror dm_region_hash dm_log iw_cm dm_mod aes_ce_blk crypto_simd cryptd aes_ce_cipher ses ghash_ce sha2_ce enclosure sha256_arm64 sg sha1_ce hisi_sas_v2_hw hibmc_drm sbsa_gwdt hisi_sas_main ip_tables mlx5_ib ib_uverbs marvell ib_core mlx5_core ixgbe mdio hns_dsaf ipmi_devintf hns_enet_drv ipmi_msghandler hns_mdio [last unloaded: ipmi_si]
+[ 1623.532410] CPU: 30 PID: 11438 Comm: cat Kdump: loaded Tainted: G E 5.0.0-rc3+ #168
+[ 1623.541498] Hardware name: Huawei TaiShan 2280 /BC11SPCD, BIOS 1.37 11/21/2017
+[ 1623.548822] pstate: a0000005 (NzCv daif -PAN -UAO)
+[ 1623.553684] pc : string+0x28/0x98
+[ 1623.557040] lr : vsnprintf+0x368/0x5e8
+[ 1623.560837] sp : ffff000013213a80
+[ 1623.564191] x29: ffff000013213a80 x28: ffff00001138abb5
+[ 1623.569577] x27: ffff000013213c18 x26: ffff805f67d06049
+[ 1623.574963] x25: 0000000000000000 x24: ffff00001138abb5
+[ 1623.580349] x23: 0000000000000fb7 x22: ffff0000117ed000
+[ 1623.585734] x21: ffff000011188fd8 x20: ffff805f67d07000
+[ 1623.591119] x19: ffff805f67d06061 x18: ffffffffffffffff
+[ 1623.596505] x17: 0000000000000200 x16: 0000000000000000
+[ 1623.601890] x15: ffff0000117ed748 x14: ffff805f67d07000
+[ 1623.607276] x13: ffff805f67d0605e x12: 0000000000000000
+[ 1623.612661] x11: 0000000000000000 x10: 0000000000000000
+[ 1623.618046] x9 : 0000000000000000 x8 : 000000000000000f
+[ 1623.623432] x7 : ffff805f67d06061 x6 : fffffffffffffffe
+[ 1623.628817] x5 : 0000000000000012 x4 : ffff00000901d478
+[ 1623.634203] x3 : ffff0a00ffffff04 x2 : ffff805f67d07000
+[ 1623.639588] x1 : ffff805f67d07000 x0 : ffffffffffffffff
+[ 1623.644974] Process cat (pid: 11438, stack limit = 0x000000008d4cbc10)
+[ 1623.651592] Call trace:
+[ 1623.654068] string+0x28/0x98
+[ 1623.657071] vsnprintf+0x368/0x5e8
+[ 1623.660517] seq_vprintf+0x70/0x98
+[ 1623.668009] seq_printf+0x7c/0xa0
+[ 1623.675530] r_show+0xc8/0xf8
+[ 1623.682558] seq_read+0x330/0x440
+[ 1623.689877] proc_reg_read+0x78/0xd0
+[ 1623.697346] __vfs_read+0x60/0x1a0
+[ 1623.704564] vfs_read+0x94/0x150
+[ 1623.711339] ksys_read+0x6c/0xd8
+[ 1623.717939] __arm64_sys_read+0x24/0x30
+[ 1623.725077] el0_svc_common+0x120/0x148
+[ 1623.732035] el0_svc_handler+0x30/0x40
+[ 1623.738757] el0_svc+0x8/0xc
+[ 1623.744520] Code: d1000406 aa0103e2 54000149 b4000080 (39400085)
+[ 1623.753441] ---[ end trace f91b6a4937de9835 ]---
+[ 1623.760871] Kernel panic - not syncing: Fatal exception
+[ 1623.768935] SMP: stopping secondary CPUs
+[ 1623.775718] Kernel Offset: disabled
+[ 1623.781998] CPU features: 0x002,21006008
+[ 1623.788777] Memory Limit: none
+[ 1623.798329] Starting crashdump kernel...
+[ 1623.805202] Bye!
+
+If io_setup is called successful in try_smi_init() but try_smi_init()
+goes out_err before calling ipmi_register_smi(), so ipmi_unregister_smi()
+will not be called while removing module. It leads to the resource that
+allocated in io_setup() can not be freed, but the name(DEVICE_NAME) of
+resource is freed while removing the module. It causes use-after-free
+when cat /proc/ioports.
+
+Fix this by calling io_cleanup() while try_smi_init() goes to out_err.
+and don't call io_cleanup() until io_setup() returns successful to avoid
+warning prints.
+
+Fixes: 93c303d2045b ("ipmi_si: Clean up shutdown a bit")
+Cc: stable@vger.kernel.org
+Reported-by: NuoHan Qiao <qiaonuohan@huawei.com>
+Suggested-by: Corey Minyard <cminyard@mvista.com>
+Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
+Signed-off-by: Corey Minyard <cminyard@mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/ipmi/ipmi_si_intf.c | 5 +++++
+ drivers/char/ipmi/ipmi_si_mem_io.c | 5 +++--
+ drivers/char/ipmi/ipmi_si_port_io.c | 5 +++--
+ 3 files changed, 11 insertions(+), 4 deletions(-)
+
+--- a/drivers/char/ipmi/ipmi_si_intf.c
++++ b/drivers/char/ipmi/ipmi_si_intf.c
+@@ -2097,6 +2097,11 @@ static int try_smi_init(struct smi_info
+ WARN_ON(new_smi->io.dev->init_name != NULL);
+
+ out_err:
++ if (rv && new_smi->io.io_cleanup) {
++ new_smi->io.io_cleanup(&new_smi->io);
++ new_smi->io.io_cleanup = NULL;
++ }
++
+ kfree(init_name);
+ return rv;
+ }
+--- a/drivers/char/ipmi/ipmi_si_mem_io.c
++++ b/drivers/char/ipmi/ipmi_si_mem_io.c
+@@ -81,8 +81,6 @@ int ipmi_si_mem_setup(struct si_sm_io *i
+ if (!addr)
+ return -ENODEV;
+
+- io->io_cleanup = mem_cleanup;
+-
+ /*
+ * Figure out the actual readb/readw/readl/etc routine to use based
+ * upon the register size.
+@@ -141,5 +139,8 @@ int ipmi_si_mem_setup(struct si_sm_io *i
+ mem_region_cleanup(io, io->io_size);
+ return -EIO;
+ }
++
++ io->io_cleanup = mem_cleanup;
++
+ return 0;
+ }
+--- a/drivers/char/ipmi/ipmi_si_port_io.c
++++ b/drivers/char/ipmi/ipmi_si_port_io.c
+@@ -68,8 +68,6 @@ int ipmi_si_port_setup(struct si_sm_io *
+ if (!addr)
+ return -ENODEV;
+
+- io->io_cleanup = port_cleanup;
+-
+ /*
+ * Figure out the actual inb/inw/inl/etc routine to use based
+ * upon the register size.
+@@ -109,5 +107,8 @@ int ipmi_si_port_setup(struct si_sm_io *
+ return -EIO;
+ }
+ }
++
++ io->io_cleanup = port_cleanup;
++
+ return 0;
+ }
--- /dev/null
+From 46c039d06b6ecabb94bd16c3a999b28dc83b79ce Mon Sep 17 00:00:00 2001
+From: Cody P Schafer <dev@codyps.com>
+Date: Mon, 14 Jan 2019 19:14:24 -0500
+Subject: media: cx25840: mark pad sig_types to fix cx231xx init
+
+From: Cody P Schafer <dev@codyps.com>
+
+commit 46c039d06b6ecabb94bd16c3a999b28dc83b79ce upstream.
+
+Without this, we get failures like this when the kernel attempts to
+initialize a cx231xx device:
+
+ [16046.153653] cx231xx 3-1.2:1.1: New device Hauppauge Hauppauge Device @ 480 Mbps (2040:c200) with 6 interfaces
+ [16046.153900] cx231xx 3-1.2:1.1: can't change interface 3 alt no. to 3: Max. Pkt size = 0
+ [16046.153907] cx231xx 3-1.2:1.1: Identified as Hauppauge USB Live 2 (card=9)
+ [16046.154350] i2c i2c-11: Added multiplexed i2c bus 13
+ [16046.154379] i2c i2c-11: Added multiplexed i2c bus 14
+ [16046.267194] cx25840 10-0044: cx23102 A/V decoder found @ 0x88 (cx231xx #0-0)
+ [16048.424551] cx25840 10-0044: loaded v4l-cx231xx-avcore-01.fw firmware (16382 bytes)
+ [16048.463224] cx231xx 3-1.2:1.1: v4l2 driver version 0.0.3
+ [16048.567878] cx231xx 3-1.2:1.1: Registered video device video2 [v4l2]
+ [16048.568001] cx231xx 3-1.2:1.1: Registered VBI device vbi0
+ [16048.568419] cx231xx 3-1.2:1.1: audio EndPoint Addr 0x83, Alternate settings: 3
+ [16048.568425] cx231xx 3-1.2:1.1: video EndPoint Addr 0x84, Alternate settings: 5
+ [16048.568431] cx231xx 3-1.2:1.1: VBI EndPoint Addr 0x85, Alternate settings: 2
+ [16048.568436] cx231xx 3-1.2:1.1: sliced CC EndPoint Addr 0x86, Alternate settings: 2
+ [16048.568448] usb 3-1.2: couldn't get decoder output pad for V4L I/O
+ [16048.568453] cx231xx 3-1.2:1.1: V4L2 device vbi0 deregistered
+ [16048.568579] cx231xx 3-1.2:1.1: V4L2 device video2 deregistered
+ [16048.569001] cx231xx: probe of 3-1.2:1.1 failed with error -22
+
+Likely a regession since Commit 9d6d20e652c0
+("media: v4l2-mc: switch it to use the new approach to setup pipelines")
+(v4.19-rc1-100-g9d6d20e652c0), which introduced the use of
+PAD_SIGNAL_DV within v4l2_mc_create_media_graph().
+
+This also modifies cx25840 to remove the VBI pad, matching the action
+taken in Commit 092a37875a22 ("media: v4l2: remove VBI output pad").
+
+Fixes: 9d6d20e652c0 ("media: v4l2-mc: switch it to use the new approach to setup pipelines")
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Cody P Schafer <dev@codyps.com>
+Tested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/i2c/cx25840/cx25840-core.c | 3 ++-
+ drivers/media/i2c/cx25840/cx25840-core.h | 1 -
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/i2c/cx25840/cx25840-core.c
++++ b/drivers/media/i2c/cx25840/cx25840-core.c
+@@ -5216,8 +5216,9 @@ static int cx25840_probe(struct i2c_clie
+ * those extra inputs. So, let's add it only when needed.
+ */
+ state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
++ state->pads[CX25840_PAD_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+- state->pads[CX25840_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
++ state->pads[CX25840_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
+ sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
+
+ ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
+--- a/drivers/media/i2c/cx25840/cx25840-core.h
++++ b/drivers/media/i2c/cx25840/cx25840-core.h
+@@ -40,7 +40,6 @@ enum cx25840_model {
+ enum cx25840_media_pads {
+ CX25840_PAD_INPUT,
+ CX25840_PAD_VID_OUT,
+- CX25840_PAD_VBI_OUT,
+
+ CX25840_NUM_PADS
+ };