| @@ -39,6 +39,7 @@ · 38 unmodified lines |
| 39 | #include <linux/rcupdate.h> | 39 | #include <linux/rcupdate.h> |
| 40 | #include <linux/ipmi.h> | 40 | #include <linux/ipmi.h> |
| 41 | #include <linux/ipmi_smi.h> | 41 | #include <linux/ipmi_smi.h> |
| | 42 | #include <linux/workqueue.h> |
| 42 | #include "ipmi_si.h" | 43 | #include "ipmi_si.h" |
| 43 | #include "ipmi_si_sm.h" | 44 | #include "ipmi_si_sm.h" |
| 44 | #include <linux/string.h> | 45 | #include <linux/string.h> |
| @@ -252,6 +253,8 @@ struct smi_info { · 207 unmodified lines |
| 252 | | 253 | |
| 253 | struct task_struct *thread; | 254 | struct task_struct *thread; |
| 254 | | 255 | |
| | 256 | struct work_struct init_work; |
| | 257 | |
| 255 | struct list_head link; | 258 | struct list_head link; |
| 256 | }; | 259 | }; |
| 257 | | 260 | |
| @@ -272,6 +275,7 @@ static bool unload_when_empty = true; · 14 unmodified lines |
| 272 | static int try_smi_init(struct smi_info *smi); | 275 | static int try_smi_init(struct smi_info *smi); |
| 273 | static void cleanup_one_si(struct smi_info *smi_info); | 276 | static void cleanup_one_si(struct smi_info *smi_info); |
| 274 | static void cleanup_ipmi_si(void); | 277 | static void cleanup_ipmi_si(void); |
| | 278 | static void smi_init_work_fn(struct work_struct *work); |
| 275 | | 279 | |
| 276 | #ifdef DEBUG_TIMING | 280 | #ifdef DEBUG_TIMING |
| 277 | void debug_timestamp(struct smi_info *smi_info, char *msg) | 281 | void debug_timestamp(struct smi_info *smi_info, char *msg) |
| @@ -1970,6 +1974,7 @@ int ipmi_si_add_smi(struct si_sm_io *io) · 1692 unmodified lines |
| 1970 | if (!new_smi) | 1974 | if (!new_smi) |
| 1971 | return -ENOMEM; | 1975 | return -ENOMEM; |
| 1972 | spin_lock_init(&new_smi->si_lock); | 1976 | spin_lock_init(&new_smi->si_lock); |
| | 1977 | INIT_WORK(&new_smi->init_work, smi_init_work_fn); |
| 1973 | | 1978 | |
| 1974 | new_smi->io = *io; | 1979 | new_smi->io = *io; |
| 1975 | | 1980 | |
| @@ -1982,7 +1987,12 @@ int ipmi_si_add_smi(struct si_sm_io *io) · 6 unmodified lines |
| 1982 | dev_info(dup->io.dev, | 1987 | dev_info(dup->io.dev, |
| 1983 | "Removing SMBIOS-specified %s state machine in favor of ACPI\n", | 1988 | "Removing SMBIOS-specified %s state machine in favor of ACPI\n", |
| 1984 | si_to_str[new_smi->io.si_info->type]); | 1989 | si_to_str[new_smi->io.si_info->type]); |
| | 1990 | list_del(&dup->link); |
| | 1991 | mutex_unlock(&smi_infos_lock); |
| | 1992 | |
| 1985 | cleanup_one_si(dup); | 1993 | cleanup_one_si(dup); |
| | 1994 | |
| | 1995 | mutex_lock(&smi_infos_lock); |
| 1986 | } else { | 1996 | } else { |
| 1987 | dev_info(new_smi->io.dev, | 1997 | dev_info(new_smi->io.dev, |
| 1988 | "%s-specified %s state machine: duplicate\n", | 1998 | "%s-specified %s state machine: duplicate\n", |
| @@ -2000,8 +2010,12 @@ int ipmi_si_add_smi(struct si_sm_io *io) · 11 unmodified lines |
| 2000 | | 2010 | |
| 2001 | list_add_tail(&new_smi->link, &smi_infos); | 2011 | list_add_tail(&new_smi->link, &smi_infos); |
| 2002 | | 2012 | |
| 2003 | if (initialized) | 2013 | if (initialized) { |
| 2004 | rv = try_smi_init(new_smi); | 2014 | if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT)) |
| | 2015 | queue_work(system_dfl_wq, &new_smi->init_work); |
| | 2016 | else |
| | 2017 | rv = try_smi_init(new_smi); |
| | 2018 | } |
| 2005 | out_err: | 2019 | out_err: |
| 2006 | mutex_unlock(&smi_infos_lock); | 2020 | mutex_unlock(&smi_infos_lock); |
| 2007 | return rv; | 2021 | return rv; |
| @@ -2174,6 +2188,15 @@ static bool __init ipmi_smi_info_same(struct smi_info *e1, struct smi_info *e2) · 166 unmodified lines |
| 2174 | e1->io.addr_data == e2->io.addr_data); | 2188 | e1->io.addr_data == e2->io.addr_data); |
| 2175 | } | 2189 | } |
| 2176 | | 2190 | |
| | 2191 | static void smi_init_work_fn(struct work_struct *work) |
| | 2192 | { |
| | 2193 | struct smi_info *smi = container_of(work, struct smi_info, init_work); |
| | 2194 | |
| | 2195 | mutex_lock(&smi_infos_lock); |
| | 2196 | try_smi_init(smi); |
| | 2197 | mutex_unlock(&smi_infos_lock); |
| | 2198 | } |
| | 2199 | |
| 2177 | static int __init init_ipmi_si(void) | 2200 | static int __init init_ipmi_si(void) |
| 2178 | { | 2201 | { |
| 2179 | struct smi_info *e, *e2; | 2202 | struct smi_info *e, *e2; |
| @@ -2219,8 +2242,12 @@ static int __init init_ipmi_si(void) · 39 unmodified lines |
| 2219 | break; | 2242 | break; |
| 2220 | } | 2243 | } |
| 2221 | } | 2244 | } |
| 2222 | if (!dup) | 2245 | if (!dup) { |
| 2223 | try_smi_init(e); | 2246 | if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT)) |
| | 2247 | queue_work(system_unbound_wq, &e->init_work); |
| | 2248 | else |
| | 2249 | try_smi_init(e); |
| | 2250 | } |
| 2224 | } | 2251 | } |
| 2225 | | 2252 | |
| 2226 | /* | 2253 | /* |
| @@ -2253,8 +2280,12 @@ static int __init init_ipmi_si(void) · 26 unmodified lines |
| 2253 | break; | 2280 | break; |
| 2254 | } | 2281 | } |
| 2255 | } | 2282 | } |
| 2256 | if (!dup) | 2283 | if (!dup) { |
| 2257 | try_smi_init(e); | 2284 | if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT)) |
| | 2285 | queue_work(system_unbound_wq, &e->init_work); |
| | 2286 | else |
| | 2287 | try_smi_init(e); |
| | 2288 | } |
| 2258 | } | 2289 | } |
| 2259 | | 2290 | |
| 2260 | initialized = true; | 2291 | initialized = true; |
| @@ -2344,31 +2375,36 @@ static void shutdown_smi(void *send_info) · 83 unmodified lines |
| 2344 | } | 2375 | } |
| 2345 | | 2376 | |
| 2346 | /* | 2377 | /* |
| 2347 | * Must be called with smi_infos_lock held, to serialize the | 2378 | * Must be called with smi_info unlinked from smi_infos and smi_infos_lock released. |
| 2348 | * smi_info->intf check. | | |
| 2349 | */ | 2379 | */ |
| 2350 | static void cleanup_one_si(struct smi_info *smi_info) | 2380 | static void cleanup_one_si(struct smi_info *smi_info) |
| 2351 | { | 2381 | { |
| 2352 | if (!smi_info) | 2382 | if (!smi_info) |
| 2353 | return; | 2383 | return; |
| 2354 | | 2384 | |
| 2355 | list_del(&smi_info->link); | 2385 | if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT)) |
| | 2386 | cancel_work_sync(&smi_info->init_work); |
| | 2387 | |
| 2356 | ipmi_unregister_smi(smi_info->intf); | 2388 | ipmi_unregister_smi(smi_info->intf); |
| 2357 | kfree(smi_info); | 2389 | kfree(smi_info); |
| 2358 | } | 2390 | } |
| 2359 | | 2391 | |
| 2360 | void ipmi_si_remove_by_dev(struct device *dev) | 2392 | void ipmi_si_remove_by_dev(struct device *dev) |
| 2361 | { | 2393 | { |
| 2362 | struct smi_info *e; | 2394 | struct smi_info *e = NULL, *tmp; |
| 2363 | | 2395 | |
| 2364 | mutex_lock(&smi_infos_lock); | 2396 | mutex_lock(&smi_infos_lock); |
| 2365 | list_for_each_entry(e, &smi_infos, link) { | 2397 | list_for_each_entry(tmp, &smi_infos, link) { |
| 2366 | if (e->io.dev == dev) { | 2398 | if (tmp->io.dev == dev) { |
| 2367 | cleanup_one_si(e); | 2399 | e = tmp; |
| | 2400 | list_del(&e->link); |
| 2368 | break; | 2401 | break; |
| 2369 | } | 2402 | } |
| 2370 | } | 2403 | } |
| 2371 | mutex_unlock(&smi_infos_lock); | 2404 | mutex_unlock(&smi_infos_lock); |
| | 2405 | |
| | 2406 | if (e) |
| | 2407 | cleanup_one_si(e); |
| 2372 | } | 2408 | } |
| 2373 | | 2409 | |
| 2374 | struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, | 2410 | struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, |
| @@ -2377,6 +2413,7 @@ struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, · 2 unmodified lines |
| 2377 | /* remove */ | 2413 | /* remove */ |
| 2378 | struct smi_info *e, *tmp_e; | 2414 | struct smi_info *e, *tmp_e; |
| 2379 | struct device *dev = NULL; | 2415 | struct device *dev = NULL; |
| | 2416 | LIST_HEAD(to_clean); |
| 2380 | | 2417 | |
| 2381 | mutex_lock(&smi_infos_lock); | 2418 | mutex_lock(&smi_infos_lock); |
| 2382 | list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { | 2419 | list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { |
| @@ -2386,17 +2423,23 @@ struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, · 3 unmodified lines |
| 2386 | continue; | 2423 | continue; |
| 2387 | if (e->io.addr_data == addr) { | 2424 | if (e->io.addr_data == addr) { |
| 2388 | dev = get_device(e->io.dev); | 2425 | dev = get_device(e->io.dev); |
| 2389 | cleanup_one_si(e); | 2426 | list_move_tail(&e->link, &to_clean); |
| 2390 | } | 2427 | } |
| 2391 | } | 2428 | } |
| 2392 | mutex_unlock(&smi_infos_lock); | 2429 | mutex_unlock(&smi_infos_lock); |
| 2393 | | 2430 | |
| | 2431 | list_for_each_entry_safe(e, tmp_e, &to_clean, link) { |
| | 2432 | list_del(&e->link); |
| | 2433 | cleanup_one_si(e); |
| | 2434 | } |
| | 2435 | |
| 2394 | return dev; | 2436 | return dev; |
| 2395 | } | 2437 | } |
| 2396 | | 2438 | |
| 2397 | static void cleanup_ipmi_si(void) | 2439 | static void cleanup_ipmi_si(void) |
| 2398 | { | 2440 | { |
| 2399 | struct smi_info *e, *tmp_e; | 2441 | struct smi_info *e, *tmp_e; |
| | 2442 | LIST_HEAD(to_clean); |
| 2400 | | 2443 | |
| 2401 | if (!initialized) | 2444 | if (!initialized) |
| 2402 | return; | 2445 | return; |
| @@ -2410,10 +2453,14 @@ static void cleanup_ipmi_si(void) · 7 unmodified lines |
| 2410 | ipmi_si_platform_shutdown(); | 2453 | ipmi_si_platform_shutdown(); |
| 2411 | | 2454 | |
| 2412 | mutex_lock(&smi_infos_lock); | 2455 | mutex_lock(&smi_infos_lock); |
| 2413 | list_for_each_entry_safe(e, tmp_e, &smi_infos, link) | 2456 | list_splice_init(&smi_infos, &to_clean); |
| 2414 | cleanup_one_si(e); | | |
| 2415 | mutex_unlock(&smi_infos_lock); | 2457 | mutex_unlock(&smi_infos_lock); |
| 2416 | | 2458 | |
| | 2459 | list_for_each_entry_safe(e, tmp_e, &to_clean, link) { |
| | 2460 | list_del(&e->link); |
| | 2461 | cleanup_one_si(e); |
| | 2462 | } |
| | 2463 | |
| 2417 | ipmi_si_hardcode_exit(); | 2464 | ipmi_si_hardcode_exit(); |
| 2418 | ipmi_si_hotmod_exit(); | 2465 | ipmi_si_hotmod_exit(); |
| 2419 | } | 2466 | } |