dd69abbd9a
- Fix, SMT state is not honored when new CPUs are added dynamically Resolves: RHEL-62938
305 lines
8.9 KiB
Diff
305 lines
8.9 KiB
Diff
commit 4e6670df0da2b92a33dd880ce987823358f298bf
|
|
Author: Haren Myneni <haren@linux.ibm.com>
|
|
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 <haren@linux.ibm.com>
|
|
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
|
|
|
|
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)
|
|
{
|