aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSahil Mehta <sahilmehta17@gmail.com>2017-02-15 13:45:56 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2017-02-17 01:57:30 -0500
commit333f7b76865bec24c66710cf352f892d69e3ba0a (patch)
tree0fab9fb29b3b62927c1113598e327b5a0069d67a
parenta90e883d8b8fb07ddea4d9618ce58bf72bce7f00 (diff)
powerpc/pseries: Implement indexed-count hotplug memory add
Indexed-count add for memory hotplug guarantees that a contiguous block of <count> lmbs beginning at a specified <drc index> will be assigned, any LMBs in this range that are not already assigned will be DLPAR added. Because of Qemu's per-DIMM memory management, the addition of a contiguous block of memory currently requires a series of individual calls to add each LMB in the block. Indexed-count add reduces this series of calls to a single call for the entire block. Signed-off-by: Sahil Mehta <sahilmehta17@gmail.com> Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/rtas.h2
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c38
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c119
3 files changed, 147 insertions, 12 deletions
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 076b89247ab5..ec9dd79398ee 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -307,6 +307,7 @@ struct pseries_hp_errorlog {
307 union { 307 union {
308 __be32 drc_index; 308 __be32 drc_index;
309 __be32 drc_count; 309 __be32 drc_count;
310 struct { __be32 count, index; } ic;
310 char drc_name[1]; 311 char drc_name[1];
311 } _drc_u; 312 } _drc_u;
312}; 313};
@@ -323,6 +324,7 @@ struct pseries_hp_errorlog {
323#define PSERIES_HP_ELOG_ID_DRC_NAME 1 324#define PSERIES_HP_ELOG_ID_DRC_NAME 1
324#define PSERIES_HP_ELOG_ID_DRC_INDEX 2 325#define PSERIES_HP_ELOG_ID_DRC_INDEX 2
325#define PSERIES_HP_ELOG_ID_DRC_COUNT 3 326#define PSERIES_HP_ELOG_ID_DRC_COUNT 3
327#define PSERIES_HP_ELOG_ID_DRC_IC 4
326 328
327struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log, 329struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
328 uint16_t section_id); 330 uint16_t section_id);
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index d3a81e746fc4..193e052fa0dd 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -354,11 +354,17 @@ static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
354 switch (hp_elog->id_type) { 354 switch (hp_elog->id_type) {
355 case PSERIES_HP_ELOG_ID_DRC_COUNT: 355 case PSERIES_HP_ELOG_ID_DRC_COUNT:
356 hp_elog->_drc_u.drc_count = 356 hp_elog->_drc_u.drc_count =
357 be32_to_cpu(hp_elog->_drc_u.drc_count); 357 be32_to_cpu(hp_elog->_drc_u.drc_count);
358 break; 358 break;
359 case PSERIES_HP_ELOG_ID_DRC_INDEX: 359 case PSERIES_HP_ELOG_ID_DRC_INDEX:
360 hp_elog->_drc_u.drc_index = 360 hp_elog->_drc_u.drc_index =
361 be32_to_cpu(hp_elog->_drc_u.drc_index); 361 be32_to_cpu(hp_elog->_drc_u.drc_index);
362 break;
363 case PSERIES_HP_ELOG_ID_DRC_IC:
364 hp_elog->_drc_u.ic.count =
365 be32_to_cpu(hp_elog->_drc_u.ic.count);
366 hp_elog->_drc_u.ic.index =
367 be32_to_cpu(hp_elog->_drc_u.ic.index);
362 } 368 }
363 369
364 switch (hp_elog->resource) { 370 switch (hp_elog->resource) {
@@ -467,7 +473,33 @@ static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog)
467 if (!arg) 473 if (!arg)
468 return -EINVAL; 474 return -EINVAL;
469 475
470 if (sysfs_streq(arg, "index")) { 476 if (sysfs_streq(arg, "indexed-count")) {
477 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_IC;
478 arg = strsep(cmd, " ");
479 if (!arg) {
480 pr_err("No DRC count specified.\n");
481 return -EINVAL;
482 }
483
484 if (kstrtou32(arg, 0, &count)) {
485 pr_err("Invalid DRC count specified.\n");
486 return -EINVAL;
487 }
488
489 arg = strsep(cmd, " ");
490 if (!arg) {
491 pr_err("No DRC Index specified.\n");
492 return -EINVAL;
493 }
494
495 if (kstrtou32(arg, 0, &index)) {
496 pr_err("Invalid DRC Index specified.\n");
497 return -EINVAL;
498 }
499
500 hp_elog->_drc_u.ic.count = cpu_to_be32(count);
501 hp_elog->_drc_u.ic.index = cpu_to_be32(index);
502 } else if (sysfs_streq(arg, "index")) {
471 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; 503 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
472 arg = strsep(cmd, " "); 504 arg = strsep(cmd, " ");
473 if (!arg) { 505 if (!arg) {
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index b3b92814ce87..ad8b3a606a8e 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -779,6 +779,97 @@ static int dlpar_memory_add_by_index(u32 drc_index, struct property *prop)
779 return rc; 779 return rc;
780} 780}
781 781
782static int dlpar_memory_add_by_ic(u32 lmbs_to_add, u32 drc_index,
783 struct property *prop)
784{
785 struct of_drconf_cell *lmbs;
786 u32 num_lmbs, *p;
787 int i, rc, start_lmb_found;
788 int lmbs_available = 0, start_index = 0, end_index;
789
790 pr_info("Attempting to hot-add %u LMB(s) at index %x\n",
791 lmbs_to_add, drc_index);
792
793 if (lmbs_to_add == 0)
794 return -EINVAL;
795
796 p = prop->value;
797 num_lmbs = *p++;
798 lmbs = (struct of_drconf_cell *)p;
799 start_lmb_found = 0;
800
801 /* Navigate to drc_index */
802 while (start_index < num_lmbs) {
803 if (lmbs[start_index].drc_index == drc_index) {
804 start_lmb_found = 1;
805 break;
806 }
807
808 start_index++;
809 }
810
811 if (!start_lmb_found)
812 return -EINVAL;
813
814 end_index = start_index + lmbs_to_add;
815
816 /* Validate that the LMBs in this range are not reserved */
817 for (i = start_index; i < end_index; i++) {
818 if (lmbs[i].flags & DRCONF_MEM_RESERVED)
819 break;
820
821 lmbs_available++;
822 }
823
824 if (lmbs_available < lmbs_to_add)
825 return -EINVAL;
826
827 for (i = start_index; i < end_index; i++) {
828 if (lmbs[i].flags & DRCONF_MEM_ASSIGNED)
829 continue;
830
831 rc = dlpar_acquire_drc(lmbs[i].drc_index);
832 if (rc)
833 break;
834
835 rc = dlpar_add_lmb(&lmbs[i]);
836 if (rc) {
837 dlpar_release_drc(lmbs[i].drc_index);
838 break;
839 }
840
841 lmbs[i].reserved = 1;
842 }
843
844 if (rc) {
845 pr_err("Memory indexed-count-add failed, removing any added LMBs\n");
846
847 for (i = start_index; i < end_index; i++) {
848 if (!lmbs[i].reserved)
849 continue;
850
851 rc = dlpar_remove_lmb(&lmbs[i]);
852 if (rc)
853 pr_err("Failed to remove LMB, drc index %x\n",
854 be32_to_cpu(lmbs[i].drc_index));
855 else
856 dlpar_release_drc(lmbs[i].drc_index);
857 }
858 rc = -EINVAL;
859 } else {
860 for (i = start_index; i < end_index; i++) {
861 if (!lmbs[i].reserved)
862 continue;
863
864 pr_info("Memory at %llx (drc index %x) was hot-added\n",
865 lmbs[i].base_addr, lmbs[i].drc_index);
866 lmbs[i].reserved = 0;
867 }
868 }
869
870 return rc;
871}
872
782int dlpar_memory(struct pseries_hp_errorlog *hp_elog) 873int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
783{ 874{
784 struct device_node *dn; 875 struct device_node *dn;
@@ -786,9 +877,6 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
786 u32 count, drc_index; 877 u32 count, drc_index;
787 int rc; 878 int rc;
788 879
789 count = hp_elog->_drc_u.drc_count;
790 drc_index = hp_elog->_drc_u.drc_index;
791
792 lock_device_hotplug(); 880 lock_device_hotplug();
793 881
794 dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); 882 dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
@@ -805,22 +893,35 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
805 893
806 switch (hp_elog->action) { 894 switch (hp_elog->action) {
807 case PSERIES_HP_ELOG_ACTION_ADD: 895 case PSERIES_HP_ELOG_ACTION_ADD:
808 if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) 896 if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) {
897 count = hp_elog->_drc_u.drc_count;
809 rc = dlpar_memory_add_by_count(count, prop); 898 rc = dlpar_memory_add_by_count(count, prop);
810 else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) 899 } else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) {
900 drc_index = hp_elog->_drc_u.drc_index;
811 rc = dlpar_memory_add_by_index(drc_index, prop); 901 rc = dlpar_memory_add_by_index(drc_index, prop);
812 else 902 } else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_IC) {
903 count = hp_elog->_drc_u.ic.count;
904 drc_index = hp_elog->_drc_u.ic.index;
905 rc = dlpar_memory_add_by_ic(count, drc_index, prop);
906 } else {
813 rc = -EINVAL; 907 rc = -EINVAL;
908 }
909
814 break; 910 break;
815 case PSERIES_HP_ELOG_ACTION_REMOVE: 911 case PSERIES_HP_ELOG_ACTION_REMOVE:
816 if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) 912 if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) {
913 count = hp_elog->_drc_u.drc_count;
817 rc = dlpar_memory_remove_by_count(count, prop); 914 rc = dlpar_memory_remove_by_count(count, prop);
818 else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) 915 } else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) {
916 drc_index = hp_elog->_drc_u.drc_index;
819 rc = dlpar_memory_remove_by_index(drc_index, prop); 917 rc = dlpar_memory_remove_by_index(drc_index, prop);
820 else 918 } else {
821 rc = -EINVAL; 919 rc = -EINVAL;
920 }
921
822 break; 922 break;
823 case PSERIES_HP_ELOG_ACTION_READD: 923 case PSERIES_HP_ELOG_ACTION_READD:
924 drc_index = hp_elog->_drc_u.drc_index;
824 rc = dlpar_memory_readd_by_index(drc_index, prop); 925 rc = dlpar_memory_readd_by_index(drc_index, prop);
825 break; 926 break;
826 default: 927 default: