Blob Blame History Raw
From 95e300c052fd9dbb05f289a912c138ed03320ec5 Mon Sep 17 00:00:00 2001
From: Corey Minyard <cminyard@mvista.com>
Date: Mon, 18 Sep 2017 12:38:17 -0500
Subject: [PATCH] ipmi: Make the DMI probe into a generic platform probe
Git-commit: 95e300c052fd9dbb05f289a912c138ed03320ec5
Patch-mainline: v4.15-rc1
References: FATE#326156

Rework the DMI probe function to be a generic platform probe, and
then rework the DMI code (and a few other things) to use the more
generic information.  This is so other things can declare platform
IPMI devices.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/char/ipmi/ipmi_dmi.c         |  70 +++++++++++++------
 drivers/char/ipmi/ipmi_dmi.h         |   8 +--
 drivers/char/ipmi/ipmi_msghandler.c  |   2 +-
 drivers/char/ipmi/ipmi_si_intf.c     |   2 +-
 drivers/char/ipmi/ipmi_si_platform.c | 101 ++++++++++++---------------
 drivers/char/ipmi/ipmi_si_sm.h       |   2 +-
 drivers/char/ipmi/ipmi_ssif.c        |  12 +---
 include/linux/ipmi.h                 |   2 +-
 8 files changed, 104 insertions(+), 95 deletions(-)

diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c
index 2a84401dea05..d08d41903b0f 100644
--- a/drivers/char/ipmi/ipmi_dmi.c
+++ b/drivers/char/ipmi/ipmi_dmi.c
@@ -8,10 +8,16 @@
 #include <linux/dmi.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
+#include "ipmi_si_sm.h"
 #include "ipmi_dmi.h"
 
+#define IPMI_DMI_TYPE_KCS	0x01
+#define IPMI_DMI_TYPE_SMIC	0x02
+#define IPMI_DMI_TYPE_BT	0x03
+#define IPMI_DMI_TYPE_SSIF	0x04
+
 struct ipmi_dmi_info {
-	int type;
+	enum si_type si_type;
 	u32 flags;
 	unsigned long addr;
 	u8 slave_addr;
@@ -22,6 +28,15 @@ static struct ipmi_dmi_info *ipmi_dmi_infos;
 
 static int ipmi_dmi_nr __initdata;
 
+#define set_prop_entry(_p_, _name_, type, val)	\
+do {					\
+	struct property_entry *_p = &_p_;	\
+	_p->name = _name_;			\
+	_p->length = sizeof(type);		\
+	_p->is_string = false;			\
+	_p->value.type##_data = val;		\
+} while(0)
+
 static void __init dmi_add_platform_ipmi(unsigned long base_addr,
 					 u32 flags,
 					 u8 slave_addr,
@@ -32,27 +47,14 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
 	struct platform_device *pdev;
 	struct resource r[4];
 	unsigned int num_r = 1, size;
-	struct property_entry p[4] = {
-		PROPERTY_ENTRY_U8("slave-addr", slave_addr),
-		PROPERTY_ENTRY_U8("ipmi-type", type),
-		PROPERTY_ENTRY_U16("i2c-addr", base_addr),
-		{ }
-	};
+	struct property_entry p[5];
+	unsigned int pidx = 0;
 	char *name, *override;
 	int rv;
+	enum si_type si_type;
 	struct ipmi_dmi_info *info;
 
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (!info) {
-		pr_warn("ipmi:dmi: Could not allocate dmi info\n");
-	} else {
-		info->type = type;
-		info->flags = flags;
-		info->addr = base_addr;
-		info->slave_addr = slave_addr;
-		info->next = ipmi_dmi_infos;
-		ipmi_dmi_infos = info;
-	}
+	memset(p, 0, sizeof(p));
 
 	name = "dmi-ipmi-si";
 	override = "ipmi_si";
@@ -62,19 +64,42 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
 		override = "ipmi_ssif";
 		offset = 1;
 		size = 1;
+		si_type = SI_TYPE_INVALID;
 		break;
 	case IPMI_DMI_TYPE_BT:
 		size = 3;
+		si_type = SI_BT;
 		break;
 	case IPMI_DMI_TYPE_KCS:
+		size = 2;
+		si_type = SI_KCS;
+		break;
 	case IPMI_DMI_TYPE_SMIC:
 		size = 2;
+		si_type = SI_SMIC;
 		break;
 	default:
 		pr_err("ipmi:dmi: Invalid IPMI type: %d", type);
 		return;
 	}
 
+	if (si_type != SI_TYPE_INVALID)
+		set_prop_entry(p[pidx++], "ipmi-type", u8, si_type);
+	set_prop_entry(p[pidx++], "slave-addr", u8, slave_addr);
+	set_prop_entry(p[pidx++], "addr-source", u8, SI_SMBIOS);
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		pr_warn("ipmi:dmi: Could not allocate dmi info\n");
+	} else {
+		info->si_type = si_type;
+		info->flags = flags;
+		info->addr = base_addr;
+		info->slave_addr = slave_addr;
+		info->next = ipmi_dmi_infos;
+		ipmi_dmi_infos = info;
+	}
+
 	pdev = platform_device_alloc(name, ipmi_dmi_nr);
 	if (!pdev) {
 		pr_err("ipmi:dmi: Error allocation IPMI platform device");
@@ -82,8 +107,10 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
 	}
 	pdev->driver_override = override;
 
