aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Barrat <fbarrat@linux.ibm.com>2020-02-17 10:43:49 +0100
committerVasant Hegde <hegdevasant@linux.vnet.ibm.com>2020-03-10 16:06:10 +0530
commit6e7aa58b2ab1e8e7f46289b50c82b68afbdda240 (patch)
tree9bce883ee1c3d6f1668703cd2f689e4cc33be314
parentd0e472a76f1ad5f8ce0f1b7929db1eea55041609 (diff)
downloadskiboot-6e7aa58b2ab1e8e7f46289b50c82b68afbdda240.zip
skiboot-6e7aa58b2ab1e8e7f46289b50c82b68afbdda240.tar.gz
skiboot-6e7aa58b2ab1e8e7f46289b50c82b68afbdda240.tar.bz2
npu2-opencapi: Don't drive reset signal permanently
[ Upstream commit 53408440edb30de7ad18f12db285f15a0863fbc3 ] A problem was found with the way we manage the I2C signal to reset adapters. Skiboot currently always drives the value of the opencapi reset signal. We set the I2C pin for reset in output mode and keep it in output mode permanently. And since the reset signal is inverted, it is explicitly set to high by the I2C controller pretty much all the time. When the opencapi card is powered off, for example on a reboot, actively driving the I2C reset pin to high keeps applying a voltage to part of the FPGA, which can leak current, send the FPGA in a bad state since it's unexpected or even damage the card. To prevent damaging adapters, the recommendation from the hardware team is to switch back the pin to input mode at the end of a reset cycle. There are pull-up resistors on the planar of all the platforms to make sure the reset signal is high "naturally". When the slot is powered off, the reset pin won't be kept high by the i2c controller any more. Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
-rw-r--r--hw/npu2-opencapi.c46
1 files changed, 40 insertions, 6 deletions
diff --git a/hw/npu2-opencapi.c b/hw/npu2-opencapi.c
index a54ef63..9ddb603 100644
--- a/hw/npu2-opencapi.c
+++ b/hw/npu2-opencapi.c
@@ -919,19 +919,53 @@ err:
static void deassert_adapter_reset(struct npu2_dev *dev)
{
uint8_t pin, data;
- int rc;
+ int rc, rc2;
pin = get_reset_pin(dev);
+ /*
+ * All we need to do here is deassert the reset signal by
+ * setting the reset pin to high. However, we cannot leave the
+ * pin in output mode, as it can cause troubles with the
+ * opencapi adapter: when the slot is powered off (on a reboot
+ * for example), if the i2c controller is actively setting the
+ * reset signal to high, it maintains voltage on part of the
+ * fpga and can leak current. It can lead the fpga to be in an
+ * unspecified state and potentially cause damage.
+ *
+ * The circumvention is to set the pin back to input
+ * mode. There are pullup resistors on the planar on all
+ * platforms to make sure the signal will "naturally" be high,
+ * without the i2c controller actively setting it, so we won't
+ * have problems when the slot is powered off. And it takes
+ * the adapter out of reset.
+ *
+ * To summarize:
+ * 1. set the pin to input mode. That is enough to raise the
+ * signal
+ * 2. set the value of the pin to high. The pin is input mode,
+ * so it won't really do anything. But it's more coherent
+ * and avoids bad surprises on the next call to
+ * assert_adapter_reset()
+ */
lock(&dev->npu->i2c_lock);
- dev->npu->i2c_pin_wr_state |= pin;
- data = dev->npu->i2c_pin_wr_state;
+ dev->npu->i2c_pin_mode |= pin;
+ data = dev->npu->i2c_pin_mode;
rc = i2c_request_send(dev->npu->i2c_port_id_ocapi,
- platform.ocapi->i2c_reset_addr, SMBUS_WRITE,
- 0x1, 1,
- &data, sizeof(data), 120);
+ platform.ocapi->i2c_reset_addr, SMBUS_WRITE,
+ 0x3, 1,
+ &data, sizeof(data), 120);
+
+ dev->npu->i2c_pin_wr_state |= pin;
+ data = dev->npu->i2c_pin_wr_state;
+ rc2 = i2c_request_send(dev->npu->i2c_port_id_ocapi,
+ platform.ocapi->i2c_reset_addr, SMBUS_WRITE,
+ 0x1, 1,
+ &data, sizeof(data), 120);
unlock(&dev->npu->i2c_lock);
+ if (!rc)
+ rc = rc2;
if (rc) {
/**
* @fwts-label OCAPIDeviceResetFailed