From: Zhao yakui <yakui.zhao@xxxxxxxxx> Signed-off-by: Zhao yakui <yakui.zhao@xxxxxxxxx> cc: Bjorn Helgaas <bjorn.helgaas@xxxxxx> --- drivers/char/ipmi/ipmi_si_intf.c | 63 ++++++++++++++++++++++++++++++++++++++ include/linux/ipmi.h | 8 +++++ 2 files changed, 71 insertions(+), 0 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 094bdc3..91c5d37 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -65,6 +65,7 @@ #include <linux/string.h> #include <linux/ctype.h> #include <linux/pnp.h> +#include <linux/ipmi.h> #ifdef CONFIG_PPC_OF #include <linux/of_device.h> @@ -1907,6 +1908,13 @@ static __devinit void hardcode_find_bmc(void) */ static int acpi_failure; +static BLOCKING_NOTIFIER_HEAD(pnp_ipmi_notifier); +static LIST_HEAD(pnp_ipmi_list); +struct pnp_ipmi_device { + struct list_head head; + struct pnp_dev *pnp_dev; +}; + /* For GPE-type interrupts. */ static u32 ipmi_acpi_gpe(void *context) { @@ -2124,6 +2132,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, acpi_handle handle; acpi_status status; unsigned long long tmp; + struct pnp_ipmi_device *pnp_ipmi; acpi_dev = pnp_acpi_device(dev); if (!acpi_dev) @@ -2133,6 +2142,11 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, if (!info) return -ENOMEM; + pnp_ipmi = kzalloc(sizeof(*pnp_ipmi), GFP_KERNEL); + if (!pnp_ipmi) { + kfree(info); + return -ENOMEM; + } info->addr_source = SI_ACPI; printk(KERN_INFO PFX "probing via ACPI\n"); @@ -2196,20 +2210,69 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, res, info->io.regsize, info->io.regspacing, info->irq); + pnp_ipmi->pnp_dev = dev; + list_add_tail(&pnp_ipmi->head, &pnp_ipmi_list); + blocking_notifier_call_chain(&pnp_ipmi_notifier, IPMI_PNP_ADD, + (void *)dev); + return add_smi(info); err_free: kfree(info); + kfree(pnp_ipmi); return -EINVAL; } static void __devexit ipmi_pnp_remove(struct pnp_dev *dev) { struct smi_info *info = pnp_get_drvdata(dev); + struct pnp_ipmi_device *pnp_ipmi; + + list_for_each_entry(pnp_ipmi, &pnp_ipmi_list, head) { + if (pnp_ipmi->pnp_dev == dev) { + list_del(&pnp_ipmi->head); + blocking_notifier_call_chain(&pnp_ipmi_notifier, + IPMI_PNP_REMOVE, (void *)dev); + break; + } + } cleanup_one_si(info); } +int acpi_ipmi_notifier_register(struct notifier_block *nb) +{ + int ret; + struct pnp_ipmi_device *pnp_ipmi; + + ret = blocking_notifier_chain_register(&pnp_ipmi_notifier, nb); + if (ret == 0) { + /* + * Maybe we already get the corresponding pnp_ipmi_list before + * registering the notifier chain. So call the notifer + * chain list for every pnp_ipmi device. + */ + list_for_each_entry(pnp_ipmi, &pnp_ipmi_list, head) { + blocking_notifier_call_chain(&pnp_ipmi_notifier, + IPMI_PNP_ADD, (void *)(pnp_ipmi->pnp_dev)); + } + } + return ret; +} +EXPORT_SYMBOL(acpi_ipmi_notifier_register); + +int acpi_ipmi_notifier_unregister(struct notifier_block *nb) +{ + struct pnp_ipmi_device *pnp_ipmi; + + list_for_each_entry(pnp_ipmi, &pnp_ipmi_list, head) { + blocking_notifier_call_chain(&pnp_ipmi_notifier, + IPMI_PNP_REMOVE, (void *)(pnp_ipmi->pnp_dev)); + } + return blocking_notifier_chain_unregister(&pnp_ipmi_notifier, nb); +} +EXPORT_SYMBOL(acpi_ipmi_notifier_unregister); + static const struct pnp_device_id pnp_dev_table[] = { {"IPI0001", 0}, {"", 0}, diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 65aae34..4ea2a69 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -694,4 +694,12 @@ struct ipmi_timing_parms { #define IPMICTL_GET_MAINTENANCE_MODE_CMD _IOR(IPMI_IOC_MAGIC, 30, int) #define IPMICTL_SET_MAINTENANCE_MODE_CMD _IOW(IPMI_IOC_MAGIC, 31, int) +#ifdef CONFIG_ACPI +#define IPMI_PNP_ADD 1 +#define IPMI_PNP_REMOVE 2 +extern int acpi_ipmi_notifier_register(struct notifier_block *nb); +extern int acpi_ipmi_notifier_unregister(struct notifier_block *nb); + +#endif + #endif /* __LINUX_IPMI_H */ -- 1.5.4.5 -- 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