* [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v3
@ 2010-09-21 22:46 Vernon Mauery
2010-09-23 21:38 ` Randy Dunlap
0 siblings, 1 reply; 20+ messages in thread
From: Vernon Mauery @ 2010-09-21 22:46 UTC (permalink / raw)
To: Linux Kernel Mailing List; +Cc: Keith Mannthey
IBM Real-Time "SMI Free" mode driver
This driver supports the Real-Time Linux (RTL) BIOS feature.
The RTL feature allows non-fatal System Management Interrupts
(SMIs) to be disabled on supported IBM platforms and is
intended to be coupled with a user-space daemon to monitor
the hardware in a way that can be prioritized and scheduled
to better suit the requirements for the system.
The Device is presented as a special "_RTL_" table to the OS
in the Extended BIOS Data Area. There is a simple protocol
for entering and exiting the mode at runtime. This driver
creates a simple sysfs interface to allow a simple entry and
exit from RTL mode in the UFI/BIOS.
This patch has taken the feedback in response to previous posts
by Keith Mannthey <kmannth@us.ibm.com> in addition to a couple
of more improvements, including using a DMI probe to reduce the
probability of getting into trouble on non-IBM systems.
Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..16ba6e6 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -590,4 +590,20 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config IBM_RTL
+ tristate "Device driver to enable PRTL support"
+ depends on X86 && PCI
+ ---help---
+ Enable support for IBM Preimium Real Time Mode (PRTM).
+ This module will allow you the enter and exit PRTM in the BIOS via
+ sysfs on platforms that support this feature. System in PRTM will
+ not recive cpu generated SMIs for recoverable errors. Use of this
+ feature without proper support may void your hardware warrenty.
+
+ If the proper bios support is found the driver will load and create
+ /sys/devices/system/ibm_rtl/. The "state" varable will indicate
+ weather or not the BIOS is in PRTM.
+ state = 0 (BIOS SMI's on)
+ state = 1 (BIOS SMI's off)
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b8..50fae7a 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -30,4 +30,5 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
+obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644
index 0000000..37bf610
--- /dev/null
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -0,0 +1,352 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <asm/bios_ebda.h>
+#include <linux/mutex.h>
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+enum rtl_addr_type {
+ RTL_ADDR_TYPE_IO = 1,
+ RTL_ADDR_TYPE_MMIO,
+} __attribute__((packed));
+
+enum rtl_cmd_type {
+ RTL_CMD_NOP = 0,
+ RTL_CMD_ENTER_PRTM,
+ RTL_CMD_EXIT_PRTM,
+} __attribute__((packed));
+
+/* The RTL table looks something like: */
+struct ibm_rtl_table {
+ char signature[5];
+ u8 version;
+ u8 rt_status;
+ enum rtl_cmd_type command;
+ u8 command_status;
+ enum rtl_addr_type cmd_address_type;
+ u8 cmd_granularity;
+ u8 cmd_offset;
+ u16 reserve1;
+ u8 cmd_port_address[4]; /* platform dependent address */
+ u8 cmd_port_value[4]; /* platform dependent value */
+};
+
+#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
+
+#define ERROR(A, B...) printk(KERN_ERR "ibm-rtl: " A, ##B )
+#define WARNING(A, B...) printk(KERN_WARNING "ibm-rtl: " A, ##B )
+#define DEBUG(A, B...) do { \
+ if (debug) \
+ printk(KERN_INFO "ibm-rtl: " A, ##B ); \
+} while (0)
+
+DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table = NULL;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_iomem_addr = NULL;
+static u32 rtl_cmd_port_addr;
+static enum rtl_addr_type rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static int ibm_rtl_write(u8 value)
+{
+ int ret = 0, count = 0;
+ static u32 cmd_port_val;
+
+ DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+ mutex_lock(&rtl_lock);
+
+ if (ioread8(&rtl_table->rt_status) != value) {
+ if (value == 1)
+ iowrite8(RTL_CMD_ENTER_PRTM, &rtl_table->command);
+ else
+ iowrite8(RTL_CMD_EXIT_PRTM, &rtl_table->command);
+
+ DEBUG("rtl_cmd_port_addr = %#x\n", rtl_cmd_port_addr);
+ DEBUG("rtl_cmd_type = %d\n", rtl_cmd_type);
+
+ switch (rtl_cmd_width) {
+ case 8:
+ cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+ DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iowrite8((u8)cmd_port_val, rtl_cmd_iomem_addr);
+ else
+ outb((u8)cmd_port_val, rtl_cmd_port_addr);
+ break;
+ case 16:
+ cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+ DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iowrite16((u16)cmd_port_val, rtl_cmd_iomem_addr);
+ else
+ outw((u16)cmd_port_val, rtl_cmd_port_addr);
+ break;
+ case 32:
+ cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+ DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iowrite32(cmd_port_val, rtl_cmd_iomem_addr);
+ else
+ outl(cmd_port_val, rtl_cmd_port_addr);
+ break;
+ }
+
+ while (ioread8(&rtl_table->command)) {
+ msleep(10);
+ if (count++ > 500) {
+ ERROR("Hardware not responding to "
+ "mode switch request\n");
+ ret = -EIO;
+ break;
+ }
+
+ }
+
+ if (ioread8(&rtl_table->command_status)) {
+ DEBUG("command_status reports failed command\n");
+ ret = -EIO;
+ }
+ }
+
+ mutex_unlock(&rtl_lock);
+ return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+
+ if (count < 1 || count > 2)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ ret = ibm_rtl_write(0);
+ break;
+ case '1':
+ ret = ibm_rtl_write(1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret >= 0)
+ ret = count;
+
+ return ret;
+}
+
+static struct sysdev_class class_rtl = {
+ .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+ &attr_version,
+ &attr_state,
+ NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+ int ret, i;
+ ret = sysdev_class_register(&class_rtl);
+
+ if (!ret) {
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+ }
+ return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+ int i;
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+ sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ DEBUG("ibm-rtl: found IBM server '%s'\n", id->ident);
+ return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE) \
+{ \
+ .ident = NAME, \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+ }, \
+ .callback = dmi_check_cb \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+ ibm_dmi_entry("BladeCenter LS21", "7971"),
+ ibm_dmi_entry("BladeCenter LS22", "7901"),
+ ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+ ibm_dmi_entry("BladeCenter HS22", "7870"),
+ ibm_dmi_entry("BladeCenter HS22V", "7871"),
+ ibm_dmi_entry("System x3550 M2", "7946"),
+ ibm_dmi_entry("System x3650 M2", "7947"),
+ ibm_dmi_entry("System x3550 M3", "7944"),
+ ibm_dmi_entry("System x3650 M3", "7945"),
+ { }
+};
+
+static int __init ibm_rtl_init(void) {
+ unsigned long ebda_addr, ebda_size;
+ unsigned int ebda_kb;
+ int ret = -ENODEV, i;
+
+ if (force)
+ WARNING("module loaded by force!\n");
+ /* first ensure that we are running on IBM HW */
+ else if (!dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+ ebda_addr = get_bios_ebda();
+ if (!ebda_addr) {
+ DEBUG("no BIOS EBDA found\n");
+ return -ENODEV;
+ }
+
+ ebda_map = ioremap(ebda_addr, 4);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* First word in the EDBA is the Size in KB */
+ ebda_kb = ioread16(ebda_map);
+ DEBUG("EBDA is %d kB\n", ebda_kb);
+
+ if (ebda_kb == 0)
+ goto out;
+
+ iounmap(ebda_map);
+ ebda_size = ebda_kb*1024;
+
+ /* Remap the whole table */
+ ebda_map = ioremap(ebda_addr, ebda_size);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* search for the _RTL_ signature at the start of the table */
+ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+ struct ibm_rtl_table __iomem * tmp;
+ tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+ if (ioread32(&tmp->signature) == RTL_SIGNATURE) {
+ DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+ rtl_table = tmp;
+ /* The address, value, width and offset are platform
+ * dependent and found in the ibm_rtl_table */
+ rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+ rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+ DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+ rtl_cmd_width, rtl_cmd_type);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO) {
+ u32 addr;
+ addr = ioread32(&rtl_table->cmd_port_address);
+ rtl_cmd_iomem_addr = ioremap(addr, 4);
+ DEBUG("rtl_cmd_iomem_addr = %#llx\n",
+ (u64)rtl_cmd_iomem_addr);
+ if (!rtl_cmd_iomem_addr) {
+ ret = -ENOMEM;
+ break;
+ }
+ } else {
+ rtl_cmd_port_addr =
+ ioread32(&rtl_table->cmd_port_address);
+ DEBUG("rtl_cmd_port_addr = %#x\n",
+ rtl_cmd_port_addr);
+ }
+ ret = rtl_setup_sysfs();
+ break;
+ }
+ }
+
+out:
+ if (ret) {
+ iounmap(ebda_map);
+ if (rtl_cmd_iomem_addr)
+ iounmap(rtl_cmd_iomem_addr);
+ }
+
+ return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+ if (rtl_table) {
+ DEBUG("cleaning up");
+ /* do not leave the machine in SMI-free mode */
+ ibm_rtl_write(0);
+ /* unmap, unlink and remove all traces */
+ rtl_teardown_sysfs();
+ iounmap(ebda_map);
+ if (rtl_cmd_iomem_addr)
+ iounmap(rtl_cmd_iomem_addr);
+ }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v3
2010-09-21 22:46 [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v3 Vernon Mauery
@ 2010-09-23 21:38 ` Randy Dunlap
2010-09-23 22:12 ` Vernon Mauery
0 siblings, 1 reply; 20+ messages in thread
From: Randy Dunlap @ 2010-09-23 21:38 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Linux Kernel Mailing List, Keith Mannthey
On Tue, 21 Sep 2010 15:46:10 -0700 Vernon Mauery wrote:
> IBM Real-Time "SMI Free" mode driver
>
> Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index cff7cc2..16ba6e6 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -590,4 +590,20 @@ config INTEL_IPS
> functionality. If in doubt, say Y here; it will only load on
> supported platforms.
>
> +config IBM_RTL
> + tristate "Device driver to enable PRTL support"
> + depends on X86 && PCI
> + ---help---
> + Enable support for IBM Preimium Real Time Mode (PRTM).
What is Preimium?
> + This module will allow you the enter and exit PRTM in the BIOS via
> + sysfs on platforms that support this feature. System in PRTM will
> + not recive cpu generated SMIs for recoverable errors. Use of this
receive CPU-generated
> + feature without proper support may void your hardware warrenty.
warranty.
> +
> + If the proper bios support is found the driver will load and create
BIOS
> + /sys/devices/system/ibm_rtl/. The "state" varable will indicate
variable
> + weather or not the BIOS is in PRTM.
whether
> + state = 0 (BIOS SMI's on)
> + state = 1 (BIOS SMI's off)
> +
> endif # X86_PLATFORM_DEVICES
> diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
> new file mode 100644
> index 0000000..37bf610
> --- /dev/null
> +++ b/drivers/platform/x86/ibm_rtl.c
> @@ -0,0 +1,352 @@
> +/*
> + * IBM Real-Time Linux driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + *
> + * Copyright (C) IBM Corporation, 2010
> + *
> + * Author: Keith Mannthey <kmannth@us.ibm.com>
> + * Vernon Mauery <vernux@us.ibm.com>
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/sysdev.h>
> +#include <linux/dmi.h>
> +#include <asm/bios_ebda.h>
> +#include <linux/mutex.h>
<asm> after all <linux> headers, please.
> +
> +static int force;
> +module_param(force, bool, 0);
> +MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
> +
> +static int debug;
> +module_param(debug, bool, 0644);
> +MODULE_PARM_DESC(debug, "Show debug output");
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
> +MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
> +
> +enum rtl_addr_type {
> + RTL_ADDR_TYPE_IO = 1,
> + RTL_ADDR_TYPE_MMIO,
> +} __attribute__((packed));
> +
> +enum rtl_cmd_type {
> + RTL_CMD_NOP = 0,
> + RTL_CMD_ENTER_PRTM,
> + RTL_CMD_EXIT_PRTM,
> +} __attribute__((packed));
What does packed do to an enum list?
> +
> +/* The RTL table looks something like: */
Unsure of this?
> +struct ibm_rtl_table {
> + char signature[5];
> + u8 version;
> + u8 rt_status;
> + enum rtl_cmd_type command;
> + u8 command_status;
> + enum rtl_addr_type cmd_address_type;
> + u8 cmd_granularity;
> + u8 cmd_offset;
> + u16 reserve1;
> + u8 cmd_port_address[4]; /* platform dependent address */
> + u8 cmd_port_value[4]; /* platform dependent value */
> +};
> +
> +#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
> +
> +#define ERROR(A, B...) printk(KERN_ERR "ibm-rtl: " A, ##B )
> +#define WARNING(A, B...) printk(KERN_WARNING "ibm-rtl: " A, ##B )
> +#define DEBUG(A, B...) do { \
> + if (debug) \
> + printk(KERN_INFO "ibm-rtl: " A, ##B ); \
> +} while (0)
> +
> +DEFINE_MUTEX(rtl_lock);
static DEFINE_MUTEX(rtl_lock);
> +static struct ibm_rtl_table __iomem *rtl_table = NULL;
> +static void __iomem *ebda_map;
> +static void __iomem *rtl_cmd_iomem_addr = NULL;
> +static u32 rtl_cmd_port_addr;
> +static enum rtl_addr_type rtl_cmd_type;
> +static u8 rtl_cmd_width;
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v3
2010-09-23 21:38 ` Randy Dunlap
@ 2010-09-23 22:12 ` Vernon Mauery
2010-09-23 22:53 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4 Vernon Mauery
0 siblings, 1 reply; 20+ messages in thread
From: Vernon Mauery @ 2010-09-23 22:12 UTC (permalink / raw)
To: Randy Dunlap; +Cc: Linux Kernel Mailing List, Keith Mannthey
On 23-Sep-2010 02:38 PM, Randy Dunlap wrote:
>On Tue, 21 Sep 2010 15:46:10 -0700 Vernon Mauery wrote:
>
>> IBM Real-Time "SMI Free" mode driver
>>
>> Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
>>
>> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
>> index cff7cc2..16ba6e6 100644
>> --- a/drivers/platform/x86/Kconfig
>> +++ b/drivers/platform/x86/Kconfig
>> @@ -590,4 +590,20 @@ config INTEL_IPS
>> functionality. If in doubt, say Y here; it will only load on
>> supported platforms.
>>
>> +config IBM_RTL
>> + tristate "Device driver to enable PRTL support"
>> + depends on X86 && PCI
>> + ---help---
>> + Enable support for IBM Preimium Real Time Mode (PRTM).
>
> What is Preimium?
Okay, this is just plain embarrassing. Or should I say embarasing? :)
I swear I already fixed those from when you commented on Keith's patch.
I must have copied over my changes somehow.
These are fixed in the forthcoming patch. Thanks for your patience.
>
>> + This module will allow you the enter and exit PRTM in the BIOS via
>> + sysfs on platforms that support this feature. System in PRTM will
>> + not recive cpu generated SMIs for recoverable errors. Use of this
>
> receive CPU-generated
>
>> + feature without proper support may void your hardware warrenty.
>
> warranty.
>
>> +
>> + If the proper bios support is found the driver will load and create
>
> BIOS
>
>> + /sys/devices/system/ibm_rtl/. The "state" varable will indicate
>
> variable
>
>> + weather or not the BIOS is in PRTM.
>
> whether
>
>> + state = 0 (BIOS SMI's on)
>> + state = 1 (BIOS SMI's off)
>> +
>> endif # X86_PLATFORM_DEVICES
>
>> diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
>> new file mode 100644
>> index 0000000..37bf610
>> --- /dev/null
>> +++ b/drivers/platform/x86/ibm_rtl.c
>> @@ -0,0 +1,352 @@
>> +/*
>> + * IBM Real-Time Linux driver
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>> + *
>> + * Copyright (C) IBM Corporation, 2010
>> + *
>> + * Author: Keith Mannthey <kmannth@us.ibm.com>
>> + * Vernon Mauery <vernux@us.ibm.com>
>> + *
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/io.h>
>> +#include <linux/sysdev.h>
>> +#include <linux/dmi.h>
>> +#include <asm/bios_ebda.h>
>> +#include <linux/mutex.h>
>
><asm> after all <linux> headers, please.
>
>> +
>> +static int force;
>> +module_param(force, bool, 0);
>> +MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
>> +
>> +static int debug;
>> +module_param(debug, bool, 0644);
>> +MODULE_PARM_DESC(debug, "Show debug output");
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
>> +MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
>> +
>> +enum rtl_addr_type {
>> + RTL_ADDR_TYPE_IO = 1,
>> + RTL_ADDR_TYPE_MMIO,
>> +} __attribute__((packed));
>> +
>> +enum rtl_cmd_type {
>> + RTL_CMD_NOP = 0,
>> + RTL_CMD_ENTER_PRTM,
>> + RTL_CMD_EXIT_PRTM,
>> +} __attribute__((packed));
>
>What does packed do to an enum list?
>
>> +
>> +/* The RTL table looks something like: */
>
>Unsure of this?
:) Not really. A little less waffling never hurts.
>
>> +struct ibm_rtl_table {
>> + char signature[5];
>> + u8 version;
>> + u8 rt_status;
>> + enum rtl_cmd_type command;
>> + u8 command_status;
>> + enum rtl_addr_type cmd_address_type;
>> + u8 cmd_granularity;
>> + u8 cmd_offset;
>> + u16 reserve1;
>> + u8 cmd_port_address[4]; /* platform dependent address */
>> + u8 cmd_port_value[4]; /* platform dependent value */
>> +};
>> +
>> +#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
>> +
>> +#define ERROR(A, B...) printk(KERN_ERR "ibm-rtl: " A, ##B )
>> +#define WARNING(A, B...) printk(KERN_WARNING "ibm-rtl: " A, ##B )
>> +#define DEBUG(A, B...) do { \
>> + if (debug) \
>> + printk(KERN_INFO "ibm-rtl: " A, ##B ); \
>> +} while (0)
>> +
>> +DEFINE_MUTEX(rtl_lock);
>
>static DEFINE_MUTEX(rtl_lock);
Thanks for your review.
--Vernon
>
>> +static struct ibm_rtl_table __iomem *rtl_table = NULL;
>> +static void __iomem *ebda_map;
>> +static void __iomem *rtl_cmd_iomem_addr = NULL;
>> +static u32 rtl_cmd_port_addr;
>> +static enum rtl_addr_type rtl_cmd_type;
>> +static u8 rtl_cmd_width;
>
>
>---
>~Randy
>*** Remember to use Documentation/SubmitChecklist when testing your code ***
>
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-23 22:12 ` Vernon Mauery
@ 2010-09-23 22:53 ` Vernon Mauery
2010-09-24 13:12 ` Arnd Bergmann
0 siblings, 1 reply; 20+ messages in thread
From: Vernon Mauery @ 2010-09-23 22:53 UTC (permalink / raw)
To: Randy Dunlap; +Cc: Linux Kernel Mailing List, Keith Mannthey
IBM Real-Time "SMI Free" mode driver
This driver supports the Real-Time Linux (RTL) BIOS feature.
The RTL feature allows non-fatal System Management Interrupts
(SMIs) to be disabled on supported IBM platforms and is
intended to be coupled with a user-space daemon to monitor
the hardware in a way that can be prioritized and scheduled
to better suit the requirements for the system.
The Device is presented as a special "_RTL_" table to the OS
in the Extended BIOS Data Area. There is a simple protocol
for entering and exiting the mode at runtime. This driver
creates a simple sysfs interface to allow a simple entry and
exit from RTL mode in the UFI/BIOS.
This patch has taken the feedback in response to previous posts
by Keith Mannthey <kmannth@us.ibm.com> in addition to a couple
of more improvements, including using a DMI probe to reduce the
probability of getting into trouble on non-IBM systems.
Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
--
diff --git a/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
new file mode 100644
index 0000000..b82deea
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
@@ -0,0 +1,22 @@
+What: state
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The state file allows a means by which to change in and
+ out of Premium Real-Time Mode (PRTM), as well as the
+ ability to query the current state.
+ 0 => PRTM off
+ 1 => PRTM enabled
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
+What: version
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The version file provides a means by which to query
+ the RTL table version that lives in the Extended
+ BIOS Data Area (EBDA).
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..5fba368 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -590,4 +590,20 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config IBM_RTL
+ tristate "Device driver to enable PRTL support"
+ depends on X86 && PCI
+ ---help---
+ Enable support for IBM Premium Real Time Mode (PRTM).
+ This module will allow you the enter and exit PRTM in the BIOS via
+ sysfs on platforms that support this feature. System in PRTM will
+ not recive CPU-generated SMIs for recoverable errors. Use of this
+ feature without proper support may void your hardware warranty.
+
+ If the proper BIOS support is found the driver will load and create
+ /sys/devices/system/ibm_rtl/. The "state" variable will indicate
+ whether or not the BIOS is in PRTM.
+ state = 0 (BIOS SMIs on)
+ state = 1 (BIOS SMIs off)
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b8..50fae7a 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -30,4 +30,5 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
+obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644
index 0000000..c7a991f
--- /dev/null
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -0,0 +1,352 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <asm/bios_ebda.h>
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+enum rtl_addr_type {
+ RTL_ADDR_TYPE_IO = 1,
+ RTL_ADDR_TYPE_MMIO,
+} __attribute__((packed));
+
+enum rtl_cmd_type {
+ RTL_CMD_NOP = 0,
+ RTL_CMD_ENTER_PRTM,
+ RTL_CMD_EXIT_PRTM,
+} __attribute__((packed));
+
+/* The RTL table as presented by the EBDA: */
+struct ibm_rtl_table {
+ char signature[5];
+ u8 version;
+ u8 rt_status;
+ enum rtl_cmd_type command;
+ u8 command_status;
+ enum rtl_addr_type cmd_address_type;
+ u8 cmd_granularity;
+ u8 cmd_offset;
+ u16 reserve1;
+ u8 cmd_port_address[4]; /* platform dependent address */
+ u8 cmd_port_value[4]; /* platform dependent value */
+};
+
+#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
+
+#define ERROR(A, B...) printk(KERN_ERR "ibm-rtl: " A, ##B )
+#define WARNING(A, B...) printk(KERN_WARNING "ibm-rtl: " A, ##B )
+#define DEBUG(A, B...) do { \
+ if (debug) \
+ printk(KERN_INFO "ibm-rtl: " A, ##B ); \
+} while (0)
+
+static DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table = NULL;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_iomem_addr = NULL;
+static u32 rtl_cmd_port_addr;
+static enum rtl_addr_type rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static int ibm_rtl_write(u8 value)
+{
+ int ret = 0, count = 0;
+ static u32 cmd_port_val;
+
+ DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+ mutex_lock(&rtl_lock);
+
+ if (ioread8(&rtl_table->rt_status) != value) {
+ if (value == 1)
+ iowrite8(RTL_CMD_ENTER_PRTM, &rtl_table->command);
+ else
+ iowrite8(RTL_CMD_EXIT_PRTM, &rtl_table->command);
+
+ DEBUG("rtl_cmd_port_addr = %#x\n", rtl_cmd_port_addr);
+ DEBUG("rtl_cmd_type = %d\n", rtl_cmd_type);
+
+ switch (rtl_cmd_width) {
+ case 8:
+ cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+ DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iowrite8((u8)cmd_port_val, rtl_cmd_iomem_addr);
+ else
+ outb((u8)cmd_port_val, rtl_cmd_port_addr);
+ break;
+ case 16:
+ cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+ DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iowrite16((u16)cmd_port_val, rtl_cmd_iomem_addr);
+ else
+ outw((u16)cmd_port_val, rtl_cmd_port_addr);
+ break;
+ case 32:
+ cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+ DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iowrite32(cmd_port_val, rtl_cmd_iomem_addr);
+ else
+ outl(cmd_port_val, rtl_cmd_port_addr);
+ break;
+ }
+
+ while (ioread8(&rtl_table->command)) {
+ msleep(10);
+ if (count++ > 500) {
+ ERROR("Hardware not responding to "
+ "mode switch request\n");
+ ret = -EIO;
+ break;
+ }
+
+ }
+
+ if (ioread8(&rtl_table->command_status)) {
+ DEBUG("command_status reports failed command\n");
+ ret = -EIO;
+ }
+ }
+
+ mutex_unlock(&rtl_lock);
+ return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+
+ if (count < 1 || count > 2)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ ret = ibm_rtl_write(0);
+ break;
+ case '1':
+ ret = ibm_rtl_write(1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret >= 0)
+ ret = count;
+
+ return ret;
+}
+
+static struct sysdev_class class_rtl = {
+ .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+ &attr_version,
+ &attr_state,
+ NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+ int ret, i;
+ ret = sysdev_class_register(&class_rtl);
+
+ if (!ret) {
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+ }
+ return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+ int i;
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+ sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ DEBUG("found IBM server '%s'\n", id->ident);
+ return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE) \
+{ \
+ .ident = NAME, \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+ }, \
+ .callback = dmi_check_cb \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+ ibm_dmi_entry("BladeCenter LS21", "7971"),
+ ibm_dmi_entry("BladeCenter LS22", "7901"),
+ ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+ ibm_dmi_entry("BladeCenter HS22", "7870"),
+ ibm_dmi_entry("BladeCenter HS22V", "7871"),
+ ibm_dmi_entry("System x3550 M2", "7946"),
+ ibm_dmi_entry("System x3650 M2", "7947"),
+ ibm_dmi_entry("System x3550 M3", "7944"),
+ ibm_dmi_entry("System x3650 M3", "7945"),
+ { }
+};
+
+static int __init ibm_rtl_init(void) {
+ unsigned long ebda_addr, ebda_size;
+ unsigned int ebda_kb;
+ int ret = -ENODEV, i;
+
+ if (force)
+ WARNING("module loaded by force!\n");
+ /* first ensure that we are running on IBM HW */
+ else if (!dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+ ebda_addr = get_bios_ebda();
+ if (!ebda_addr) {
+ DEBUG("no BIOS EBDA found\n");
+ return -ENODEV;
+ }
+
+ ebda_map = ioremap(ebda_addr, 4);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* First word in the EDBA is the Size in KB */
+ ebda_kb = ioread16(ebda_map);
+ DEBUG("EBDA is %d kB\n", ebda_kb);
+
+ if (ebda_kb == 0)
+ goto out;
+
+ iounmap(ebda_map);
+ ebda_size = ebda_kb*1024;
+
+ /* Remap the whole table */
+ ebda_map = ioremap(ebda_addr, ebda_size);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* search for the _RTL_ signature at the start of the table */
+ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+ struct ibm_rtl_table __iomem * tmp;
+ tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+ if (ioread32(&tmp->signature) == RTL_SIGNATURE) {
+ DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+ rtl_table = tmp;
+ /* The address, value, width and offset are platform
+ * dependent and found in the ibm_rtl_table */
+ rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+ rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+ DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+ rtl_cmd_width, rtl_cmd_type);
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO) {
+ u32 addr;
+ addr = ioread32(&rtl_table->cmd_port_address);
+ rtl_cmd_iomem_addr = ioremap(addr, 4);
+ DEBUG("rtl_cmd_iomem_addr = %#llx\n",
+ (u64)rtl_cmd_iomem_addr);
+ if (!rtl_cmd_iomem_addr) {
+ ret = -ENOMEM;
+ break;
+ }
+ } else {
+ rtl_cmd_port_addr =
+ ioread32(&rtl_table->cmd_port_address);
+ DEBUG("rtl_cmd_port_addr = %#x\n",
+ rtl_cmd_port_addr);
+ }
+ ret = rtl_setup_sysfs();
+ break;
+ }
+ }
+
+out:
+ if (ret) {
+ iounmap(ebda_map);
+ if (rtl_cmd_iomem_addr)
+ iounmap(rtl_cmd_iomem_addr);
+ }
+
+ return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+ if (rtl_table) {
+ DEBUG("cleaning up");
+ /* do not leave the machine in SMI-free mode */
+ ibm_rtl_write(0);
+ /* unmap, unlink and remove all traces */
+ rtl_teardown_sysfs();
+ iounmap(ebda_map);
+ if (rtl_cmd_iomem_addr)
+ iounmap(rtl_cmd_iomem_addr);
+ }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-23 22:53 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4 Vernon Mauery
@ 2010-09-24 13:12 ` Arnd Bergmann
2010-09-24 14:14 ` Vernon Mauery
0 siblings, 1 reply; 20+ messages in thread
From: Arnd Bergmann @ 2010-09-24 13:12 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On Friday 24 September 2010, Vernon Mauery wrote:
> +enum rtl_addr_type {
> + RTL_ADDR_TYPE_IO = 1,
> + RTL_ADDR_TYPE_MMIO,
> +} __attribute__((packed));
> +
> +enum rtl_cmd_type {
> + RTL_CMD_NOP = 0,
> + RTL_CMD_ENTER_PRTM,
> + RTL_CMD_EXIT_PRTM,
> +} __attribute__((packed));
You didn't reply to Randy's comment about the packed attribute.
I think it's rather confusing here.
> +/* The RTL table as presented by the EBDA: */
> +struct ibm_rtl_table {
> + char signature[5];
> + u8 version;
> + u8 rt_status;
> + enum rtl_cmd_type command;
> + u8 command_status;
> + enum rtl_addr_type cmd_address_type;
> + u8 cmd_granularity;
> + u8 cmd_offset;
> + u16 reserve1;
> + u8 cmd_port_address[4]; /* platform dependent address */
> + u8 cmd_port_value[4]; /* platform dependent value */
> +};
I would recommend marking the member in this structure as packed instead,
not the enum.
> +#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
> +
> +#define ERROR(A, B...) printk(KERN_ERR "ibm-rtl: " A, ##B )
> +#define WARNING(A, B...) printk(KERN_WARNING "ibm-rtl: " A, ##B )
> +#define DEBUG(A, B...) do { \
> + if (debug) \
> + printk(KERN_INFO "ibm-rtl: " A, ##B ); \
> +} while (0)
We already have wrappers for these, no need to define your own.
Please just use dev_{err,warn,dbg} or pr_{err,warning,debug}.
> +static DEFINE_MUTEX(rtl_lock);
> +static struct ibm_rtl_table __iomem *rtl_table = NULL;
> +static void __iomem *ebda_map;
> +static void __iomem *rtl_cmd_iomem_addr = NULL;
> +static u32 rtl_cmd_port_addr;
> +static enum rtl_addr_type rtl_cmd_type;
> +static u8 rtl_cmd_width;
This is somewhat inconsistent, some of these are implicitly initialized,
others have an explicit "= NULL". I would recommend leaving out the
initialization, which is the historic way to do this in the kernel.
Some people find it cleaner to define a structure containing all the
driver specific data. Since there can be only one of these devices
in your case, it's probably not important.
> + if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
> + iowrite8((u8)cmd_port_val, rtl_cmd_iomem_addr);
> + else
> + outb((u8)cmd_port_val, rtl_cmd_port_addr);
ioread/iowrite already has the capability to use both mmio and pio
addresses. You can use ioport_map() to create an __iomem token that
corresponds to your rtl_cmd_port_addr and get rid of the rtl_cmd_type
variable.
Arnd
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 13:12 ` Arnd Bergmann
@ 2010-09-24 14:14 ` Vernon Mauery
2010-09-24 14:24 ` Arnd Bergmann
` (2 more replies)
0 siblings, 3 replies; 20+ messages in thread
From: Vernon Mauery @ 2010-09-24 14:14 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On Fri, Sep 24, 2010 at 6:12 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday 24 September 2010, Vernon Mauery wrote:
>> +enum rtl_addr_type {
>> + RTL_ADDR_TYPE_IO = 1,
>> + RTL_ADDR_TYPE_MMIO,
>> +} __attribute__((packed));
>> +
>> +enum rtl_cmd_type {
>> + RTL_CMD_NOP = 0,
>> + RTL_CMD_ENTER_PRTM,
>> + RTL_CMD_EXIT_PRTM,
>> +} __attribute__((packed));
>
> You didn't reply to Randy's comment about the packed attribute.
> I think it's rather confusing here.
Sorry. I missed that comment. The packed attribute on an enum forces
it into the smallest int type it can be. enums are normally the size
of an int, but this enum in the RTL table must fit in an 8-bit int.
>> +/* The RTL table as presented by the EBDA: */
>> +struct ibm_rtl_table {
>> + char signature[5];
>> + u8 version;
>> + u8 rt_status;
>> + enum rtl_cmd_type command;
>> + u8 command_status;
>> + enum rtl_addr_type cmd_address_type;
>> + u8 cmd_granularity;
>> + u8 cmd_offset;
>> + u16 reserve1;
>> + u8 cmd_port_address[4]; /* platform dependent address */
>> + u8 cmd_port_value[4]; /* platform dependent value */
>> +};
>
> I would recommend marking the member in this structure as packed instead,
> not the enum.
It does not have the same effect. Without the packed attribute on the
enums, they end up to be the wrong size and then we would be reading
from the wrong location in memory.
>> +#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
>> +
>> +#define ERROR(A, B...) printk(KERN_ERR "ibm-rtl: " A, ##B )
>> +#define WARNING(A, B...) printk(KERN_WARNING "ibm-rtl: " A, ##B )
>> +#define DEBUG(A, B...) do { \
>> + if (debug) \
>> + printk(KERN_INFO "ibm-rtl: " A, ##B ); \
>> +} while (0)
>
> We already have wrappers for these, no need to define your own.
> Please just use dev_{err,warn,dbg} or pr_{err,warning,debug}.
Ack.
>> +static DEFINE_MUTEX(rtl_lock);
>> +static struct ibm_rtl_table __iomem *rtl_table = NULL;
>> +static void __iomem *ebda_map;
>> +static void __iomem *rtl_cmd_iomem_addr = NULL;
>> +static u32 rtl_cmd_port_addr;
>> +static enum rtl_addr_type rtl_cmd_type;
>> +static u8 rtl_cmd_width;
>
> This is somewhat inconsistent, some of these are implicitly initialized,
> others have an explicit "= NULL". I would recommend leaving out the
> initialization, which is the historic way to do this in the kernel.
The variables that have an explicit initialization are the variables
that I read before I write. It just looks funny to me to read a
variable that hasn't been initialized. But I can axe the
initializations for the sake of consistency.
> Some people find it cleaner to define a structure containing all the
> driver specific data. Since there can be only one of these devices
> in your case, it's probably not important.
>
>> + if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
>> + iowrite8((u8)cmd_port_val, rtl_cmd_iomem_addr);
>> + else
>> + outb((u8)cmd_port_val, rtl_cmd_port_addr);
>
> ioread/iowrite already has the capability to use both mmio and pio
> addresses. You can use ioport_map() to create an __iomem token that
> corresponds to your rtl_cmd_port_addr and get rid of the rtl_cmd_type
> variable.
Thank you for that tip. I will look into it and roll out another version.
--Vernon
> Arnd
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 14:14 ` Vernon Mauery
@ 2010-09-24 14:24 ` Arnd Bergmann
2010-09-24 16:56 ` Randy Dunlap
2010-09-24 17:09 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4 Vernon Mauery
2 siblings, 0 replies; 20+ messages in thread
From: Arnd Bergmann @ 2010-09-24 14:24 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On Friday 24 September 2010, Vernon Mauery wrote:
> >> +static DEFINE_MUTEX(rtl_lock);
> >> +static struct ibm_rtl_table __iomem *rtl_table = NULL;
> >> +static void __iomem *ebda_map;
> >> +static void __iomem *rtl_cmd_iomem_addr = NULL;
> >> +static u32 rtl_cmd_port_addr;
> >> +static enum rtl_addr_type rtl_cmd_type;
> >> +static u8 rtl_cmd_width;
> >
> > This is somewhat inconsistent, some of these are implicitly initialized,
> > others have an explicit "= NULL". I would recommend leaving out the
> > initialization, which is the historic way to do this in the kernel.
>
> The variables that have an explicit initialization are the variables
> that I read before I write. It just looks funny to me to read a
> variable that hasn't been initialized. But I can axe the
> initializations for the sake of consistency.
Ok. Global variables are by definition initialized to zero.
Old gcc versions used to allocate space in the .data section
if you had explicit = NULL statements while they would end
up in .bss otherwise, resulting in a smaller binary image.
With newer gcc versions, it doesn't make a difference, but
many people have the "don't initialize globals to zero" meme
hardcoded to their brains now ;-)
Arnd
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 14:14 ` Vernon Mauery
2010-09-24 14:24 ` Arnd Bergmann
@ 2010-09-24 16:56 ` Randy Dunlap
2010-09-24 21:06 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5 Vernon Mauery
2010-09-24 17:09 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4 Vernon Mauery
2 siblings, 1 reply; 20+ messages in thread
From: Randy Dunlap @ 2010-09-24 16:56 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Arnd Bergmann, Linux Kernel Mailing List, Keith Mannthey
On Fri, 24 Sep 2010 07:14:27 -0700 Vernon Mauery wrote:
> On Fri, Sep 24, 2010 at 6:12 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Friday 24 September 2010, Vernon Mauery wrote:
> >> +enum rtl_addr_type {
> >> + RTL_ADDR_TYPE_IO = 1,
> >> + RTL_ADDR_TYPE_MMIO,
> >> +} __attribute__((packed));
> >> +
> >> +enum rtl_cmd_type {
> >> + RTL_CMD_NOP = 0,
> >> + RTL_CMD_ENTER_PRTM,
> >> + RTL_CMD_EXIT_PRTM,
> >> +} __attribute__((packed));
> >
> > You didn't reply to Randy's comment about the packed attribute.
> > I think it's rather confusing here.
thanks.
> Sorry. I missed that comment. The packed attribute on an enum forces
> it into the smallest int type it can be. enums are normally the size
> of an int, but this enum in the RTL table must fit in an 8-bit int.
I think you would be better off making 'command' below be a u8 then.
Otherwise someone else might add an enum value that is > 255 and the
struct size will change. I.e., the current way is error-prone.
Just using u8 for command's type is safer.
> >> +/* The RTL table as presented by the EBDA: */
> >> +struct ibm_rtl_table {
> >> + char signature[5];
> >> + u8 version;
> >> + u8 rt_status;
> >> + enum rtl_cmd_type command;
> >> + u8 command_status;
> >> + enum rtl_addr_type cmd_address_type;
> >> + u8 cmd_granularity;
> >> + u8 cmd_offset;
> >> + u16 reserve1;
> >> + u8 cmd_port_address[4]; /* platform dependent address */
> >> + u8 cmd_port_value[4]; /* platform dependent value */
> >> +};
> >
> > I would recommend marking the member in this structure as packed instead,
> > not the enum.
>
> It does not have the same effect. Without the packed attribute on the
> enums, they end up to be the wrong size and then we would be reading
> from the wrong location in memory.
Thanks for the explanation.
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5
2010-09-24 16:56 ` Randy Dunlap
@ 2010-09-24 21:06 ` Vernon Mauery
2010-09-24 21:20 ` Randy Dunlap
0 siblings, 1 reply; 20+ messages in thread
From: Vernon Mauery @ 2010-09-24 21:06 UTC (permalink / raw)
To: Randy Dunlap; +Cc: Arnd Bergmann, Linux Kernel Mailing List, Keith Mannthey
On 24-Sep-2010 09:56 AM, Randy Dunlap wrote:
>On Fri, 24 Sep 2010 07:14:27 -0700 Vernon Mauery wrote:
>
>> On Fri, Sep 24, 2010 at 6:12 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>> > On Friday 24 September 2010, Vernon Mauery wrote:
>> >> +enum rtl_addr_type {
>> >> + RTL_ADDR_TYPE_IO = 1,
>> >> + RTL_ADDR_TYPE_MMIO,
>> >> +} __attribute__((packed));
>> >> +
>> >> +enum rtl_cmd_type {
>> >> + RTL_CMD_NOP = 0,
>> >> + RTL_CMD_ENTER_PRTM,
>> >> + RTL_CMD_EXIT_PRTM,
>> >> +} __attribute__((packed));
>> >
>> > You didn't reply to Randy's comment about the packed attribute.
>> > I think it's rather confusing here.
>
>thanks.
>
>> Sorry. I missed that comment. The packed attribute on an enum forces
>> it into the smallest int type it can be. enums are normally the size
>> of an int, but this enum in the RTL table must fit in an 8-bit int.
>
>I think you would be better off making 'command' below be a u8 then.
>Otherwise someone else might add an enum value that is > 255 and the
>struct size will change. I.e., the current way is error-prone.
>Just using u8 for command's type is safer.
Here is a new and improved version that includes your changes as well as
Arnd's suggestions. Thank you both for your reviews.
--Vernon
-------------------------------
IBM Real-Time "SMI Free" mode driver
This driver supports the Real-Time Linux (RTL) BIOS feature.
The RTL feature allows non-fatal System Management Interrupts
(SMIs) to be disabled on supported IBM platforms and is
intended to be coupled with a user-space daemon to monitor
the hardware in a way that can be prioritized and scheduled
to better suit the requirements for the system.
The Device is presented as a special "_RTL_" table to the OS
in the Extended BIOS Data Area. There is a simple protocol
for entering and exiting the mode at runtime. This driver
creates a simple sysfs interface to allow a simple entry and
exit from RTL mode in the UFI/BIOS.
Since the driver is specific to IBM SystemX hardware (x86-
based servers) it only builds on x86 builds. To reduce the
risk of loading on the wrong hardware, the module uses DMI
information and checks a list of servers that are known to
work.
Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
diff --git a/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
new file mode 100644
index 0000000..b82deea
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
@@ -0,0 +1,22 @@
+What: state
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The state file allows a means by which to change in and
+ out of Premium Real-Time Mode (PRTM), as well as the
+ ability to query the current state.
+ 0 => PRTM off
+ 1 => PRTM enabled
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
+What: version
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The version file provides a means by which to query
+ the RTL table version that lives in the Extended
+ BIOS Data Area (EBDA).
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..5fba368 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -590,4 +590,20 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config IBM_RTL
+ tristate "Device driver to enable PRTL support"
+ depends on X86 && PCI
+ ---help---
+ Enable support for IBM Premium Real Time Mode (PRTM).
+ This module will allow you the enter and exit PRTM in the BIOS via
+ sysfs on platforms that support this feature. System in PRTM will
+ not recive CPU-generated SMIs for recoverable errors. Use of this
+ feature without proper support may void your hardware warranty.
+
+ If the proper BIOS support is found the driver will load and create
+ /sys/devices/system/ibm_rtl/. The "state" variable will indicate
+ whether or not the BIOS is in PRTM.
+ state = 0 (BIOS SMIs on)
+ state = 1 (BIOS SMIs off)
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b8..50fae7a 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -30,4 +30,5 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
+obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644
index 0000000..2a0a390
--- /dev/null
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -0,0 +1,339 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <asm/bios_ebda.h>
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+#define RTL_ADDR_TYPE_IO 1
+#define RTL_ADDR_TYPE_MMIO 2
+
+#define RTL_CMD_ENTER_PRTM 1
+#define RTL_CMD_EXIT_PRTM 2
+
+/* The RTL table as presented by the EBDA: */
+struct ibm_rtl_table {
+ char signature[5];
+ u8 version;
+ u8 rt_status;
+ u8 command;
+ u8 command_status;
+ u8 cmd_address_type;
+ u8 cmd_granularity;
+ u8 cmd_offset;
+ u16 reserve1;
+ u32 cmd_port_address; /* platform dependent address */
+ u32 cmd_port_value; /* platform dependent value */
+} __attribute__((packed));
+
+#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
+
+#define RTL_DEBUG(A, ...) do { \
+ if (debug) \
+ pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
+} while (0)
+
+static DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_addr;
+static u8 rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
+{
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ return ioremap(addr, len);
+ return ioport_map(addr, len);
+}
+
+static void rtl_port_unmap(void __iomem *addr)
+{
+ if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iounmap(addr);
+ else
+ ioport_unmap(addr);
+}
+
+static int ibm_rtl_write(u8 value)
+{
+ int ret = 0, count = 0;
+ static u32 cmd_port_val;
+
+ RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+ value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
+
+ mutex_lock(&rtl_lock);
+
+ if (ioread8(&rtl_table->rt_status) != value) {
+ iowrite8(value, &rtl_table->command);
+
+ switch (rtl_cmd_width) {
+ case 8:
+ cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite8((u8)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 16:
+ cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite16((u16)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 32:
+ cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite32(cmd_port_val, rtl_cmd_addr);
+ break;
+ }
+
+ while (ioread8(&rtl_table->command)) {
+ msleep(10);
+ if (count++ > 500) {
+ pr_err("ibm-rtl: Hardware not responding to "
+ "mode switch request\n");
+ ret = -EIO;
+ break;
+ }
+
+ }
+
+ if (ioread8(&rtl_table->command_status)) {
+ RTL_DEBUG("command_status reports failed command\n");
+ ret = -EIO;
+ }
+ }
+
+ mutex_unlock(&rtl_lock);
+ return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+
+ if (count < 1 || count > 2)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ ret = ibm_rtl_write(0);
+ break;
+ case '1':
+ ret = ibm_rtl_write(1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret >= 0)
+ ret = count;
+
+ return ret;
+}
+
+static struct sysdev_class class_rtl = {
+ .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+ &attr_version,
+ &attr_state,
+ NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+ int ret, i;
+ ret = sysdev_class_register(&class_rtl);
+
+ if (!ret) {
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+ }
+ return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+ int i;
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+ sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ RTL_DEBUG("found IBM server '%s'\n", id->ident);
+ return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE) \
+{ \
+ .ident = NAME, \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+ }, \
+ .callback = dmi_check_cb \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+ ibm_dmi_entry("BladeCenter LS21", "7971"),
+ ibm_dmi_entry("BladeCenter LS22", "7901"),
+ ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+ ibm_dmi_entry("BladeCenter HS22", "7870"),
+ ibm_dmi_entry("BladeCenter HS22V", "7871"),
+ ibm_dmi_entry("System x3550 M2", "7946"),
+ ibm_dmi_entry("System x3650 M2", "7947"),
+ ibm_dmi_entry("System x3550 M3", "7944"),
+ ibm_dmi_entry("System x3650 M3", "7945"),
+ { }
+};
+
+static int __init ibm_rtl_init(void) {
+ unsigned long ebda_addr, ebda_size;
+ unsigned int ebda_kb;
+ int ret = -ENODEV, i;
+
+ if (force)
+ pr_warning("ibm-rtl: module loaded by force!\n");
+ /* first ensure that we are running on IBM HW */
+ else if (!dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+ ebda_addr = get_bios_ebda();
+ if (!ebda_addr) {
+ RTL_DEBUG("no BIOS EBDA found\n");
+ return -ENODEV;
+ }
+
+ ebda_map = ioremap(ebda_addr, 4);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* First word in the EDBA is the Size in KB */
+ ebda_kb = ioread16(ebda_map);
+ RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
+
+ if (ebda_kb == 0)
+ goto out;
+
+ iounmap(ebda_map);
+ ebda_size = ebda_kb*1024;
+
+ /* Remap the whole table */
+ ebda_map = ioremap(ebda_addr, ebda_size);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* search for the _RTL_ signature at the start of the table */
+ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+ struct ibm_rtl_table __iomem * tmp;
+ tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+ if (ioread32(&tmp->signature) == RTL_SIGNATURE) {
+ phys_addr_t addr;
+ unsigned int plen;
+ RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+ rtl_table = tmp;
+ /* The address, value, width and offset are platform
+ * dependent and found in the ibm_rtl_table */
+ rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+ rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+ RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+ rtl_cmd_width, rtl_cmd_type);
+ addr = ioread32(&rtl_table->cmd_port_address);
+ RTL_DEBUG("addr = %#llx\n", addr);
+ plen = rtl_cmd_width/sizeof(char);
+ rtl_cmd_addr = rtl_port_map(addr, plen);
+ RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
+ if (!rtl_cmd_addr) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = rtl_setup_sysfs();
+ break;
+ }
+ }
+
+out:
+ if (ret) {
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+
+ return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+ if (rtl_table) {
+ RTL_DEBUG("cleaning up");
+ /* do not leave the machine in SMI-free mode */
+ ibm_rtl_write(0);
+ /* unmap, unlink and remove all traces */
+ rtl_teardown_sysfs();
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5
2010-09-24 21:06 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5 Vernon Mauery
@ 2010-09-24 21:20 ` Randy Dunlap
2010-09-24 21:30 ` Vernon Mauery
0 siblings, 1 reply; 20+ messages in thread
From: Randy Dunlap @ 2010-09-24 21:20 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Arnd Bergmann, Linux Kernel Mailing List, Keith Mannthey
On Fri, 24 Sep 2010 14:06:42 -0700 Vernon Mauery wrote:
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index cff7cc2..5fba368 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -590,4 +590,20 @@ config INTEL_IPS
> functionality. If in doubt, say Y here; it will only load on
> supported platforms.
>
> +config IBM_RTL
> + tristate "Device driver to enable PRTL support"
> + depends on X86 && PCI
> + ---help---
> + Enable support for IBM Premium Real Time Mode (PRTM).
> + This module will allow you the enter and exit PRTM in the BIOS via
> + sysfs on platforms that support this feature. System in PRTM will
> + not recive CPU-generated SMIs for recoverable errors. Use of this
receive (again/still)
> + feature without proper support may void your hardware warranty.
> +
> + If the proper BIOS support is found the driver will load and create
> + /sys/devices/system/ibm_rtl/. The "state" variable will indicate
> + whether or not the BIOS is in PRTM.
> + state = 0 (BIOS SMIs on)
> + state = 1 (BIOS SMIs off)
> +
> endif # X86_PLATFORM_DEVICES
> diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
> new file mode 100644
> index 0000000..2a0a390
> --- /dev/null
> +++ b/drivers/platform/x86/ibm_rtl.c
> @@ -0,0 +1,339 @@
> +/*
> + * IBM Real-Time Linux driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + *
> + * Copyright (C) IBM Corporation, 2010
> + *
> + * Author: Keith Mannthey <kmannth@us.ibm.com>
> + * Vernon Mauery <vernux@us.ibm.com>
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/sysdev.h>
> +#include <linux/dmi.h>
> +#include <linux/mutex.h>
> +#include <asm/bios_ebda.h>
> +
> +static int force;
s/int/bool/
> +module_param(force, bool, 0);
> +MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
> +
> +static int debug;
s/int/bool/
> +module_param(debug, bool, 0644);
> +MODULE_PARM_DESC(debug, "Show debug output");
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
> +MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
> +
> +#define RTL_ADDR_TYPE_IO 1
> +#define RTL_ADDR_TYPE_MMIO 2
> +
> +#define RTL_CMD_ENTER_PRTM 1
> +#define RTL_CMD_EXIT_PRTM 2
> +
> +/* The RTL table as presented by the EBDA: */
> +struct ibm_rtl_table {
> + char signature[5];
Question: are all 5 bytes of signature[] used? It looks like the search code
only checks for 32 bits of signature (and the last byte can be garbage?).
> + u8 version;
> + u8 rt_status;
> + u8 command;
> + u8 command_status;
> + u8 cmd_address_type;
> + u8 cmd_granularity;
> + u8 cmd_offset;
> + u16 reserve1;
> + u32 cmd_port_address; /* platform dependent address */
> + u32 cmd_port_value; /* platform dependent value */
> +} __attribute__((packed));
> +
> +#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
> +
> +#define RTL_DEBUG(A, ...) do { \
> + if (debug) \
> + pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
> +} while (0)
> +
> +static DEFINE_MUTEX(rtl_lock);
> +static struct ibm_rtl_table __iomem *rtl_table;
> +static void __iomem *ebda_map;
> +static void __iomem *rtl_cmd_addr;
> +static u8 rtl_cmd_type;
> +static u8 rtl_cmd_width;
...
> +static int __init ibm_rtl_init(void) {
> + unsigned long ebda_addr, ebda_size;
> + unsigned int ebda_kb;
> + int ret = -ENODEV, i;
> +
> + if (force)
> + pr_warning("ibm-rtl: module loaded by force!\n");
Please drop the '!'.
> + /* first ensure that we are running on IBM HW */
> + else if (!dmi_check_system(ibm_rtl_dmi_table))
> + return -ENODEV;
> +
> + /* Get the address for the Extended BIOS Data Area */
> + ebda_addr = get_bios_ebda();
> + if (!ebda_addr) {
> + RTL_DEBUG("no BIOS EBDA found\n");
> + return -ENODEV;
> + }
> +
> + ebda_map = ioremap(ebda_addr, 4);
> + if (!ebda_map)
> + return -ENOMEM;
> +
> + /* First word in the EDBA is the Size in KB */
> + ebda_kb = ioread16(ebda_map);
> + RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
> +
> + if (ebda_kb == 0)
> + goto out;
> +
> + iounmap(ebda_map);
> + ebda_size = ebda_kb*1024;
> +
> + /* Remap the whole table */
> + ebda_map = ioremap(ebda_addr, ebda_size);
> + if (!ebda_map)
> + return -ENOMEM;
> +
> + /* search for the _RTL_ signature at the start of the table */
> + for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
> + struct ibm_rtl_table __iomem * tmp;
> + tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
> + if (ioread32(&tmp->signature) == RTL_SIGNATURE) {
> + phys_addr_t addr;
> + unsigned int plen;
> + RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
> + rtl_table = tmp;
> + /* The address, value, width and offset are platform
> + * dependent and found in the ibm_rtl_table */
> + rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
> + rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
> + RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
> + rtl_cmd_width, rtl_cmd_type);
> + addr = ioread32(&rtl_table->cmd_port_address);
> + RTL_DEBUG("addr = %#llx\n", addr);
> + plen = rtl_cmd_width/sizeof(char);
> + rtl_cmd_addr = rtl_port_map(addr, plen);
> + RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
> + if (!rtl_cmd_addr) {
> + ret = -ENOMEM;
> + break;
> + }
> + ret = rtl_setup_sysfs();
> + break;
> + }
> + }
> +
> +out:
> + if (ret) {
> + iounmap(ebda_map);
> + rtl_port_unmap(rtl_cmd_addr);
> + }
> +
> + return ret;
> +}
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5
2010-09-24 21:20 ` Randy Dunlap
@ 2010-09-24 21:30 ` Vernon Mauery
2010-09-24 21:35 ` Randy Dunlap
2010-09-25 2:07 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5 Henrique de Moraes Holschuh
0 siblings, 2 replies; 20+ messages in thread
From: Vernon Mauery @ 2010-09-24 21:30 UTC (permalink / raw)
To: Randy Dunlap; +Cc: Arnd Bergmann, Linux Kernel Mailing List, Keith Mannthey
On 24-Sep-2010 02:20 PM, Randy Dunlap wrote:
>On Fri, 24 Sep 2010 14:06:42 -0700 Vernon Mauery wrote:
>
>> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
>> index cff7cc2..5fba368 100644
>> --- a/drivers/platform/x86/Kconfig
>> +++ b/drivers/platform/x86/Kconfig
>> @@ -590,4 +590,20 @@ config INTEL_IPS
>> functionality. If in doubt, say Y here; it will only load on
>> supported platforms.
>>
>> +config IBM_RTL
>> + tristate "Device driver to enable PRTL support"
>> + depends on X86 && PCI
>> + ---help---
>> + Enable support for IBM Premium Real Time Mode (PRTM).
>> + This module will allow you the enter and exit PRTM in the BIOS via
>> + sysfs on platforms that support this feature. System in PRTM will
>> + not recive CPU-generated SMIs for recoverable errors. Use of this
>
> receive (again/still)
Ack. Again.
>> + feature without proper support may void your hardware warranty.
>> +
>> + If the proper BIOS support is found the driver will load and create
>> + /sys/devices/system/ibm_rtl/. The "state" variable will indicate
>> + whether or not the BIOS is in PRTM.
[snip]
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/io.h>
>> +#include <linux/sysdev.h>
>> +#include <linux/dmi.h>
>> +#include <linux/mutex.h>
>> +#include <asm/bios_ebda.h>
>> +
>> +static int force;
>
>s/int/bool/
>
>> +module_param(force, bool, 0);
>> +MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
>> +
>> +static int debug;
>
>s/int/bool/
Ack.
>> +module_param(debug, bool, 0644);
>> +MODULE_PARM_DESC(debug, "Show debug output");
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
>> +MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
>> +
>> +#define RTL_ADDR_TYPE_IO 1
>> +#define RTL_ADDR_TYPE_MMIO 2
>> +
>> +#define RTL_CMD_ENTER_PRTM 1
>> +#define RTL_CMD_EXIT_PRTM 2
>> +
>> +/* The RTL table as presented by the EBDA: */
>> +struct ibm_rtl_table {
>> + char signature[5];
>
>Question: are all 5 bytes of signature[] used? It looks like the search code
>only checks for 32 bits of signature (and the last byte can be garbage?).
Technically, the 5 bytes are supposed to be "_RTL_", but it is a lot
easier to just check _RTL since we can do that with a single read. I
suppose I could do a 64-bit read and mask the bits that matter. Do you
have an opinion on the matter?
>> + u8 version;
>> + u8 rt_status;
>> + u8 command;
>> + u8 command_status;
>> + u8 cmd_address_type;
>> + u8 cmd_granularity;
>> + u8 cmd_offset;
>> + u16 reserve1;
>> + u32 cmd_port_address; /* platform dependent address */
>> + u32 cmd_port_value; /* platform dependent value */
>> +} __attribute__((packed));
>> +
>> +#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
>> +
>> +#define RTL_DEBUG(A, ...) do { \
>> + if (debug) \
>> + pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
>> +} while (0)
>> +
>> +static DEFINE_MUTEX(rtl_lock);
>> +static struct ibm_rtl_table __iomem *rtl_table;
>> +static void __iomem *ebda_map;
>> +static void __iomem *rtl_cmd_addr;
>> +static u8 rtl_cmd_type;
>> +static u8 rtl_cmd_width;
>
>...
>
>> +static int __init ibm_rtl_init(void) {
>> + unsigned long ebda_addr, ebda_size;
>> + unsigned int ebda_kb;
>> + int ret = -ENODEV, i;
>> +
>> + if (force)
>> + pr_warning("ibm-rtl: module loaded by force!\n");
>
>Please drop the '!'.
Ack.
--Vernon
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5
2010-09-24 21:30 ` Vernon Mauery
@ 2010-09-24 21:35 ` Randy Dunlap
2010-09-24 21:58 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v6 Vernon Mauery
2010-09-25 2:07 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5 Henrique de Moraes Holschuh
1 sibling, 1 reply; 20+ messages in thread
From: Randy Dunlap @ 2010-09-24 21:35 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Arnd Bergmann, Linux Kernel Mailing List, Keith Mannthey
On Fri, 24 Sep 2010 14:30:09 -0700 Vernon Mauery wrote:
> >> +/* The RTL table as presented by the EBDA: */
> >> +struct ibm_rtl_table {
> >> + char signature[5];
> >
> >Question: are all 5 bytes of signature[] used? It looks like the search code
> >only checks for 32 bits of signature (and the last byte can be garbage?).
>
> Technically, the 5 bytes are supposed to be "_RTL_", but it is a lot
> easier to just check _RTL since we can do that with a single read. I
> suppose I could do a 64-bit read and mask the bits that matter. Do you
> have an opinion on the matter?
I would just comment that the first 4 bytes are checked.
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v6
2010-09-24 21:35 ` Randy Dunlap
@ 2010-09-24 21:58 ` Vernon Mauery
0 siblings, 0 replies; 20+ messages in thread
From: Vernon Mauery @ 2010-09-24 21:58 UTC (permalink / raw)
To: Randy Dunlap; +Cc: Arnd Bergmann, Linux Kernel Mailing List, Keith Mannthey
On 24-Sep-2010 02:35 PM, Randy Dunlap wrote:
>On Fri, 24 Sep 2010 14:30:09 -0700 Vernon Mauery wrote:
>
>> >> +/* The RTL table as presented by the EBDA: */
>> >> +struct ibm_rtl_table {
>> >> + char signature[5];
>> >
>> >Question: are all 5 bytes of signature[] used? It looks like the search code
>> >only checks for 32 bits of signature (and the last byte can be garbage?).
>>
>> Technically, the 5 bytes are supposed to be "_RTL_", but it is a lot
>> easier to just check _RTL since we can do that with a single read. I
>> suppose I could do a 64-bit read and mask the bits that matter. Do you
>> have an opinion on the matter?
>
>I would just comment that the first 4 bytes are checked.
Okay. I think I have something that should pass. Thanks again for your
review.
--Vernon
-----------------------------------------------------
IBM Real-Time "SMI Free" mode driver
This driver supports the Real-Time Linux (RTL) BIOS feature.
The RTL feature allows non-fatal System Management Interrupts
(SMIs) to be disabled on supported IBM platforms and is
intended to be coupled with a user-space daemon to monitor
the hardware in a way that can be prioritized and scheduled
to better suit the requirements for the system.
The Device is presented as a special "_RTL_" table to the OS
in the Extended BIOS Data Area. There is a simple protocol
for entering and exiting the mode at runtime. This driver
creates a simple sysfs interface to allow a simple entry and
exit from RTL mode in the UFI/BIOS.
Since the driver is specific to IBM SystemX hardware (x86-
based servers) it only builds on x86 builds. To reduce the
risk of loading on the wrong hardware, the module uses DMI
information and checks a list of servers that are known to
work.
Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
diff --git a/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
new file mode 100644
index 0000000..b82deea
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
@@ -0,0 +1,22 @@
+What: state
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The state file allows a means by which to change in and
+ out of Premium Real-Time Mode (PRTM), as well as the
+ ability to query the current state.
+ 0 => PRTM off
+ 1 => PRTM enabled
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
+What: version
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The version file provides a means by which to query
+ the RTL table version that lives in the Extended
+ BIOS Data Area (EBDA).
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..55c6b86 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -590,4 +590,20 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config IBM_RTL
+ tristate "Device driver to enable PRTL support"
+ depends on X86 && PCI
+ ---help---
+ Enable support for IBM Premium Real Time Mode (PRTM).
+ This module will allow you the enter and exit PRTM in the BIOS via
+ sysfs on platforms that support this feature. System in PRTM will
+ not receive CPU-generated SMIs for recoverable errors. Use of this
+ feature without proper support may void your hardware warranty.
+
+ If the proper BIOS support is found the driver will load and create
+ /sys/devices/system/ibm_rtl/. The "state" variable will indicate
+ whether or not the BIOS is in PRTM.
+ state = 0 (BIOS SMIs on)
+ state = 1 (BIOS SMIs off)
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b8..50fae7a 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -30,4 +30,5 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
+obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644
index 0000000..7065cc0
--- /dev/null
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -0,0 +1,341 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <asm/bios_ebda.h>
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+#define RTL_ADDR_TYPE_IO 1
+#define RTL_ADDR_TYPE_MMIO 2
+
+#define RTL_CMD_ENTER_PRTM 1
+#define RTL_CMD_EXIT_PRTM 2
+
+/* The RTL table as presented by the EBDA: */
+struct ibm_rtl_table {
+ char signature[5]; /* signature should be "_RTL_" */
+ u8 version;
+ u8 rt_status;
+ u8 command;
+ u8 command_status;
+ u8 cmd_address_type;
+ u8 cmd_granularity;
+ u8 cmd_offset;
+ u16 reserve1;
+ u32 cmd_port_address; /* platform dependent address */
+ u32 cmd_port_value; /* platform dependent value */
+} __attribute__((packed));
+
+/* For ease of locating the signature, we only test the
+ * first four bytes (32-bit int compare) instead of strcmp */
+#define RTL_SIGNATURE (('L'<<24)|('T'<<16)|('R'<<8)|'_')
+
+#define RTL_DEBUG(A, ...) do { \
+ if (debug) \
+ pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
+} while (0)
+
+static DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_addr;
+static u8 rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
+{
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ return ioremap(addr, len);
+ return ioport_map(addr, len);
+}
+
+static void rtl_port_unmap(void __iomem *addr)
+{
+ if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iounmap(addr);
+ else
+ ioport_unmap(addr);
+}
+
+static int ibm_rtl_write(u8 value)
+{
+ int ret = 0, count = 0;
+ static u32 cmd_port_val;
+
+ RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+ value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
+
+ mutex_lock(&rtl_lock);
+
+ if (ioread8(&rtl_table->rt_status) != value) {
+ iowrite8(value, &rtl_table->command);
+
+ switch (rtl_cmd_width) {
+ case 8:
+ cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite8((u8)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 16:
+ cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite16((u16)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 32:
+ cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite32(cmd_port_val, rtl_cmd_addr);
+ break;
+ }
+
+ while (ioread8(&rtl_table->command)) {
+ msleep(10);
+ if (count++ > 500) {
+ pr_err("ibm-rtl: Hardware not responding to "
+ "mode switch request\n");
+ ret = -EIO;
+ break;
+ }
+
+ }
+
+ if (ioread8(&rtl_table->command_status)) {
+ RTL_DEBUG("command_status reports failed command\n");
+ ret = -EIO;
+ }
+ }
+
+ mutex_unlock(&rtl_lock);
+ return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+
+ if (count < 1 || count > 2)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ ret = ibm_rtl_write(0);
+ break;
+ case '1':
+ ret = ibm_rtl_write(1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret >= 0)
+ ret = count;
+
+ return ret;
+}
+
+static struct sysdev_class class_rtl = {
+ .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+ &attr_version,
+ &attr_state,
+ NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+ int ret, i;
+ ret = sysdev_class_register(&class_rtl);
+
+ if (!ret) {
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+ }
+ return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+ int i;
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+ sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ RTL_DEBUG("found IBM server '%s'\n", id->ident);
+ return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE) \
+{ \
+ .ident = NAME, \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+ }, \
+ .callback = dmi_check_cb \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+ ibm_dmi_entry("BladeCenter LS21", "7971"),
+ ibm_dmi_entry("BladeCenter LS22", "7901"),
+ ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+ ibm_dmi_entry("BladeCenter HS22", "7870"),
+ ibm_dmi_entry("BladeCenter HS22V", "7871"),
+ ibm_dmi_entry("System x3550 M2", "7946"),
+ ibm_dmi_entry("System x3650 M2", "7947"),
+ ibm_dmi_entry("System x3550 M3", "7944"),
+ ibm_dmi_entry("System x3650 M3", "7945"),
+ { }
+};
+
+static int __init ibm_rtl_init(void) {
+ unsigned long ebda_addr, ebda_size;
+ unsigned int ebda_kb;
+ int ret = -ENODEV, i;
+
+ if (force)
+ pr_warning("ibm-rtl: module loaded by force\n");
+ /* first ensure that we are running on IBM HW */
+ else if (!dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+ ebda_addr = get_bios_ebda();
+ if (!ebda_addr) {
+ RTL_DEBUG("no BIOS EBDA found\n");
+ return -ENODEV;
+ }
+
+ ebda_map = ioremap(ebda_addr, 4);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* First word in the EDBA is the Size in KB */
+ ebda_kb = ioread16(ebda_map);
+ RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
+
+ if (ebda_kb == 0)
+ goto out;
+
+ iounmap(ebda_map);
+ ebda_size = ebda_kb*1024;
+
+ /* Remap the whole table */
+ ebda_map = ioremap(ebda_addr, ebda_size);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* search for the _RTL_ signature at the start of the table */
+ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+ struct ibm_rtl_table __iomem * tmp;
+ tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+ if (ioread32(&tmp->signature) == RTL_SIGNATURE) {
+ phys_addr_t addr;
+ unsigned int plen;
+ RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+ rtl_table = tmp;
+ /* The address, value, width and offset are platform
+ * dependent and found in the ibm_rtl_table */
+ rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+ rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+ RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+ rtl_cmd_width, rtl_cmd_type);
+ addr = ioread32(&rtl_table->cmd_port_address);
+ RTL_DEBUG("addr = %#llx\n", addr);
+ plen = rtl_cmd_width/sizeof(char);
+ rtl_cmd_addr = rtl_port_map(addr, plen);
+ RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
+ if (!rtl_cmd_addr) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = rtl_setup_sysfs();
+ break;
+ }
+ }
+
+out:
+ if (ret) {
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+
+ return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+ if (rtl_table) {
+ RTL_DEBUG("cleaning up");
+ /* do not leave the machine in SMI-free mode */
+ ibm_rtl_write(0);
+ /* unmap, unlink and remove all traces */
+ rtl_teardown_sysfs();
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5
2010-09-24 21:30 ` Vernon Mauery
2010-09-24 21:35 ` Randy Dunlap
@ 2010-09-25 2:07 ` Henrique de Moraes Holschuh
2010-09-25 14:42 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v6 Vernon Mauery
1 sibling, 1 reply; 20+ messages in thread
From: Henrique de Moraes Holschuh @ 2010-09-25 2:07 UTC (permalink / raw)
To: Vernon Mauery
Cc: Randy Dunlap, Arnd Bergmann, Linux Kernel Mailing List,
Keith Mannthey
On Fri, 24 Sep 2010, Vernon Mauery wrote:
> >>+/* The RTL table as presented by the EBDA: */
> >>+struct ibm_rtl_table {
> >>+ char signature[5];
> >
> >Question: are all 5 bytes of signature[] used? It looks like the search code
> >only checks for 32 bits of signature (and the last byte can be garbage?).
>
> Technically, the 5 bytes are supposed to be "_RTL_", but it is a lot
> easier to just check _RTL since we can do that with a single read.
> I suppose I could do a 64-bit read and mask the bits that matter.
Well, as long as you guys write in stone there at IBM that you will
remember to not have a possible future _RTL2_ that would clash horribly
with an non-up-to-date version of the driver that has no clue about
RTL2 and still would match the signature because it only looks at the first
32 bits...
--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v6
2010-09-25 2:07 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5 Henrique de Moraes Holschuh
@ 2010-09-25 14:42 ` Vernon Mauery
0 siblings, 0 replies; 20+ messages in thread
From: Vernon Mauery @ 2010-09-25 14:42 UTC (permalink / raw)
To: Henrique de Moraes Holschuh
Cc: Randy Dunlap, Arnd Bergmann, Linux Kernel Mailing List,
Keith Mannthey
On 24-Sep-2010 11:07 PM, Henrique de Moraes Holschuh wrote:
>On Fri, 24 Sep 2010, Vernon Mauery wrote:
>> >>+/* The RTL table as presented by the EBDA: */
>> >>+struct ibm_rtl_table {
>> >>+ char signature[5];
>> >
>> >Question: are all 5 bytes of signature[] used? It looks like the search code
>> >only checks for 32 bits of signature (and the last byte can be garbage?).
>>
>> Technically, the 5 bytes are supposed to be "_RTL_", but it is a lot
>> easier to just check _RTL since we can do that with a single read.
>> I suppose I could do a 64-bit read and mask the bits that matter.
>
>Well, as long as you guys write in stone there at IBM that you will
>remember to not have a possible future _RTL2_ that would clash horribly
>with an non-up-to-date version of the driver that has no clue about
>RTL2 and still would match the signature because it only looks at the first
>32 bits...
I do not have a strong opinion either way. Yes, a 5-byte compare is more
precise, but 4-bytes is very likely to be unique. There is a spec
(written in stone, as it were) that tells what the table looks like. It
says a 5-byte signature followed by a 1-byte version number. Currently
there is only one version, but rather than change the signature on
future versions, we will change the version number.
That said, here is a new version that does a 5-byte masked quad-word
compare to find the signature.
--Vernon
IBM Real-Time "SMI Free" mode driver
This driver supports the Real-Time Linux (RTL) BIOS feature.
The RTL feature allows non-fatal System Management Interrupts
(SMIs) to be disabled on supported IBM platforms and is
intended to be coupled with a user-space daemon to monitor
the hardware in a way that can be prioritized and scheduled
to better suit the requirements for the system.
The Device is presented as a special "_RTL_" table to the OS
in the Extended BIOS Data Area. There is a simple protocol
for entering and exiting the mode at runtime. This driver
creates a simple sysfs interface to allow a simple entry and
exit from RTL mode in the UFI/BIOS.
Since the driver is specific to IBM SystemX hardware (x86-
based servers) it only builds on x86 builds. To reduce the
risk of loading on the wrong hardware, the module uses DMI
information and checks a list of servers that are known to
work.
Signed-off-by: Vernon Mauery <vernux@us.ibm.com>
diff --git a/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
new file mode 100644
index 0000000..b82deea
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
@@ -0,0 +1,22 @@
+What: state
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The state file allows a means by which to change in and
+ out of Premium Real-Time Mode (PRTM), as well as the
+ ability to query the current state.
+ 0 => PRTM off
+ 1 => PRTM enabled
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
+What: version
+Date: Sep 2010
+KernelVersion: 2.6.37
+Contact: Vernon Mauery <vernux@us.ibm.com>
+Description: The version file provides a means by which to query
+ the RTL table version that lives in the Extended
+ BIOS Data Area (EBDA).
+Users: The ibm-prtm userspace daemon uses this interface.
+
+
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..55c6b86 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -590,4 +590,20 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config IBM_RTL
+ tristate "Device driver to enable PRTL support"
+ depends on X86 && PCI
+ ---help---
+ Enable support for IBM Premium Real Time Mode (PRTM).
+ This module will allow you the enter and exit PRTM in the BIOS via
+ sysfs on platforms that support this feature. System in PRTM will
+ not receive CPU-generated SMIs for recoverable errors. Use of this
+ feature without proper support may void your hardware warranty.
+
+ If the proper BIOS support is found the driver will load and create
+ /sys/devices/system/ibm_rtl/. The "state" variable will indicate
+ whether or not the BIOS is in PRTM.
+ state = 0 (BIOS SMIs on)
+ state = 1 (BIOS SMIs off)
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b8..50fae7a 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -30,4 +30,5 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
+obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
new file mode 100644
index 0000000..3c2c6b9
--- /dev/null
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -0,0 +1,341 @@
+/*
+ * IBM Real-Time Linux driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Keith Mannthey <kmannth@us.ibm.com>
+ * Vernon Mauery <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <asm/bios_ebda.h>
+
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Show debug output");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
+MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
+
+#define RTL_ADDR_TYPE_IO 1
+#define RTL_ADDR_TYPE_MMIO 2
+
+#define RTL_CMD_ENTER_PRTM 1
+#define RTL_CMD_EXIT_PRTM 2
+
+/* The RTL table as presented by the EBDA: */
+struct ibm_rtl_table {
+ char signature[5]; /* signature should be "_RTL_" */
+ u8 version;
+ u8 rt_status;
+ u8 command;
+ u8 command_status;
+ u8 cmd_address_type;
+ u8 cmd_granularity;
+ u8 cmd_offset;
+ u16 reserve1;
+ u32 cmd_port_address; /* platform dependent address */
+ u32 cmd_port_value; /* platform dependent value */
+} __attribute__((packed));
+
+/* to locate "_RTL_" signature do a masked 5-byte integer compare */
+#define RTL_SIGNATURE 0x0000005f4c54525fULL
+#define RTL_MASK 0x000000ffffffffffULL
+
+#define RTL_DEBUG(A, ...) do { \
+ if (debug) \
+ pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
+} while (0)
+
+static DEFINE_MUTEX(rtl_lock);
+static struct ibm_rtl_table __iomem *rtl_table;
+static void __iomem *ebda_map;
+static void __iomem *rtl_cmd_addr;
+static u8 rtl_cmd_type;
+static u8 rtl_cmd_width;
+
+static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
+{
+ if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ return ioremap(addr, len);
+ return ioport_map(addr, len);
+}
+
+static void rtl_port_unmap(void __iomem *addr)
+{
+ if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+ iounmap(addr);
+ else
+ ioport_unmap(addr);
+}
+
+static int ibm_rtl_write(u8 value)
+{
+ int ret = 0, count = 0;
+ static u32 cmd_port_val;
+
+ RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
+
+ value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
+
+ mutex_lock(&rtl_lock);
+
+ if (ioread8(&rtl_table->rt_status) != value) {
+ iowrite8(value, &rtl_table->command);
+
+ switch (rtl_cmd_width) {
+ case 8:
+ cmd_port_val = ioread8(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite8((u8)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 16:
+ cmd_port_val = ioread16(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite16((u16)cmd_port_val, rtl_cmd_addr);
+ break;
+ case 32:
+ cmd_port_val = ioread32(&rtl_table->cmd_port_value);
+ RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
+ iowrite32(cmd_port_val, rtl_cmd_addr);
+ break;
+ }
+
+ while (ioread8(&rtl_table->command)) {
+ msleep(10);
+ if (count++ > 500) {
+ pr_err("ibm-rtl: Hardware not responding to "
+ "mode switch request\n");
+ ret = -EIO;
+ break;
+ }
+
+ }
+
+ if (ioread8(&rtl_table->command_status)) {
+ RTL_DEBUG("command_status reports failed command\n");
+ ret = -EIO;
+ }
+ }
+
+ mutex_unlock(&rtl_lock);
+ return ret;
+}
+
+static ssize_t rtl_show_version(struct sysdev_class * dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
+}
+
+static ssize_t rtl_show_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
+}
+
+static ssize_t rtl_set_state(struct sysdev_class *dev,
+ struct sysdev_class_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+
+ if (count < 1 || count > 2)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ ret = ibm_rtl_write(0);
+ break;
+ case '1':
+ ret = ibm_rtl_write(1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret >= 0)
+ ret = count;
+
+ return ret;
+}
+
+static struct sysdev_class class_rtl = {
+ .name = "ibm_rtl",
+};
+
+static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
+static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
+
+static struct sysdev_class_attribute *rtl_attributes[] = {
+ &attr_version,
+ &attr_state,
+ NULL
+};
+
+
+static int rtl_setup_sysfs(void) {
+ int ret, i;
+ ret = sysdev_class_register(&class_rtl);
+
+ if (!ret) {
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
+ }
+ return ret;
+}
+
+static void rtl_teardown_sysfs(void) {
+ int i;
+ for (i = 0; rtl_attributes[i]; i ++)
+ sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
+ sysdev_class_unregister(&class_rtl);
+}
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ RTL_DEBUG("found IBM server '%s'\n", id->ident);
+ return 0;
+}
+
+#define ibm_dmi_entry(NAME, TYPE) \
+{ \
+ .ident = NAME, \
+ .matches = { \
+ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \
+ }, \
+ .callback = dmi_check_cb \
+}
+
+static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
+ ibm_dmi_entry("BladeCenter LS21", "7971"),
+ ibm_dmi_entry("BladeCenter LS22", "7901"),
+ ibm_dmi_entry("BladeCenter HS21 XM", "7995"),
+ ibm_dmi_entry("BladeCenter HS22", "7870"),
+ ibm_dmi_entry("BladeCenter HS22V", "7871"),
+ ibm_dmi_entry("System x3550 M2", "7946"),
+ ibm_dmi_entry("System x3650 M2", "7947"),
+ ibm_dmi_entry("System x3550 M3", "7944"),
+ ibm_dmi_entry("System x3650 M3", "7945"),
+ { }
+};
+
+static int __init ibm_rtl_init(void) {
+ unsigned long ebda_addr, ebda_size;
+ unsigned int ebda_kb;
+ int ret = -ENODEV, i;
+
+ if (force)
+ pr_warning("ibm-rtl: module loaded by force\n");
+ /* first ensure that we are running on IBM HW */
+ else if (!dmi_check_system(ibm_rtl_dmi_table))
+ return -ENODEV;
+
+ /* Get the address for the Extended BIOS Data Area */
+ ebda_addr = get_bios_ebda();
+ if (!ebda_addr) {
+ RTL_DEBUG("no BIOS EBDA found\n");
+ return -ENODEV;
+ }
+
+ ebda_map = ioremap(ebda_addr, 4);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* First word in the EDBA is the Size in KB */
+ ebda_kb = ioread16(ebda_map);
+ RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
+
+ if (ebda_kb == 0)
+ goto out;
+
+ iounmap(ebda_map);
+ ebda_size = ebda_kb*1024;
+
+ /* Remap the whole table */
+ ebda_map = ioremap(ebda_addr, ebda_size);
+ if (!ebda_map)
+ return -ENOMEM;
+
+ /* search for the _RTL_ signature at the start of the table */
+ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
+ struct ibm_rtl_table __iomem * tmp;
+ tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
+ if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) {
+ phys_addr_t addr;
+ unsigned int plen;
+ RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
+ rtl_table = tmp;
+ /* The address, value, width and offset are platform
+ * dependent and found in the ibm_rtl_table */
+ rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
+ rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
+ RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
+ rtl_cmd_width, rtl_cmd_type);
+ addr = ioread32(&rtl_table->cmd_port_address);
+ RTL_DEBUG("addr = %#llx\n", addr);
+ plen = rtl_cmd_width/sizeof(char);
+ rtl_cmd_addr = rtl_port_map(addr, plen);
+ RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
+ if (!rtl_cmd_addr) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = rtl_setup_sysfs();
+ break;
+ }
+ }
+
+out:
+ if (ret) {
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+
+ return ret;
+}
+
+static void __exit ibm_rtl_exit(void)
+{
+ if (rtl_table) {
+ RTL_DEBUG("cleaning up");
+ /* do not leave the machine in SMI-free mode */
+ ibm_rtl_write(0);
+ /* unmap, unlink and remove all traces */
+ rtl_teardown_sysfs();
+ iounmap(ebda_map);
+ rtl_port_unmap(rtl_cmd_addr);
+ }
+}
+
+module_init(ibm_rtl_init);
+module_exit(ibm_rtl_exit);
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 14:14 ` Vernon Mauery
2010-09-24 14:24 ` Arnd Bergmann
2010-09-24 16:56 ` Randy Dunlap
@ 2010-09-24 17:09 ` Vernon Mauery
2010-09-24 17:40 ` Arnd Bergmann
2 siblings, 1 reply; 20+ messages in thread
From: Vernon Mauery @ 2010-09-24 17:09 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On 24-Sep-2010 07:14 AM, Vernon Mauery wrote:
>On Fri, Sep 24, 2010 at 6:12 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>> On Friday 24 September 2010, Vernon Mauery wrote:
[snip]
>>> + if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
>>> + iowrite8((u8)cmd_port_val, rtl_cmd_iomem_addr);
>>> + else
>>> + outb((u8)cmd_port_val, rtl_cmd_port_addr);
>>
>> ioread/iowrite already has the capability to use both mmio and pio
>> addresses. You can use ioport_map() to create an __iomem token that
>> corresponds to your rtl_cmd_port_addr and get rid of the rtl_cmd_type
>> variable.
>
>Thank you for that tip. I will look into it and roll out another version.
I looked into this and tested it on some hardware, but it doesn't work.
After more digging and poking, it looks like the reason is that the port
IO address is not within the x86 standard port IO range.
I tried something like this:
addr = ioread32(&rtl_table->cmd_port_address);
plen = rtl_cmd_width/8;
if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
rtl_cmd_addr = ioremap(addr, plen);
else
rtl_cmd_addr = ioport_map(addr, plen);
RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
It printed out that rtl_cmd_addr was 0, meaning the ioport_map failed.
After more digging, it turns out that on at least one of the machines
this code is targeted for, the port IO address (from the first line
above) is 0x40000. Even if this did get mapped, the IO_COND macro would
target it for MMIO access instead of PIO access. So I don't think I can
use this method (even though it did make my code *a lot* nicer to read).
Any suggestions?
--Vernon
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 17:09 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4 Vernon Mauery
@ 2010-09-24 17:40 ` Arnd Bergmann
2010-09-24 18:23 ` Vernon Mauery
0 siblings, 1 reply; 20+ messages in thread
From: Arnd Bergmann @ 2010-09-24 17:40 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On Friday 24 September 2010 19:09:43 Vernon Mauery wrote:
> I looked into this and tested it on some hardware, but it doesn't work.
> After more digging and poking, it looks like the reason is that the port
> IO address is not within the x86 standard port IO range.
>
> I tried something like this:
>
> addr = ioread32(&rtl_table->cmd_port_address);
> plen = rtl_cmd_width/8;
> if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
> rtl_cmd_addr = ioremap(addr, plen);
> else
> rtl_cmd_addr = ioport_map(addr, plen);
> RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
>
> It printed out that rtl_cmd_addr was 0, meaning the ioport_map failed.
> After more digging, it turns out that on at least one of the machines
> this code is targeted for, the port IO address (from the first line
> above) is 0x40000. Even if this did get mapped, the IO_COND macro would
> target it for MMIO access instead of PIO access. So I don't think I can
> use this method (even though it did make my code a lot nicer to read).
>
> Any suggestions?
That seems really strange. I thought the inb/outb instructions could not
actually operate on addresses above 0x10000 at all, since they take a 16
bit address operand (DX register). Passing 0x40000 into inb should have the
same effect as zero AFAICT, which means that your existing code should not
work either.
For non-x86 architectures, I would recommend defining HAVE_ARCH_PIO_SIZE
and setting PIO_RESERVED to a higher value.
Arnd
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 17:40 ` Arnd Bergmann
@ 2010-09-24 18:23 ` Vernon Mauery
2010-09-24 20:40 ` Arnd Bergmann
2010-09-24 20:45 ` Vernon Mauery
0 siblings, 2 replies; 20+ messages in thread
From: Vernon Mauery @ 2010-09-24 18:23 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On 24-Sep-2010 07:40 PM, Arnd Bergmann wrote:
>On Friday 24 September 2010 19:09:43 Vernon Mauery wrote:
>> I looked into this and tested it on some hardware, but it doesn't work.
>> After more digging and poking, it looks like the reason is that the port
>> IO address is not within the x86 standard port IO range.
>>
>> I tried something like this:
>>
>> addr = ioread32(&rtl_table->cmd_port_address);
>> plen = rtl_cmd_width/8;
>> if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
>> rtl_cmd_addr = ioremap(addr, plen);
>> else
>> rtl_cmd_addr = ioport_map(addr, plen);
>> RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
>>
>> It printed out that rtl_cmd_addr was 0, meaning the ioport_map failed.
>> After more digging, it turns out that on at least one of the machines
>> this code is targeted for, the port IO address (from the first line
>> above) is 0x40000. Even if this did get mapped, the IO_COND macro would
>> target it for MMIO access instead of PIO access. So I don't think I can
>> use this method (even though it did make my code a lot nicer to read).
>>
>> Any suggestions?
>
>That seems really strange. I thought the inb/outb instructions could not
>actually operate on addresses above 0x10000 at all, since they take a 16
>bit address operand (DX register). Passing 0x40000 into inb should have the
>same effect as zero AFAICT, which means that your existing code should not
>work either.
No, inb/outb have address as as unsigned long, which would explain why
0x40000 works with PIO. When doing inb/outb via the ioread/iowrite
macros, the port value is the address (minus the offset) masked off to
PIO_MASK, which is 16 bits on x86.
So it looks like this really not going to work and I will have to go
back to how it was before. Would it be tacky to write my own little
macro?
>For non-x86 architectures, I would recommend defining HAVE_ARCH_PIO_SIZE
>and setting PIO_RESERVED to a higher value.
Unfortunately, this is targeted only for x86 platforms.
--Vernon
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 18:23 ` Vernon Mauery
@ 2010-09-24 20:40 ` Arnd Bergmann
2010-09-24 20:45 ` Vernon Mauery
1 sibling, 0 replies; 20+ messages in thread
From: Arnd Bergmann @ 2010-09-24 20:40 UTC (permalink / raw)
To: Vernon Mauery; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On Friday 24 September 2010 20:23:27 Vernon Mauery wrote:
> No, inb/outb have address as as unsigned long, which would explain why
> 0x40000 works with PIO. When doing inb/outb via the ioread/iowrite
> macros, the port value is the address (minus the offset) masked off to
> PIO_MASK, which is 16 bits on x86.
What I meant is that the inb/outb *instructions* only take a 16 bit
argument, not the kernel functions. You should really try to find
out what is going on there.
Arnd
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4
2010-09-24 18:23 ` Vernon Mauery
2010-09-24 20:40 ` Arnd Bergmann
@ 2010-09-24 20:45 ` Vernon Mauery
1 sibling, 0 replies; 20+ messages in thread
From: Vernon Mauery @ 2010-09-24 20:45 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Randy Dunlap, Linux Kernel Mailing List, Keith Mannthey
On 24-Sep-2010 11:23 AM, Vernon Mauery wrote:
>On 24-Sep-2010 07:40 PM, Arnd Bergmann wrote:
>>On Friday 24 September 2010 19:09:43 Vernon Mauery wrote:
>>>I looked into this and tested it on some hardware, but it doesn't work.
>>>After more digging and poking, it looks like the reason is that the port
>>>IO address is not within the x86 standard port IO range.
>>>
>>>I tried something like this:
>>>
>>> addr = ioread32(&rtl_table->cmd_port_address);
>>> plen = rtl_cmd_width/8;
>>> if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
>>> rtl_cmd_addr = ioremap(addr, plen);
>>> else
>>> rtl_cmd_addr = ioport_map(addr, plen);
>>> RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
>>>
>>>It printed out that rtl_cmd_addr was 0, meaning the ioport_map failed.
>>>After more digging, it turns out that on at least one of the machines
>>>this code is targeted for, the port IO address (from the first line
>>>above) is 0x40000. Even if this did get mapped, the IO_COND macro would
>>>target it for MMIO access instead of PIO access. So I don't think I can
>>>use this method (even though it did make my code a lot nicer to read).
>>>
>>>Any suggestions?
>>
>>That seems really strange. I thought the inb/outb instructions could not
>>actually operate on addresses above 0x10000 at all, since they take a 16
>>bit address operand (DX register). Passing 0x40000 into inb should have the
>>same effect as zero AFAICT, which means that your existing code should not
>>work either.
>
>No, inb/outb have address as as unsigned long, which would explain
>why 0x40000 works with PIO. When doing inb/outb via the
>ioread/iowrite macros, the port value is the address (minus the
>offset) masked off to PIO_MASK, which is 16 bits on x86.
>
>So it looks like this really not going to work and I will have to go
>back to how it was before. Would it be tacky to write my own little
>macro?
Okay. I finally have it. In one of my changes, I inadvertently changed
the shape of the struct ibm_rtl_table, which is where I read the ioport
address from. This explains why the weird port. Once I fixed my table
so it was correct again, the port is 0x600, which is completely
reasonable and will work just fine with the iowrite functions. Thanks
for bringing this up -- it greatly simplifies things.
--Vernon
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2010-09-25 14:43 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-09-21 22:46 [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v3 Vernon Mauery
2010-09-23 21:38 ` Randy Dunlap
2010-09-23 22:12 ` Vernon Mauery
2010-09-23 22:53 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4 Vernon Mauery
2010-09-24 13:12 ` Arnd Bergmann
2010-09-24 14:14 ` Vernon Mauery
2010-09-24 14:24 ` Arnd Bergmann
2010-09-24 16:56 ` Randy Dunlap
2010-09-24 21:06 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5 Vernon Mauery
2010-09-24 21:20 ` Randy Dunlap
2010-09-24 21:30 ` Vernon Mauery
2010-09-24 21:35 ` Randy Dunlap
2010-09-24 21:58 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v6 Vernon Mauery
2010-09-25 2:07 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v5 Henrique de Moraes Holschuh
2010-09-25 14:42 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v6 Vernon Mauery
2010-09-24 17:09 ` [RFC][Patch] IBM Real-Time "SMI Free" mode driver -v4 Vernon Mauery
2010-09-24 17:40 ` Arnd Bergmann
2010-09-24 18:23 ` Vernon Mauery
2010-09-24 20:40 ` Arnd Bergmann
2010-09-24 20:45 ` Vernon Mauery
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox