op-pwrctl: Hold PCI resets until BootProgress passes BASE_INITIALIZATION state
When powering on host, hold PCI resets until hostboot passes stage
"BASE_INITIALIZATION"(0x14).
This fix applies to Firestone and Garrison.
Partially resolves openbmc/openbmc#315
Change-Id: Ic71c81406ac188b34df89569e2264ea0b94406f3
Signed-off-by: Yi Li <adamliyi@msn.com>
diff --git a/configs/Barreleye.py b/configs/Barreleye.py
index 8e7af2c..e8e8d57 100644
--- a/configs/Barreleye.py
+++ b/configs/Barreleye.py
@@ -558,14 +558,17 @@
}
POWER_CONFIG = {
- 'power_good_in' : 'PGOOD',
- 'power_up_outs' : [
+ 'power_good_in': 'PGOOD',
+ 'power_up_outs': [
('POWER_PIN', False),
],
- 'reset_outs' : [
- ('PCIE_RESET', False),
+ 'reset_outs': [
('USB_RESET', False),
],
+ 'pci_reset_outs': [
+ # net name, polarity, reset hold
+ ('PCIE_RESET', False, False),
+ ],
}
# Miscellaneous non-poll sensor with system specific properties.
diff --git a/configs/Firestone.py b/configs/Firestone.py
index 0b7eb17..285c397 100644
--- a/configs/Firestone.py
+++ b/configs/Firestone.py
@@ -460,9 +460,13 @@
('CM1_OE_R_N', True),
('BMC_CP0_RESET_N', False),
('BMC_CFAM_RESET_N_R', False),
- ('PEX8718_DEVICES_RESET_N', False),
- ('CP0_DEVICES_RESET_N', False),
- ('CP1_DEVICES_RESET_N', False),
+ ],
+ 'pci_reset_outs' : [
+ # net name, polarity, reset hold
+ # if 'reset hold' set to 'True', BMC will hold pci reset until host CPU ready to drive PCI
+ ('PEX8718_DEVICES_RESET_N', False, True),
+ ('CP0_DEVICES_RESET_N', False, True),
+ ('CP1_DEVICES_RESET_N', False, True),
],
}
diff --git a/configs/Garrison.py b/configs/Garrison.py
index 8d29750..aef0720 100644
--- a/configs/Garrison.py
+++ b/configs/Garrison.py
@@ -461,9 +461,13 @@
('CM1_OE_R_N', True),
('BMC_CP0_RESET_N', False),
('BMC_CFAM_RESET_N_R', False),
- ('PEX8718_DEVICES_RESET_N', False),
- ('CP0_DEVICES_RESET_N', False),
- ('CP1_DEVICES_RESET_N', False),
+ ],
+ 'pci_reset_outs' : [
+ # net name, polarity, reset hold
+ # if 'reset hold' set to 'True', BMC will hold pci reset until host CPU ready to drive PCI
+ ('PEX8718_DEVICES_RESET_N', False, True),
+ ('CP0_DEVICES_RESET_N', False, True),
+ ('CP1_DEVICES_RESET_N', False, True),
],
}
diff --git a/configs/Palmetto.py b/configs/Palmetto.py
index 19037a1..7ed578c 100644
--- a/configs/Palmetto.py
+++ b/configs/Palmetto.py
@@ -131,14 +131,17 @@
}
POWER_CONFIG = {
- 'power_good_in' : 'PGOOD',
- 'power_up_outs' : [
+ 'power_good_in': 'PGOOD',
+ 'power_up_outs': [
('POWER_PIN', False),
],
- 'reset_outs' : [
- ('PCIE_RESET', False),
+ 'reset_outs': [
('USB_RESET', False),
],
+ 'pci_reset_outs': [
+ # net name, polarity, reset hold
+ ('PCIE_RESET', False, False),
+ ],
}
# Miscellaneous non-poll sensor with system specific properties.
diff --git a/configs/Witherspoon.py b/configs/Witherspoon.py
index 27fc88f..3250fb2 100644
--- a/configs/Witherspoon.py
+++ b/configs/Witherspoon.py
@@ -479,11 +479,11 @@
POWER_CONFIG = {
- 'power_good_in' : 'SYS_PWROK_BUFF',
- 'power_up_outs' : [
+ 'power_good_in': 'SYS_PWROK_BUFF',
+ 'power_up_outs': [
('BMC_POWER_UP', True),
],
- 'reset_outs' : [
+ 'reset_outs': [
],
}
diff --git a/configs/Zaius.py b/configs/Zaius.py
index bb70846..2160e69 100644
--- a/configs/Zaius.py
+++ b/configs/Zaius.py
@@ -393,13 +393,13 @@
}
POWER_CONFIG = {
- 'latch_out' : 'BMC_UCD_LATCH_LE',
- 'power_good_in' : 'SYS_PWROK_BUFF',
- 'power_up_outs' : [
+ 'latch_out': 'BMC_UCD_LATCH_LE',
+ 'power_good_in': 'SYS_PWROK_BUFF',
+ 'power_up_outs': [
('SOFTWARE_PGOOD', True),
('BMC_POWER_UP', True),
],
- 'reset_outs' : [
+ 'reset_outs': [
],
}
diff --git a/libopenbmc_intf/power_gpio.c b/libopenbmc_intf/power_gpio.c
index 543281f..3c44c81 100644
--- a/libopenbmc_intf/power_gpio.c
+++ b/libopenbmc_intf/power_gpio.c
@@ -31,10 +31,14 @@
gchar *latch_out_name;
GVariantIter *power_up_outs_iter;
GVariantIter *reset_outs_iter;
+ GVariantIter *pci_reset_outs_iter;
gchar *power_up_out_name;
gchar *reset_out_name;
+ gchar *pci_reset_out_name;
gboolean power_up_polarity;
gboolean reset_out_polarity;
+ gboolean pci_reset_out_polarity;
+ gboolean pci_reset_out_hold;
int i;
proxy = g_dbus_proxy_new_sync(connection,
@@ -67,8 +71,8 @@
g_assert(value != NULL);
memset(power_gpio, 0, sizeof(*power_gpio));
- g_variant_get(value, "(&s&sa(sb)a(sb))", &power_good_in_name, &latch_out_name,
- &power_up_outs_iter, &reset_outs_iter);
+ g_variant_get(value, "(&s&sa(sb)a(sb)a(sbb))", &power_good_in_name, &latch_out_name,
+ &power_up_outs_iter, &reset_outs_iter, &pci_reset_outs_iter);
g_print("Power GPIO latch output %s\n", latch_out_name);
if(*latch_out_name != '\0') { /* latch is optional */
@@ -105,8 +109,28 @@
power_gpio->reset_pols[i] = reset_out_polarity;
}
+ power_gpio->num_pci_reset_outs = g_variant_iter_n_children(pci_reset_outs_iter);
+ g_print("Power GPIO %d pci reset outputs\n", power_gpio->num_pci_reset_outs);
+ power_gpio->pci_reset_outs = g_malloc0_n(power_gpio->num_pci_reset_outs,
+ sizeof(GPIO));
+ power_gpio->pci_reset_pols = g_malloc0_n(power_gpio->num_pci_reset_outs,
+ sizeof(gboolean));
+ power_gpio->pci_reset_holds = g_malloc0_n(power_gpio->num_pci_reset_outs,
+ sizeof(gboolean));
+ for(i = 0; g_variant_iter_next(pci_reset_outs_iter, "(&sbb)", &pci_reset_out_name,
+ &pci_reset_out_polarity, &pci_reset_out_hold); i++) {
+ g_print("Power GPIO pci reset[%d] = %s active %s, hold - %s\n", i,
+ pci_reset_out_name,
+ pci_reset_out_polarity ? "HIGH" : "LOW",
+ pci_reset_out_hold ? "Yes" : "No");
+ power_gpio->pci_reset_outs[i].name = g_strdup(pci_reset_out_name);
+ power_gpio->pci_reset_pols[i] = pci_reset_out_polarity;
+ power_gpio->pci_reset_holds[i] = pci_reset_out_hold;
+ }
+
g_variant_iter_free(power_up_outs_iter);
g_variant_iter_free(reset_outs_iter);
+ g_variant_iter_free(pci_reset_outs_iter);
g_variant_unref(value);
return TRUE;
@@ -126,4 +150,10 @@
}
g_free(power_gpio->reset_outs);
g_free(power_gpio->reset_pols);
+ for(i = 0; i < power_gpio->num_pci_reset_outs; i++) {
+ g_free(power_gpio->pci_reset_outs[i].name);
+ }
+ g_free(power_gpio->pci_reset_outs);
+ g_free(power_gpio->pci_reset_pols);
+ g_free(power_gpio->pci_reset_holds);
}
diff --git a/libopenbmc_intf/power_gpio.h b/libopenbmc_intf/power_gpio.h
index 77e1c9c..e3714d0 100644
--- a/libopenbmc_intf/power_gpio.h
+++ b/libopenbmc_intf/power_gpio.h
@@ -37,6 +37,11 @@
GPIO *reset_outs;
/* TRUE for active high */
gboolean *reset_pols;
+ size_t num_pci_reset_outs;
+ GPIO *pci_reset_outs;
+ /* TRUE for active high */
+ gboolean *pci_reset_pols;
+ gboolean *pci_reset_holds;
} PowerGpio;
/* Read system configuration for power GPIOs. */
diff --git a/op-pwrctl/power_control_obj.c b/op-pwrctl/power_control_obj.c
index eb6be21..f6cfdbc 100644
--- a/op-pwrctl/power_control_obj.c
+++ b/op-pwrctl/power_control_obj.c
@@ -17,6 +17,8 @@
static const gchar* instance_name = "power0";
static const gchar* dbus_name = "org.openbmc.control.Power";
+static int g_pci_reset_held = 1;
+
static PowerGpio g_power_gpio;
static GDBusObjectManagerServer *manager = NULL;
@@ -70,6 +72,7 @@
{
control_power_emit_power_lost(control_power);
control_emit_goto_system_state(control,"HOST_POWERED_OFF");
+ g_pci_reset_held = 1;
}
else
{
@@ -94,6 +97,36 @@
gpio_write(reset_out, reset_state);
gpio_close(reset_out);
}
+
+ for(i = 0; i < g_power_gpio.num_pci_reset_outs; i++)
+ {
+ GPIO *pci_reset_out = &g_power_gpio.pci_reset_outs[i];
+ if(pgood_state == 1)
+ {
+ /*
+ * When powering on, hold PCI reset until
+ * the processor can forward clocks and control reset.
+ */
+ if(g_power_gpio.pci_reset_holds[i])
+ {
+ g_print("Holding pci reset: %s\n", pci_reset_out->name);
+ continue;
+ }
+ }
+ rc = gpio_open(pci_reset_out);
+ if(rc != GPIO_OK)
+ {
+ g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
+ pci_reset_out->name, rc);
+ continue;
+ }
+
+ reset_state = pgood_state ^ !g_power_gpio.pci_reset_pols[i];
+ g_print("PowerControl: setting pci reset %s to %d\n", pci_reset_out->name,
+ (int)reset_state);
+ gpio_write(pci_reset_out, reset_state);
+ gpio_close(pci_reset_out);
+ }
}
} else {
g_print("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",
@@ -116,6 +149,70 @@
return TRUE;
}
+/* Handler for BootProgress signal from BootProgress sensor */
+static void
+on_boot_progress(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ gchar *boot_progress;
+ uint8_t pgood_state;
+ uint8_t reset_state;
+ int rc;
+ int i;
+
+ if(!parameters)
+ return;
+
+ /* prevent release again */
+ if(!g_pci_reset_held)
+ return;
+
+ g_variant_get(parameters, "(s)", &boot_progress);
+ /* Release PCI reset when FW boot progress goes beyond 'Baseboard Init' */
+ if(strcmp(boot_progress, "FW Progress, Baseboard Init") == 0)
+ return;
+
+ rc = gpio_open(&g_power_gpio.power_good_in);
+ if(rc != GPIO_OK)
+ {
+ g_print("ERROR PowerControl: on_boot_progress(): GPIO open error (gpio=%s,rc=%d)\n",
+ g_power_gpio.power_good_in.name, rc);
+ return;
+ }
+ rc = gpio_read(&g_power_gpio.power_good_in, &pgood_state);
+ gpio_close(&g_power_gpio.power_good_in);
+ if(rc != GPIO_OK || pgood_state != 1)
+ return;
+
+ for(i = 0; i < g_power_gpio.num_pci_reset_outs; i++)
+ {
+ GPIO *pci_reset_out = &g_power_gpio.pci_reset_outs[i];
+
+ if(!g_power_gpio.pci_reset_holds[i])
+ continue;
+ rc = gpio_open(pci_reset_out);
+ if(rc != GPIO_OK)
+ {
+ g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
+ pci_reset_out->name, rc);
+ continue;
+ }
+
+ reset_state = pgood_state ^ !g_power_gpio.pci_reset_pols[i];
+ g_print("PowerControl: setting pci reset %s to %d\n", pci_reset_out->name,
+ (int)reset_state);
+ gpio_write(pci_reset_out, reset_state);
+ gpio_close(pci_reset_out);
+ g_print("Released pci reset: %s - %s\n", pci_reset_out->name, boot_progress);
+ }
+ g_pci_reset_held = 0;
+}
+
static gboolean
on_set_power_state(ControlPower *pwr,
GDBusMethodInvocation *invocation,
@@ -230,6 +327,12 @@
error = rc;
}
}
+ for(int i = 0; i < power_gpio->num_pci_reset_outs; i++) {
+ rc = gpio_init(connection, &power_gpio->pci_reset_outs[i]);
+ if(rc != GPIO_OK) {
+ error = rc;
+ }
+ }
/* If there's a latch, it only needs to be set once. */
if(power_gpio->latch_out.name != NULL) {
@@ -309,6 +412,17 @@
G_CALLBACK(on_init),
object); /* user_data */
+ /* Listen for BootProgress signal from BootProgress sensor */
+ g_dbus_connection_signal_subscribe(connection,
+ NULL, /* service */
+ NULL, /* interface_name */
+ "BootProgress", /* member: name of the signal */
+ "/org/openbmc/sensors/host/BootProgress", /* obj path */
+ NULL, /* arg0 */
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) on_boot_progress,
+ object, /* user data */
+ NULL );
/* Export the object (@manager takes its own reference to @object) */
g_dbus_object_manager_server_set_connection(manager, connection);
diff --git a/pysystemmgr/system_manager.py b/pysystemmgr/system_manager.py
index e6bdd29..5152ff2 100644
--- a/pysystemmgr/system_manager.py
+++ b/pysystemmgr/system_manager.py
@@ -184,13 +184,14 @@
return r
@dbus.service.method(DBUS_NAME, in_signature='',
- out_signature='ssa(sb)a(sb)')
+ out_signature='ssa(sb)a(sb)a(sbb)')
def getPowerConfiguration(self):
power_good_in = System.POWER_CONFIG.get('power_good_in', '')
latch_out = System.POWER_CONFIG.get('latch_out', '')
power_up_outs = System.POWER_CONFIG.get('power_up_outs', [])
reset_outs = System.POWER_CONFIG.get('reset_outs', [])
- r = [power_good_in, latch_out, power_up_outs, reset_outs]
+ pci_reset_outs = System.POWER_CONFIG.get('pci_reset_outs', [])
+ r = [power_good_in, latch_out, power_up_outs, reset_outs, pci_reset_outs]
print "Power GPIO config: " + str(r)
return r