[Skiboot] [PATCH 2/2] centaur: Add indirect XSCOM support

Benjamin Herrenschmidt benh at kernel.crashing.org
Wed Sep 30 15:47:03 AEST 2015


It works just like P8, we copy the code for now rather than make
it somewhat common due to our locking differences and to limit
the risk close to release. We can refactor later.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
 hw/centaur.c    | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 hw/xscom.c      |  12 -------
 include/xscom.h |  12 +++++++
 3 files changed, 118 insertions(+), 15 deletions(-)

diff --git a/hw/centaur.c b/hw/centaur.c
index 3df1291..5e594c1 100644
--- a/hw/centaur.c
+++ b/hw/centaur.c
@@ -82,7 +82,7 @@ static int64_t centaur_fsiscom_complete(struct centaur_chip *centaur)
 	if (stat == 0xffffffffu) {
 		cent_log(PR_ERR, centaur, "Chip appears to be dead !\n");
 		centaur->valid = false;
-		
+
 		/* Here, hostboot grabs a pile of FFDC from the FSI layer,
 		 * we could do that too ...
 		 */
@@ -215,6 +215,103 @@ struct centaur_chip *get_centaur(uint32_t part_id)
 	return centaur;
 }
 
+/*
+ * Indirect XSCOM access functions. Copied from xscom.c, at a
+ * latter date, we should merge these properly.
+ */
+static void centaur_xscom_handle_ind_error(struct centaur_chip *centaur,
+					   uint64_t data, uint64_t pcb_addr,
+					   bool is_write)
+{
+	unsigned int stat = GETFIELD(XSCOM_DATA_IND_ERR, data);
+	bool timeout = !(data & XSCOM_DATA_IND_COMPLETE);
+
+	/* XXX: Create error log entry ? */
+	if (timeout)
+		cent_log(PR_ERR, centaur,
+			 "inddirect %s timeout, pcb_addr=0x%llx stat=0x%x\n",
+			is_write ? "write" : "read", pcb_addr, stat);
+	else
+		cent_log(PR_ERR, centaur,
+			 "indirect %s error, pcb_addr=0x%llx stat=0x%x\n",
+			is_write ? "write" : "read", pcb_addr, stat);
+}
+
+static int centaur_xscom_ind_read(struct centaur_chip *centaur,
+				  uint64_t pcb_addr, uint64_t *val)
+{
+	uint32_t addr;
+	uint64_t data;
+	int rc, retries;
+
+	/* Write indirect address */
+	addr = pcb_addr & 0x7fffffff;
+	data = XSCOM_DATA_IND_READ |
+		(pcb_addr & XSCOM_ADDR_IND_ADDR);
+	rc = centaur_fsiscom_write(centaur, addr, data);
+	if (rc)
+		goto bail;
+
+	/* Wait for completion */
+	for (retries = 0; retries < XSCOM_IND_MAX_RETRIES; retries++) {
+		rc = centaur_fsiscom_read(centaur, addr, &data);
+		if (rc)
+			goto bail;
+		if ((data & XSCOM_DATA_IND_COMPLETE) &&
+		    ((data & XSCOM_DATA_IND_ERR) == 0)) {
+			*val = data & XSCOM_DATA_IND_DATA;
+			break;
+		}
+		if ((data & XSCOM_DATA_IND_COMPLETE) ||
+		    (retries >= XSCOM_IND_MAX_RETRIES)) {
+			centaur_xscom_handle_ind_error(centaur, data, pcb_addr,
+						       false);
+			rc = OPAL_HARDWARE;
+			goto bail;
+		}
+	}
+ bail:
+	if (rc)
+		*val = (uint64_t)-1;
+	return rc;
+}
+
+static int centaur_xscom_ind_write(struct centaur_chip *centaur,
+				   uint64_t pcb_addr, uint64_t val)
+{
+	uint32_t addr;
+	uint64_t data;
+	int rc, retries;
+
+	/* Write indirect address & data */
+	addr = pcb_addr & 0x7fffffff;
+	data = pcb_addr & XSCOM_ADDR_IND_ADDR;
+	data |= val & XSCOM_ADDR_IND_DATA;
+
+	rc = centaur_fsiscom_write(centaur, addr, data);
+	if (rc)
+		goto bail;
+
+	/* Wait for completion */
+	for (retries = 0; retries < XSCOM_IND_MAX_RETRIES; retries++) {
+		rc = centaur_fsiscom_read(centaur, addr, &data);
+		if (rc)
+			goto bail;
+		if ((data & XSCOM_DATA_IND_COMPLETE) &&
+		    ((data & XSCOM_DATA_IND_ERR) == 0))
+			break;
+		if ((data & XSCOM_DATA_IND_COMPLETE) ||
+		    (retries >= XSCOM_IND_MAX_RETRIES)) {
+			centaur_xscom_handle_ind_error(centaur, data, pcb_addr,
+						       true);
+			rc = OPAL_HARDWARE;
+			goto bail;
+		}
+	}
+ bail:
+	return rc;
+}
+
 int64_t centaur_xscom_read(uint32_t id, uint64_t pcb_addr, uint64_t *val)
 {
 	struct centaur_chip *centaur = get_centaur(id);
@@ -224,7 +321,10 @@ int64_t centaur_xscom_read(uint32_t id, uint64_t pcb_addr, uint64_t *val)
 		return OPAL_PARAMETER;
 
 	lock(&centaur->lock);
-	rc = centaur_fsiscom_read(centaur, pcb_addr, val);
+	if (pcb_addr & XSCOM_ADDR_IND_FLAG)
+		rc = centaur_xscom_ind_read(centaur, pcb_addr, val);
+	else
+		rc = centaur_fsiscom_read(centaur, pcb_addr, val);
 	unlock(&centaur->lock);
 
 	return rc;
@@ -239,7 +339,10 @@ int64_t centaur_xscom_write(uint32_t id, uint64_t pcb_addr, uint64_t val)
 		return OPAL_PARAMETER;
 
 	lock(&centaur->lock);
-	rc = centaur_fsiscom_write(centaur, pcb_addr, val);
+	if (pcb_addr & XSCOM_ADDR_IND_FLAG)
+		rc = centaur_xscom_ind_write(centaur, pcb_addr, val);
+	else
+		rc = centaur_fsiscom_write(centaur, pcb_addr, val);
 	unlock(&centaur->lock);
 
 	return rc;
diff --git a/hw/xscom.c b/hw/xscom.c
index f803615..c8e13be 100644
--- a/hw/xscom.c
+++ b/hw/xscom.c
@@ -29,18 +29,6 @@
 			   SPR_HMER_XSCOM_DONE | \
 			   SPR_HMER_XSCOM_STATUS))
 