-	if (type == IPMI_DMI_TYPE_SSIF)
+	if (type == IPMI_DMI_TYPE_SSIF) {
+		set_prop_entry(p[pidx++], "i2c-addr", u16, base_addr);
 		goto add_properties;
+	}
 
 	memset(r, 0, sizeof(r));
 
@@ -151,12 +178,13 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
  * This function allows an ACPI-specified IPMI device to look up the
  * slave address from the DMI table.
  */
-int ipmi_dmi_get_slave_addr(int type, u32 flags, unsigned long base_addr)
+int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
+			    unsigned long base_addr)
 {
 	struct ipmi_dmi_info *info = ipmi_dmi_infos;
 
 	while (info) {
-		if (info->type == type &&
+		if (info->si_type == si_type &&
 		    info->flags == flags &&
 		    info->addr == base_addr)
 			return info->slave_addr;
diff --git a/drivers/char/ipmi/ipmi_dmi.h b/drivers/char/ipmi/ipmi_dmi.h
index 0a1afe5ceb1e..062015b8f520 100644
--- a/drivers/char/ipmi/ipmi_dmi.h
+++ b/drivers/char/ipmi/ipmi_dmi.h
@@ -2,11 +2,7 @@
  * DMI defines for use by IPMI
  */
 
-#define IPMI_DMI_TYPE_KCS	0x01
-#define IPMI_DMI_TYPE_SMIC	0x02
-#define IPMI_DMI_TYPE_BT	0x03
-#define IPMI_DMI_TYPE_SSIF	0x04
-
 #ifdef CONFIG_IPMI_DMI_DECODE
-int ipmi_dmi_get_slave_addr(int type, u32 flags, unsigned long base_addr);
+int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
+			    unsigned long base_addr);
 #endif
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index fd3ac6b50412..9d1eaf70f406 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -594,7 +594,7 @@ static DEFINE_MUTEX(smi_watchers_mutex);
 
 static const char * const addr_src_to_str[] = {
 	"invalid", "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI",
-	"device-tree"
+	"device-tree", "platform"
 };
 
 const char *ipmi_addr_src_to_str(enum ipmi_addr_src src)
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index efc8ee9b5071..55e0c42bee4d 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -89,7 +89,7 @@ enum si_intf_state {
 #define IPMI_BT_INTMASK_CLEAR_IRQ_BIT	2
 #define IPMI_BT_INTMASK_ENABLE_IRQ_BIT	1
 
-static const char * const si_to_str[] = { "kcs", "smic", "bt" };
+static const char * const si_to_str[] = { "invalid", "kcs", "smic", "bt" };
 
 static int initialized;
 
diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c
index cf5c3e5e72e2..9573f1116450 100644
--- a/drivers/char/ipmi/ipmi_si_platform.c
+++ b/drivers/char/ipmi/ipmi_si_platform.c
@@ -6,14 +6,13 @@
  */
 #include <linux/types.h>
 #include <linux/module.h>
-#include "ipmi_dmi.h"
-#include <linux/dmi.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/acpi.h>
 #include "ipmi_si.h"
+#include "ipmi_dmi.h"
 
 #define PFX "ipmi_platform: "
 
@@ -21,19 +20,29 @@ static bool si_tryplatform = true;
 #ifdef CONFIG_ACPI
 static bool          si_tryacpi = true;
 #endif
+#ifdef CONFIG_OF
+static bool          si_tryopenfirmware = true;
+#endif
 #ifdef CONFIG_DMI
 static bool          si_trydmi = true;
+#else
+static bool          si_trydmi = false;
 #endif
 
 module_param_named(tryplatform, si_tryplatform, bool, 0);
 MODULE_PARM_DESC(tryplatform, "Setting this to zero will disable the"
 		 " default scan of the interfaces identified via platform"
-		 " interfaces like openfirmware");
+		 " interfaces besides ACPI, OpenFirmware, and DMI");
 #ifdef CONFIG_ACPI
 module_param_named(tryacpi, si_tryacpi, bool, 0);
 MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the"
 		 " default scan of the interfaces identified via ACPI");
 #endif
+#ifdef CONFIG_OF
+module_param_named(tryopenfirmware, si_tryopenfirmware, bool, 0);
+MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the"
+		 " default scan of the interfaces identified via OpenFirmware");
+#endif
 #ifdef CONFIG_DMI
 module_param_named(trydmi, si_trydmi, bool, 0);
 MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the"
