RE: [Openipmi-developer] acpi_find_bmc() and acpi_get_table()

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

 



Corey,

  Here is the patch (RHEL5 base code) I've been testing that detects the ACPI namespace object.
The IPI0001 device doesn't contain the register spacing directly; it has a _CRS resource object that
(for KCS) has two I/O port entries.  I save the first port in io.addr_data, then calculate the register spacing based on subtracting the 2nd port address and the 1st.

I'm thinking of changing the register spacing to using an array of port/memory addresses to make calculating interface addresses more generic.

eg.
static unsigned char port_inb(struct si_sm_io *io, unsigned int offset)
{
        unsigned int addr = io->addr_data;

        return inb(addr + (offset * io->regspacing));
}

would become something like:
static unsigned char port_inb(struct si_sm_io *io, unsigned int offset)
{
        unsigned int addr = io->addr_data[offset];

        return inb(addr);
}

--jordan hargrave
Dell Enterprise Linux Engineering



-----Original Message-----
From: Matt Domsch [mailto:Matt_Domsch@xxxxxxxx]
Sent: Sun 2/25/2007 3:59 PM
To: Corey Minyard; Hargrave, Jordan
Cc: Alexey Starikovskiy; linux-acpi@xxxxxxxxxxxxxxx; openipmi; Len Brown; Bjorn Helgaas
Subject: Re: [Openipmi-developer] acpi_find_bmc() and acpi_get_table()
 
On Tue, Feb 20, 2007 at 07:55:36AM -0600, Corey Minyard wrote:
> Alexey Starikovskiy wrote:
> > Bjorn Helgaas wrote:
> >> On Thursday 15 February 2007 22:15, Corey Minyard wrote:
> >>  
> >>> Bjorn Helgaas wrote:
> >>>    
> >>>> On Saturday 10 February 2007 21:27, Len Brown wrote:
> >>>>        
> >>>>> acpi_find_bmc() appears to be searching for multiple SPMI tables 
> >>>>> in the RSDT and running
> >>>>> try_init_acpi() on each of them
> >>>>> until it doesn't find any more.
> >>>>>             
> >>>> I can't remember why we look at the SPMI table(s) rather than
> >>>> registering a normal ACPI (or even PNP) driver.  Unless we
> >>>> need to poke the BMC very early, wouldn't it be better to
> >>>> rely on the device description in the namespace?
> >>>>         
> >>> For some strange reason the normal ACPI information does not
> >>> have all the information needed by the driver.  It doesn't have
> >>> register size or spacing information.
> >>>     
> >>
> >> I guess that would be a defect in the way ACPI is being used,
> >> wouldn't it?  A PNP ID should define the device programming
> >> model, including things like register size and spacing.  It
> >> sounds like somebody didn't define a new PNP ID when he should
> >> have.  I wonder whether it's worth trying to fix this.
> >>
> >>   
> > Yes, it is considered an ACPI fault. Could you please describe in 
> > detail, which registers miss the information? And probably your 
> > acpidump will help as well.
> I don't have a machine with an ACPI description of the BMC.  I'll copy 
> the mailing list to see if anyone has an ACPI-described BMC.
> 
> I don't know that much about ACPI, so maybe that information is 
> described somehow in a way the IPMI spec doesn't talk about directly, 
> like in the _CRS object.

Let me copy my teammate Jordan Hargrave in on this, as he's been
working with our BIOS team to implement discovery through an IPI0
object in the namespace, and thinks he can derive the register spacing
and interrupt assignment (if any).

-- 
Matt Domsch
Software Architect
Dell Linux Solutions linux.dell.com & www.dell.com/linux
Linux on Dell mailing lists @ http://lists.us.dell.com


