From: minyard@acm.org
To: Jean Delvare <jdelvare@suse.de>
Cc: openipmi-developer@lists.sourceforge.net,
linux-kernel@vger.kernel.org, Andy Lutomirski <luto@kernel.org>,
Corey Minyard <cminyard@mvista.com>
Subject: [PATCH v5 3/5] dmi: Add IPMI DMI scanning to the DMI code
Date: Wed, 17 May 2017 14:56:22 -0500 [thread overview]
Message-ID: <1495050984-5602-4-git-send-email-minyard@acm.org> (raw)
In-Reply-To: <1495050984-5602-1-git-send-email-minyard@acm.org>
From: Corey Minyard <cminyard@mvista.com>
It makes more sense to be there, and it's cleaner with the
upcoming conversion of IPMI DMI to a platform device.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Jean Delvare <jdelvare@suse.de>
Cc: Andy Lutomirski <luto@kernel.org>
Tested-by: Andy Lutomirski <luto@kernel.org>
---
drivers/firmware/dmi_scan.c | 108 ++++++++++++++++++++++++++++++++++++++++++--
include/linux/dmi.h | 26 +++++++++++
2 files changed, 129 insertions(+), 5 deletions(-)
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 78ef357..96c0743 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -303,9 +303,105 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
}
}
+#define DMI_IPMI_MIN_LENGTH 0x10
+#define DMI_IPMI_VER2_LENGTH 0x12
+#define DMI_IPMI_TYPE 4
+#define DMI_IPMI_SLAVEADDR 6
+#define DMI_IPMI_ADDR 8
+#define DMI_IPMI_ACCESS 0x10
+#define DMI_IPMI_IRQ 0x11
+#define DMI_IPMI_IO_MASK 0xfffe
+
+static void __init dmi_decode_ipmi(struct dmi_dev_ipmi *dev,
+ const struct dmi_header *dm)
+{
+ const u8 *data = (const u8 *) dm;
+ unsigned long base_addr;
+ u8 len = dm->length;
+ bool slave_addr_set;
+
+ if (len < DMI_IPMI_MIN_LENGTH)
+ return;
+
+ dev->type = data[DMI_IPMI_TYPE];
+
+ memcpy(&base_addr, data + DMI_IPMI_ADDR, sizeof(unsigned long));
+ if (len >= DMI_IPMI_VER2_LENGTH) {
+ if (dev->type == IPMI_DMI_TYPE_SSIF) {
+ if ((data[DMI_IPMI_ADDR] >> 1) == 0) {
+ /*
+ * Some broken systems put the I2C address in
+ * the slave address field. We try to
+ * accommodate them here.
+ */
+ dev->base_addr = data[DMI_IPMI_SLAVEADDR] >> 1;
+ dev->slave_addr = 0;
+ slave_addr_set = true;
+ } else {
+ dev->base_addr = data[DMI_IPMI_ADDR] >> 1;
+ }
+ } else {
+ if (base_addr & 1) {
+ /* I/O */
+ base_addr &= DMI_IPMI_IO_MASK;
+ dev->is_io_space = 1;
+ } else {
+ /* Memory */
+ dev->is_io_space = 0;
+ }
+
+ /*
+ * If bit 4 of byte 0x10 is set, then the lsb
+ * for the address is odd.
+ */
+ base_addr |= (data[DMI_IPMI_ACCESS] >> 4) & 1;
+
+ dev->base_addr = base_addr;
+ dev->irq = data[DMI_IPMI_IRQ];
+
+ /*
+ * The top two bits of byte 0x10 hold the
+ * register spacing.
+ */
+ switch ((data[DMI_IPMI_ACCESS] >> 6) & 3) {
+ case 0: /* Byte boundaries */
+ dev->offset = 1;
+ break;
+ case 1: /* 32-bit boundaries */
+ dev->offset = 4;
+ break;
+ case 2: /* 16-byte boundaries */
+ dev->offset = 16;
+ break;
+ default:
+ /* Leave 0 for undefined. */
+ return;
+ }
+ }
+ } else {
+ /* Old DMI spec. */
+ /*
+ * Note that technically, the lower bit of the base
+ * address should be 1 if the address is I/O and 0 if
+ * the address is in memory. So many systems get that
+ * wrong (and all that I have seen are I/O) so we just
+ * ignore that bit and assume I/O. Systems that use
+ * memory should use the newer spec, anyway.
+ */
+ dev->base_addr = base_addr & DMI_IPMI_IO_MASK;
+ dev->is_io_space = 1;
+ dev->offset = 1;
+ }
+
+ if (!slave_addr_set)
+ dev->slave_addr = data[DMI_IPMI_SLAVEADDR];
+
+ dev->good_data = 1;
+}
+
static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
{
- struct dmi_device *dev;
+ struct dmi_dev_ipmi *dev;
void *data;
data = dmi_alloc(dm->length);
@@ -318,11 +414,13 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
if (!dev)
return;
- dev->type = DMI_DEV_TYPE_IPMI;
- dev->name = "IPMI controller";
- dev->device_data = data;
+ dev->dev.type = DMI_DEV_TYPE_IPMI;
+ dev->dev.name = "IPMI controller";
+ dev->dev.device_data = data;
- dmi_devices_list_add(dev);
+ dmi_decode_ipmi(dev, dm);
+
+ dmi_devices_list_add(&dev->dev);
}
static void __init dmi_save_dev_pciaddr(int instance, int segment, int bus,
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index c8dd5b8..96dc644 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -97,6 +97,24 @@ struct dmi_dev_onboard {
int devfn;
};
+/* Device data for an IPMI entry. */
+struct dmi_dev_ipmi {
+ struct dmi_device dev;
+ u8 good_data;
+ u8 type;
+ u8 is_io_space;
+ u8 irq;
+ u8 offset;
+ u8 slave_addr;
+ unsigned long base_addr;
+};
+
+/* dmi_ipmi_data type field */
+#define IPMI_DMI_TYPE_KCS 0x01
+#define IPMI_DMI_TYPE_SMIC 0x02
+#define IPMI_DMI_TYPE_BT 0x03
+#define IPMI_DMI_TYPE_SSIF 0x04
+
extern struct kobject *dmi_kobj;
extern int dmi_check_system(const struct dmi_system_id *list);
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
@@ -127,6 +145,14 @@ static inline struct dmi_device *to_dmi_device(struct fwnode_handle *fwnode)
return NULL;
}
+static inline struct dmi_dev_ipmi *to_dmi_dev_ipmi(struct dmi_device *dev)
+{
+ if (!dev || dev->type != DMI_DEV_TYPE_IPMI)
+ return NULL;
+
+ return container_of(dev, struct dmi_dev_ipmi, dev);
+}
+
#else
static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; }
--
2.7.4
next prev parent reply other threads:[~2017-05-17 19:56 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-17 19:56 [PATCH v5 0/5] Create DMI sysfs code and add IPMI platform device minyard
2017-05-17 19:56 ` [PATCH v5 1/5] dmi: remove const from return of dmi_find_device minyard
2017-05-17 19:56 ` [PATCH v5 2/5] dmi: Add a DMI firmware node and handling minyard
2017-05-17 19:56 ` minyard [this message]
2017-05-17 19:56 ` [PATCH v5 4/5] dmi: Add IPMI DMI devices as platform devices minyard
2017-05-17 19:56 ` [PATCH v5 5/5] ipmi: Convert DMI handling over to a platform device minyard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1495050984-5602-4-git-send-email-minyard@acm.org \
--to=minyard@acm.org \
--cc=cminyard@mvista.com \
--cc=jdelvare@suse.de \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=openipmi-developer@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome