aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2009-11-17 19:05:34 -0500
committerLen Brown <len.brown@intel.com>2009-12-15 17:35:54 -0500
commit9e368fa011d4e0aa050db348d69514900520e40b (patch)
tree1b5dfaa305964791a2af6959a47b7bb6c89e471d /drivers/char/ipmi
parent18a3e0bfbcd589599d0affbfd484ba9a97e5f122 (diff)
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 <bjorn.helgaas@hp.com> Signed-off-by: Myron Stowe <myron.stowe@hp.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c104
1 files changed, 104 insertions, 0 deletions
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 @@
64#include <linux/dmi.h> 64#include <linux/dmi.h>
65#include <linux/string.h> 65#include <linux/string.h>
66#include <linux/ctype.h> 66#include <linux/ctype.h>
67#include <linux/pnp.h>
67 68
68#ifdef CONFIG_PPC_OF 69#ifdef CONFIG_PPC_OF
69#include <linux/of_device.h> 70#include <linux/of_device.h>
@@ -2023,6 +2024,103 @@ static __devinit void spmi_find_bmc(void)
2023 try_init_spmi(spmi); 2024 try_init_spmi(spmi);
2024 } 2025 }
2025} 2026}
2027
2028static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
2029 const struct pnp_device_id *dev_id)
2030{
2031 struct acpi_device *acpi_dev;
2032 struct smi_info *info;
2033 acpi_handle handle;
2034 acpi_status status;
2035 unsigned long long tmp;
2036
2037 acpi_dev = pnp_acpi_device(dev);
2038 if (!acpi_dev)
2039 return -ENODEV;
2040
2041 info = kzalloc(sizeof(*info), GFP_KERNEL);
2042 if (!info)
2043 return -ENOMEM;
2044
2045 info->addr_source = "ACPI";
2046
2047 handle = acpi_dev->handle;
2048
2049 /* _IFT tells us the interface type: KCS, BT, etc */
2050 status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
2051 if (ACPI_FAILURE(status))
2052 goto err_free;
2053
2054 switch (tmp) {
2055 case 1:
2056 info->si_type = SI_KCS;
2057 break;
2058 case 2:
2059 info->si_type = SI_SMIC;
2060 break;
2061 case 3:
2062 info->si_type = SI_BT;
2063 break;
2064 default:
2065 dev_info(&dev->dev, "unknown interface type %lld\n", tmp);
2066 goto err_free;
2067 }
2068
2069 if (pnp_port_valid(dev, 0)) {
2070 info->io_setup = port_setup;
2071 info->io.addr_type = IPMI_IO_ADDR_SPACE;
2072 info->io.addr_data = pnp_port_start(dev, 0);
2073 } else if (pnp_mem_valid(dev, 0)) {
2074 info->io_setup = mem_setup;
2075 info->io.addr_type = IPMI_MEM_ADDR_SPACE;
2076 info->io.addr_data = pnp_mem_start(dev, 0);
2077 } else {
2078 dev_err(&dev->dev, "no I/O or memory address\n");
2079 goto err_free;
2080 }
2081
2082 info->io.regspacing = DEFAULT_REGSPACING;
2083 info->io.regsize = DEFAULT_REGSPACING;
2084 info->io.regshift = 0;
2085
2086 /* If _GPE exists, use it; otherwise use standard interrupts */
2087 status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
2088 if (ACPI_SUCCESS(status)) {
2089 info->irq = tmp;
2090 info->irq_setup = acpi_gpe_irq_setup;
2091 } else if (pnp_irq_valid(dev, 0)) {
2092 info->irq = pnp_irq(dev, 0);
2093 info->irq_setup = std_irq_setup;
2094 }
2095
2096 info->dev = &acpi_dev->dev;
2097 pnp_set_drvdata(dev, info);
2098
2099 return try_smi_init(info);
2100
2101err_free:
2102 kfree(info);
2103 return -EINVAL;
2104}
2105
2106static void __devexit ipmi_pnp_remove(struct pnp_dev *dev)
2107{
2108 struct smi_info *info = pnp_get_drvdata(dev);
2109
2110 cleanup_one_si(info);
2111}
2112
2113static const struct pnp_device_id pnp_dev_table[] = {
2114 {"IPI0001", 0},
2115 {"", 0},
2116};
2117
2118static struct pnp_driver ipmi_pnp_driver = {
2119 .name = DEVICE_NAME,
2120 .probe = ipmi_pnp_probe,
2121 .remove = __devexit_p(ipmi_pnp_remove),
2122 .id_table = pnp_dev_table,
2123};
2026#endif 2124#endif
2027 2125
2028#ifdef CONFIG_DMI 2126#ifdef CONFIG_DMI
@@ -3106,6 +3204,9 @@ static __devinit int init_ipmi_si(void)
3106#ifdef CONFIG_ACPI 3204#ifdef CONFIG_ACPI
3107 spmi_find_bmc(); 3205 spmi_find_bmc();
3108#endif 3206#endif
3207#ifdef CONFIG_PNP
3208 pnp_register_driver(&ipmi_pnp_driver);
3209#endif
3109 3210
3110#ifdef CONFIG_PCI 3211#ifdef CONFIG_PCI
3111 rv = pci_register_driver(&ipmi_pci_driver); 3212 rv = pci_register_driver(&ipmi_pci_driver);
@@ -3229,6 +3330,9 @@ static __exit void cleanup_ipmi_si(void)
3229#ifdef CONFIG_PCI 3330#ifdef CONFIG_PCI
3230 pci_unregister_driver(&ipmi_pci_driver); 3331 pci_unregister_driver(&ipmi_pci_driver);
3231#endif 3332#endif
3333#ifdef CONFIG_PNP
3334 pnp_unregister_driver(&ipmi_pnp_driver);
3335#endif
3232 3336
3233#ifdef CONFIG_PPC_OF 3337#ifdef CONFIG_PPC_OF
3234 of_unregister_platform_driver(&ipmi_of_platform_driver); 3338 of_unregister_platform_driver(&ipmi_of_platform_driver);