.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Support for dynamic reconfiguration for PCI, Memory, and CPU |
---|
3 | 4 | * Hotplug and Dynamic Logical Partitioning on RPA platforms. |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2009 Nathan Fontenot |
---|
6 | 7 | * Copyright (C) 2009 IBM Corporation |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or |
---|
9 | | - * modify it under the terms of the GNU General Public License version |
---|
10 | | - * 2 as published by the Free Software Foundation. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #define pr_fmt(fmt) "dlpar: " fmt |
---|
.. | .. |
---|
32 | 29 | struct pseries_hp_work { |
---|
33 | 30 | struct work_struct work; |
---|
34 | 31 | struct pseries_hp_errorlog *errlog; |
---|
35 | | - struct completion *hp_completion; |
---|
36 | | - int *rc; |
---|
37 | 32 | }; |
---|
38 | 33 | |
---|
39 | 34 | struct cc_workarea { |
---|
.. | .. |
---|
334 | 329 | return 0; |
---|
335 | 330 | } |
---|
336 | 331 | |
---|
337 | | -static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) |
---|
| 332 | +int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) |
---|
338 | 333 | { |
---|
339 | 334 | int rc; |
---|
340 | 335 | |
---|
.. | .. |
---|
362 | 357 | case PSERIES_HP_ELOG_RESOURCE_CPU: |
---|
363 | 358 | rc = dlpar_cpu(hp_elog); |
---|
364 | 359 | break; |
---|
| 360 | + case PSERIES_HP_ELOG_RESOURCE_PMEM: |
---|
| 361 | + rc = dlpar_hp_pmem(hp_elog); |
---|
| 362 | + break; |
---|
| 363 | + |
---|
365 | 364 | default: |
---|
366 | 365 | pr_warn_ratelimited("Invalid resource (%d) specified\n", |
---|
367 | 366 | hp_elog->resource); |
---|
.. | .. |
---|
376 | 375 | struct pseries_hp_work *hp_work = |
---|
377 | 376 | container_of(work, struct pseries_hp_work, work); |
---|
378 | 377 | |
---|
379 | | - if (hp_work->rc) |
---|
380 | | - *(hp_work->rc) = handle_dlpar_errorlog(hp_work->errlog); |
---|
381 | | - else |
---|
382 | | - handle_dlpar_errorlog(hp_work->errlog); |
---|
383 | | - |
---|
384 | | - if (hp_work->hp_completion) |
---|
385 | | - complete(hp_work->hp_completion); |
---|
| 378 | + handle_dlpar_errorlog(hp_work->errlog); |
---|
386 | 379 | |
---|
387 | 380 | kfree(hp_work->errlog); |
---|
388 | 381 | kfree((void *)work); |
---|
389 | 382 | } |
---|
390 | 383 | |
---|
391 | | -void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog, |
---|
392 | | - struct completion *hotplug_done, int *rc) |
---|
| 384 | +void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog) |
---|
393 | 385 | { |
---|
394 | 386 | struct pseries_hp_work *work; |
---|
395 | 387 | struct pseries_hp_errorlog *hp_errlog_copy; |
---|
396 | 388 | |
---|
397 | | - hp_errlog_copy = kmalloc(sizeof(struct pseries_hp_errorlog), |
---|
398 | | - GFP_KERNEL); |
---|
399 | | - memcpy(hp_errlog_copy, hp_errlog, sizeof(struct pseries_hp_errorlog)); |
---|
| 389 | + hp_errlog_copy = kmemdup(hp_errlog, sizeof(*hp_errlog), GFP_ATOMIC); |
---|
| 390 | + if (!hp_errlog_copy) |
---|
| 391 | + return; |
---|
400 | 392 | |
---|
401 | | - work = kmalloc(sizeof(struct pseries_hp_work), GFP_KERNEL); |
---|
| 393 | + work = kmalloc(sizeof(struct pseries_hp_work), GFP_ATOMIC); |
---|
402 | 394 | if (work) { |
---|
403 | 395 | INIT_WORK((struct work_struct *)work, pseries_hp_work_fn); |
---|
404 | 396 | work->errlog = hp_errlog_copy; |
---|
405 | | - work->hp_completion = hotplug_done; |
---|
406 | | - work->rc = rc; |
---|
407 | 397 | queue_work(pseries_hp_wq, (struct work_struct *)work); |
---|
408 | 398 | } else { |
---|
409 | | - *rc = -ENOMEM; |
---|
410 | 399 | kfree(hp_errlog_copy); |
---|
411 | | - complete(hotplug_done); |
---|
412 | 400 | } |
---|
413 | 401 | } |
---|
414 | 402 | |
---|
.. | .. |
---|
526 | 514 | static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, |
---|
527 | 515 | const char *buf, size_t count) |
---|
528 | 516 | { |
---|
529 | | - struct pseries_hp_errorlog *hp_elog; |
---|
530 | | - struct completion hotplug_done; |
---|
| 517 | + struct pseries_hp_errorlog hp_elog; |
---|
531 | 518 | char *argbuf; |
---|
532 | 519 | char *args; |
---|
533 | 520 | int rc; |
---|
534 | 521 | |
---|
535 | 522 | args = argbuf = kstrdup(buf, GFP_KERNEL); |
---|
536 | | - hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL); |
---|
537 | | - if (!hp_elog || !argbuf) { |
---|
| 523 | + if (!argbuf) { |
---|
538 | 524 | pr_info("Could not allocate resources for DLPAR operation\n"); |
---|
539 | 525 | kfree(argbuf); |
---|
540 | | - kfree(hp_elog); |
---|
541 | 526 | return -ENOMEM; |
---|
542 | 527 | } |
---|
543 | 528 | |
---|
.. | .. |
---|
545 | 530 | * Parse out the request from the user, this will be in the form: |
---|
546 | 531 | * <resource> <action> <id_type> <id> |
---|
547 | 532 | */ |
---|
548 | | - rc = dlpar_parse_resource(&args, hp_elog); |
---|
| 533 | + rc = dlpar_parse_resource(&args, &hp_elog); |
---|
549 | 534 | if (rc) |
---|
550 | 535 | goto dlpar_store_out; |
---|
551 | 536 | |
---|
552 | | - rc = dlpar_parse_action(&args, hp_elog); |
---|
| 537 | + rc = dlpar_parse_action(&args, &hp_elog); |
---|
553 | 538 | if (rc) |
---|
554 | 539 | goto dlpar_store_out; |
---|
555 | 540 | |
---|
556 | | - rc = dlpar_parse_id_type(&args, hp_elog); |
---|
| 541 | + rc = dlpar_parse_id_type(&args, &hp_elog); |
---|
557 | 542 | if (rc) |
---|
558 | 543 | goto dlpar_store_out; |
---|
559 | 544 | |
---|
560 | | - init_completion(&hotplug_done); |
---|
561 | | - queue_hotplug_event(hp_elog, &hotplug_done, &rc); |
---|
562 | | - wait_for_completion(&hotplug_done); |
---|
| 545 | + rc = handle_dlpar_errorlog(&hp_elog); |
---|
563 | 546 | |
---|
564 | 547 | dlpar_store_out: |
---|
565 | 548 | kfree(argbuf); |
---|
566 | | - kfree(hp_elog); |
---|
567 | 549 | |
---|
568 | 550 | if (rc) |
---|
569 | 551 | pr_err("Could not handle DLPAR request \"%s\"\n", buf); |
---|