@@ -235,7 +244,6 @@ static void spmi_find_bmc(void)
 }
 #endif
 
-#if defined(CONFIG_DMI) || defined(CONFIG_ACPI)
 static struct resource *
 ipmi_get_info_from_resources(struct platform_device *pdev,
 			     struct si_sm_io *io)
@@ -271,48 +279,52 @@ ipmi_get_info_from_resources(struct platform_device *pdev,
 	return res;
 }
 
-#endif
-
-#ifdef CONFIG_DMI
-static int dmi_ipmi_probe(struct platform_device *pdev)
+static int platform_ipmi_probe(struct platform_device *pdev)
 {
 	struct si_sm_io io;
-	u8 type, slave_addr;
+	u8 type, slave_addr, addr_source;
 	int rv;
 
-	if (!si_trydmi)
-		return -ENODEV;
+	rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source);
+	if (rv)
+		addr_source = SI_PLATFORM;
+	if (addr_source >= SI_LAST)
+		return -EINVAL;
+
+	if (addr_source == SI_SMBIOS) {
+		if (!si_trydmi)
+			return -ENODEV;
+	} else {
+		if (!si_tryplatform)
+			return -ENODEV;
+	}
 
 	rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type);
 	if (rv)
 		return -ENODEV;
 
 	memset(&io, 0, sizeof(io));
-	io.addr_source = SI_SMBIOS;
-	pr_info(PFX "probing via SMBIOS\n");
+	io.addr_source = addr_source;
+	dev_info(&pdev->dev, PFX "probing via %s\n",
+		 ipmi_addr_src_to_str(addr_source));
 
 	switch (type) {
-	case IPMI_DMI_TYPE_KCS:
-		io.si_type = SI_KCS;
-		break;
-	case IPMI_DMI_TYPE_SMIC:
-		io.si_type = SI_SMIC;
-		break;
-	case IPMI_DMI_TYPE_BT:
-		io.si_type = SI_BT;
+	case SI_KCS:
+	case SI_SMIC:
+	case SI_BT:
+		io.si_type = type;
 		break;
 	default:
+		dev_err(&pdev->dev, "ipmi-type property is invalid\n");
 		return -EINVAL;
 	}
 
-	if (!ipmi_get_info_from_resources(pdev, &io)) {
-		rv = -EINVAL;
-		goto err_free;
-	}
+	if (!ipmi_get_info_from_resources(pdev, &io))
+		return -EINVAL;
 
 	rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr);
 	if (rv) {
-		dev_warn(&pdev->dev, "device has no slave-addr property");
+		dev_warn(&pdev->dev, "device has no slave-addr property\n");
 		io.slave_addr = 0x20;
 	} else {
 		io.slave_addr = slave_addr;
@@ -333,16 +345,7 @@ static int dmi_ipmi_probe(struct platform_device *pdev)
 	ipmi_si_add_smi(&io);
 
 	return 0;
-
-err_free:
-	return rv;
 }
