@@ -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},
@@ -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 */