aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2020-04-02 22:13:53 +1100
committerOliver O'Halloran <oohall@gmail.com>2020-04-08 14:38:33 +1000
commit7b57002d3f5fd45caeb53240bf401803c528b865 (patch)
tree0d8d0585e1af9611bf1ee6f88e71fd094f70f598
parentec7be0894c652bfda961418d79dd19838678abfc (diff)
downloadskiboot-7b57002d3f5fd45caeb53240bf401803c528b865.zip
skiboot-7b57002d3f5fd45caeb53240bf401803c528b865.tar.gz
skiboot-7b57002d3f5fd45caeb53240bf401803c528b865.tar.bz2
hw/xscom: Add scom infrastructure
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>
-rw-r--r--hw/xscom.c75
-rw-r--r--include/xscom.h12
2 files changed, 87 insertions, 0 deletions
diff --git a/hw/xscom.c b/hw/xscom.c
index 88e22da..32c813e 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 110aa8d..bd8bb89 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 */