| .. | .. |
|---|
| 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); |
|---|