summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2019-03-26 19:18:19 +1100
committerStewart Smith <stewart@linux.ibm.com>2019-03-28 15:24:13 +1100
commit517f088a8e39e344565d820eda6f9ebf571a3fa7 (patch)
tree3d21ea4e8754db0275dcd7b30b0ea73afb621fa7
parent319e7d935f1354f317f32816293ade0dfd827b81 (diff)
downloadtalos-skiboot-517f088a8e39e344565d820eda6f9ebf571a3fa7.tar.gz
talos-skiboot-517f088a8e39e344565d820eda6f9ebf571a3fa7.zip
platforms/firenze: Rework I2C controller fixups
For some system planars we need to apply some fixups to the PCI slot power controllers. These are done at boot time and a slightly bizzare in their construction since they share the I2C request completion callback with the runtime slot power on method which affects the PCI slot state machine. This is confusing to say the least, so this patch reworks the fixup code to use the synchronus I2C request code rather than open-coding the wait based on what PCI slot state is in use. It also does some general control flow cleanup and adds some comments explaining what the fixups are for. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
-rw-r--r--platforms/ibm-fsp/firenze-pci.c100
1 files changed, 51 insertions, 49 deletions
diff --git a/platforms/ibm-fsp/firenze-pci.c b/platforms/ibm-fsp/firenze-pci.c
index dc0ff568..ac2580fb 100644
--- a/platforms/ibm-fsp/firenze-pci.c
+++ b/platforms/ibm-fsp/firenze-pci.c
@@ -146,6 +146,11 @@ static struct firenze_pci_slot_info firenze_pci_slots[] = {
{ 0x07, "C3", 1, 1, 0x10, 1, 0, 0x3A, 1, 0xAA, 12 },
{ 0x06, "C2", 1, 1, 0x10, 1, 0, 0x3A, 0, 0xAA, 12 }
};
+
+/*
+ * I2C power controller register fix up table. Not sure what they do, but
+ * they seem to relate to the fast-trip setpoint.
+ */
static struct firenze_pci_slot_fixup_info firenze_pci_slot_fixup_tbl[] = {
{ "C3", 0x5e, 0xfb },
{ "C3", 0x5b, 0xff },
@@ -737,62 +742,52 @@ static struct i2c_bus *firenze_pci_find_i2c_bus(uint8_t chip,
}
static int64_t firenze_pci_slot_fixup_one_reg(struct pci_slot *slot,
- struct firenze_pci_slot_fixup_info *fixup,
- bool write)
+ struct firenze_pci_slot_fixup_info *fixup)
{
struct firenze_pci_slot *plat_slot = slot->data;
- struct i2c_request *req = plat_slot->req;
- int32_t retries = FIRENZE_PCI_SLOT_RETRIES;
- int64_t rc = OPAL_SUCCESS;
-
- req->offset = fixup->reg;
- if (write) {
- req->op = SMBUS_WRITE;
- *(uint8_t *)(req->rw_buf) = fixup->val;
- } else {
- req->op = SMBUS_READ;
- *(uint8_t *)(req->rw_buf) = 0;
- }
- pci_slot_set_state(slot, FIRENZE_PCI_SLOT_FRESET_WAIT_RSP);
- req->timeout = FIRENZE_PCI_I2C_TIMEOUT;
- i2c_queue_req(plat_slot->req);
-
- while (retries-- > 0) {
- check_timers(false);
- if (slot->state == FIRENZE_PCI_SLOT_FRESET_DELAY)
- break;
-
- time_wait_ms(FIRENZE_PCI_SLOT_DELAY);
- }
+ struct i2c_request req;
+ uint8_t buf;
+ int64_t rc;
- if (slot->state != FIRENZE_PCI_SLOT_FRESET_DELAY) {
- rc = OPAL_BUSY;
- prlog(PR_ERR, "Timeout %s PCI slot [%s] - (%02x, %02x)\n",
- write ? "writing" : "reading", fixup->label,
- fixup->reg, fixup->val);
- goto out;
- }
+ /*
+ * Fill out our own request structure since we don't want to invoke the
+ * normal completion handler.
+ */
+ memset(&req, 0, sizeof(req));
+ req.dev_addr = plat_slot->req->dev_addr;
+ req.bus = plat_slot->req->bus;
+ req.offset = fixup->reg;
+ req.offset_bytes = 1;
+ req.rw_buf = &buf;
+ req.rw_len = 1;
+ req.timeout = FIRENZE_PCI_I2C_TIMEOUT;
+
+ req.op = SMBUS_WRITE;
+ buf = fixup->val;
+ rc = i2c_request_sync(&req);
+ if (rc < 0)
+ return rc;
- if (!write && (*(uint8_t *)(req->rw_buf)) != fixup->val) {
- rc = OPAL_INTERNAL_ERROR;
- prlog(PR_ERR, "Error fixing PCI slot [%s] - (%02x, %02x, %02x)\n",
- fixup->label, fixup->reg, fixup->val,
- (*(uint8_t *)(req->rw_buf)));
+ /*
+ * Check the register fixup has been applied. It's not the end of the
+ * world we don't, but eh...
+ */
+ req.op = SMBUS_READ;
+ rc = i2c_request_sync(&req);
+ if (rc == OPAL_SUCCESS && buf != fixup->val) {
+ prlog(PR_ERR, "Error verifying fixup [%s] - (%02x, %02x, %02x)\n",
+ fixup->label, fixup->reg, fixup->val, buf);
}
-out:
- pci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);
return rc;
}
static void firenze_pci_slot_fixup(struct pci_slot *slot,
struct firenze_pci_slot_info *info)
{
- struct firenze_pci_slot_fixup_info *fixup;
+ int64_t rc, i, applied = 0;
const uint32_t *p;
uint64_t id;
- uint32_t i;
- int64_t rc;
p = dt_prop_get_def(dt_root, "ibm,vpd-lx-info", NULL);
id = p ? (((uint64_t)p[1] << 32) | p[2]) : 0ul;
@@ -800,19 +795,26 @@ static void firenze_pci_slot_fixup(struct pci_slot *slot,
id != LX_VPD_1S4U_BACKPLANE)
return;
- fixup = firenze_pci_slot_fixup_tbl;
- for (i = 0; i < ARRAY_SIZE(firenze_pci_slot_fixup_tbl); i++, fixup++) {
+ for (i = 0; i < ARRAY_SIZE(firenze_pci_slot_fixup_tbl); i++) {
+ struct firenze_pci_slot_fixup_info *fixup =
+ &firenze_pci_slot_fixup_tbl[i];
+
if (strcmp(info->label, fixup->label))
continue;
- rc = firenze_pci_slot_fixup_one_reg(slot, fixup, true);
- if (rc)
+ rc = firenze_pci_slot_fixup_one_reg(slot, fixup);
+ if (rc) {
+ prlog(PR_ERR, "I2C error (%lld) applying fixup [%s] - (%02x, %02x)\n",
+ rc, fixup->label, fixup->reg, fixup->val);
return;
+ }
- rc = firenze_pci_slot_fixup_one_reg(slot, fixup, false);
- if (rc)
- return;
+ applied++;
}
+
+ if (applied)
+ prlog(PR_INFO, "Applied %lld fixups for [%s]\n",
+ applied, info->label);
}
static void firenze_pci_setup_power_mgt(struct pci_slot *slot,
OpenPOWER on IntegriCloud