-#define XSCOM_ADDR_IND_FLAG		PPC_BIT(0)
-#define XSCOM_ADDR_IND_ADDR		PPC_BITMASK(12,31)
-#define XSCOM_ADDR_IND_DATA		PPC_BITMASK(48,63)
-
-#define XSCOM_DATA_IND_READ		PPC_BIT(0)
-#define XSCOM_DATA_IND_COMPLETE		PPC_BIT(32)
-#define XSCOM_DATA_IND_ERR		PPC_BITMASK(33,35)
-#define XSCOM_DATA_IND_DATA		PPC_BITMASK(48,63)
-
-/* HB folks say: try 10 time for now */
-#define XSCOM_IND_MAX_RETRIES		10
-
 DEFINE_LOG_ENTRY(OPAL_RC_XSCOM_RW, OPAL_PLATFORM_ERR_EVT, OPAL_XSCOM,
 		OPAL_CEC_HARDWARE, OPAL_PREDICTIVE_ERR_GENERAL,
 		OPAL_NA);
diff --git a/include/xscom.h b/include/xscom.h
index 6e47c0d..933af6a 100644
--- a/include/xscom.h
+++ b/include/xscom.h
@@ -154,6 +154,18 @@
 #define EX_PM_IDLE_ST_HIST_PM_STATE_MASK	PPC_BITMASK(0, 2)
 #define EX_PM_IDLE_ST_HIST_PM_STATE_LSH		PPC_BITLSHIFT(2)
 
+/* Definitions relating to indirect XSCOMs shared with centaur */
+#define XSCOM_ADDR_IND_FLAG		PPC_BIT(0)
+#define XSCOM_ADDR_IND_ADDR		PPC_BITMASK(12,31)
+#define XSCOM_ADDR_IND_DATA		PPC_BITMASK(48,63)
+
+#define XSCOM_DATA_IND_READ		PPC_BIT(0)
+#define XSCOM_DATA_IND_COMPLETE		PPC_BIT(32)
+#define XSCOM_DATA_IND_ERR		PPC_BITMASK(33,35)
+#define XSCOM_DATA_IND_DATA		PPC_BITMASK(48,63)
+
+/* HB folks say: try 10 time for now */
+#define XSCOM_IND_MAX_RETRIES		10
 
 /*
  * Error handling:




More information about the Skiboot mailing list