[PATCH 13/13] ACPI/IPMI: Add IPMI operation region test device driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch is only used for test purpose and should not be merged by any
public Linux kernel repositories.

This patch contains one driver that can drive a fake test device accessing
IPMI operation region fields.

Signed-off-by: Lv Zheng <lv.zheng@xxxxxxxxx>
---
 drivers/acpi/Kconfig     |   68 +++++++++++++
 drivers/acpi/Makefile    |    1 +
 drivers/acpi/ipmi_test.c |  254 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 323 insertions(+)
 create mode 100644 drivers/acpi/ipmi_test.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index d129869..e3dd3fd 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -377,6 +377,74 @@ config ACPI_BGRT
 	  data from the firmware boot splash. It will appear under
 	  /sys/firmware/acpi/bgrt/ .
 
+config ACPI_IPMI_TEST
+	tristate "IPMI operation region tester"
+	help
+	  This is a test device written for such fake ACPI namespace device.
+	    Device (PMIT)
+	    {
+	        Name (_HID, "ZETA0000")  // _HID: Hardware ID
+	        Name (_STA, 0x0F)  // _STA: Status
+	        OperationRegion (SYSI, IPMI, 0x0600, 0x0100)
+	        Field (SYSI, BufferAcc, Lock, Preserve)
+	        {
+	            AccessAs (BufferAcc, 0x01),
+                   Offset (0x01),
+	            GDIC,   8,	// Get Device ID Command
+	        }
+	        Method (GDIM, 0, NotSerialized)  // GDIM: Get Device ID Method
+	        {
+	            Name (GDIR, Package (0x08)
+	            {
+	                0x00,
+	                0x00,
+	                0x0000,
+	                0x00,
+	                0x00,
+	                Buffer (0x03) {0x00, 0x00, 0x00},
+	                Buffer (0x02) {0x00, 0x00},
+	                0x00000000
+	            })
+	            Name (BUFF, Buffer (0x42) {})
+	            CreateByteField (BUFF, 0x00, STAT)
+	            CreateByteField (BUFF, 0x01, LENG)
+	            CreateByteField (BUFF, 0x02, CMPC)
+	            CreateByteField (BUFF, 0x03, DID)
+	            CreateByteField (BUFF, 0x04, DREV)
+	            CreateWordField (BUFF, 0x05, FREV)
+	            CreateByteField (BUFF, 0x07, SREV)
+	            CreateByteField (BUFF, 0x08, ADS)
+	            CreateByteField (BUFF, 0x09, VID0)
+	            CreateByteField (BUFF, 0x0A, VID1)
+	            CreateByteField (BUFF, 0x0B, VID2)
+	            CreateByteField (BUFF, 0x0C, PID0)
+	            CreateByteField (BUFF, 0x0D, PID1)
+	            CreateDWordField (BUFF, 0x0E, AFRI)
+	            Store (0x00, LENG)
+	            Store (Store (BUFF, GDIC), BUFF)
+	            If (LAnd (LEqual (STAT, 0x00), LEqual (CMPC, 0x00)))
+	            {
+	                Name (VBUF, Buffer (0x03) { 0x00, 0x00, 0x00 })
+	                Name (PBUF, Buffer (0x02) { 0x00, 0x00 })
+	                Store (DID, Index (GDIR, 0x00))
+	                Store (DREV, Index (GDIR, 0x01))
+	                Store (FREV, Index (GDIR, 0x02))
+	                Store (SREV, Index (GDIR, 0x03))
+	                Store (ADS, Index (GDIR, 0x04))
+	                Store (VID0, Index (VBUF, 0x00))
+	                Store (VID1, Index (VBUF, 0x01))
+	                Store (VID2, Index (VBUF, 0x02))
+	                Store (VBUF, Index (GDIR, 0x05))
+	                Store (PID0, Index (PBUF, 0x00))
+	                Store (PID1, Index (PBUF, 0x01))
+	                Store (PBUF, Index (GDIR, 0x06))
+	                Store (AFRI, Index (GDIR, 0x07))
+	            }
+	            Return (GDIR)
+	        }
+	    }
+	  It is for validation purpose, only calls "Get Device ID" command.
+
 source "drivers/acpi/apei/Kconfig"
 
 endif	# ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 81dbeb8..1476623 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
 obj-$(CONFIG_ACPI_I2C)		+= acpi_i2c.o
