--- /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,