diff options
author | Matthew Garrett <mjg@redhat.com> | 2010-05-26 17:43:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 12:12:49 -0400 |
commit | 2407d77a1a013b88ee3b817f2b934e420e5376f5 (patch) | |
tree | bb7eeb2621dccc01964612e664de17d612a7aa11 /drivers | |
parent | 5fedc4a282f0c6f5be5e4bebc8840f6022153bb3 (diff) |
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: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 130 |
1 files changed, 84 insertions, 46 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 93ab75887fbf..3f2a4900fe18 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -308,6 +308,7 @@ static int num_max_busy_us; | |||
308 | 308 | ||
309 | static int unload_when_empty = 1; | 309 | static int unload_when_empty = 1; |
310 | 310 | ||
311 | static int add_smi(struct smi_info *smi); | ||
311 | static int try_smi_init(struct smi_info *smi); | 312 | static int try_smi_init(struct smi_info *smi); |
312 | static void cleanup_one_si(struct smi_info *to_clean); | 313 | static void cleanup_one_si(struct smi_info *to_clean); |
313 | 314 | ||
@@ -1785,7 +1786,9 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) | |||
1785 | info->irq_setup = std_irq_setup; | 1786 | info->irq_setup = std_irq_setup; |
1786 | info->slave_addr = ipmb; | 1787 | info->slave_addr = ipmb; |
1787 | 1788 | ||
1788 | try_smi_init(info); | 1789 | if (!add_smi(info)) |
1790 | if (try_smi_init(info)) | ||
1791 | cleanup_one_si(info); | ||
1789 | } else { | 1792 | } else { |
1790 | /* remove */ | 1793 | /* remove */ |
1791 | struct smi_info *e, *tmp_e; | 1794 | struct smi_info *e, *tmp_e; |
@@ -1871,7 +1874,9 @@ static __devinit void hardcode_find_bmc(void) | |||
1871 | info->irq_setup = std_irq_setup; | 1874 | info->irq_setup = std_irq_setup; |
1872 | info->slave_addr = slave_addrs[i]; | 1875 | info->slave_addr = slave_addrs[i]; |
1873 | 1876 | ||
1874 | try_smi_init(info); | 1877 | if (!add_smi(info)) |
1878 | if (try_smi_init(info)) | ||
1879 | cleanup_one_si(info); | ||
1875 | } | 1880 | } |
1876 | } | 1881 | } |
1877 | 1882 | ||
@@ -2069,7 +2074,7 @@ static __devinit int try_init_spmi(struct SPMITable *spmi) | |||
2069 | } | 2074 | } |
2070 | info->io.addr_data = spmi->addr.address; | 2075 | info->io.addr_data = spmi->addr.address; |
2071 | 2076 | ||
2072 | try_smi_init(info); | 2077 | add_smi(info); |
2073 | 2078 | ||
2074 | return 0; | 2079 | return 0; |
2075 | } | 2080 | } |
@@ -2167,7 +2172,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, | |||
2167 | info->dev = &acpi_dev->dev; | 2172 | info->dev = &acpi_dev->dev; |
2168 | pnp_set_drvdata(dev, info); | 2173 | pnp_set_drvdata(dev, info); |
2169 | 2174 | ||
2170 | return try_smi_init(info); | 2175 | return add_smi(info); |
2171 | 2176 | ||
2172 | err_free: | 2177 | err_free: |
2173 | kfree(info); | 2178 | kfree(info); |
@@ -2326,7 +2331,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) | |||
2326 | if (info->irq) | 2331 | if (info->irq) |
2327 | info->irq_setup = std_irq_setup; | 2332 | info->irq_setup = std_irq_setup; |
2328 | 2333 | ||
2329 | try_smi_init(info); | 2334 | add_smi(info); |
2330 | } | 2335 | } |
2331 | 2336 | ||
2332 | static void __devinit dmi_find_bmc(void) | 2337 | static void __devinit dmi_find_bmc(void) |
@@ -2429,7 +2434,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
2429 | info->dev = &pdev->dev; | 2434 | info->dev = &pdev->dev; |
2430 | pci_set_drvdata(pdev, info); | 2435 | pci_set_drvdata(pdev, info); |
2431 | 2436 | ||
2432 | return try_smi_init(info); | 2437 | return add_smi(info); |
2433 | } | 2438 | } |
2434 | 2439 | ||
2435 | static void __devexit ipmi_pci_remove(struct pci_dev *pdev) | 2440 | 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 | 2547 | ||
2543 | dev_set_drvdata(&dev->dev, info); | 2548 | dev_set_drvdata(&dev->dev, info); |
2544 | 2549 | ||
2545 | return try_smi_init(info); | 2550 | return add_smi(info); |
2546 | } | 2551 | } |
2547 | 2552 | ||
2548 | static int __devexit ipmi_of_remove(struct of_device *dev) | 2553 | static int __devexit ipmi_of_remove(struct of_device *dev) |
@@ -2971,14 +2976,16 @@ static __devinit void default_find_bmc(void) | |||
2971 | info->io.regsize = DEFAULT_REGSPACING; | 2976 | info->io.regsize = DEFAULT_REGSPACING; |
2972 | info->io.regshift = 0; | 2977 | info->io.regshift = 0; |
2973 | 2978 | ||
2974 | if (try_smi_init(info) == 0) { | 2979 | if (add_smi(info) == 0) { |
2975 | /* Found one... */ | 2980 | if ((try_smi_init(info)) == 0) { |
2976 | printk(KERN_INFO "ipmi_si: Found default %s state" | 2981 | /* Found one... */ |
2977 | " machine at %s address 0x%lx\n", | 2982 | printk(KERN_INFO "ipmi_si: Found default %s" |
2978 | si_to_str[info->si_type], | 2983 | " state machine at %s address 0x%lx\n", |
2979 | addr_space_to_str[info->io.addr_type], | 2984 | si_to_str[info->si_type], |
2980 | info->io.addr_data); | 2985 | addr_space_to_str[info->io.addr_type], |
2981 | return; | 2986 | info->io.addr_data); |
2987 | } else | ||
2988 | cleanup_one_si(info); | ||
2982 | } | 2989 | } |
2983 | } | 2990 | } |
2984 | } | 2991 | } |
@@ -2997,32 +3004,48 @@ static int is_new_interface(struct smi_info *info) | |||
2997 | return 1; | 3004 | return 1; |
2998 | } | 3005 | } |
2999 | 3006 | ||
3000 | static int try_smi_init(struct smi_info *new_smi) | 3007 | static int add_smi(struct smi_info *new_smi) |
3001 | { | 3008 | { |
3002 | int rv; | 3009 | int rv = 0; |
3003 | int i; | ||
3004 | |||
3005 | printk(KERN_INFO "ipmi_si: Trying %s-specified %s state" | ||
3006 | " machine at %s address 0x%lx, slave address 0x%x," | ||
3007 | " irq %d\n", | ||
3008 | ipmi_addr_src_to_str[new_smi->addr_source], | ||
3009 | si_to_str[new_smi->si_type], | ||
3010 | addr_space_to_str[new_smi->io.addr_type], | ||
3011 | new_smi->io.addr_data, | ||
3012 | new_smi->slave_addr, new_smi->irq); | ||
3013 | 3010 | ||
3011 | printk(KERN_INFO "ipmi_si: Adding %s-specified %s state machine", | ||
3012 | ipmi_addr_src_to_str[new_smi->addr_source], | ||
3013 | si_to_str[new_smi->si_type]); | ||
3014 | mutex_lock(&smi_infos_lock); | 3014 | mutex_lock(&smi_infos_lock); |
3015 | if (!is_new_interface(new_smi)) { | 3015 | if (!is_new_interface(new_smi)) { |
3016 | printk(KERN_WARNING "ipmi_si: duplicate interface\n"); | 3016 | printk(KERN_CONT ": duplicate interface\n"); |
3017 | rv = -EBUSY; | 3017 | rv = -EBUSY; |
3018 | goto out_err; | 3018 | goto out_err; |
3019 | } | 3019 | } |
3020 | 3020 | ||
3021 | printk(KERN_CONT "\n"); | ||
3022 | |||
3021 | /* So we know not to free it unless we have allocated one. */ | 3023 | /* So we know not to free it unless we have allocated one. */ |
3022 | new_smi->intf = NULL; | 3024 | new_smi->intf = NULL; |
3023 | new_smi->si_sm = NULL; | 3025 | new_smi->si_sm = NULL; |
3024 | new_smi->handlers = NULL; | 3026 | new_smi->handlers = NULL; |
3025 | 3027 | ||
3028 | list_add_tail(&new_smi->link, &smi_infos); | ||
3029 | |||
3030 | out_err: | ||
3031 | mutex_unlock(&smi_infos_lock); | ||
3032 | return rv; | ||
3033 | } | ||
3034 | |||
3035 | static int try_smi_init(struct smi_info *new_smi) | ||
3036 | { | ||
3037 | int rv = 0; | ||
3038 | int i; | ||
3039 | |||
3040 | printk(KERN_INFO "ipmi_si: Trying %s-specified %s state" | ||
3041 | " machine at %s address 0x%lx, slave address 0x%x," | ||
3042 | " irq %d\n", | ||
3043 | ipmi_addr_src_to_str[new_smi->addr_source], | ||
3044 | si_to_str[new_smi->si_type], | ||
3045 | addr_space_to_str[new_smi->io.addr_type], | ||
3046 | new_smi->io.addr_data, | ||
3047 | new_smi->slave_addr, new_smi->irq); | ||
3048 | |||
3026 | switch (new_smi->si_type) { | 3049 | switch (new_smi->si_type) { |
3027 | case SI_KCS: | 3050 | case SI_KCS: |
3028 | new_smi->handlers = &kcs_smi_handlers; | 3051 | new_smi->handlers = &kcs_smi_handlers; |
@@ -3183,10 +3206,6 @@ static int try_smi_init(struct smi_info *new_smi) | |||
3183 | goto out_err_stop_timer; | 3206 | goto out_err_stop_timer; |
3184 | } | 3207 | } |
3185 | 3208 | ||
3186 | list_add_tail(&new_smi->link, &smi_infos); | ||
3187 | |||
3188 | mutex_unlock(&smi_infos_lock); | ||
3189 | |||
3190 | printk(KERN_INFO "IPMI %s interface initialized\n", | 3209 | printk(KERN_INFO "IPMI %s interface initialized\n", |
3191 | si_to_str[new_smi->si_type]); | 3210 | si_to_str[new_smi->si_type]); |
3192 | 3211 | ||
@@ -3197,11 +3216,17 @@ static int try_smi_init(struct smi_info *new_smi) | |||
3197 | wait_for_timer_and_thread(new_smi); | 3216 | wait_for_timer_and_thread(new_smi); |
3198 | 3217 | ||
3199 | out_err: | 3218 | out_err: |
3200 | if (new_smi->intf) | 3219 | new_smi->interrupt_disabled = 1; |
3220 | |||
3221 | if (new_smi->intf) { | ||
3201 | ipmi_unregister_smi(new_smi->intf); | 3222 | ipmi_unregister_smi(new_smi->intf); |
3223 | new_smi->intf = NULL; | ||
3224 | } | ||
3202 | 3225 | ||
3203 | if (new_smi->irq_cleanup) | 3226 | if (new_smi->irq_cleanup) { |
3204 | new_smi->irq_cleanup(new_smi); | 3227 | new_smi->irq_cleanup(new_smi); |
3228 | new_smi->irq_cleanup = NULL; | ||
3229 | } | ||
3205 | 3230 | ||
3206 | /* | 3231 | /* |
3207 | * Wait until we know that we are out of any interrupt | 3232 | * 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 | if (new_smi->handlers) | 3239 | if (new_smi->handlers) |
3215 | new_smi->handlers->cleanup(new_smi->si_sm); | 3240 | new_smi->handlers->cleanup(new_smi->si_sm); |
3216 | kfree(new_smi->si_sm); | 3241 | kfree(new_smi->si_sm); |
3242 | new_smi->si_sm = NULL; | ||
3217 | } | 3243 | } |
3218 | if (new_smi->addr_source_cleanup) | 3244 | if (new_smi->addr_source_cleanup) { |
3219 | new_smi->addr_source_cleanup(new_smi); | 3245 | new_smi->addr_source_cleanup(new_smi); |
3220 | if (new_smi->io_cleanup) | 3246 | new_smi->addr_source_cleanup = NULL; |
3247 | } | ||
3248 | if (new_smi->io_cleanup) { | ||
3221 | new_smi->io_cleanup(new_smi); | 3249 | new_smi->io_cleanup(new_smi); |
3250 | new_smi->io_cleanup = NULL; | ||
3251 | } | ||
3222 | 3252 | ||
3223 | if (new_smi->dev_registered) | 3253 | if (new_smi->dev_registered) { |
3224 | platform_device_unregister(new_smi->pdev); | 3254 | platform_device_unregister(new_smi->pdev); |
3225 | 3255 | new_smi->dev_registered = 0; | |
3226 | kfree(new_smi); | 3256 | } |
3227 | |||
3228 | mutex_unlock(&smi_infos_lock); | ||
3229 | 3257 | ||
3230 | return rv; | 3258 | return rv; |
3231 | } | 3259 | } |
@@ -3235,6 +3263,7 @@ static __devinit int init_ipmi_si(void) | |||
3235 | int i; | 3263 | int i; |
3236 | char *str; | 3264 | char *str; |
3237 | int rv; | 3265 | int rv; |
3266 | struct smi_info *e; | ||
3238 | 3267 | ||
3239 | if (initialized) | 3268 | if (initialized) |
3240 | return 0; | 3269 | return 0; |
@@ -3292,15 +3321,21 @@ static __devinit int init_ipmi_si(void) | |||
3292 | of_register_platform_driver(&ipmi_of_platform_driver); | 3321 | of_register_platform_driver(&ipmi_of_platform_driver); |
3293 | #endif | 3322 | #endif |
3294 | 3323 | ||
3324 | mutex_lock(&smi_infos_lock); | ||
3325 | list_for_each_entry(e, &smi_infos, link) { | ||
3326 | if (!e->si_sm) | ||
3327 | try_smi_init(e); | ||
3328 | } | ||
3329 | mutex_unlock(&smi_infos_lock); | ||
3330 | |||
3295 | if (si_trydefaults) { | 3331 | if (si_trydefaults) { |
3296 | mutex_lock(&smi_infos_lock); | 3332 | mutex_lock(&smi_infos_lock); |
3297 | if (list_empty(&smi_infos)) { | 3333 | if (list_empty(&smi_infos)) { |
3298 | /* No BMC was found, try defaults. */ | 3334 | /* No BMC was found, try defaults. */ |
3299 | mutex_unlock(&smi_infos_lock); | 3335 | mutex_unlock(&smi_infos_lock); |
3300 | default_find_bmc(); | 3336 | default_find_bmc(); |
3301 | } else { | 3337 | } else |
3302 | mutex_unlock(&smi_infos_lock); | 3338 | mutex_unlock(&smi_infos_lock); |
3303 | } | ||
3304 | } | 3339 | } |
3305 | 3340 | ||
3306 | mutex_lock(&smi_infos_lock); | 3341 | mutex_lock(&smi_infos_lock); |
@@ -3326,7 +3361,7 @@ module_init(init_ipmi_si); | |||
3326 | 3361 | ||
3327 | static void cleanup_one_si(struct smi_info *to_clean) | 3362 | static void cleanup_one_si(struct smi_info *to_clean) |
3328 | { | 3363 | { |
3329 | int rv; | 3364 | int rv = 0; |
3330 | unsigned long flags; | 3365 | unsigned long flags; |
3331 | 3366 | ||
3332 | if (!to_clean) | 3367 | if (!to_clean) |
@@ -3370,14 +3405,17 @@ static void cleanup_one_si(struct smi_info *to_clean) | |||
3370 | schedule_timeout_uninterruptible(1); | 3405 | schedule_timeout_uninterruptible(1); |
3371 | } | 3406 | } |
3372 | 3407 | ||
3373 | rv = ipmi_unregister_smi(to_clean->intf); | 3408 | if (to_clean->intf) |
3409 | rv = ipmi_unregister_smi(to_clean->intf); | ||
3410 | |||
3374 | if (rv) { | 3411 | if (rv) { |
3375 | printk(KERN_ERR | 3412 | printk(KERN_ERR |
3376 | "ipmi_si: Unable to unregister device: errno=%d\n", | 3413 | "ipmi_si: Unable to unregister device: errno=%d\n", |
3377 | rv); | 3414 | rv); |
3378 | } | 3415 | } |
3379 | 3416 | ||
3380 | to_clean->handlers->cleanup(to_clean->si_sm); | 3417 | if (to_clean->handlers) |
3418 | to_clean->handlers->cleanup(to_clean->si_sm); | ||
3381 | 3419 | ||
3382 | kfree(to_clean->si_sm); | 3420 | kfree(to_clean->si_sm); |
3383 | 3421 | ||