+obj-$(CONFIG_ACPI_IPMI_TEST)	+= ipmi_test.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/ipmi_test.c b/drivers/acpi/ipmi_test.c
new file mode 100644
index 0000000..5d144e4
--- /dev/null
+++ b/drivers/acpi/ipmi_test.c
@@ -0,0 +1,254 @@
+/*
+ * An IPMI operation region tester driver
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *   Author: Lv Zheng <lv.zheng@xxxxxxxxx>
+ *
+ * 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
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+
+#define ACPI_IPMI_TEST_NAME		"ipmi_test"
+ACPI_MODULE_NAME(ACPI_IPMI_TEST_NAME);
+
+#define ACPI_IPMI_TEST_DEVICE		"IPMI Test"
+#define ACPI_IPMI_TEST_CLASS		"ipmi_tester"
+
+static const struct acpi_device_id acpi_ipmi_test_ids[] = {
+	{"ZETA0000", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, acpi_ipmi_test_ids);
+
+struct acpi_ipmi_device_id {
+	u64	device_id;
+	u64	device_rev;
+	u64	firmware_rev;
+	u64	ipmi_version;
+	u64	additional_dev_support;
+	u8	*vendor_id;
+	u8	*product_id;
+	u64	aux_firm_rev_info;
+	u8	extra_buf[5];
+} __packed;
+
+struct acpi_ipmi_tester {
+	struct acpi_device	*adev;
+	acpi_bus_id		name;
+	struct acpi_ipmi_device_id	device_id;
+	int			registered_group;
+};
+
+#define ipmi_err(tester, fmt, ...)	\
+	dev_err(&(tester)->adev->dev, fmt, ##__VA_ARGS__)
+#define ipmi_info(tester, fmt, ...)	\
+	dev_info(&(tester)->adev->dev, fmt, ##__VA_ARGS__)
+#define IPMI_ACPI_HANDLE(tester)	((tester)->adev->handle)
+
+static int acpi_ipmi_update_device_id(struct acpi_ipmi_tester *tester)
+{
+	int res = 0;
+	acpi_status status;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer format = { sizeof("NNNNNBBN"), "NNNNNBBN" };
+	struct acpi_buffer device_id = { 0, NULL };
+	union acpi_object *did;
+
+	status = acpi_evaluate_object(IPMI_ACPI_HANDLE(tester), "GDIM", NULL,
+				      &buffer);
+	if (ACPI_FAILURE(status) || !buffer.pointer) {
+		ipmi_err(tester, "Evaluating GDIM, status - %d\n", status);
+		return -ENODEV;
+	}
+
+	did = buffer.pointer;
+	if (did->type != ACPI_TYPE_PACKAGE || did->package.count != 8) {
+		ipmi_err(tester, "Invalid GDIM data, type - %d, count - %d\n",
+			 did->type, did->package.count);
+		res = -EFAULT;
+		goto err_buf;
+	}
+
+	device_id.length = sizeof(struct acpi_ipmi_device_id);
+	device_id.pointer = &tester->device_id;
+
+	status = acpi_extract_package(did, &format, &device_id);
+	if (ACPI_FAILURE(status)) {
+		ipmi_err(tester, "Invalid GDIM data\n");
+		res = -EFAULT;
+		goto err_buf;
+	}
+
+err_buf:
+	kfree(buffer.pointer);
+	return res;
+}
+
+static ssize_t show_device_id(struct device *device,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(device);
+	struct acpi_ipmi_tester *tester = adev->driver_data;
+
+	acpi_ipmi_update_device_id(tester);
+	return sprintf(buf, "%llu\n", tester->device_id.device_id);
+}
+
+static ssize_t show_device_rev(struct device *device,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(device);
+	struct acpi_ipmi_tester *tester = adev->driver_data;
+
+	acpi_ipmi_update_device_id(tester);
+	return sprintf(buf, "%llu\n", tester->device_id.device_rev);
+}
+
+static ssize_t show_firmware_rev(struct device *device,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(device);
+	struct acpi_ipmi_tester *tester = adev->driver_data;
+
+	acpi_ipmi_update_device_id(tester);
+	return sprintf(buf, "%llu\n", tester->device_id.firmware_rev);
+}
+
+static ssize_t show_ipmi_version(struct device *device,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(device);
+	struct acpi_ipmi_tester *tester = adev->driver_data;
+
+	acpi_ipmi_update_device_id(tester);
+	return sprintf(buf, "%llu\n", tester->device_id.ipmi_version);
+}
+
+static ssize_t show_vendor_id(struct device *device,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(device);
+	struct acpi_ipmi_tester *tester = adev->driver_data;
+
+	acpi_ipmi_update_device_id(tester);
+	return sprintf(buf, "%02x %02x %02x\n",
+		       tester->device_id.vendor_id[0],
+		       tester->device_id.vendor_id[1],
+		       tester->device_id.vendor_id[2]);
+}
+
+static ssize_t show_product_id(struct device *device,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(device);
+	struct acpi_ipmi_tester *tester = adev->driver_data;
+
+	acpi_ipmi_update_device_id(tester);
+	return sprintf(buf, "%02x %02x\n",
+		       tester->device_id.product_id[0],
+		       tester->device_id.product_id[1]);
+}
+
+static DEVICE_ATTR(device_id, S_IRUGO, show_device_id, NULL);
+static DEVICE_ATTR(device_rev, S_IRUGO, show_device_rev, NULL);
+static DEVICE_ATTR(firmware_rev, S_IRUGO, show_firmware_rev, NULL);
+static DEVICE_ATTR(ipmi_version, S_IRUGO, show_ipmi_version, NULL);
+static DEVICE_ATTR(vendor_id, S_IRUGO, show_vendor_id, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, show_product_id, NULL);
+
+static struct attribute *acpi_ipmi_test_attrs[] = {
+	&dev_attr_device_id.attr,
+	&dev_attr_device_rev.attr,
+	&dev_attr_firmware_rev.attr,
+	&dev_attr_ipmi_version.attr,
+	&dev_attr_vendor_id.attr,
+	&dev_attr_product_id.attr,
+	NULL,
+};
+
+static struct attribute_group acpi_ipmi_test_group = {
+	.attrs	= acpi_ipmi_test_attrs,
+};
+
+static int acpi_ipmi_test_add(struct acpi_device *device)
+{
+	struct acpi_ipmi_tester *tester;
+
+	if (!device)
+		return -EINVAL;
+
+	tester = kzalloc(sizeof(struct acpi_ipmi_tester), GFP_KERNEL);
+	if (!tester)
+		return -ENOMEM;
+
+	tester->adev = device;
+	strcpy(acpi_device_name(device), ACPI_IPMI_TEST_DEVICE);
+	strcpy(acpi_device_class(device), ACPI_IPMI_TEST_CLASS);
+	device->driver_data = tester;
+	if (sysfs_create_group(&device->dev.kobj, &acpi_ipmi_test_group) == 0)
+		tester->registered_group = 1;
+
+	return 0;
+}
+
+static int acpi_ipmi_test_remove(struct acpi_device *device)
+{
+	struct acpi_ipmi_tester *tester;
+
+	if (!device || !acpi_driver_data(device))
+		return -EINVAL;
+
+	tester = acpi_driver_data(device);
+
+	if (tester->registered_group)
+		sysfs_remove_group(&device->dev.kobj, &acpi_ipmi_test_group);
+
+	kfree(tester);
+	return 0;
+}
+
+static struct acpi_driver acpi_ipmi_test_driver = {
+	.name = "ipmi_test",
+	.class = ACPI_IPMI_TEST_CLASS,
+	.ids = acpi_ipmi_test_ids,
+	.ops = {
+		.add = acpi_ipmi_test_add,
+		.remove = acpi_ipmi_test_remove,
+	},
+};
+
+static int __init acpi_ipmi_test_init(void)
+{
+	return acpi_bus_register_driver(&acpi_ipmi_test_driver);
+}
+module_init(acpi_ipmi_test_init);
+
+static void __exit acpi_ipmi_test_exit(void)
+{
+	acpi_bus_unregister_driver(&acpi_ipmi_test_driver);
+}
+module_exit(acpi_ipmi_test_exit);
+
+MODULE_AUTHOR("Lv Zheng <lv.zheng@xxxxxxxxx>");
+MODULE_DESCRIPTION("ACPI IPMI operation region tester driver");
+MODULE_LICENSE("GPL");
-- 
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux