diff mbox series

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

Message ID 20201027001612.148724-1-oohall@gmail.com
State Under Review
Headers show
Series [1/4] hw/lpc: add helpers to copy in/out of fw space | 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 (233ade2f6ffdfa406100276784eb447d062fe8e7)

Commit Message

Oliver O'Halloran Oct. 27, 2020, 12:16 a.m. UTC
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@gmail.com>
---
 hw/lpc.c      | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/lpc.h |  7 +++++
 2 files changed, 81 insertions(+)

Comments

Vasant Hegde Oct. 29, 2020, 4:17 p.m. UTC | #1
On 10/27/20 5:46 AM, Oliver O'Halloran wrote:
> 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@gmail.com>

Looks good to me.

Reviewed-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>

-Vasant
diff mbox series

Patch

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);