diff mbox series

[1/4] hw/xscom: Add scom infrastructure

Message ID 20200402111356.1413-1-oohall@gmail.com
State Accepted
Headers show
Series [1/4] hw/xscom: Add scom infrastructure | expand

Checks

Context Check Description
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (ec7be0894c652bfda961418d79dd19838678abfc)

Commit Message

Oliver O'Halloran April 2, 2020, 11:13 a.m. UTC
Currently the top nibble of the "part ID" is used to determine the type
of a xscom_read() / xscom_write() call. This was mainly done for the
benefit of PRD on P8 which would do "targeted" SCOMs to EX (core)
chiplets and rely on skiboot to do find the actual scom address.
Similarly, PRD also relied on this to access the SCOMs of centaur
chips which are accessed via FSI on P8.

On P9 PRD moved to only doing non-targeted scoms where it would
only ever supply a "part ID" which was the fabric ID of the chip
to be SCOMed. The centaur support was also unnecessary since OPAL
didn't support any P9 systems with Centaurs. However, on future
systems we will have to support memory buffer chips again so we need
to expand the SCOM support to accomodate them.

To do this, allow skiboot components to register a SCOM read and write()
function for chip ID. This will allow us to ensure the P8 EX chiplet and
Centaur SCOM code is only ever used on P8, freeing up the Part ID
address space for other uses.

Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
---
 hw/xscom.c      | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/xscom.h | 12 ++++++++
 2 files changed, 87 insertions(+)
diff mbox series

Patch

diff --git a/hw/xscom.c b/hw/xscom.c
index 88e22da76424..32c813e572a6 100644
--- a/hw/xscom.c
+++ b/hw/xscom.c
@@ -580,11 +580,75 @@  void _xscom_unlock(void)
 	unlock(&xscom_lock);
 }
 
+/* sorted by the scom controller's partid */
+static LIST_HEAD(scom_list);
+
+int64_t scom_register(struct scom_controller *new)
+{
+	struct scom_controller *cur;
+
+	list_for_each(&scom_list, cur, link) {
+		if (cur->part_id == new->part_id) {
+			prerror("Attempted to add duplicate scom, partid %x\n",
+				new->part_id);
+			return OPAL_BUSY;
+		}
+
+		if (cur->part_id > new->part_id) {
+			list_add_before(&scom_list, &new->link, &cur->link);
+			return 0;
+		}
+	}
+
+	/* if we never find a larger partid then this is the largest */
+	list_add_tail(&scom_list, &new->link);
+
+	return 0;
+}
+
+static struct scom_controller *scom_find(uint32_t partid)
+{
+	struct scom_controller *cur;
+
+	list_for_each(&scom_list, cur, link)
+		if (partid == cur->part_id)
+			return cur;
+
+	return NULL;
+}
+
+static int64_t scom_read(struct scom_controller *scom, uint32_t partid,
+			 uint64_t pcbaddr, uint64_t *val)
+{
+	int64_t rc = scom->read(scom, partid, pcbaddr, val);
+
+	if (rc) {
+		prerror("%s: to %x off: %llx rc = %lld\n",
+			__func__, partid, pcbaddr, rc);
+	}
+
+	return rc;
+}
+
+static int64_t scom_write(struct scom_controller *scom, uint32_t partid,
+			  uint64_t pcbaddr, uint64_t val)
+{
+	int64_t rc = scom->write(scom, partid, pcbaddr, val);
+
+	if (rc) {
+		prerror("%s: to %x off: %llx rc = %lld\n",
+			__func__, partid, pcbaddr, rc);
+	}
+
+	return rc;
+}
+
 /*
  * External API
  */
 int _xscom_read(uint32_t partid, uint64_t pcb_addr, uint64_t *val, bool take_lock)
 {
+	struct scom_controller *scom;
 	uint32_t gcid;
 	int rc;
 
@@ -611,6 +675,11 @@  int _xscom_read(uint32_t partid, uint64_t pcb_addr, uint64_t *val, bool take_loc
 			return OPAL_UNSUPPORTED;
 		break;
 	default:
+		/* is it one of our hacks? */
+		scom = scom_find(partid);
+		if (scom)
+			return scom_read(scom, partid, pcb_addr, val);
+
 		/**
 		 * @fwts-label XSCOMReadInvalidPartID
 		 * @fwts-advice xscom_read was called with an invalid partid.
@@ -652,6 +721,7 @@  opal_call(OPAL_XSCOM_READ, opal_xscom_read, 3);
 
 int _xscom_write(uint32_t partid, uint64_t pcb_addr, uint64_t val, bool take_lock)
 {
+	struct scom_controller *scom;
 	uint32_t gcid;
 	int rc;
 
@@ -666,6 +736,11 @@  int _xscom_write(uint32_t partid, uint64_t pcb_addr, uint64_t val, bool take_loc
 		gcid = xscom_decode_chiplet(partid, &pcb_addr);
 		break;
 	default:
+		/* is it one of our hacks? */
+		scom = scom_find(partid);
+		if (scom)
+			return scom_write(scom, partid, pcb_addr, val);
+
 		/**
 		 * @fwts-label XSCOMWriteInvalidPartID
 		 * @fwts-advice xscom_write was called with an invalid partid.
diff --git a/include/xscom.h b/include/xscom.h
index 110aa8d62981..bd8bb89ac2ab 100644
--- a/include/xscom.h
+++ b/include/xscom.h
@@ -197,4 +197,16 @@  extern bool xscom_ok(void);
 extern int64_t xscom_read_cfam_chipid(uint32_t partid, uint32_t *chip_id);
 extern int64_t xscom_trigger_xstop(void);
 
+
+struct scom_controller {
+	uint32_t part_id;
+	void *private;
+	int64_t (*read)(struct scom_controller *, uint32_t chip, uint64_t reg, uint64_t *val);
+	int64_t (*write)(struct scom_controller *, uint32_t chip, uint64_t reg, uint64_t val);
+
+	struct list_node link;
+};
+
+int64_t scom_register(struct scom_controller *new);
+
 #endif /* __XSCOM_H */