-#else
-static int dmi_ipmi_probe(struct platform_device *pdev)
-{
-	return -ENODEV;
-}
-#endif /* CONFIG_DMI */
 
 #ifdef CONFIG_OF
 static const struct of_device_id of_ipmi_match[] = {
@@ -366,6 +369,9 @@ static int of_ipmi_probe(struct platform_device *pdev)
 	int ret;
 	int proplen;
 
+	if (!si_tryopenfirmware)
+		return -ENODEV;
+
 	dev_info(&pdev->dev, "probing via device tree\n");
 
 	match = of_match_device(of_ipmi_match, &pdev->dev);
@@ -436,25 +442,12 @@ static int find_slave_address(struct si_sm_io *io, int slave_addr)
 {
 #ifdef CONFIG_IPMI_DMI_DECODE
 	if (!slave_addr) {
-		int type = -1;
 		u32 flags = IORESOURCE_IO;
 
-		switch (io->si_type) {
-		case SI_KCS:
-			type = IPMI_DMI_TYPE_KCS;
-			break;
-		case SI_BT:
-			type = IPMI_DMI_TYPE_BT;
-			break;
-		case SI_SMIC:
-			type = IPMI_DMI_TYPE_SMIC;
-			break;
-		}
-
 		if (io->addr_type == IPMI_MEM_ADDR_SPACE)
 			flags = IORESOURCE_MEM;
 
-		slave_addr = ipmi_dmi_get_slave_addr(type, flags,
+		slave_addr = ipmi_dmi_get_slave_addr(io->si_type, flags,
 						     io->addr_data);
 	}
 #endif
@@ -563,7 +556,7 @@ static int ipmi_probe(struct platform_device *pdev)
 	if (acpi_ipmi_probe(pdev) == 0)
 		return 0;
 
-	return dmi_ipmi_probe(pdev);
+	return platform_ipmi_probe(pdev);
 }
 
 static int ipmi_remove(struct platform_device *pdev)
@@ -583,11 +576,9 @@ struct platform_driver ipmi_platform_driver = {
 
 void ipmi_si_platform_init(void)
 {
-	if (si_tryplatform) {
-		int rv = platform_driver_register(&ipmi_platform_driver);
-		if (rv)
-			pr_err(PFX "Unable to register driver: %d\n", rv);
-	}
+	int rv = platform_driver_register(&ipmi_platform_driver);
+	if (rv)
+		pr_err(PFX "Unable to register driver: %d\n", rv);
 
 #ifdef CONFIG_ACPI
 	if (si_tryacpi)
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
index fbf5bfccde2e..aa8d88ab4433 100644
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -43,7 +43,7 @@
 struct si_sm_data;
 
 enum si_type {
-	SI_KCS, SI_SMIC, SI_BT
+	SI_TYPE_INVALID, SI_KCS, SI_SMIC, SI_BT
 };
 
 /*
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index aadec879d052..466b3a1c0adf 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -53,6 +53,7 @@
 #include <linux/acpi.h>
 #include <linux/ctype.h>
 #include <linux/time64.h>
+#include "ipmi_si_sm.h"
 #include "ipmi_dmi.h"
 
 #define PFX "ipmi_ssif: "
@@ -1482,7 +1483,7 @@ static int find_slave_address(struct i2c_client *client, int slave_addr)
 #ifdef CONFIG_IPMI_DMI_DECODE
 	if (!slave_addr)
 		slave_addr = ipmi_dmi_get_slave_addr(
-			IPMI_DMI_TYPE_SSIF,
+			SI_TYPE_INVALID,
 			i2c_adapter_id(client->adapter),
 			client->addr);
 #endif
@@ -2013,20 +2014,13 @@ static void spmi_find_bmc(void) { }
 #ifdef CONFIG_DMI
 static int dmi_ipmi_probe(struct platform_device *pdev)
 {
-	u8 type, slave_addr = 0;
+	u8 slave_addr = 0;
 	u16 i2c_addr;
 	int rv;
 
 	if (!ssif_trydmi)
 		return -ENODEV;
 
-	rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type);
-	if (rv)
-		return -ENODEV;
-
-	if (type != IPMI_DMI_TYPE_SSIF)
-		return -ENODEV;
-
 	rv = device_property_read_u16(&pdev->dev, "i2c-addr", &i2c_addr);
 	if (rv) {
 		dev_warn(&pdev->dev, PFX "No i2c-addr property\n");
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index 80fc3f798984..f4ffacf4fe9d 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -277,7 +277,7 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len);
  */
 enum ipmi_addr_src {
 	SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS,
-	SI_PCI,	SI_DEVICETREE, SI_LAST
+	SI_PCI,	SI_DEVICETREE, SI_PLATFORM, SI_LAST
 };
 const char *ipmi_addr_src_to_str(enum ipmi_addr_src src);
 
-- 
2.19.2