From c4da6940a7a41c72781ff2d62ebd4b99f3749f14 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 17 Nov 2009 17:05:14 -0700 Subject: [PATCH 1/5] PNPACPI: save struct acpi_device, not just acpi_handle Some drivers need to look at things in the acpi_device structure besides the handle. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/core.c | 17 ++++++++++++----- drivers/pnp/pnpacpi/rsparser.c | 9 ++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 83b8b5ac49c9..b2348fc2378e 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -80,7 +80,8 @@ static int pnpacpi_get_resources(struct pnp_dev *dev) static int pnpacpi_set_resources(struct pnp_dev *dev) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; struct acpi_buffer buffer; int ret; @@ -103,7 +104,8 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) static int pnpacpi_disable_resources(struct pnp_dev *dev) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; int ret; dev_dbg(&dev->dev, "disable resources\n"); @@ -121,6 +123,8 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) #ifdef CONFIG_ACPI_SLEEP static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) { + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; int power_state; power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); @@ -128,12 +132,15 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) power_state = (state.event == PM_EVENT_ON) ? ACPI_STATE_D0 : ACPI_STATE_D3; - return acpi_bus_set_power((acpi_handle) dev->data, power_state); + return acpi_bus_set_power(handle, power_state); } static int pnpacpi_resume(struct pnp_dev *dev) { - return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0); + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; + + return acpi_bus_set_power(handle, ACPI_STATE_D0); } #endif @@ -168,7 +175,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) if (!dev) return -ENOMEM; - dev->data = device->handle; + dev->data = device; /* .enabled means the device can decode the resources */ dev->active = device->status.enabled; status = acpi_get_handle(device->handle, "_SRS", &temp); diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index ef3a2cd3a7a0..5702b2c8691f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -465,7 +465,8 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; acpi_status status; pnp_dbg(&dev->dev, "parse allocated resources\n"); @@ -773,7 +774,8 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; acpi_status status; struct acpipnp_parse_option_s parse_data; @@ -845,7 +847,8 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) int pnpacpi_build_resource_template(struct pnp_dev *dev, struct acpi_buffer *buffer) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; struct acpi_resource *resource; int res_cnt = 0; acpi_status status; From 9065ce4500085b9ca66b19d3c4d21a73cb410173 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 17 Nov 2009 17:05:19 -0700 Subject: [PATCH 2/5] PNP: add interface to retrieve ACPI device from a PNPACPI device Add pnp_acpi_device(pnp_dev), which takes a PNP device and returns the associated ACPI device (or NULL, if the device is not a PNPACPI device). This allows us to write a PNP driver that can manage both traditional PNPBIOS and ACPI devices, treating ACPI-only functionality as an optional extension. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/core.c | 3 ++- include/linux/pnp.h | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index b2348fc2378e..5314bf630bc4 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -144,7 +144,7 @@ static int pnpacpi_resume(struct pnp_dev *dev) } #endif -static struct pnp_protocol pnpacpi_protocol = { +struct pnp_protocol pnpacpi_protocol = { .name = "Plug and Play ACPI", .get = pnpacpi_get_resources, .set = pnpacpi_set_resources, @@ -154,6 +154,7 @@ static struct pnp_protocol pnpacpi_protocol = { .resume = pnpacpi_resume, #endif }; +EXPORT_SYMBOL(pnpacpi_protocol); static int __init pnpacpi_add_device(struct acpi_device *device) { diff --git a/include/linux/pnp.h b/include/linux/pnp.h index fddfafaed024..7c4193eb0072 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -334,6 +334,19 @@ extern struct pnp_protocol pnpbios_protocol; #define pnp_device_is_pnpbios(dev) 0 #endif +#ifdef CONFIG_PNPACPI +extern struct pnp_protocol pnpacpi_protocol; + +static inline struct acpi_device *pnp_acpi_device(struct pnp_dev *dev) +{ + if (dev->protocol == &pnpacpi_protocol) + return dev->data; + return NULL; +} +#else +#define pnp_acpi_device(dev) 0 +#endif + /* status */ #define PNP_READY 0x0000 #define PNP_ATTACHED 0x0001 From ad497680a5ff646e645752e3e065a752f32f12f8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 17 Nov 2009 17:05:24 -0700 Subject: [PATCH 3/5] ipmi: remove unused PCI probe code Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/char/ipmi/ipmi_si_intf.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index d2e698096ace..aaf6eadaa4f9 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2202,7 +2202,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, int rv; int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; struct smi_info *info; - int first_reg_offset = 0; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) @@ -2241,9 +2240,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, info->addr_source_cleanup = ipmi_pci_cleanup; info->addr_source_data = pdev; - if (pdev->subsystem_vendor == PCI_HP_VENDOR_ID) - first_reg_offset = 1; - if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { info->io_setup = port_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; From 18a3e0bfbcd589599d0affbfd484ba9a97e5f122 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 17 Nov 2009 17:05:29 -0700 Subject: [PATCH 4/5] ipmi: refer to table as "SPMI", not "ACPI" This discovery method uses the SPMI table, not the ACPI namespace. In the future, we will look in the namespace, so let's refer to the table as "SPMI" and save "ACPI" for the namespace. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/char/ipmi/ipmi_si_intf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index aaf6eadaa4f9..b58e587d2990 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1919,7 +1919,7 @@ struct SPMITable { s8 spmi_id[1]; /* A '\0' terminated array starts here. */ }; -static __devinit int try_init_acpi(struct SPMITable *spmi) +static __devinit int try_init_spmi(struct SPMITable *spmi) { struct smi_info *info; u8 addr_space; @@ -1940,7 +1940,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) return -ENOMEM; } - info->addr_source = "ACPI"; + info->addr_source = "SPMI"; /* Figure out the interface type. */ switch (spmi->InterfaceType) { @@ -2002,7 +2002,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) return 0; } -static __devinit void acpi_find_bmc(void) +static __devinit void spmi_find_bmc(void) { acpi_status status; struct SPMITable *spmi; @@ -2020,7 +2020,7 @@ static __devinit void acpi_find_bmc(void) if (status != AE_OK) return; - try_init_acpi(spmi); + try_init_spmi(spmi); } } #endif @@ -3104,7 +3104,7 @@ static __devinit int init_ipmi_si(void) #endif #ifdef CONFIG_ACPI - acpi_find_bmc(); + spmi_find_bmc(); #endif #ifdef CONFIG_PCI From 9e368fa011d4e0aa050db348d69514900520e40b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 17 Nov 2009 17:05:34 -0700 Subject: [PATCH 5/5] ipmi: add PNP discovery (ACPI namespace via PNPACPI) This allows ipmi_si_intf.c to claim IPMI devices described in the ACPI namespace. Using PNP makes it simpler to parse the IRQ/IO/memory resources of the device. We look at any SPMI tables before looking for devices in the namespace. This is based on ipmi_pci_probe(). Signed-off-by: Bjorn Helgaas Signed-off-by: Myron Stowe Signed-off-by: Len Brown --- drivers/char/ipmi/ipmi_si_intf.c | 104 +++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b58e587d2990..679cd08b80b4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -64,6 +64,7 @@ #include #include #include +#include #ifdef CONFIG_PPC_OF #include @@ -2023,6 +2024,103 @@ static __devinit void spmi_find_bmc(void) try_init_spmi(spmi); } } + +static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, + const struct pnp_device_id *dev_id) +{ + struct acpi_device *acpi_dev; + struct smi_info *info; + acpi_handle handle; + acpi_status status; + unsigned long long tmp; + + acpi_dev = pnp_acpi_device(dev); + if (!acpi_dev) + return -ENODEV; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->addr_source = "ACPI"; + + handle = acpi_dev->handle; + + /* _IFT tells us the interface type: KCS, BT, etc */ + status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); + if (ACPI_FAILURE(status)) + goto err_free; + + switch (tmp) { + 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: + dev_info(&dev->dev, "unknown interface type %lld\n", tmp); + goto err_free; + } + + if (pnp_port_valid(dev, 0)) { + info->io_setup = port_setup; + info->io.addr_type = IPMI_IO_ADDR_SPACE; + info->io.addr_data = pnp_port_start(dev, 0); + } else if (pnp_mem_valid(dev, 0)) { + info->io_setup = mem_setup; + info->io.addr_type = IPMI_MEM_ADDR_SPACE; + info->io.addr_data = pnp_mem_start(dev, 0); + } else { + dev_err(&dev->dev, "no I/O or memory address\n"); + goto err_free; + } + + info->io.regspacing = DEFAULT_REGSPACING; + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = 0; + + /* If _GPE exists, use it; otherwise use standard interrupts */ + status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); + if (ACPI_SUCCESS(status)) { + info->irq = tmp; + info->irq_setup = acpi_gpe_irq_setup; + } else if (pnp_irq_valid(dev, 0)) { + info->irq = pnp_irq(dev, 0); + info->irq_setup = std_irq_setup; + } + + info->dev = &acpi_dev->dev; + pnp_set_drvdata(dev, info); + + return try_smi_init(info); + +err_free: + kfree(info); + return -EINVAL; +} + +static void __devexit ipmi_pnp_remove(struct pnp_dev *dev) +{ + struct smi_info *info = pnp_get_drvdata(dev); + + cleanup_one_si(info); +} + +static const struct pnp_device_id pnp_dev_table[] = { + {"IPI0001", 0}, + {"", 0}, +}; + +static struct pnp_driver ipmi_pnp_driver = { + .name = DEVICE_NAME, + .probe = ipmi_pnp_probe, + .remove = __devexit_p(ipmi_pnp_remove), + .id_table = pnp_dev_table, +}; #endif #ifdef CONFIG_DMI @@ -3106,6 +3204,9 @@ static __devinit int init_ipmi_si(void) #ifdef CONFIG_ACPI spmi_find_bmc(); #endif +#ifdef CONFIG_PNP + pnp_register_driver(&ipmi_pnp_driver); +#endif #ifdef CONFIG_PCI rv = pci_register_driver(&ipmi_pci_driver); @@ -3229,6 +3330,9 @@ static __exit void cleanup_ipmi_si(void) #ifdef CONFIG_PCI pci_unregister_driver(&ipmi_pci_driver); #endif +#ifdef CONFIG_PNP + pnp_unregister_driver(&ipmi_pnp_driver); +#endif #ifdef CONFIG_PPC_OF of_unregister_platform_driver(&ipmi_of_platform_driver);