diff --git a/powerpc-utils-1.3.12-lparstat-fix-idle-busy-purr-spurr.patch b/powerpc-utils-1.3.12-lparstat-fix-idle-busy-purr-spurr.patch new file mode 100644 index 0000000..c34eaa5 --- /dev/null +++ b/powerpc-utils-1.3.12-lparstat-fix-idle-busy-purr-spurr.patch @@ -0,0 +1,228 @@ +commit 2af8c0b9a285e8a6104560d0f482819e56060443 +Author: Saket Kumar Bhaskar +Date: Thu Jul 18 00:39:24 2024 +0530 + + lparstat: Fix Idle and busy PURR/SPURR + + lparstat -E gives %busy and %idle for actual(PURR based) and normalized + (SPURR based).Idle and busy PURR/SPURR values are not adding upto 100% + in case of dedicated-donate and shared partitions, with the present + formula. Because of this, users might get a false impression of resource + utilisation. This is expected because a core can be in either + idle or busy state out of total of 100(core's shared resource can + either be consumed or be left idle). When lpar is in dedicated-donate + or shared,the purr values are not being counted when the CPU is ceded. + The idle_purr is calculated by taking snapshots of purr values at + every idle entry and idle exit. So, when a CPU is ceded, the calculation + for idle_purr will be wrong as purr is not being counted. + + Before Change: + |-----------------------------------------------------------------| + | Dedicated-donate (8 cores) : | + |----------------------|---------------------|--------------------| + | | Actual | Normalized | + | Stress-ng threads |---------------------|--------------------| + | | %busy | %idle | %busy | %idle | + |----------------------|----------|----------|---------|----------| + | 0 threads | 0.02 | 0.05 | 0.02 | 0.05 | + |----------------------|----------|----------|---------|----------| + | 8 threads | 32.64 | 17.37 | 35.25 | 18.77 | + |----------------------|----------|----------|---------|----------| + | 16 threads | 58.61 | 16.42 | 63.29 | 17.74 | + |----------------------|----------|----------|---------|----------| + | 24 threads | 78.14 | 21.86 | 84.39 | 23.61 | + |----------------------|----------|----------|---------|----------| + | 32 threads | 83.60 | 16.40 | 90.30 | 17.71 | + |----------------------|----------|----------|---------|----------| + | 40 threads | 91.90 | 6.94 | 98.31 | 7.46 | + |----------------------|----------|----------|---------|----------| + | 48 threads | 96.08 | 3.92 | 102.79 | 4.21 | + |----------------------|----------|----------|---------|----------| + | 56 threads | 98.42 | 1.57 | 105.31 | 1.69 | + |----------------------|----------|----------|---------|----------| + | 64 threads | 100.00 | 0.00 | 106.00 | 0.00 | + |----------------------|----------|----------|---------|----------| + + |-----------------------------------------------------------------| + | Shared Capped (8 VP / 4 EC) : | + |----------------------|---------------------|--------------------| + | | Actual | Normalized | + | Stress-ng threads |---------------------|--------------------| + | | %busy | %idle | %busy | %idle | + |----------------------|----------|----------|---------|----------| + | 0 threads | 0.04 | 0.18 | 0.03 | 0.19 | + |----------------------|----------|----------|---------|----------| + | 8 threads | 35.90 | 14.09 | 38.77 | 15.21 | + |----------------------|----------|----------|---------|----------| + | 16 threads | 35.25 | 14.84 | 38.08 | 16.02 | + |----------------------|----------|----------|---------|----------| + | 24 threads | 40.13 | 9.73 | 42.93 | 10.43 | + |----------------------|----------|----------|---------|----------| + | 32 threads | 44.13 | 5.73 | 47.22 | 6.14 | + |----------------------|----------|----------|---------|----------| + | 40 threads | 46.47 | 3.42 | 50.18 | 3.69 | + |----------------------|----------|----------|---------|----------| + | 48 threads | 48.03 | 1.83 | 51.39 | 1.96 | + |----------------------|----------|----------|---------|----------| + | 56 threads | 49.04 | 0.86 | 52.47 | 0.93 | + |----------------------|----------|----------|---------|----------| + | 64 threads | 49.87 | 0.00 | 53.36 | 0.00 | + |----------------------|----------|----------|---------|----------| + + This commit, rather than considering delta_idle_purr for calculation of + idle ticks, takes (delta_tb - delta_purr + delta_idle_purr) as total + ticks for which the CPUs were idle. Here, since delta_idle_purr will + also contain some idle ticks, thats why it is added to the formula. + Since, the output was correct for dedicated capped mode, changes has + been made only for shared and dedicated-donate mode. + Further, no changes has been made for calculation of %busy. + + Similar changes has been done for SPURR. + + After Change: + + |-----------------------------------------------------------------| + | Dedicated-donate (8 cores) : | + |----------------------|---------------------|--------------------| + | | Actual | Normalized | + | Stress-ng threads |---------------------|--------------------| + | | %busy | %idle | %busy | %idle | + |----------------------|----------|----------|---------|----------| + | 0 threads | 0.02 | 99.98 | 0.02 | 100.04 | + |----------------------|----------|----------|---------|----------| + | 8 threads | 35.97 | 64.03 | 38.84 | 61.51 | + |----------------------|----------|----------|---------|----------| + | 16 threads | 58.60 | 41.40 | 63.28 | 37.08 | + |----------------------|----------|----------|---------|----------| + | 24 threads | 78.14 | 21.86 | 84.39 | 23.61 | + |----------------------|----------|----------|---------|----------| + | 32 threads | 83.60 | 16.41 | 90.29 | 17.71 | + |----------------------|----------|----------|---------|----------| + | 40 threads | 92.96 | 7.04 | 100.39 | 7.61 | + |----------------------|----------|----------|---------|----------| + | 48 threads | 96.08 | 3.92 | 103.77 | 4.24 | + |----------------------|----------|----------|---------|----------| + | 56 threads | 98.42 | 1.58 | 105.31 | 1.68 | + |----------------------|----------|----------|---------|----------| + | 64 threads | 100.00 | 0.00 | 107.00 | 0.00 | + |----------------------|----------|----------|---------|----------| + + |-----------------------------------------------------------------| + | Shared Capped (8 VP / 4 EC) : | + |----------------------|---------------------|--------------------| + | | Actual | Normalized | + | Stress-ng threads |---------------------|--------------------| + | | %busy | %idle | %busy | %idle | + |----------------------|----------|----------|---------|----------| + | 0 threads | 0.03 | 99.97 | 0.19 | 99.44 | + |----------------------|----------|----------|---------|----------| + | 8 threads | 35.91 | 64.09 | 38.78 | 61.58 | + |----------------------|----------|----------|---------|----------| + | 16 threads | 36.83 | 63.17 | 39.78 | 60.55 | + |----------------------|----------|----------|---------|----------| + | 24 threads | 40.16 | 59.84 | 43.37 | 56.95 | + |----------------------|----------|----------|---------|----------| + | 32 threads | 44.47 | 55.53 | 48.02 | 52.38 | + |----------------------|----------|----------|---------|----------| + | 40 threads | 46.55 | 53.45 | 50.27 | 50.04 | + |----------------------|----------|----------|---------|----------| + | 48 threads | 48.13 | 51.87 | 52.48 | 47.82 | + |----------------------|----------|----------|---------|----------| + | 56 threads | 49.01 | 50.99 | 52.93 | 47.41 | + |----------------------|----------|----------|---------|----------| + | 64 threads | 49.90 | 50.10 | 53.40 | 46.19 | + |----------------------|----------|----------|---------|----------| + + Before Change: + %idle = delta_idle_purr / delta_tb * 100 + + After Change: + %idle = (delta_tb - delta_purr + delta_idle_purr) / delta_tb * 100 + + Signed-off-by: Saket Kumar Bhaskar + Signed-off-by: Tyrel Datwyler + +diff --git a/src/lparstat.c b/src/lparstat.c +index d2fdb3f..9d9ba1b 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -515,11 +515,17 @@ void get_cpu_idle_purr(struct sysentry *unused_se, char *buf) + { + double delta_tb, delta_purr, delta_idle_purr; + double physc, idle; ++ char *descr; ++ char mode[32]; + + delta_tb = get_scaled_tb(); + delta_purr = get_delta_value("purr"); + delta_idle_purr = get_delta_value("idle_purr"); + ++ get_sysdata("shared_processor_mode", &descr, mode); ++ if (!strcmp(mode, "Dedicated")) ++ get_sysdata("DedDonMode", &descr, mode); ++ + /* + * Given that these values are read from different + * sources (purr from lparcfg and idle_purr from sysfs), +@@ -528,10 +534,23 @@ void get_cpu_idle_purr(struct sysentry *unused_se, char *buf) + */ + if (delta_idle_purr > delta_purr) + delta_idle_purr = delta_purr; +- +- physc = (delta_purr - delta_idle_purr) / delta_tb; +- idle = (delta_purr / delta_tb) - physc; +- idle *= 100.00; ++ /* ++ * Round down delta_purr to delta_tb if delta_tb - delta_purr ++ * error is under -1%. ++ */ ++ if (((delta_tb - delta_purr + delta_idle_purr) / delta_tb * 100) > -1 && ((delta_tb - delta_purr + delta_idle_purr) / delta_tb * 100) < 0) ++ delta_purr = delta_tb; ++ ++ if (!strcmp(mode, "Capped")) { ++ /* For dedicated - capped mode */ ++ physc = (delta_purr - delta_idle_purr) / delta_tb; ++ idle = (delta_purr / delta_tb) - physc; ++ idle *= 100.00; ++ } else { ++ /* For shared and dedicated - donate mode */ ++ idle = (delta_tb - delta_purr + delta_idle_purr) / delta_tb; ++ idle *= 100.00; ++ } + + sprintf(buf, "%.2f", idle); + } +@@ -559,14 +578,30 @@ void get_cpu_idle_spurr(struct sysentry *unused_se, char *buf) + double delta_tb, delta_spurr, delta_idle_spurr; + double physc, idle; + double rfreq; ++ char *descr; ++ char mode[32]; + + delta_tb = get_scaled_tb(); + delta_spurr = get_delta_value("spurr"); + delta_idle_spurr = get_delta_value("idle_spurr"); + +- physc = (delta_spurr - delta_idle_spurr) / delta_tb; +- idle = (delta_spurr / delta_tb) - physc; +- idle *= 100.00; ++ get_sysdata("shared_processor_mode", &descr, mode); ++ if (!strcmp(mode, "Dedicated")) ++ get_sysdata("DedDonMode", &descr, mode); ++ ++ if (delta_spurr > delta_tb) ++ delta_spurr = delta_tb; ++ ++ if (!strcmp(mode, "Capped")) { ++ /* For dedicated - capped mode */ ++ physc = (delta_spurr - delta_idle_spurr) / delta_tb; ++ idle = (delta_spurr / delta_tb) - physc; ++ idle *= 100.00; ++ } else { ++ /* For shared and dedicated - donate mode */ ++ idle = (delta_tb - delta_spurr + delta_idle_spurr) / delta_tb; ++ idle *= 100.00; ++ } + + rfreq = round_off_freq(); + idle += ((idle * rfreq) / 100); diff --git a/powerpc-utils-1.3.12-support-partial-smt-level-through-sysfs.patch b/powerpc-utils-1.3.12-support-partial-smt-level-through-sysfs.patch new file mode 100644 index 0000000..182d7ca --- /dev/null +++ b/powerpc-utils-1.3.12-support-partial-smt-level-through-sysfs.patch @@ -0,0 +1,44 @@ +diff -up powerpc-utils-1.3.12/src/ppc64_cpu.c.me powerpc-utils-1.3.12/src/ppc64_cpu.c +--- powerpc-utils-1.3.12/src/ppc64_cpu.c.me 2024-11-14 17:00:06.002985884 +0100 ++++ powerpc-utils-1.3.12/src/ppc64_cpu.c 2024-11-14 17:03:10.401499208 +0100 +@@ -56,6 +56,8 @@ + #define DIAGNOSTICS_RUN_MODE 42 + #define CPU_OFFLINE -1 + ++#define SYS_SMT_CONTROL "/sys/devices/system/cpu/smt/control" ++ + #ifdef HAVE_LINUX_PERF_EVENT_H + struct cpu_freq { + int offline; +@@ -360,6 +362,20 @@ static int is_dscr_capable(void) + return 0; + } + ++/* ++ * Depends on kernel's CONFIG_HOTPLUG_CPU ++ */ ++static int set_smt_control(int smt_state) ++{ ++ if (set_attribute(SYS_SMT_CONTROL, "%d", smt_state)) { ++ /* Silently ignore kernel not supporting this feature */ ++ if (errno != ENODEV) ++ perror(SYS_SMT_CONTROL); ++ return -1; ++ } ++ return 0; ++} ++ + static int do_smt(char *state, bool numeric) + { + int rc = 0; +@@ -388,7 +404,9 @@ static int do_smt(char *state, bool nume + return -1; + } + +- rc = set_smt_state(smt_state); ++ /* Try using smt/control if failing, fall back to the legacy way */ ++ if (set_smt_control(smt_state)) ++ rc = set_smt_state(smt_state); + } + + return rc; diff --git a/powerpc-utils-1.3.12.drmgr-support-01.patch b/powerpc-utils-1.3.12.drmgr-support-01.patch new file mode 100644 index 0000000..a227d36 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-01.patch @@ -0,0 +1,27 @@ +commit 1dc1ecf7dce7825d352b045c98aa51711b58aaca +Author: Haren Myneni +Date: Fri Jun 21 15:39:42 2024 -0700 + + drmgr: Return from get_node_by_name() if matched DRC index + + get_node_by_name() should return dr_node if the DRC name or DRC + index is matched. But the current code returns only if the DRC + name is matched. This patch fixes this issue and returns dr_node + if the index is matched. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common_pci.c b/src/drmgr/common_pci.c +index c6dcfdf..2e0e5fb 100644 +--- a/src/drmgr/common_pci.c ++++ b/src/drmgr/common_pci.c +@@ -969,7 +969,7 @@ get_node_by_name(const char *drc_name, uint32_t node_type) + /* See if the drc index was specified */ + drc_index = strtoul(drc_name, NULL, 0); + if (node->drc_index == drc_index) +- continue; ++ break; + + for (child = node->children; child; child = child->next) { + if (strcmp(drc_name, child->drc_name) == 0) diff --git a/powerpc-utils-1.3.12.drmgr-support-02.patch b/powerpc-utils-1.3.12.drmgr-support-02.patch new file mode 100644 index 0000000..abd6250 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-02.patch @@ -0,0 +1,153 @@ +commit 3a7e77497d2dcf84b5d6525cdfb6e59dfea7ffbb +Author: Haren Myneni +Date: Fri Jun 21 15:40:56 2024 -0700 + + drmgr: Retrieve dr_connector with the specified DRC index + + search_drc_list() provides the search based on the key type such + as DRC_NAME, DRC_TYPE, DRC_INDEX or DRC_POWERDOMAIN. But the + current code has get_drc_by_index() which looks in to the DRC list + passed to this function instead of all DRC lists and is not used + right now. + + This patch modifies get_drc_by_index() and the corresponding + changes such that it retrieves dr_connector with the specified DRC + index as does in the case of get_drc_by_name(). + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common_ofdt.c b/src/drmgr/common_ofdt.c +index 1d9b7e7..655c9d2 100644 +--- a/src/drmgr/common_ofdt.c ++++ b/src/drmgr/common_ofdt.c +@@ -650,23 +650,24 @@ drc_index_to_name(uint32_t index, struct dr_connector *drc_list) + } + + /** +- * get_drc_by_name +- * @brief Retrieve a dr_connector with the specified drc_name ++ * search_drc_by_key ++ * @brief Retrieve a dr_connector based on DRC name or DRC index + * + * This routine searches the drc lists for a dr_connector with the +- * specified name starting at the specified directory. If a dr_connector +- * is found the root_dir that the dr_connector was found in is also +- * filled out. ++ * specified name or index starting at the specified directory. If ++ * a dr_connector is found the root_dir that the dr_connector was ++ * found in is also filled out. + * +- * @param drc_name name of the dr_connector to search for ++ * @param key to serach for the dr_connector + * @param drc pointer to a drc to point to the found dr_connector + * @param root_dir pointer to buf to fill in with root directory + * @param start_dir, directory to start searching ++ * @param key_type whether the key is DRC name or DRC index + * @returns 0 on success (drc and root_dir filled in), !0 on failure + */ + int +-get_drc_by_name(char *drc_name, struct dr_connector *drc, char *root_dir, +- char *start_dir) ++search_drc_by_key(void *key, struct dr_connector *drc, char *root_dir, ++ char *start_dir, int key_type) + { + struct dr_connector *drc_list = NULL; + struct dr_connector *drc_entry; +@@ -681,7 +682,7 @@ get_drc_by_name(char *drc_name, struct dr_connector *drc, char *root_dir, + if (drc_list == NULL) + return -1; + +- drc_entry = search_drc_list(drc_list, NULL, DRC_NAME, drc_name); ++ drc_entry = search_drc_list(drc_list, NULL, key_type, key); + if (drc_entry != NULL) { + memcpy(drc, drc_entry, sizeof(*drc)); + sprintf(root_dir, "%s", start_dir); +@@ -700,7 +701,8 @@ get_drc_by_name(char *drc_name, struct dr_connector *drc, char *root_dir, + continue; + + sprintf(dir_path, "%s/%s", start_dir, de->d_name); +- rc = get_drc_by_name(drc_name, drc, root_dir, dir_path); ++ rc = search_drc_by_key(key, drc, root_dir, dir_path, ++ key_type); + if (rc == 0) + break; + } +@@ -709,17 +711,57 @@ get_drc_by_name(char *drc_name, struct dr_connector *drc, char *root_dir, + return rc; + } + +-struct dr_connector * +-get_drc_by_index(uint32_t drc_index, struct dr_connector *drc_list) ++/** ++ * get_drc_by_name ++ * @brief Retrieve a dr_connector with the specified drc_name ++ * ++ * This routine searches the drc lists for a dr_connector with the ++ * specified name starting at the specified directory. If a dr_connector ++ * is found the root_dir that the dr_connector was found in is also ++ * filled out. ++ * ++ * @param drc_name name of the dr_connector to search for ++ * @param drc pointer to a drc to point to the found dr_connector ++ * @param root_dir pointer to buf to fill in with root directory ++ * @param start_dir, directory to start searching ++ * @returns 0 on success (drc and root_dir filled in), !0 on failure ++ */ ++int ++get_drc_by_name(char *drc_name, struct dr_connector *drc, char *root_dir, ++ char *start_dir) + { +- struct dr_connector *drc; ++ int rc; + +- for (drc = drc_list; drc; drc = drc->next) { +- if (drc->index == drc_index) +- return drc; +- } ++ rc = search_drc_by_key(drc_name, drc, root_dir, start_dir, DRC_NAME); + +- return NULL; ++ return rc; ++} ++ ++/** ++ * get_drc_by_index ++ * @brief Retrieve a dr_connector with the specified index ++ * ++ * This routine searches the drc lists for a dr_connector with the ++ * specified index starting at the specified directory. If a dr_connector ++ * is found the root_dir that the dr_connector was found in is also ++ * filled out. ++ * ++ * @param index of the dr_connector to search for ++ * @param drc pointer to a drc to point to the found dr_connector ++ * @param root_dir pointer to buf to fill in with root directory ++ * @param start_dir, directory to start searching ++ * @returns 0 on success (drc and root_dir filled in), !0 on failure ++ */ ++int ++get_drc_by_index(uint32_t index, struct dr_connector *drc, char *root_dir, ++ char *start_dir) ++{ ++ int rc; ++ ++ rc = search_drc_by_key((void *)&index, drc, root_dir, start_dir, ++ DRC_INDEX); ++ ++ return rc; + } + + /* +diff --git a/src/drmgr/ofdt.h b/src/drmgr/ofdt.h +index bd90810..6c1b961 100644 +--- a/src/drmgr/ofdt.h ++++ b/src/drmgr/ofdt.h +@@ -177,6 +177,7 @@ int get_my_drc_index(char *, uint32_t *); + int drc_name_to_index(const char *, struct dr_connector *); + char * drc_index_to_name(uint32_t, struct dr_connector *); + int get_drc_by_name(char *, struct dr_connector *, char *, char *); ++int get_drc_by_index(uint32_t, struct dr_connector *, char *, char *); + + int get_min_common_depth(void); + int get_assoc_arrays(const char *dir, struct assoc_arrays *aa, diff --git a/powerpc-utils-1.3.12.drmgr-support-03.patch b/powerpc-utils-1.3.12.drmgr-support-03.patch new file mode 100644 index 0000000..8a6b944 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-03.patch @@ -0,0 +1,57 @@ +commit aa5feef7c7657fb764d732e831c9f7c7b9820498 +Author: Haren Myneni +Date: Fri Jun 21 15:41:46 2024 -0700 + + drmgr: Introduce get_my_partner_drc_index() + + get_my_partner_drc_index() is called to retrieve DRC index from the + "ibm,multipath-partner-drc" property. This property is available + in the parent device node if the device has miltipath partner device. + "ibm,multipath-partner-drc" has the DRC index of the partner device. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common_ofdt.c b/src/drmgr/common_ofdt.c +index 655c9d2..1e5fe53 100644 +--- a/src/drmgr/common_ofdt.c ++++ b/src/drmgr/common_ofdt.c +@@ -609,6 +609,26 @@ get_my_drc_index(char *of_path, uint32_t *index) + return rc; + } + ++/** ++ * get_my_partner_drc_index ++ * ++ * @param of_full_path ++ * @param index ++ * @returns 0 on success, !0 otherwise ++ */ ++int get_my_partner_drc_index(struct dr_node *node, uint32_t *index) ++{ ++ int rc; ++ ++ if (node == NULL) ++ return -1; ++ ++ rc = get_ofdt_uint_property(node->ofdt_path, ++ "ibm,multipath-partner-drc", index); ++ ++ return rc; ++} ++ + /** + * drc_name_to_index + * @brief Find the drc index for the given name +diff --git a/src/drmgr/ofdt.h b/src/drmgr/ofdt.h +index 6c1b961..08d34e1 100644 +--- a/src/drmgr/ofdt.h ++++ b/src/drmgr/ofdt.h +@@ -174,6 +174,7 @@ struct dr_connector *search_drc_list(struct dr_connector *, + struct dr_connector *, int, void *); + + int get_my_drc_index(char *, uint32_t *); ++int get_my_partner_drc_index(struct dr_node *, uint32_t *); + int drc_name_to_index(const char *, struct dr_connector *); + char * drc_index_to_name(uint32_t, struct dr_connector *); + int get_drc_by_name(char *, struct dr_connector *, char *, char *); diff --git a/powerpc-utils-1.3.12.drmgr-support-04.patch b/powerpc-utils-1.3.12.drmgr-support-04.patch new file mode 100644 index 0000000..a2cfa58 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-04.patch @@ -0,0 +1,70 @@ +commit 8751abf3cf0eb2733162931a6b38db4431699ebd +Author: Haren Myneni +Date: Fri Jun 21 15:42:45 2024 -0700 + + drmgr/phb: Add multipath partner device support for remove + + The PHB node can have "ibm,multipath-partner-drc" property + which means the device can be also configured with multipath + partner path. This property provides the DRC index of the + partner device. For the hotplug removal, both paths should + be removed and the following steps will be executed: + + - Find the partner path DRC index from "ibm,multipath-partner-drc" + property for the specified device + - If the partner path is configured, notify user about the + removal of partner path if available. Then the user should issue + issue separate drmgr command to remove the partner path. + - Remove the primary path + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/drslot_chrp_phb.c b/src/drmgr/drslot_chrp_phb.c +index f59baa4..b3a4190 100644 +--- a/src/drmgr/drslot_chrp_phb.c ++++ b/src/drmgr/drslot_chrp_phb.c +@@ -283,9 +283,11 @@ static int disable_os_hp_children(struct dr_node *phb) + */ + static int remove_phb(void) + { +- struct dr_node *phb; ++ struct dr_node *phb, *partner_phb = NULL; + struct dr_node *child; + struct dr_node *hp_list = NULL; ++ uint32_t partner_drc_index = 0; ++ char drc_index_str[10]; + int rc = 0; + + phb = get_node_by_name(usr_drc_name, PHB_NODES); +@@ -305,6 +307,20 @@ static int remove_phb(void) + goto phb_remove_error; + } + ++ /* Find the multipath partner device index if available */ ++ rc = get_my_partner_drc_index(phb, &partner_drc_index); ++ if (!rc && partner_drc_index) { ++ sprintf(drc_index_str, "%d", partner_drc_index); ++ ++ /* Find the partner phb device */ ++ partner_phb = get_node_by_name(drc_index_str, PHB_NODES); ++ if (partner_phb) { ++ printf("Partner adapter location : %s", ++ partner_phb->drc_name); ++ printf(" Partner adapter must be removed\n"); ++ } ++ } ++ + /* Now, disable any hotplug children */ + hp_list = get_hp_nodes(); + +@@ -358,6 +374,9 @@ phb_remove_error: + if (phb) + free_node(phb); + ++ if (partner_phb) ++ free_node(partner_phb); ++ + if (hp_list) + free_node(hp_list); + diff --git a/powerpc-utils-1.3.12.drmgr-support-05.patch b/powerpc-utils-1.3.12.drmgr-support-05.patch new file mode 100644 index 0000000..9c2481d --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-05.patch @@ -0,0 +1,84 @@ +commit fe0c826464620fde9124f903d97102bb4237afa7 +Author: Haren Myneni +Date: Fri Jun 21 15:43:24 2024 -0700 + + drmgr/phb: Add multipath partner device support for hotplug add + + The PHB node can have "ibm,multipath-partner-drc" property + which means the device can be also configured with multipath + partner path. This property provides the DRC index of the + partner device. So for the hotplug add, both paths should be + added and the following steps will be executed for the PHB add: + + - Add the specified PHB device + - Find the partner path DRC index from "ibm,multipath-partner-drc" + property for the specified device + - If the node has this property and the partner path is + already added, notify user about the partner device. + - If the node has this property and the partner path can be + configured, notify user to configure and add the partner + device. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/drslot_chrp_phb.c b/src/drmgr/drslot_chrp_phb.c +index b3a4190..220d844 100644 +--- a/src/drmgr/drslot_chrp_phb.c ++++ b/src/drmgr/drslot_chrp_phb.c +@@ -441,8 +441,13 @@ static int acquire_phb(char *drc_name, struct dr_node **phb) + */ + static int add_phb(void) + { +- struct dr_node *phb = NULL; ++ struct dr_node *phb = NULL, *partner_phb = NULL; ++ uint32_t partner_drc_index = 0; ++ char drc_index_str[10]; + int rc, n_children = 0; ++ struct dr_connector drc; ++ char path[DR_PATH_MAX]; ++ int partner_rc = 0; + + phb = get_node_by_name(usr_drc_name, PHB_NODES); + if (phb) { +@@ -507,10 +512,40 @@ static int add_phb(void) + } + } + ++ if (!rc) { ++ /* Find the multipath partner device index if available */ ++ partner_rc = get_my_partner_drc_index(phb, &partner_drc_index); ++ if (!partner_rc && partner_drc_index) { ++ sprintf(drc_index_str, "%d", partner_drc_index); ++ /* If the partner device is already added */ ++ partner_phb = get_node_by_name(drc_index_str, ++ PHB_NODES); ++ if (partner_phb) { ++ printf("<%s> has partner device <%s>\n", ++ phb->drc_name, partner_phb->drc_name); ++ } else { ++ /* ++ * Find out if the partner device can be ++ * configured. Get the DRC info for the ++ * partner DRC index ++ */ ++ partner_rc = get_drc_by_index(partner_drc_index, ++ &drc, path, OFDT_BASE); ++ if (partner_rc) ++ printf("<%s> can have partner " ++ "device but not assigned to " ++ "LPAR yet\n", phb->drc_name); ++ } ++ } ++ } ++ + phb_add_error: + if (phb) + free_node(phb); + ++ if (partner_phb) ++ free_node(partner_phb); ++ + return rc; + } + diff --git a/powerpc-utils-1.3.12.drmgr-support-06.patch b/powerpc-utils-1.3.12.drmgr-support-06.patch new file mode 100644 index 0000000..370337a --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-06.patch @@ -0,0 +1,334 @@ +commit 1f8b5ef8092a8466bdcb29604939ae7193b79ba0 +Author: Haren Myneni +Date: Fri Jun 21 15:44:36 2024 -0700 + + drmgr/pci: Add multipath partner device support for hotplug remove + + If the PCI device has multipath partner device, its device node + contains "ibm,multipath-partner-drc" property which gives the + DRC index of the partner device. For the hotplug removal, if + the partner path is also configured, both paths must be + removed before instructing the user to remove the device from + identified slot. + + So the following steps will be executed for the removal: + - Find the partner path DRC index from "ibm,multipath-partner-drc" + property + - Remove the primary path + - Remove the partner path if it is configured. + - Notify user to remove PCI card from the specified slot. + + Since both paths will be using the same slot, LED indicators and + the slot identification will be done only for the primary device. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/drslot_chrp_pci.c b/src/drmgr/drslot_chrp_pci.c +index f2b76ef..87edf67 100644 +--- a/src/drmgr/drslot_chrp_pci.c ++++ b/src/drmgr/drslot_chrp_pci.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include "rtas_calls.h" + #include "dr.h" +@@ -99,9 +100,9 @@ identify_slot(struct dr_node *node) + if (process_led(node, LED_ID)) + return USER_QUIT; + +- printf("The visual indicator for the specified PCI slot has\n" +- "been set to the identify state. Press Enter to continue\n" +- "or enter x to exit.\n"); ++ printf("The visual indicator for the PCI slot <%s>\n" ++ "has been set to the identify state. Press Enter to\n" ++ "continue or enter x to exit.\n", node->drc_name); + + if (getchar() == '\n') + return (USER_CONT); +@@ -146,7 +147,8 @@ find_drc_name(uint32_t drc_index, struct dr_node *all_nodes) + * @returns pointer to slot on success, NULL otherwise + */ + static struct dr_node * +-find_slot(char *drc_name, struct dr_node *all_nodes) ++find_slot(char *drc_name, uint32_t drc_index, ++ struct dr_node *all_nodes, bool partner) + { + struct dr_node *node; /* working pointer */ + +@@ -157,11 +159,17 @@ find_slot(char *drc_name, struct dr_node *all_nodes) + while (node != NULL) { + if (cmp_drcname(node->drc_name, drc_name)) + break; ++ else if (drc_index && (node->drc_index == drc_index)) ++ break; + else + node = node->next; + } + +- if ((node == NULL) || (node->skip)) ++ /* ++ * Partner path may not be assigned to LPAR. ++ * So ignore if can not find the node for the partner. ++ */ ++ if ((!partner && (node == NULL)) || (node && (node->skip))) + say(ERROR, "The specified PCI slot is either invalid\n" + "or does not support hot plug operations.\n"); + +@@ -316,7 +324,7 @@ static int do_identify(struct dr_node *all_nodes) + int usr_key; + int led_state; + +- node = find_slot(usr_drc_name, all_nodes); ++ node = find_slot(usr_drc_name, 0, all_nodes, 0); + if (node == NULL) + return -1; + +@@ -509,6 +517,32 @@ static int do_insert_card_work(struct dr_node *node) + return 0; + } + ++/** ++ * find_partner_node ++ * ++ * Find the partner DRC index and retrieve the partner node. ++ */ ++static struct dr_node * ++find_partner_node(struct dr_node *node, struct dr_node *all_nodes) ++{ ++ struct dr_node *partner_node = NULL; ++ uint32_t partner_index = 0; ++ int rc; ++ ++ /* ++ * Expect the partner device only for the PCI node ++ */ ++ if (!node->children) ++ return NULL; ++ ++ /* Find the multipath partner device index if available */ ++ rc = get_my_partner_drc_index(node->children, &partner_index); ++ if (!rc) ++ partner_node = find_slot(NULL, partner_index, all_nodes, 1); ++ ++ return partner_node; ++} ++ + /** + * do_add + * +@@ -530,7 +564,7 @@ static int do_add(struct dr_node *all_nodes) + int usr_key = USER_CONT; + int rc; + +- node = find_slot(usr_drc_name, all_nodes); ++ node = find_slot(usr_drc_name, 0, all_nodes, 0); + if (node == NULL) + return -1; + +@@ -602,50 +636,50 @@ static int do_add(struct dr_node *all_nodes) + * Open Firmware device tree. The slot is isolated and powered off, + * and the LED is turned off. + * +- * @returns pointer slot on success, NULL on failure ++ * @returns 0 on success, -1 on failure + */ +-static struct dr_node *remove_work(struct dr_node *all_nodes) ++static int remove_work(struct dr_node *node, bool partner_device) + { +- struct dr_node *node; + struct dr_node *child; + int rc; + int usr_key = USER_CONT; + +- node = find_slot(usr_drc_name, all_nodes); + if (node == NULL) +- return NULL; ++ return -1; + + say(DEBUG, "found node: drc name=%s, index=0x%x, path=%s\n", + node->drc_name, node->drc_index, node->ofdt_path); + + if (is_display_adapter(node)) { + say(ERROR, "DLPAR of display adapters is not supported.\n"); +- return NULL; ++ return -1; + } + +- if (usr_prompt) { +- if (usr_slot_identification) +- usr_key = identify_slot(node); ++ if (!partner_device) { ++ if (usr_prompt) { ++ if (usr_slot_identification) ++ usr_key = identify_slot(node); + +- if (usr_key == USER_QUIT) { +- if (node->children == NULL) +- process_led(node, LED_OFF); +- else +- process_led(node, LED_ON); +- return NULL; ++ if (usr_key == USER_QUIT) { ++ if (node->children == NULL) ++ process_led(node, LED_OFF); ++ else ++ process_led(node, LED_ON); ++ return -1; ++ } + } +- } + +- /* Turn on the LED while we go do some work. */ +- if (process_led(node, LED_ON)) +- return NULL; ++ /* Turn on the LED while we go do some work. */ ++ if (process_led(node, LED_ON)) ++ return -1; + +- /* Make sure there's something there to remove. */ +- if (node->children == NULL) { +- process_led(node, LED_OFF); +- say(ERROR, "There is no configured card to remove from the " +- "specified PCI slot.\n"); +- return NULL; ++ /* Make sure there's something there to remove. */ ++ if (node->children == NULL) { ++ process_led(node, LED_OFF); ++ say(ERROR, "There is no configured card to remove " ++ "from the specified PCI slot.\n"); ++ return -1; ++ } + } + + if (!pci_virtio) { +@@ -660,7 +694,7 @@ static struct dr_node *remove_work(struct dr_node *all_nodes) + int rc = get_hp_adapter_status(node->drc_name); + if (rc != NOT_CONFIG) { + say(ERROR, "Unconfig adapter failed.\n"); +- return NULL; ++ return -1; + } + } else { + /* In certain cases such as a complete failure of the +@@ -697,12 +731,12 @@ static struct dr_node *remove_work(struct dr_node *all_nodes) + rtas_set_indicator(ISOLATION_STATE, node->drc_index, + ISOLATE); + set_power(node->drc_power, POWER_OFF); +- return NULL; ++ return -1; + } + } + + if (pci_hotplug_only) +- return node; ++ return 0; + + /* We have to isolate and power off before + * allowing the user to physically remove +@@ -719,7 +753,7 @@ static struct dr_node *remove_work(struct dr_node *all_nodes) + say(ERROR, "%s", sw_error); + + set_power(node->drc_power, POWER_OFF); +- return NULL; ++ return rc; + } + + say(DEBUG, "is calling set_power(POWER_OFF index 0x%x, power_domain " +@@ -733,10 +767,10 @@ static struct dr_node *remove_work(struct dr_node *all_nodes) + say(ERROR, "%s", sw_error); + + set_power(node->drc_power, POWER_OFF); +- return NULL; ++ return rc; + } + +- return node; ++ return 0; + } + + /** +@@ -759,13 +793,27 @@ static struct dr_node *remove_work(struct dr_node *all_nodes) + */ + static int do_remove(struct dr_node *all_nodes) + { +- struct dr_node *node; ++ struct dr_node *node, *partner_node = NULL; + +- /* Remove the specified slot and update the device-tree */ +- node = remove_work(all_nodes); ++ node = find_slot(usr_drc_name, 0, all_nodes, 0); + if (node == NULL) + return -1; + ++ partner_node = find_partner_node(node, all_nodes); ++ if (partner_node) ++ printf("<%s> and <%s> are\nmultipath partner devices. " ++ "So <%s> will\nbe also removed.\n", node->drc_name, ++ partner_node->drc_name, partner_node->drc_name); ++ ++ /* Remove the specified slot and update the device-tree */ ++ if (remove_work(node, false)) ++ return -1; ++ ++ if (partner_node) { ++ if (remove_work(partner_node, true)) ++ return -1; ++ } ++ + /* Prompt user to remove card and to press + * Enter to continue. Can't exit out of here. + */ +@@ -773,10 +821,10 @@ static int do_remove(struct dr_node *all_nodes) + if (process_led(node, LED_ACTION)) + return -1; + +- printf("The visual indicator for the specified PCI slot " +- "has\nbeen set to the action state. Remove the PCI " +- "card\nfrom the identified slot and press Enter to " +- "continue.\n"); ++ printf("The visual indicator for the specified PCI " ++ "slot has\nbeen set to the action state. " ++ "Remove the PCI card\nfrom the identified " ++ "slot and press Enter to continue.\n"); + getchar(); + if (process_led(node, LED_OFF)) + return -1; +@@ -810,11 +858,14 @@ static int do_replace(struct dr_node *all_nodes) + struct dr_node *repl_node; + int rc; + ++ repl_node = find_slot(usr_drc_name, 0, all_nodes, 0); ++ if (repl_node == NULL) ++ return -1; ++ + /* Call the routine which does the work of getting the node info, + * then removing it from the OF device tree. + */ +- repl_node = remove_work(all_nodes); +- if (repl_node == NULL) ++ if (remove_work(repl_node, false)) + return -1; + + if (!repl_node->children) { +@@ -856,12 +907,16 @@ static int do_replace(struct dr_node *all_nodes) + + if (repl_node->post_replace_processing) { + int prompt_save = usr_prompt; ++ struct dr_node *node = repl_node; + + say(DEBUG, "Doing post replacement processing...\n"); + /* disable prompting for post-processing */ + usr_prompt = 0;; + +- repl_node = remove_work(repl_node); ++ repl_node = find_slot(usr_drc_name, 0, node, 0); ++ if (remove_work(repl_node, false)) ++ return -1; ++ + rc = add_work(repl_node); + if (!rc) + set_hp_adapter_status(PHP_CONFIG_ADAPTER, diff --git a/powerpc-utils-1.3.12.drmgr-support-07.patch b/powerpc-utils-1.3.12.drmgr-support-07.patch new file mode 100644 index 0000000..f167807 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-07.patch @@ -0,0 +1,304 @@ +commit 4e6670df0da2b92a33dd880ce987823358f298bf +Author: Haren Myneni +Date: Fri Jun 21 15:45:20 2024 -0700 + + drmgr/pci: Add multipath partner device support for hotplug add + + If the PCI device has multipath partner device, the firmware + provides partner DRC index in "ibm,multipath-partner-drc" + property and this property is available in the PCI device node. + So when the PCI device add is initiated, both paths will be + added if the partner path is also configured and enabled with + the following steps: + + - Identify slot and notify user to add the device + - Add the path and enable for the specified device + - Find the partner path DRC index from "ibm,multipath-partner-drc" + property for the specified device + - Add the partner path if it is also configured + - Notify user about adding partner path + + Since both paths will be using the same slot, LED indicators and + the slot identification will be done only for the primary device. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common_pci.c b/src/drmgr/common_pci.c +index 2e0e5fb..2411641 100644 +--- a/src/drmgr/common_pci.c ++++ b/src/drmgr/common_pci.c +@@ -295,7 +295,7 @@ add_child_node(struct dr_node *parent, char *child_path) + * @param node + * @returns 0 on success, !0 otherwise + */ +-static int ++int + init_node(struct dr_node *node) + { + DIR *d; +diff --git a/src/drmgr/drslot_chrp_pci.c b/src/drmgr/drslot_chrp_pci.c +index 87edf67..2b8579b 100644 +--- a/src/drmgr/drslot_chrp_pci.c ++++ b/src/drmgr/drslot_chrp_pci.c +@@ -31,6 +31,7 @@ + #include "rtas_calls.h" + #include "dr.h" + #include "drpci.h" ++#include "ofdt.h" + + static char *sw_error = "Internal software error. Contact your service " + "representative.\n"; +@@ -367,27 +368,38 @@ static int do_identify(struct dr_node *all_nodes) + * off, isolated, and the LED is turned off. + * + * @param slot ++ * @param partner path or not + * @returns 0 on success, !0 on failure + */ +-static int add_work(struct dr_node *node) ++static int add_work(struct dr_node *node, bool partner_device) + { +- int pow_state; /* Tells us if power was turned on when */ +- int iso_state; /* Tells us isolation state after */ ++ int pow_state = POWER_OFF; /* Tells us if power was turned */ ++ /* on when */ ++ int iso_state = ISOLATE; /* Tells us isolation state after */ + int rc; + struct of_node *new_nodes;/* nodes returned from configure_connector */ + +- /* if we're continuing, set LED_ON and see if a card is really there. */ +- if (process_led(node, LED_ON)) +- return -1; ++ /* ++ * Already checked the card presence for the original device ++ * and both multipaths use the same card. So do not need to ++ * check the card presence again for the partner device. ++ */ ++ if (!partner_device) { ++ /* if we're continuing, set LED_ON and see if a card */ ++ /* is really there. */ ++ if (process_led(node, LED_ON)) ++ return -1; + +- say(DEBUG, "is calling card_present\n"); +- rc = card_present(node, &pow_state, &iso_state); +- if (!rc) { +- say(ERROR, "No PCI card was detected in the specified " +- "PCI slot.\n"); +- rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); +- set_power(node->drc_power, POWER_OFF); +- return -1; ++ say(DEBUG, "is calling card_present\n"); ++ rc = card_present(node, &pow_state, &iso_state); ++ if (!rc) { ++ say(ERROR, "No PCI card was detected in the specified " ++ "PCI slot.\n"); ++ rtas_set_indicator(ISOLATION_STATE, node->drc_index, ++ ISOLATE); ++ set_power(node->drc_power, POWER_OFF); ++ return -1; ++ } + } + + if (!pow_state) { +@@ -461,7 +473,7 @@ static int add_work(struct dr_node *node) + * power to a slot off. The prompts the user to insert the new card + * into the slot. + */ +-static int do_insert_card_work(struct dr_node *node) ++static int do_insert_card_work(struct dr_node *node, bool partner_device) + { + int rc; + +@@ -495,18 +507,18 @@ static int do_insert_card_work(struct dr_node *node) + return -1; + } + +- if (usr_prompt) { ++ if (usr_prompt && !partner_device) { + /* Prompt user to put in card and to press + * Enter to continue or other key to exit. + */ + if (process_led(node, LED_ACTION)) + return -1; + +- printf("The visual indicator for the specified PCI slot has\n" +- "been set to the action state. Insert the PCI card\n" +- "into the identified slot, connect any devices to be\n" +- "configured and press Enter to continue. Enter x to " +- "exit.\n"); ++ printf("The visual indicator for the PCI slot <%s>\n" ++ "has been set to the action state. Insert the PCI\n" ++ "card into the identified slot, connect any devices\n" ++ "to be configured and press Enter to continue.\n" ++ "Enter x to exit.\n", node->drc_name); + + if (!(getchar() == '\n')) { + process_led(node, LED_OFF); +@@ -543,6 +555,58 @@ find_partner_node(struct dr_node *node, struct dr_node *all_nodes) + return partner_node; + } + ++static int insert_add_work(struct dr_node *node, bool partner_device) ++{ ++ int usr_key = USER_CONT; ++ int rc; ++ ++ if (!partner_device) { ++ /* Prompt user only if in interactive mode. */ ++ if (usr_prompt) { ++ if (usr_slot_identification) ++ usr_key = identify_slot(node); ++ ++ if (usr_key == USER_QUIT) { ++ if (node->children == NULL) ++ process_led(node, LED_OFF); ++ else ++ process_led(node, LED_ON); ++ return 0; ++ } ++ } ++ ++ if (node->children != NULL) { ++ /* If there's already something here, turn the ++ * LED on and exit with user error. ++ */ ++ process_led(node, LED_ON); ++ say(ERROR, "The specified PCI slot is already occupied.\n"); ++ return -1; ++ } ++ } ++ ++ if (!pci_hotplug_only) { ++ rc = do_insert_card_work(node, partner_device); ++ if (rc) ++ return rc; ++ } ++ ++ /* Call the routine which determines ++ * what the user wants and does it. ++ */ ++ rc = add_work(node, partner_device); ++ if (rc) ++ return rc; ++ ++ /* ++ * Need to populate w/ children to retrieve partner device ++ */ ++ if (init_node(node)) ++ return -1; ++ ++ return 1; ++} ++ + /** + * do_add + * +@@ -560,8 +624,7 @@ find_partner_node(struct dr_node *node, struct dr_node *all_nodes) + */ + static int do_add(struct dr_node *all_nodes) + { +- struct dr_node *node; +- int usr_key = USER_CONT; ++ struct dr_node *node, *partner_node = NULL; + int rc; + + node = find_slot(usr_drc_name, 0, all_nodes, 0); +@@ -573,51 +636,32 @@ static int do_add(struct dr_node *all_nodes) + return -1; + } + +- /* Prompt user only if in interactive mode. */ +- if (usr_prompt) { +- if (usr_slot_identification) +- usr_key = identify_slot(node); +- +- if (usr_key == USER_QUIT) { +- if (node->children == NULL) +- process_led(node, LED_OFF); +- else +- process_led(node, LED_ON); +- return 0; +- } +- } +- +- if (node->children != NULL) { +- /* If there's already something here, turn the +- * LED on and exit with user error. +- */ +- process_led(node, LED_ON); +- say(ERROR, "The specified PCI slot is already occupied.\n"); +- return -1; +- } ++ rc = insert_add_work(node, false); ++ if (rc <= 0) ++ return rc; + +- if (!pci_hotplug_only) { +- rc = do_insert_card_work(node); +- if (rc) ++ partner_node = find_partner_node(node, all_nodes); ++ if (partner_node) { ++ printf("<%s> and <%s> are\nmultipath partner devices. " ++ "So <%s> is\nalso added.\n", node->drc_name, ++ partner_node->drc_name, partner_node->drc_name); ++ rc = insert_add_work(partner_node, true); ++ if (rc <= 0) + return rc; + } + +- /* Call the routine which determines +- * what the user wants and does it. +- */ +- rc = add_work(node); +- if (rc) +- return rc; +- + say(DEBUG, "is calling enable_slot to config adapter\n"); + + /* Try to config the adapter. The rpaphp module doesn't play well with + * qemu pci slots so we let the generic kernel pci code probe the device + * by rescanning the bus in the qemu virtio case. + */ +- if (!pci_virtio) ++ if (!pci_virtio) { + set_hp_adapter_status(PHP_CONFIG_ADAPTER, node->drc_name); +- else ++ if (partner_node) ++ set_hp_adapter_status(PHP_CONFIG_ADAPTER, ++ partner_node->drc_name); ++ } else + pci_rescan_bus(); + + return 0; +@@ -896,7 +940,7 @@ static int do_replace(struct dr_node *all_nodes) + } + } + +- rc = add_work(repl_node); ++ rc = add_work(repl_node, false); + if (rc) + return rc; + +@@ -917,7 +961,7 @@ static int do_replace(struct dr_node *all_nodes) + if (remove_work(repl_node, false)) + return -1; + +- rc = add_work(repl_node); ++ rc = add_work(repl_node, false); + if (!rc) + set_hp_adapter_status(PHP_CONFIG_ADAPTER, + repl_node->drc_name); +diff --git a/src/drmgr/ofdt.h b/src/drmgr/ofdt.h +index 08d34e1..e9ebd03 100644 +--- a/src/drmgr/ofdt.h ++++ b/src/drmgr/ofdt.h +@@ -184,6 +184,7 @@ int get_min_common_depth(void); + int get_assoc_arrays(const char *dir, struct assoc_arrays *aa, + int min_common_depth); + int of_associativity_to_node(const char *dir, int min_common_depth); ++int init_node(struct dr_node *); + + static inline int aa_index_to_node(struct assoc_arrays *aa, uint32_t aa_index) + { diff --git a/powerpc-utils-1.3.12.drmgr-support-08.patch b/powerpc-utils-1.3.12.drmgr-support-08.patch new file mode 100644 index 0000000..1392a69 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-08.patch @@ -0,0 +1,173 @@ +commit f40a63b15c5639df93405b925a4dde740d9bfa23 +Author: Haren Myneni +Date: Fri Jun 21 15:45:58 2024 -0700 + + drmgr/pci: Add multipath partner device support for hotplug replace + + If the PCI device has multipath partner device, its device node + contains "ibm,multipath-partner-drc" property which gives the DRC + index of the partner device. + So for the replace operation, the following steps will be executed: + - Find the device based on the partner DRC index of the requested + device + - Remove the requested device + - Remove the partner path + - Add the new device based on user input + - Find the device based on the partner DRC index of the new device + - Add the partner path of the new device + + Since both paths will be using the same slot, LED indicators and + the slot identification will be done only for the primary device + in both removal and add operations. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/drslot_chrp_pci.c b/src/drmgr/drslot_chrp_pci.c +index 2b8579b..ac078db 100644 +--- a/src/drmgr/drslot_chrp_pci.c ++++ b/src/drmgr/drslot_chrp_pci.c +@@ -877,6 +877,44 @@ static int do_remove(struct dr_node *all_nodes) + return 0; + } + ++static int replace_add_work(struct dr_node *node, bool partner_device) ++{ ++ ++ say(DEBUG, "repl_node:path=%s node:path=%s\n", ++ node->ofdt_path, node->children->ofdt_path); ++ ++ /* Prompt user to replace card and to press ++ * Enter to continue or x to exit. Exiting here ++ * means the original card has been removed. ++ */ ++ if (usr_prompt && !partner_device) { ++ if (process_led(node, LED_ACTION)) ++ return -1; ++ ++ printf("The visual indicator for the specified PCI slot <%s>\n" ++ "has been set to the action state. Replace the PCI\n" ++ "card in the identified slot and press Enter to " ++ "continue.\nEnter x to exit. Exiting now leaves the " ++ "PCI slot\nin the removed state.\n", ++ node->drc_name); ++ ++ if (!(getchar() == '\n')) { ++ process_led(node, LED_OFF); ++ return 0; ++ } ++ } ++ ++ if (add_work(node, partner_device)) ++ return -1; ++ ++ say(DEBUG, "CONFIGURING the card in node[name=%s, path=%s]\n", ++ node->drc_name, node->ofdt_path); ++ ++ set_hp_adapter_status(PHP_CONFIG_ADAPTER, node->drc_name); ++ ++ return 1; ++} ++ + /** + * do_replace + * @brief Allows the replacement of an adapter connected to a +@@ -899,55 +937,43 @@ static int do_remove(struct dr_node *all_nodes) + */ + static int do_replace(struct dr_node *all_nodes) + { +- struct dr_node *repl_node; ++ struct dr_node *repl_node, *partner_node = NULL; + int rc; + + repl_node = find_slot(usr_drc_name, 0, all_nodes, 0); + if (repl_node == NULL) + return -1; + ++ partner_node = find_partner_node(repl_node, all_nodes); ++ if (partner_node) ++ printf("<%s> and <%s> are\nmultipath partner devices. " ++ "So <%s> will\nbe also replaced.\n", ++ repl_node->drc_name, partner_node->drc_name, ++ partner_node->drc_name); ++ + /* Call the routine which does the work of getting the node info, + * then removing it from the OF device tree. + */ + if (remove_work(repl_node, false)) + return -1; + ++ if (partner_node) { ++ if (remove_work(partner_node, true)) ++ return -1; ++ } ++ + if (!repl_node->children) { + say(ERROR, "Bad node struct.\n"); + return -1; + } + +- say(DEBUG, "repl_node:path=%s node:path=%s\n", +- repl_node->ofdt_path, repl_node->children->ofdt_path); +- +- /* Prompt user to replace card and to press +- * Enter to continue or x to exit. Exiting here +- * means the original card has been removed. +- */ +- if (usr_prompt) { +- if (process_led(repl_node, LED_ACTION)) +- return -1; +- +- printf("The visual indicator for the specified PCI slot " +- "has\nbeen set to the action state. Replace the PCI " +- "card\nin the identified slot and press Enter to " +- "continue.\nEnter x to exit. Exiting now leaves the " +- "PCI slot\nin the removed state.\n"); +- +- if (!(getchar() == '\n')) { +- process_led(repl_node, LED_OFF); +- return 0; +- } +- } +- +- rc = add_work(repl_node, false); +- if (rc) ++ rc = replace_add_work(repl_node, false); ++ if (rc <= 0) + return rc; + +- say(DEBUG, "CONFIGURING the card in node[name=%s, path=%s]\n", +- repl_node->drc_name, repl_node->ofdt_path); +- +- set_hp_adapter_status(PHP_CONFIG_ADAPTER, repl_node->drc_name); ++ rc = replace_add_work(partner_node, true); ++ if (rc <= 0) ++ return rc; + + if (repl_node->post_replace_processing) { + int prompt_save = usr_prompt; +@@ -961,11 +987,24 @@ static int do_replace(struct dr_node *all_nodes) + if (remove_work(repl_node, false)) + return -1; + ++ partner_node = find_partner_node(repl_node, node); ++ if (partner_node) { ++ if (remove_work(partner_node, true)) ++ return -1; ++ } ++ + rc = add_work(repl_node, false); + if (!rc) + set_hp_adapter_status(PHP_CONFIG_ADAPTER, + repl_node->drc_name); + ++ if (partner_node) { ++ rc = add_work(partner_node, true); ++ if (!rc) ++ set_hp_adapter_status(PHP_CONFIG_ADAPTER, ++ partner_node->drc_name); ++ } ++ + usr_prompt = prompt_save; + } + diff --git a/powerpc-utils-1.3.12.drmgr-support-09.patch b/powerpc-utils-1.3.12.drmgr-support-09.patch new file mode 100644 index 0000000..be88268 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-09.patch @@ -0,0 +1,37 @@ +commit 5db2df531f9c242b13ef6520814c99685144c6d4 +Author: Haren Myneni +Date: Sat Jun 29 14:14:10 2024 -0700 + + drmgr: Free nodes returned from configure_connector + + of_nodes returned from configure_connector should be freed after + updating the device tree and is missing in acquire_hp_resource() + and add_work(). This patch calls free_of_node() in these functions. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common_pci.c b/src/drmgr/common_pci.c +index 2411641..759589a 100644 +--- a/src/drmgr/common_pci.c ++++ b/src/drmgr/common_pci.c +@@ -1434,6 +1434,7 @@ acquire_hp_resource(struct dr_connector *drc, char *of_path) + return -1; + + rc = add_device_tree_nodes(of_path, new_nodes); ++ free_of_node(new_nodes); + if (rc) { + say(ERROR, "add nodes failed for 0x%x\n", drc->index); + return rc; +diff --git a/src/drmgr/drslot_chrp_pci.c b/src/drmgr/drslot_chrp_pci.c +index ac078db..ec3c77c 100644 +--- a/src/drmgr/drslot_chrp_pci.c ++++ b/src/drmgr/drslot_chrp_pci.c +@@ -454,6 +454,7 @@ static int add_work(struct dr_node *node, bool partner_device) + + say(DEBUG, "Adding %s to %s\n", new_nodes->name, node->ofdt_path); + rc = add_device_tree_nodes(node->ofdt_path, new_nodes); ++ free_of_node(new_nodes); + if (rc) { + say(DEBUG, "add_device_tree_nodes failed at %s\n", + node->ofdt_path); diff --git a/powerpc-utils-1.3.12.drmgr-support-10.patch b/powerpc-utils-1.3.12.drmgr-support-10.patch new file mode 100644 index 0000000..5cea8fe --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-10.patch @@ -0,0 +1,183 @@ +commit 06c9922a774a6c096acbc69664646386c9e185b5 +Author: Haren Myneni +Date: Fri Aug 2 18:39:06 2024 -0700 + + drmgr/pci: Do not add partner device if exists in the device tree + + For PCI hotplug interface, the partner device will be added or + removed if configured with the primary device add / remove. + Whereas for PHB interface, drmgr notifies the user to add / remove + partner device if configured with the primary device. So there is + a possibility of partner PCI node exists in the device tree when + PCI interface for ADD is executed. The current ADD code in + drslot_chrp_pci.c does not check whether the partner device node + is present and may add / enable partner device again which may give + EEH errors. + + See the following sequence to get this scenario: + drmgr -r -c phb -s "PHB 1336" --> Remove primary PHB node + drmgr -r -c pci -s "U50EE.001.WZS000E-P3-C24-R2" --> Remove + partner PCI node + drmgr -a -c phb -s "PHB 1336" --> Add primary PHB node + drmgr -a -c pci -s "U50EE.001.WZS000E-P3-C24-R2" --> Add partner + PCI node and can try to add primary PCI node again. In this case + "U50EE.001.WZS000E-P3-C24-R1". + + This patch fixes the issue by checking the device node in the + device tree and add the device if does not present and remove + only if the corresponding device node exists. + + Fixes: 4e6670df0da2b92 ("drmgr/pci: Add multipath partner device support for hotplug add") + Signed-off-by: Haren Myneni + [tyreld: fixed up white space and replace/remove phrasing] + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/drslot_chrp_pci.c b/src/drmgr/drslot_chrp_pci.c +index ec3c77c..7a52085 100644 +--- a/src/drmgr/drslot_chrp_pci.c ++++ b/src/drmgr/drslot_chrp_pci.c +@@ -536,12 +536,15 @@ static int do_insert_card_work(struct dr_node *node, bool partner_device) + * Find the partner DRC index and retrieve the partner node. + */ + static struct dr_node * +-find_partner_node(struct dr_node *node, struct dr_node *all_nodes) ++find_partner_node(struct dr_node *node, struct dr_node *all_nodes, ++ int *dt_entry_present) + { + struct dr_node *partner_node = NULL; + uint32_t partner_index = 0; + int rc; + ++ *dt_entry_present = 0; ++ + /* + * Expect the partner device only for the PCI node + */ +@@ -550,8 +553,20 @@ find_partner_node(struct dr_node *node, struct dr_node *all_nodes) + + /* Find the multipath partner device index if available */ + rc = get_my_partner_drc_index(node->children, &partner_index); +- if (!rc) ++ if (!rc) { + partner_node = find_slot(NULL, partner_index, all_nodes, 1); ++ /* ++ * Do not add if the partner entry is already present. ++ * Nothing to remove if the partner node does not exists. ++ */ ++ if (partner_node && partner_node->children) { ++ uint32_t index; ++ rc = get_my_drc_index(partner_node->children->ofdt_path, ++ &index); ++ if (!rc && (partner_index == index)) ++ *dt_entry_present = 1; ++ } ++ } + + return partner_node; + } +@@ -626,6 +641,7 @@ static int insert_add_work(struct dr_node *node, bool partner_device) + static int do_add(struct dr_node *all_nodes) + { + struct dr_node *node, *partner_node = NULL; ++ int dt_entry; + int rc; + + node = find_slot(usr_drc_name, 0, all_nodes, 0); +@@ -641,8 +657,8 @@ static int do_add(struct dr_node *all_nodes) + if (rc <= 0) + return rc; + +- partner_node = find_partner_node(node, all_nodes); +- if (partner_node) { ++ partner_node = find_partner_node(node, all_nodes, &dt_entry); ++ if (partner_node && !dt_entry) { + printf("<%s> and <%s> are\nmultipath partner devices. " + "So <%s> is\nalso added.\n", node->drc_name, + partner_node->drc_name, partner_node->drc_name); +@@ -839,16 +855,25 @@ static int remove_work(struct dr_node *node, bool partner_device) + static int do_remove(struct dr_node *all_nodes) + { + struct dr_node *node, *partner_node = NULL; ++ int dt_entry; + + node = find_slot(usr_drc_name, 0, all_nodes, 0); + if (node == NULL) + return -1; + +- partner_node = find_partner_node(node, all_nodes); +- if (partner_node) +- printf("<%s> and <%s> are\nmultipath partner devices. " +- "So <%s> will\nbe also removed.\n", node->drc_name, +- partner_node->drc_name, partner_node->drc_name); ++ partner_node = find_partner_node(node, all_nodes, &dt_entry); ++ if (partner_node) { ++ /* ++ * Remove partner device if exists in the device tree. ++ */ ++ if (dt_entry) ++ printf("<%s> and <%s> are\nmultipath partner devices. " ++ "So <%s> will\nalso be removed.\n", ++ node->drc_name, partner_node->drc_name, ++ partner_node->drc_name); ++ else ++ partner_node = NULL; ++ } + + /* Remove the specified slot and update the device-tree */ + if (remove_work(node, false)) +@@ -939,18 +964,23 @@ static int replace_add_work(struct dr_node *node, bool partner_device) + static int do_replace(struct dr_node *all_nodes) + { + struct dr_node *repl_node, *partner_node = NULL; ++ int dt_entry; + int rc; + + repl_node = find_slot(usr_drc_name, 0, all_nodes, 0); + if (repl_node == NULL) + return -1; + +- partner_node = find_partner_node(repl_node, all_nodes); +- if (partner_node) +- printf("<%s> and <%s> are\nmultipath partner devices. " +- "So <%s> will\nbe also replaced.\n", +- repl_node->drc_name, partner_node->drc_name, +- partner_node->drc_name); ++ partner_node = find_partner_node(repl_node, all_nodes, &dt_entry); ++ if (partner_node) { ++ if (dt_entry) ++ printf("<%s> and <%s> are\nmultipath partner devices. " ++ "So <%s> will\nalso be replaced.\n", ++ repl_node->drc_name, partner_node->drc_name, ++ partner_node->drc_name); ++ else ++ partner_node = NULL; ++ } + + /* Call the routine which does the work of getting the node info, + * then removing it from the OF device tree. +@@ -972,9 +1002,11 @@ static int do_replace(struct dr_node *all_nodes) + if (rc <= 0) + return rc; + +- rc = replace_add_work(partner_node, true); +- if (rc <= 0) +- return rc; ++ if (partner_node) { ++ rc = replace_add_work(partner_node, true); ++ if (rc <= 0) ++ return rc; ++ } + + if (repl_node->post_replace_processing) { + int prompt_save = usr_prompt; +@@ -988,8 +1020,8 @@ static int do_replace(struct dr_node *all_nodes) + if (remove_work(repl_node, false)) + return -1; + +- partner_node = find_partner_node(repl_node, node); +- if (partner_node) { ++ partner_node = find_partner_node(repl_node, node, &dt_entry); ++ if (partner_node && dt_entry) { + if (remove_work(partner_node, true)) + return -1; + } diff --git a/powerpc-utils-1.3.12.drmgr-support-11.patch b/powerpc-utils-1.3.12.drmgr-support-11.patch new file mode 100644 index 0000000..8e67ebb --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-11.patch @@ -0,0 +1,92 @@ +commit 9ea191d15f4b279923a4c83a94b83436c79e3482 +Author: Haren Myneni +Date: Tue Aug 13 14:40:23 2024 -0700 + + drmgr/pci: Enable in-kernel functionality to update device tree + + drmgr updates the device tree by writing to /proc/ppc64/ofdt. Also + invokes configure_connector RTAS call to retrieve new device nodes + for IO ADD. But this functionality need /dev/mem access which is + restricted under system lockdown. + + The kernel updates provided a sysfs file (/sys/kernel/dlpar) that + will allow drmgr command invoke the following interfaces to update + the device tree. + + dt add index ---> To add new device nodes to the device + tree which is used for IO ADD. + + dt remove index ---> To remove device nodes for IO + REMOVE + + This patch checks the kernel interface for the availability of + device tree update feature and adds do_dt_kernel_dlpar() to invoke + the above kernel interfaces. + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common.c b/src/drmgr/common.c +index bfec0b9..70f4dfd 100644 +--- a/src/drmgr/common.c ++++ b/src/drmgr/common.c +@@ -1504,6 +1504,12 @@ int kernel_dlpar_exists(void) + if (strstr(buf, "cpu")) + return 1; + break; ++ case DRC_TYPE_PCI: ++ case DRC_TYPE_PHB: ++ case DRC_TYPE_SLOT: ++ if (strstr(buf, "dt")) ++ return 1; ++ break; + default: + return 0; + } +diff --git a/src/drmgr/common_pci.c b/src/drmgr/common_pci.c +index 759589a..109e0d2 100644 +--- a/src/drmgr/common_pci.c ++++ b/src/drmgr/common_pci.c +@@ -1619,3 +1619,32 @@ int disable_hp_children(char *drc_name) + } + return 0; + } ++ ++/* ++ * kernel interface to update device tree nodes. ++ * dlpar dt [add|remove] index <#drc index> ++ */ ++int do_dt_kernel_dlpar(uint32_t index, int action) ++{ ++ char cmdbuf[256]; ++ int offset; ++ ++ offset = sprintf(cmdbuf, "%s ", "dt"); ++ ++ switch (action) { ++ case ADD: ++ offset += sprintf(cmdbuf + offset, "add "); ++ break; ++ case REMOVE: ++ offset += sprintf(cmdbuf + offset, "remove "); ++ break; ++ default: ++ /* Should not happen */ ++ say(ERROR, "Invalid action type specified\n"); ++ return -EINVAL; ++ } ++ ++ offset += sprintf(cmdbuf + offset, "index 0x%x", index); ++ ++ return do_kernel_dlpar(cmdbuf, offset); ++} +diff --git a/src/drmgr/dr.h b/src/drmgr/dr.h +index 60c31c4..72ede55 100644 +--- a/src/drmgr/dr.h ++++ b/src/drmgr/dr.h +@@ -188,4 +188,5 @@ static inline int do_kernel_dlpar(const char *cmd, int len) + { + return do_kernel_dlpar_common(cmd, len, 0); + } ++int do_dt_kernel_dlpar(uint32_t, int); + #endif diff --git a/powerpc-utils-1.3.12.drmgr-support-12.patch b/powerpc-utils-1.3.12.drmgr-support-12.patch new file mode 100644 index 0000000..529bf99 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-12.patch @@ -0,0 +1,136 @@ +commit 9aaa1a625da9de1ca758c4eb8442589b46927acb +Author: Haren Myneni +Date: Tue Aug 13 14:40:24 2024 -0700 + + drmgr/phb: Add kernel interface support for device tree update + + Use the following kernel interfaces for PHB device type to update + the device tree if this feature is enabled in the kernel. + + dt add index --> for IO add + dt remove index --> for IO remove + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common_pci.c b/src/drmgr/common_pci.c +index 109e0d2..683d72d 100644 +--- a/src/drmgr/common_pci.c ++++ b/src/drmgr/common_pci.c +@@ -1390,7 +1390,6 @@ print_node_list(struct dr_node *first_node) + static int + acquire_hp_resource(struct dr_connector *drc, char *of_path) + { +- struct of_node *new_nodes; + int state; + int rc; + +@@ -1429,12 +1428,21 @@ acquire_hp_resource(struct dr_connector *drc, char *of_path) + } + + if (state == PRESENT) { +- new_nodes = configure_connector(drc->index); +- if (new_nodes == NULL) +- return -1; ++ /* ++ * Use kernel DLPAR interface if it is enabled ++ */ ++ if (kernel_dlpar_exists()) { ++ rc = do_dt_kernel_dlpar(drc->index, ADD); ++ } else { ++ struct of_node *new_nodes; ++ ++ new_nodes = configure_connector(drc->index); ++ if (new_nodes == NULL) ++ return -1; + +- rc = add_device_tree_nodes(of_path, new_nodes); +- free_of_node(new_nodes); ++ rc = add_device_tree_nodes(of_path, new_nodes); ++ free_of_node(new_nodes); ++ } + if (rc) { + say(ERROR, "add nodes failed for 0x%x\n", drc->index); + return rc; +@@ -1490,7 +1498,14 @@ release_hp_resource(struct dr_node *node) + { + int rc; + +- rc = remove_device_tree_nodes(node->ofdt_path); ++ /* ++ * Use kernel DLPAR interface if it is enabled ++ */ ++ if (kernel_dlpar_exists()) ++ rc = do_dt_kernel_dlpar(node->drc_index, REMOVE); ++ else ++ rc = remove_device_tree_nodes(node->ofdt_path); ++ + if (rc) { + say(ERROR, "failed to remove kernel nodes for index 0x%x\n", + node->drc_index); +diff --git a/src/drmgr/drslot_chrp_phb.c b/src/drmgr/drslot_chrp_phb.c +index 220d844..5bf3030 100644 +--- a/src/drmgr/drslot_chrp_phb.c ++++ b/src/drmgr/drslot_chrp_phb.c +@@ -108,17 +108,16 @@ release_phb(struct dr_node *phb) + { + int rc; + +- rc = remove_device_tree_nodes(phb->ofdt_path); +- if (rc) +- return rc; +- +- if (phb->phb_ic_ofdt_path[0] != '\0') { +- rc = remove_device_tree_nodes(phb->phb_ic_ofdt_path); +- if (rc) +- return rc; ++ if (kernel_dlpar_exists()) ++ rc = do_dt_kernel_dlpar(phb->drc_index, REMOVE); ++ else { ++ rc = remove_device_tree_nodes(phb->ofdt_path); ++ if (!rc && (phb->phb_ic_ofdt_path[0] != '\0')) ++ rc = remove_device_tree_nodes(phb->phb_ic_ofdt_path); + } + +- rc = release_drc(phb->drc_index, PHB_DEV); ++ if (!rc) ++ rc = release_drc(phb->drc_index, PHB_DEV); + + return rc; + } +@@ -390,7 +389,6 @@ phb_remove_error: + static int acquire_phb(char *drc_name, struct dr_node **phb) + { + struct dr_connector drc; +- struct of_node *of_nodes; + char path[DR_PATH_MAX]; + int rc; + +@@ -405,14 +403,20 @@ static int acquire_phb(char *drc_name, struct dr_node **phb) + if (rc) + return rc; + +- of_nodes = configure_connector(drc.index); +- if (of_nodes == NULL) { +- release_drc(drc.index, PHB_DEV); +- return -1; +- } ++ if (kernel_dlpar_exists()) { ++ rc = do_dt_kernel_dlpar(drc.index, ADD); ++ } else { ++ struct of_node *of_nodes; + +- rc = add_device_tree_nodes(path, of_nodes); +- free_of_node(of_nodes); ++ of_nodes = configure_connector(drc.index); ++ if (of_nodes == NULL) { ++ release_drc(drc.index, PHB_DEV); ++ return -1; ++ } ++ ++ rc = add_device_tree_nodes(path, of_nodes); ++ free_of_node(of_nodes); ++ } + if (rc) { + say(ERROR, "add_device_tree_nodes failed at %s\n", path); + release_drc(drc.index, PHB_DEV); diff --git a/powerpc-utils-1.3.12.drmgr-support-13.patch b/powerpc-utils-1.3.12.drmgr-support-13.patch new file mode 100644 index 0000000..df24c48 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-13.patch @@ -0,0 +1,74 @@ +commit a2d1b70cbc90ba41f16281c48e973309469f5d02 +Author: Haren Myneni +Date: Tue Aug 13 14:40:25 2024 -0700 + + drmgr/pci: Add kernel interface support for device tree update + + Use the following kernel interfaces for PCI device type to update + the device tree if this feature is enabled in the kernel. + + dt add index --> for IO add + dt remove index --> for IO remove + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/drslot_chrp_pci.c b/src/drmgr/drslot_chrp_pci.c +index 7a52085..4c41fcd 100644 +--- a/src/drmgr/drslot_chrp_pci.c ++++ b/src/drmgr/drslot_chrp_pci.c +@@ -377,7 +377,6 @@ static int add_work(struct dr_node *node, bool partner_device) + /* on when */ + int iso_state = ISOLATE; /* Tells us isolation state after */ + int rc; +- struct of_node *new_nodes;/* nodes returned from configure_connector */ + + /* + * Already checked the card presence for the original device +@@ -445,16 +444,26 @@ static int add_work(struct dr_node *node, bool partner_device) + * the return status requires a message, print it out + * and exit, otherwise, add the nodes to the OF tree. + */ +- new_nodes = configure_connector(node->drc_index); +- if (new_nodes == NULL) { +- rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); +- set_power(node->drc_power, POWER_OFF); +- return -1; ++ if (kernel_dlpar_exists()) { ++ rc = do_dt_kernel_dlpar(node->drc_index, ADD); ++ } else { ++ struct of_node *new_nodes; /* nodes returned from */ ++ /* configure_connector */ ++ ++ new_nodes = configure_connector(node->drc_index); ++ if (new_nodes == NULL) { ++ rtas_set_indicator(ISOLATION_STATE, node->drc_index, ++ ISOLATE); ++ set_power(node->drc_power, POWER_OFF); ++ return -1; ++ } ++ ++ say(DEBUG, "Adding %s to %s\n", new_nodes->name, ++ node->ofdt_path); ++ rc = add_device_tree_nodes(node->ofdt_path, new_nodes); ++ free_of_node(new_nodes); + } + +- say(DEBUG, "Adding %s to %s\n", new_nodes->name, node->ofdt_path); +- rc = add_device_tree_nodes(node->ofdt_path, new_nodes); +- free_of_node(new_nodes); + if (rc) { + say(DEBUG, "add_device_tree_nodes failed at %s\n", + node->ofdt_path); +@@ -786,7 +795,10 @@ static int remove_work(struct dr_node *node, bool partner_device) + * the device tree. + */ + for (child = node->children; child; child = child->next) { +- rc = remove_device_tree_nodes(child->ofdt_path); ++ if (kernel_dlpar_exists()) ++ rc = do_dt_kernel_dlpar(child->drc_index, REMOVE); ++ else ++ rc = remove_device_tree_nodes(child->ofdt_path); + if (rc) { + say(ERROR, "%s", sw_error); + rtas_set_indicator(ISOLATION_STATE, node->drc_index, diff --git a/powerpc-utils-1.3.12.drmgr-support-14.patch b/powerpc-utils-1.3.12.drmgr-support-14.patch new file mode 100644 index 0000000..0aafd50 --- /dev/null +++ b/powerpc-utils-1.3.12.drmgr-support-14.patch @@ -0,0 +1,67 @@ +commit bb766caa49f4aef036208023290f16ce7b1cf05d +Author: Haren Myneni +Date: Tue Aug 13 14:40:26 2024 -0700 + + drmgr/SLOT: Add kernel interface support for device tree update + + Use the following kernel interfaces for SLOT device type to update + the device tree if this feature is enabled in the kernel. + + dt add index --> for IO add + dt remove index --> for IO remove + + Signed-off-by: Haren Myneni + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/drslot_chrp_slot.c b/src/drmgr/drslot_chrp_slot.c +index 0966c25..180b108 100644 +--- a/src/drmgr/drslot_chrp_slot.c ++++ b/src/drmgr/drslot_chrp_slot.c +@@ -71,7 +71,10 @@ release_slot(struct dr_node *slot) + if (rc) + return rc; + +- rc = remove_device_tree_nodes(slot->ofdt_path); ++ if (kernel_dlpar_exists()) ++ rc = do_dt_kernel_dlpar(slot->drc_index, REMOVE); ++ else ++ rc = remove_device_tree_nodes(slot->ofdt_path); + if (rc) { + acquire_drc(slot->drc_index); + return rc; +@@ -160,7 +163,6 @@ static int + acquire_slot(char *drc_name, struct dr_node **slot) + { + struct dr_connector drc; +- struct of_node *of_nodes; + char path[DR_PATH_MAX]; + int rc; + +@@ -180,14 +182,21 @@ acquire_slot(char *drc_name, struct dr_node **slot) + if (rc) + return rc; + +- of_nodes = configure_connector(drc.index); +- if (of_nodes == NULL) { +- release_drc(drc.index, PCI_DLPAR_DEV); +- return -1; ++ if (kernel_dlpar_exists()) { ++ rc = do_dt_kernel_dlpar(drc.index, ADD); ++ } else { ++ struct of_node *of_nodes; ++ ++ of_nodes = configure_connector(drc.index); ++ if (of_nodes == NULL) { ++ release_drc(drc.index, PCI_DLPAR_DEV); ++ return -1; ++ } ++ ++ rc = add_device_tree_nodes(path, of_nodes); ++ free_of_node(of_nodes); + } + +- rc = add_device_tree_nodes(path, of_nodes); +- free_of_node(of_nodes); + if (rc) { + say(ERROR, "add_device_tree_nodes failed at %s\n", path); + release_drc(drc.index, PCI_DLPAR_DEV); diff --git a/powerpc-utils.spec b/powerpc-utils.spec index 3a0339f..08aef81 100644 --- a/powerpc-utils.spec +++ b/powerpc-utils.spec @@ -1,6 +1,6 @@ Name: powerpc-utils Version: 1.3.12 -Release: 6%{?dist} +Release: 7%{?dist} Summary: PERL-based scripts for maintaining and servicing PowerPC systems License: GPL-2.0-only @@ -9,6 +9,27 @@ Source0: https://github.com/ibm-power-utilities/%{name}/archive/v%{versio Source1: nx-gzip.udev Patch0: powerpc-utils-1.3.11-manpages.patch +# upstream patches +# drmgr support +Patch10: powerpc-utils-1.3.12.drmgr-support-01.patch +Patch11: powerpc-utils-1.3.12.drmgr-support-02.patch +Patch12: powerpc-utils-1.3.12.drmgr-support-03.patch +Patch13: powerpc-utils-1.3.12.drmgr-support-04.patch +Patch14: powerpc-utils-1.3.12.drmgr-support-05.patch +Patch15: powerpc-utils-1.3.12.drmgr-support-06.patch +Patch16: powerpc-utils-1.3.12.drmgr-support-07.patch +Patch17: powerpc-utils-1.3.12.drmgr-support-08.patch +Patch18: powerpc-utils-1.3.12.drmgr-support-09.patch +Patch19: powerpc-utils-1.3.12.drmgr-support-10.patch +Patch20: powerpc-utils-1.3.12.drmgr-support-11.patch +Patch21: powerpc-utils-1.3.12.drmgr-support-12.patch +Patch22: powerpc-utils-1.3.12.drmgr-support-13.patch +Patch23: powerpc-utils-1.3.12.drmgr-support-14.patch +# lparstat -E fails to Display Correct Values for %Busy and %Idle States +Patch30: powerpc-utils-1.3.12-lparstat-fix-idle-busy-purr-spurr.patch +# ppc64_cpu: Support partial SMT level through SYS FS smt/control files +Patch31: powerpc-utils-1.3.12-support-partial-smt-level-through-sysfs.patch + ExclusiveArch: ppc %{power64} BuildRequires: gcc @@ -209,6 +230,11 @@ systemctl enable hcn-init.service >/dev/null 2>&1 || : %changelog +* Mon Nov 18 2024 Than Ngo - 1.3.12-7 +- Add, multipath - drmgr support +- Fix, SMT state is not honored when new CPUs are added dynamically +Resolves: RHEL-62938 + * Tue Oct 29 2024 Troy Dawson - 1.3.12-6 - Bump release for October 2024 mass rebuild: Resolves: RHEL-64018