--- /usr/src/redhat/BUILD/kernel-2.6.18/linux-2.6.18.x86_64/drivers/char/ipmi/ipmi_si_intf.c	2007-02-26 10:40:55.000000000 -0600
+++ ipmi_si_intf.c	2007-02-26 12:10:05.000000000 -0600
@@ -1371,6 +1371,58 @@ static __devinit void hardcode_find_bmc(
    through the tables sequentially.  Once we don't find a table, there
    are no more. */
 static int acpi_failure = 0;
+static acpi_handle acpi_ipmi_handle;
+
+#define ACPI_IPMI_DRIVER_NAME "ipmi"
+#define ACPI_IPMI_CLASS       "ipmi"
+#define ACPI_IPMI_HID         "IPI0001"
+
+static int acpi_ipmi_add(struct acpi_device *);
+static int acpi_ipmi_remove(struct acpi_device *, int);
+
+static struct acpi_driver acpi_ipmi_driver = {
+  .name = ACPI_IPMI_DRIVER_NAME,
+  .class = ACPI_IPMI_CLASS,
+  .ids = ACPI_IPMI_HID,
+  .ops = {
+    .add = acpi_ipmi_add,
+    .remove = acpi_ipmi_remove,
+  },
+};
+
+static acpi_status
+acpi_ipmi_getresource(struct acpi_resource *res, void *context)
+{
+	struct smi_info *info = context;
+	
+	if (res->type == ACPI_RESOURCE_TYPE_IO) {
+		struct acpi_resource_io *io_res = &res->data.io;
+		if (info->io.addr_data == 0) {
+			info->io.regshift = 0;
+			info->io.regsize = io_res->address_length;
+			info->io.addr_data = io_res->minimum;
+			info->io.addr_type = IPMI_IO_ADDR_SPACE;
+			info->io_setup = port_setup;
+		}
+		else {
+			/* Calculate regspacing based on previous register */
+			info->io.regspacing = io_res->minimum - info->io.addr_data;
+		}
+	}
+	return AE_OK;
+}
+
+int acpi_ipmi_add(struct acpi_device *device)
+{
+	if (device)
+		acpi_ipmi_handle = device->handle;
+	return 0;
+}
+
+int acpi_ipmi_remove(struct acpi_device *device, int type)
+{
+	return 0;
+}
 
 /* For GPE-type interrupts. */
 static u32 ipmi_acpi_gpe(void *context)
@@ -1478,6 +1530,72 @@ struct SPMITable {
 	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
 };
 
+static __devinit int try_init_acpidev()
+{
+  	acpi_status status = AE_OK;
+	unsigned long sta, type, gpe;
+	struct smi_info  *info;
+
+	if (acpi_ipmi_handle == 0)
+	  	return -ENODEV;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (info == NULL) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
+	  	return -ENOMEM;
+	}
+
+	status = acpi_evaluate_integer(acpi_ipmi_handle, "_STA", NULL, &sta);
+	if (status != AE_OK || !(sta & ACPI_STA_DEVICE_PRESENT)) {
+		printk(KERN_ERR "ipmi_si: _STA not present\n");
+		kfree(info);
+		return -ENODEV;
+	}
+
+	status = acpi_evaluate_integer(acpi_ipmi_handle, "_IFT", NULL, &type);
+	if (status != AE_OK) {
+		printk(KERN_ERR "ipmi_si: Could not get _IFT interface type\n");
+		kfree(info);
+		return -ENODEV;
+	}
+	status = acpi_evaluate_integer(acpi_ipmi_handle, "_GPE", NULL, &gpe);
+	if (status == AE_OK) {
+		info->irq = gpe;
+		info->irq_setup = acpi_gpe_irq_setup;
+	}
+
+	info->addr_source = "ACPI";
+	switch (type) {
+	case 1:
+		info->si_type = SI_KCS;
+		break;
+	case 2:
+		info->si_type = SI_SMIC;
+		break;
+	case 3:
+		info->si_type = SI_BT;
+		break;
+	default:
+		printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",
+			type);
+		kfree(info);
+		return -EIO;
+	}
+	acpi_walk_resources(acpi_ipmi_handle, METHOD_NAME__CRS,
+			    acpi_ipmi_getresource, info);
+	if (info->io.regspacing == 0) {
+		printk(KERN_ERR "ipmi_si: Could not get register spacing!\n");
+		kfree(info);
+		return -ENODEV;
+	}
+	if (try_smi_init(info) == 0) {
+		printk(KERN_INFO "ipmi_si: Found ACPI IPMI device %s at %s address 0x%lx\n",
+			si_to_str[info->si_type], addr_space_to_str[info->io.addr_type],
+			info->io.addr_data);
+	}
+	return 0;
+}
+
 static __devinit int try_init_acpi(struct SPMITable *spmi)
 {
 	struct smi_info  *info;
@@ -1576,6 +1694,12 @@ static __devinit void acpi_find_bmc(void
 	if (acpi_failure)
 		return;
 
+	/* Really we only need to get the IPMI device handle here */
+	acpi_bus_register_driver(&acpi_ipmi_driver);
+	acpi_bus_unregister_driver(&acpi_ipmi_driver);
+	if (try_init_acpidev() == 0)
+		return;
+
 	for (i = 0; ; i++) {
 		status = acpi_get_firmware_table("SPMI", i+1,
 						 ACPI_LOGICAL_ADDRESSING,

[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