[Skiboot] [PATCH 1/4] hw/lpc: add helpers to copy in/out of fw space

Oliver O'Halloran oohall at gmail.com
Tue Oct 27 11:16:09 AEDT 2020


The normal LPC APIs are limited to 1/2/4 byte accesses. The existing SFC
controller, mbox and HIOMAP flash drivers implement more or less the
same copy loops to move data into and out of the LPC firmware space.

Add a single generic helper that can replace the seperate
implementations.

Signed-off-by: Oliver O'Halloran <oohall at gmail.com>
---
 hw/lpc.c      | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/lpc.h |  7 +++++
 2 files changed, 81 insertions(+)

diff --git a/hw/lpc.c b/hw/lpc.c
index c2a07a0db5da..c7947c07fbe9 100644
--- a/hw/lpc.c
+++ b/hw/lpc.c
@@ -667,6 +667,80 @@ int64_t lpc_probe_read(enum OpalLPCAddressType addr_type, uint32_t addr,
 	return __lpc_read_sanity(addr_type, addr, data, sz, true);
 }
 
+int64_t lpc_fw_read(uint32_t off, void *buf, uint32_t len)
+{
+	int rc;
+
+	prlog(PR_TRACE, "Reading 0x%08x bytes at FW offset 0x%08x\n",
+	      len, off);
+
+	while(len) {
+		uint32_t chunk;
+		uint32_t dat;
+
+		/* XXX: make this read until it's aligned */
+		if (len > 3 && !(off & 3)) {
+			rc = lpc_read(OPAL_LPC_FW, off, &dat, 4);
+			if (!rc) {
+				/*
+				 * lpc_read swaps to CPU endian but it's not
+				 * really a 32-bit value, so convert back.
+				 */
+				*(__be32 *)buf = cpu_to_be32(dat);
+			}
+			chunk = 4;
+		} else {
+			rc = lpc_read(OPAL_LPC_FW, off, &dat, 1);
+			if (!rc)
+				*(uint8_t *)buf = dat;
+			chunk = 1;
+		}
+		if (rc) {
+			prlog(PR_ERR, "lpc_read failure %d to FW 0x%08x\n", rc, off);
+			return rc;
+		}
+		len -= chunk;
+		off += chunk;
+		buf += chunk;
+	}
+
+	return 0;
+}
+
+int64_t lpc_fw_write(uint32_t off, const void *buf, uint32_t len)
+{
+	int rc;
+
+	prlog(PR_TRACE, "Writing 0x%08x bytes at FW offset 0x%08x\n",
+	      len, off);
+
+	while(len) {
+		uint32_t chunk;
+
+		if (len > 3 && !(off & 3)) {
+			/* endian swap: see lpc_window_write */
+			uint32_t dat = be32_to_cpu(*(__be32 *)buf);
+
+			rc = lpc_write(OPAL_LPC_FW, off, dat, 4);
+			chunk = 4;
+		} else {
+			uint8_t dat = *(uint8_t *)buf;
+
+			rc = lpc_write(OPAL_LPC_FW, off, dat, 1);
+			chunk = 1;
+		}
+		if (rc) {
+			prlog(PR_ERR, "lpc_write failure %d to FW 0x%08x\n", rc, off);
+			return rc;
+		}
+		len -= chunk;
+		off += chunk;
+		buf += chunk;
+	}
+
+	return 0;
+}
+
 /*
  * The "OPAL" variant add the emulation of 2 and 4 byte accesses using
  * byte accesses for IO and MEM space in order to be compatible with
diff --git a/include/lpc.h b/include/lpc.h
index b641aa4e6820..4d0efb8c7b55 100644
--- a/include/lpc.h
+++ b/include/lpc.h
@@ -102,6 +102,13 @@ extern int64_t lpc_probe_write(enum OpalLPCAddressType addr_type, uint32_t addr,
 extern int64_t lpc_probe_read(enum OpalLPCAddressType addr_type, uint32_t addr,
 			      uint32_t *data, uint32_t sz);
 
+/*
+ * helpers for doing a bulk io to firmware space. These can be less restrictive
+ * since FW space generally acts like "normal memory."
+ */
+extern int64_t lpc_fw_read(uint32_t addr, void *buf, uint32_t sz);
+extern int64_t lpc_fw_write(uint32_t addr, const void *buf, uint32_t sz);
+
 /* Mark LPC bus as used by console */
 extern void lpc_used_by_console(void);
 
-- 
2.26.2



More information about the Skiboot mailing list