Commit 2407d77a authored by Matthew Garrett's avatar Matthew Garrett Committed by Linus Torvalds

ipmi: split device discovery and registration

The ipmi spec indicates that we should only make use of one si per bmc, so
separate device discovery and registration to make that possible.

[thenzl@redhat.com: fix mutex use]
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
Signed-off-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5fedc4a2
...@@ -308,6 +308,7 @@ static int num_max_busy_us; ...@@ -308,6 +308,7 @@ static int num_max_busy_us;
static int unload_when_empty = 1; static int unload_when_empty = 1;
static int add_smi(struct smi_info *smi);
static int try_smi_init(struct smi_info *smi); static int try_smi_init(struct smi_info *smi);
static void cleanup_one_si(struct smi_info *to_clean); static void cleanup_one_si(struct smi_info *to_clean);
...@@ -1785,7 +1786,9 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) ...@@ -1785,7 +1786,9 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
info->irq_setup = std_irq_setup; info->irq_setup = std_irq_setup;
info->slave_addr = ipmb; info->slave_addr = ipmb;
try_smi_init(info); if (!add_smi(info))
if (try_smi_init(info))
cleanup_one_si(info);
} else { } else {
/* remove */ /* remove */
struct smi_info *e, *tmp_e; struct smi_info *e, *tmp_e;
...@@ -1871,7 +1874,9 @@ static __devinit void hardcode_find_bmc(void) ...@@ -1871,7 +1874,9 @@ static __devinit void hardcode_find_bmc(void)
info->irq_setup = std_irq_setup; info->irq_setup = std_irq_setup;
info->slave_addr = slave_addrs[i]; info->slave_addr = slave_addrs[i];
try_smi_init(info); if (!add_smi(info))
if (try_smi_init(info))
cleanup_one_si(info);
} }
} }
...@@ -2069,7 +2074,7 @@ static __devinit int try_init_spmi(struct SPMITable *spmi) ...@@ -2069,7 +2074,7 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
} }
info->io.addr_data = spmi->addr.address; info->io.addr_data = spmi->addr.address;
try_smi_init(info); add_smi(info);
return 0; return 0;
} }
...@@ -2167,7 +2172,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, ...@@ -2167,7 +2172,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
info->dev = &acpi_dev->dev; info->dev = &acpi_dev->dev;
pnp_set_drvdata(dev, info); pnp_set_drvdata(dev, info);
return try_smi_init(info); return add_smi(info);
err_free: err_free:
kfree(info); kfree(info);
...@@ -2326,7 +2331,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) ...@@ -2326,7 +2331,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
if (info->irq) if (info->irq)
info->irq_setup = std_irq_setup; info->irq_setup = std_irq_setup;
try_smi_init(info); add_smi(info);
} }
static void __devinit dmi_find_bmc(void) static void __devinit dmi_find_bmc(void)
...@@ -2429,7 +2434,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, ...@@ -2429,7 +2434,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
info->dev = &pdev->dev; info->dev = &pdev->dev;
pci_set_drvdata(pdev, info); pci_set_drvdata(pdev, info);
return try_smi_init(info); return add_smi(info);
} }
static void __devexit ipmi_pci_remove(struct pci_dev *pdev) static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
...@@ -2542,7 +2547,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev, ...@@ -2542,7 +2547,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
dev_set_drvdata(&dev->dev, info); dev_set_drvdata(&dev->dev, info);
return try_smi_init(info); return add_smi(info);
} }
static int __devexit ipmi_of_remove(struct of_device *dev) static int __devexit ipmi_of_remove(struct of_device *dev)
...@@ -2971,14 +2976,16 @@ static __devinit void default_find_bmc(void) ...@@ -2971,14 +2976,16 @@ static __devinit void default_find_bmc(void)
info->io.regsize = DEFAULT_REGSPACING; info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = 0; info->io.regshift = 0;
if (try_smi_init(info) == 0) { if (add_smi(info) == 0) {
if ((try_smi_init(info)) == 0) {
/* Found one... */ /* Found one... */
printk(KERN_INFO "ipmi_si: Found default %s state" printk(KERN_INFO "ipmi_si: Found default %s"
" machine at %s address 0x%lx\n", " state machine at %s address 0x%lx\n",
si_to_str[info->si_type], si_to_str[info->si_type],
addr_space_to_str[info->io.addr_type], addr_space_to_str[info->io.addr_type],
info->io.addr_data); info->io.addr_data);
return; } else
cleanup_one_si(info);
} }
} }
} }
...@@ -2997,32 +3004,48 @@ static int is_new_interface(struct smi_info *info) ...@@ -2997,32 +3004,48 @@ static int is_new_interface(struct smi_info *info)
return 1; return 1;
} }
static int try_smi_init(struct smi_info *new_smi) static int add_smi(struct smi_info *new_smi)
{ {
int rv; int rv = 0;
int i;
printk(KERN_INFO "ipmi_si: Trying %s-specified %s state" printk(KERN_INFO "ipmi_si: Adding %s-specified %s state machine",
" machine at %s address 0x%lx, slave address 0x%x,"
" irq %d\n",
ipmi_addr_src_to_str[new_smi->addr_source], ipmi_addr_src_to_str[new_smi->addr_source],
si_to_str[new_smi->si_type], si_to_str[new_smi->si_type]);
addr_space_to_str[new_smi->io.addr_type],
new_smi->io.addr_data,
new_smi->slave_addr, new_smi->irq);
mutex_lock(&smi_infos_lock); mutex_lock(&smi_infos_lock);
if (!is_new_interface(new_smi)) { if (!is_new_interface(new_smi)) {
printk(KERN_WARNING "ipmi_si: duplicate interface\n"); printk(KERN_CONT ": duplicate interface\n");
rv = -EBUSY; rv = -EBUSY;
goto out_err; goto out_err;
} }
printk(KERN_CONT "\n");
/* So we know not to free it unless we have allocated one. */ /* So we know not to free it unless we have allocated one. */
new_smi->intf = NULL; new_smi->intf = NULL;
new_smi->si_sm = NULL; new_smi->si_sm = NULL;
new_smi->handlers = NULL; new_smi->handlers = NULL;
list_add_tail(&new_smi->link, &smi_infos);
out_err:
mutex_unlock(&smi_infos_lock);
return rv;
}
static int try_smi_init(struct smi_info *new_smi)
{
int rv = 0;
int i;
printk(KERN_INFO "ipmi_si: Trying %s-specified %s state"
" machine at %s address 0x%lx, slave address 0x%x,"
" irq %d\n",
ipmi_addr_src_to_str[new_smi->addr_source],
si_to_str[new_smi->si_type],
addr_space_to_str[new_smi->io.addr_type],
new_smi->io.addr_data,
new_smi->slave_addr, new_smi->irq);
switch (new_smi->si_type) { switch (new_smi->si_type) {
case SI_KCS: case SI_KCS:
new_smi->handlers = &kcs_smi_handlers; new_smi->handlers = &kcs_smi_handlers;
...@@ -3183,10 +3206,6 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -3183,10 +3206,6 @@ static int try_smi_init(struct smi_info *new_smi)
goto out_err_stop_timer; goto out_err_stop_timer;
} }
list_add_tail(&new_smi->link, &smi_infos);
mutex_unlock(&smi_infos_lock);
printk(KERN_INFO "IPMI %s interface initialized\n", printk(KERN_INFO "IPMI %s interface initialized\n",
si_to_str[new_smi->si_type]); si_to_str[new_smi->si_type]);
...@@ -3197,11 +3216,17 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -3197,11 +3216,17 @@ static int try_smi_init(struct smi_info *new_smi)
wait_for_timer_and_thread(new_smi); wait_for_timer_and_thread(new_smi);
out_err: out_err:
if (new_smi->intf) new_smi->interrupt_disabled = 1;
if (new_smi->intf) {
ipmi_unregister_smi(new_smi->intf); ipmi_unregister_smi(new_smi->intf);
new_smi->intf = NULL;
}
if (new_smi->irq_cleanup) if (new_smi->irq_cleanup) {
new_smi->irq_cleanup(new_smi); new_smi->irq_cleanup(new_smi);
new_smi->irq_cleanup = NULL;
}
/* /*
* Wait until we know that we are out of any interrupt * Wait until we know that we are out of any interrupt
...@@ -3214,18 +3239,21 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -3214,18 +3239,21 @@ static int try_smi_init(struct smi_info *new_smi)
if (new_smi->handlers) if (new_smi->handlers)
new_smi->handlers->cleanup(new_smi->si_sm); new_smi->handlers->cleanup(new_smi->si_sm);
kfree(new_smi->si_sm); kfree(new_smi->si_sm);
new_smi->si_sm = NULL;
} }
if (new_smi->addr_source_cleanup) if (new_smi->addr_source_cleanup) {
new_smi->addr_source_cleanup(new_smi); new_smi->addr_source_cleanup(new_smi);
if (new_smi->io_cleanup) new_smi->addr_source_cleanup = NULL;
}
if (new_smi->io_cleanup) {
new_smi->io_cleanup(new_smi); new_smi->io_cleanup(new_smi);
new_smi->io_cleanup = NULL;
}
if (new_smi->dev_registered) if (new_smi->dev_registered) {
platform_device_unregister(new_smi->pdev); platform_device_unregister(new_smi->pdev);
new_smi->dev_registered = 0;
kfree(new_smi); }
mutex_unlock(&smi_infos_lock);
return rv; return rv;
} }
...@@ -3235,6 +3263,7 @@ static __devinit int init_ipmi_si(void) ...@@ -3235,6 +3263,7 @@ static __devinit int init_ipmi_si(void)
int i; int i;
char *str; char *str;
int rv; int rv;
struct smi_info *e;
if (initialized) if (initialized)
return 0; return 0;
...@@ -3292,16 +3321,22 @@ static __devinit int init_ipmi_si(void) ...@@ -3292,16 +3321,22 @@ static __devinit int init_ipmi_si(void)
of_register_platform_driver(&ipmi_of_platform_driver); of_register_platform_driver(&ipmi_of_platform_driver);
#endif #endif
mutex_lock(&smi_infos_lock);
list_for_each_entry(e, &smi_infos, link) {
if (!e->si_sm)
try_smi_init(e);
}
mutex_unlock(&smi_infos_lock);
if (si_trydefaults) { if (si_trydefaults) {
mutex_lock(&smi_infos_lock); mutex_lock(&smi_infos_lock);
if (list_empty(&smi_infos)) { if (list_empty(&smi_infos)) {
/* No BMC was found, try defaults. */ /* No BMC was found, try defaults. */
mutex_unlock(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
default_find_bmc(); default_find_bmc();
} else { } else
mutex_unlock(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
} }
}
mutex_lock(&smi_infos_lock); mutex_lock(&smi_infos_lock);
if (unload_when_empty && list_empty(&smi_infos)) { if (unload_when_empty && list_empty(&smi_infos)) {
...@@ -3326,7 +3361,7 @@ module_init(init_ipmi_si); ...@@ -3326,7 +3361,7 @@ module_init(init_ipmi_si);
static void cleanup_one_si(struct smi_info *to_clean) static void cleanup_one_si(struct smi_info *to_clean)
{ {
int rv; int rv = 0;
unsigned long flags; unsigned long flags;
if (!to_clean) if (!to_clean)
...@@ -3370,13 +3405,16 @@ static void cleanup_one_si(struct smi_info *to_clean) ...@@ -3370,13 +3405,16 @@ static void cleanup_one_si(struct smi_info *to_clean)
schedule_timeout_uninterruptible(1); schedule_timeout_uninterruptible(1);
} }
if (to_clean->intf)
rv = ipmi_unregister_smi(to_clean->intf); rv = ipmi_unregister_smi(to_clean->intf);
if (rv) { if (rv) {
printk(KERN_ERR printk(KERN_ERR
"ipmi_si: Unable to unregister device: errno=%d\n", "ipmi_si: Unable to unregister device: errno=%d\n",
rv); rv);
} }
if (to_clean->handlers)
to_clean->handlers->cleanup(to_clean->si_sm); to_clean->handlers->cleanup(to_clean->si_sm);
kfree(to_clean->si_sm); kfree(to_clean->si_sm);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment