diff mbox

platforms/ibm-fsp: Reuse PCI slot mechanism for fixup

Message ID 1466489951-13273-1-git-send-email-gwshan@linux.vnet.ibm.com
State Accepted
Headers show

Commit Message

Gavin Shan June 21, 2016, 6:19 a.m. UTC
Currently, we have separately I2C stubs used for PCI slot power
management and fixup. It's reasonable to merge them to one so
that the code looks unified. Also, this introduces a table tracking
PCI slot fixup info which is very easy to be extended in future.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
Tested on P83 (Tuleta) only
---
 platforms/ibm-fsp/firenze-pci.c | 228 +++++++++++++++++++---------------------
 1 file changed, 107 insertions(+), 121 deletions(-)

Comments

Stewart Smith July 19, 2016, 10:04 a.m. UTC | #1
Gavin Shan <gwshan@linux.vnet.ibm.com> writes:
> Currently, we have separately I2C stubs used for PCI slot power
> management and fixup. It's reasonable to merge them to one so
> that the code looks unified. Also, this introduces a table tracking
> PCI slot fixup info which is very easy to be extended in future.
>
> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
> ---
> Tested on P83 (Tuleta) only
> ---
>  platforms/ibm-fsp/firenze-pci.c | 228 +++++++++++++++++++---------------------
>  1 file changed, 107 insertions(+), 121 deletions(-)

Thanks, merged to master as of 5e03605
diff mbox

Patch

diff --git a/platforms/ibm-fsp/firenze-pci.c b/platforms/ibm-fsp/firenze-pci.c
index 4416f1f..aa9a231 100644
--- a/platforms/ibm-fsp/firenze-pci.c
+++ b/platforms/ibm-fsp/firenze-pci.c
@@ -98,6 +98,8 @@  struct firenze_pci_slot_info {
 	uint8_t		channel;
 	uint8_t		power_status;
 	uint8_t		buddy;
+	uint8_t		fixup;
+	uint8_t		fixup_num;
 };
 
 struct firenze_pci_inv {
@@ -124,21 +126,30 @@  struct firenze_pci_inv_data {
  */
 static struct firenze_pci_inv_data *firenze_inv_data;
 static uint32_t firenze_inv_cnt;
+static uint8_t firenze_pci_slot_fixup_tbl[] = {
+	0x5e, 0xfa,	/* C6 / C7 */
+	0x5a, 0xff,
+	0x5b, 0xff,
+	0x5e, 0xfb,	/* C5 */
+	0x5b, 0xff,
+	0x5e, 0xfb,	/* C3 */
+	0x5b, 0xff
+};
 static struct firenze_pci_slot_info firenze_pci_slots[] = {
-	{ 0x0B,  "C7", 1, 1,    0, 1, 0, 0x35, 1, 0xAA,  0 },
-	{ 0x11, "C14", 0, 1,    0, 0, 0, 0x00, 0, 0xAA,  1 },
-	{ 0x0F, "C11", 1, 1,    0, 1, 0, 0x32, 1, 0xAA,  2 },
-	{ 0x10, "C12", 1, 1,    0, 1, 0, 0x39, 0, 0xAA,  3 },
-	{ 0x0A,  "C6", 1, 1,    0, 1, 0, 0x35, 0, 0xAA,  0 },
-	{ 0x12, "C15", 0, 1,    0, 0, 0, 0x00, 0, 0xAA,  5 },
-	{ 0x01, "USB", 0, 0,    0, 0, 0, 0x00, 0, 0xAA,  6 },
-	{ 0x0C,  "C8", 1, 1,    0, 1, 0, 0x36, 0, 0xAA,  7 },
-	{ 0x0D,  "C9", 1, 1,    0, 1, 0, 0x36, 1, 0xAA,  7 },
-	{ 0x0E, "C10", 1, 1,    0, 1, 0, 0x32, 0, 0xAA,  2 },
-	{ 0x09,  "C5", 1, 1, 0x10, 1, 0, 0x39, 1, 0xAA, 10 },
-	{ 0x08,  "C4", 1, 1, 0x10, 1, 0, 0x39, 0, 0xAA, 10 },
-	{ 0x07,  "C3", 1, 1, 0x10, 1, 0, 0x3A, 1, 0xAA, 12 },
-	{ 0x06,  "C2", 1, 1, 0x10, 1, 0, 0x3A, 0, 0xAA, 12 }
+	{ 0x0B,  "C7", 1, 1,    0, 1, 0, 0x35, 1, 0xAA,  0, 0, 3 },
+	{ 0x11, "C14", 0, 1,    0, 0, 0, 0x00, 0, 0xAA,  1, 0, 0 },
+	{ 0x0F, "C11", 1, 1,    0, 1, 0, 0x32, 1, 0xAA,  2, 0, 0 },
+	{ 0x10, "C12", 1, 1,    0, 1, 0, 0x39, 0, 0xAA,  3, 0, 0 },
+	{ 0x0A,  "C6", 1, 1,    0, 1, 0, 0x35, 0, 0xAA,  0, 0, 3 },
+	{ 0x12, "C15", 0, 1,    0, 0, 0, 0x00, 0, 0xAA,  5, 0, 0 },
+	{ 0x01, "USB", 0, 0,    0, 0, 0, 0x00, 0, 0xAA,  6, 0, 0 },
+	{ 0x0C,  "C8", 1, 1,    0, 1, 0, 0x36, 0, 0xAA,  7, 0, 0 },
+	{ 0x0D,  "C9", 1, 1,    0, 1, 0, 0x36, 1, 0xAA,  7, 0, 0 },
+	{ 0x0E, "C10", 1, 1,    0, 1, 0, 0x32, 0, 0xAA,  2, 0, 0 },
+	{ 0x09,  "C5", 1, 1, 0x10, 1, 0, 0x39, 1, 0xAA, 10, 3, 2 },
+	{ 0x08,  "C4", 1, 1, 0x10, 1, 0, 0x39, 0, 0xAA, 10, 0, 0 },
+	{ 0x07,  "C3", 1, 1, 0x10, 1, 0, 0x3A, 1, 0xAA, 12, 5, 2 },
+	{ 0x06,  "C2", 1, 1, 0x10, 1, 0, 0x3A, 0, 0xAA, 12, 0, 0 }
 };
 
 static void firenze_pci_add_inventory(struct phb *phb,
@@ -742,6 +753,85 @@  static struct i2c_bus *firenze_pci_find_i2c_bus(uint8_t chip,
 	return NULL;
 }
 
+static int64_t firenze_pci_slot_fixup_one(struct pci_slot *slot,
+					  struct firenze_pci_slot_info *info,
+					  uint8_t *fixup, bool write)
+{
+	struct firenze_pci_slot *plat_slot = slot->data;
+	struct i2c_request *req = plat_slot->req;
+	int32_t retries = FIRENZE_PCI_SLOT_RETRIES;
+	uint8_t rval;
+	int64_t rc = OPAL_SUCCESS;
+
+	req->offset = *fixup;
+	if (write) {
+		req->op = SMBUS_WRITE;
+		*(uint8_t *)(req->rw_buf) = *(fixup + 1);
+	} else {
+		req->op = SMBUS_READ;
+		*(uint8_t *)(req->rw_buf) = 0;
+	}
+	pci_slot_set_state(slot, FIRENZE_PCI_SLOT_FRESET_WAIT_RSP);
+	i2c_set_req_timeout(req, 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);
+	}
+
+	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", info->label,
+		      *fixup, *(fixup + 1));
+		goto out;
+	}
+
+	if (!write) {
+		rval = *(uint8_t *)(req->rw_buf);
+		if (rval != *(fixup + 1)) {
+			rc = OPAL_INTERNAL_ERROR;
+			prlog(PR_ERR, "Error fixing PCI slot [%s] - (%02x, %02x, %02x)\n",
+			      info->label, *fixup, *(fixup + 1), rval);
+		}
+	}
+
+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)
+{
+	const uint32_t *p;
+	uint64_t id;
+	uint8_t *fixup, num, 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;
+	if (id != LX_VPD_2S4U_BACKPLANE &&
+	    id != LX_VPD_1S4U_BACKPLANE)
+		return;
+
+	fixup = &firenze_pci_slot_fixup_tbl[info->fixup * 2];
+	num   = info->fixup_num;
+	for (i = 0; i < num; i++, fixup += 2) {
+		rc = firenze_pci_slot_fixup_one(slot, info, fixup, true);
+		if (rc)
+			return;
+
+		rc = firenze_pci_slot_fixup_one(slot, info, fixup, false);
+		if (rc)
+			return;
+	}
+}
+
 static void firenze_pci_slot_init(struct pci_slot *slot)
 {
 	struct lxvpd_pci_slot *s = slot->data;
@@ -775,11 +865,13 @@  static void firenze_pci_slot_init(struct pci_slot *slot)
 	if (plat_slot->req) {
 		plat_slot->req->dev_addr	= info->slave_addr;
 		plat_slot->req->offset_bytes	= 1;
-		plat_slot->req->offset		= 0x69;
 		plat_slot->req->rw_buf		= plat_slot->i2c_rw_buf;
 		plat_slot->req->rw_len		= 1;
 		plat_slot->req->completion	= firenze_i2c_req_done;
 		plat_slot->req->user_data	= slot;
+		firenze_pci_slot_fixup(slot, info);
+
+		plat_slot->req->offset		= 0x69;
 		switch (info->channel) {
 		case 0:
 			plat_slot->power_status = &firenze_pci_slots[buddy].power_status;
@@ -864,109 +956,6 @@  void firenze_pci_setup_phb(struct phb *phb, unsigned int index)
 	}
 }
 
-static void firenze_pci_i2c_complete(int rc, struct i2c_request *req)
-{
-	*(int *)req->user_data = rc;
-}
-
-static void firenze_pci_do_i2c_byte(uint8_t chip, uint8_t eng, uint8_t port,
-				    uint8_t addr, uint8_t reg, uint8_t data)
-{
-	struct i2c_bus *bus;
-	struct i2c_request *req;
-	uint8_t verif;
-	int rc;
-
-        bus = firenze_pci_find_i2c_bus(chip, eng, port);
-        if (!bus) {
-                prerror("FIRENZE: Failed to find i2c (%d/%d/%d)\n", chip, eng, port);
-                return;
-        }
-        req = i2c_alloc_req(bus);
-        if (!req) {
-                prerror("FIRENZE: Failed to allocate i2c request\n");
-                return;
-        }
-        req->op           = SMBUS_WRITE;
-        req->dev_addr     = addr >> 1;
-        req->offset_bytes = 1;
-        req->offset       = reg;
-        req->rw_buf       = &data;
-        req->rw_len       = 1;
-        req->completion   = firenze_pci_i2c_complete;
-        req->user_data    = &rc;
-        rc = 1;
-        i2c_queue_req(req);
-        while(rc == 1) {
-                time_wait_us(10);
-        }
-        if (rc != 0) {
-                prerror("FIRENZE: I2C error %d writing byte\n", rc);
-                return;
-        }
-        req->op           = SMBUS_READ;
-        req->dev_addr     = addr >> 1;
-        req->offset_bytes = 1;
-        req->offset       = reg;
-        req->rw_buf       = &verif;
-        req->rw_len       = 1;
-        req->completion   = firenze_pci_i2c_complete;
-        req->user_data    = &rc;
-        rc = 1;
-        i2c_queue_req(req);
-        while(rc == 1) {
-                time_wait_us(10);
-        }
-        if (rc != 0) {
-                prerror("FIRENZE: I2C error %d reading byte\n", rc);
-                return;
-        }
-        if (verif != data) {
-                prerror("FIRENZE: I2C miscompare want %02x got %02x\n", data, verif);
-        }
-}
-
-static void firenze_pci_slot_fixup(struct pci_slot *slot)
-{
-	uint64_t id;
-	const uint32_t *p;
-	struct lxvpd_pci_slot *s;
-
-	p = dt_prop_get_def(dt_root, "ibm,vpd-lx-info", NULL);
-	if (!p)
-		return;
-
-	/* FIXME: support fixup with generic way */
-	id = ((uint64_t)p[1] << 32) | p[2];
-
-	if (id != LX_VPD_2S4U_BACKPLANE &&
-	    id != LX_VPD_1S4U_BACKPLANE)
-		return;
-
-	s = slot->data;
-	if (!s || !s->pluggable)
-		return;
-
-	/* Note: We apply the settings twice for C6/C7 but that shouldn't
-	 * be a problem
-	 */
-	if (!strncmp(s->label, "C6 ", 2) ||
-	    !strncmp(s->label, "C7 ", 2)) {
-		printf("FIRENZE: Fixing power on %s...\n", s->label);
-		firenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5e, 0xfa);
-		firenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5a, 0xff);
-		firenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5b, 0xff);
-	} else if (!strncmp(s->label, "C5 ", 2)) {
-                printf("FIRENZE: Fixing power on %s...\n", s->label);
-		firenze_pci_do_i2c_byte(0, 1, 0, 0x72, 0x5e, 0xfb);
-		firenze_pci_do_i2c_byte(0, 1, 0, 0x72, 0x5b, 0xff);
-        } else if (!strncmp(s->label, "C3 ", 2)) {
-		printf("FIRENZE: Fixing power on %s...\n", s->label);
-		firenze_pci_do_i2c_byte(0, 1, 0, 0x74, 0x5e, 0xfb);
-		firenze_pci_do_i2c_byte(0, 1, 0, 0x74, 0x5b, 0xff);
-        }
-}
-
 void firenze_pci_get_slot_info(struct phb *phb, struct pci_device *pd)
 {
 	struct pci_slot *slot;
@@ -996,7 +985,4 @@  void firenze_pci_get_slot_info(struct phb *phb, struct pci_device *pd)
 		lxvpd_extract_info(slot, s);
 		firenze_pci_slot_init(slot);
 	}
-
-	/* Fixup the slot's power status */
-	firenze_pci_slot_fixup(slot);
 }