Add a way for calls to readl()/writel() etc. to be picked up by a driver
in order to implement MMIO.

This works by registering some functions, which are then called when
accesses occur.

Add comments to sandbox_read() and sandbox_write() while we are here.

Signed-off-by: Simon Glass <[email protected]>
---

 arch/sandbox/cpu/mem.c           | 49 +++++++++++++++++++++++
 arch/sandbox/cpu/state.c         |  2 +
 arch/sandbox/include/asm/io.h    | 15 +++++++
 arch/sandbox/include/asm/state.h | 67 ++++++++++++++++++++++++++++++++
 4 files changed, 133 insertions(+)

diff --git a/arch/sandbox/cpu/mem.c b/arch/sandbox/cpu/mem.c
index 54a55c1558c..010dc9c16a0 100644
--- a/arch/sandbox/cpu/mem.c
+++ b/arch/sandbox/cpu/mem.c
@@ -6,6 +6,7 @@
 
 #define LOG_CATEGORY   LOGC_SANDBOX
 
+#include <alist.h>
 #include <errno.h>
 #include <log.h>
 #include <malloc.h>
@@ -231,9 +232,20 @@ void sandbox_map_list(void)
        }
 }
 
+static bool in_range(const struct sandbox_mmio *mmio, const void *addr)
+{
+       return addr >= mmio->base && addr < mmio->base + mmio->size;
+}
+
 unsigned long sandbox_read(const void *addr, enum sandboxio_size_t size)
 {
        struct sandbox_state *state = state_get_current();
+       const struct sandbox_mmio *mmio;
+
+       alist_for_each(mmio, &state->mmio) {
+               if (in_range(mmio, addr))
+                       return mmio->h_read(mmio->ctx, addr, size);
+       }
 
        if (!state->allow_memio)
                return 0;
@@ -255,6 +267,14 @@ unsigned long sandbox_read(const void *addr, enum 
sandboxio_size_t size)
 void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size)
 {
        struct sandbox_state *state = state_get_current();
+       const struct sandbox_mmio *mmio;
+
+       alist_for_each(mmio, &state->mmio) {
+               if (in_range(mmio, addr)) {
+                       mmio->h_write(mmio->ctx, addr, val, size);
+                       return;
+               }
+       }
 
        if (!state->allow_memio)
                return;
@@ -286,3 +306,32 @@ void sandbox_set_enable_pci_map(int enable)
 {
        enable_pci_map = enable;
 }
+
+int sandbox_mmio_add(void *base, ulong size, sandbox_mmio_read_func h_read,
+                    sandbox_mmio_write_func h_write, void *ctx)
+{
+       struct sandbox_state *state = state_get_current();
+       struct sandbox_mmio mmio;
+
+       mmio.base = base;
+       mmio.size = size;
+       mmio.h_read = h_read;
+       mmio.h_write = h_write;
+       mmio.ctx = ctx;
+       if (!alist_add(&state->mmio, mmio))
+               return -ENOMEM;
+
+       return 0;
+}
+
+void sandbox_mmio_remove(void *ctx)
+{
+       struct sandbox_state *state = state_get_current();
+       struct sandbox_mmio *from, *to;
+
+       alist_for_each_filter(from, to, &state->mmio) {
+               if (from->ctx != ctx)
+                       *to++ = *from;
+       }
+       alist_update_end(&state->mmio, to);
+}
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index 6a15c8b0a18..01742b63d05 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2011-2012 The Chromium OS Authors.
  */
 
+#include <alist.h>
 #include <bloblist.h>
 #include <config.h>
 #include <errno.h>
@@ -487,6 +488,7 @@ int state_init(void)
                printf("Out of memory\n");
                os_exit(1);
        }
+       alist_init_struct(&state->mmio, struct sandbox_mmio);
 
        state_reset_for_test(state);
        /*
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h
index e3034b9c703..99702532bc7 100644
--- a/arch/sandbox/include/asm/io.h
+++ b/arch/sandbox/include/asm/io.h
@@ -41,7 +41,22 @@ void unmap_physmem(const void *vaddr, unsigned long flags);
 /* Map from a pointer to our RAM buffer */
 phys_addr_t map_to_sysmem(const void *ptr);
 
+/**
+ * sandbox_read() - Perform a memory read
+ *
+ * @addr: Pointer to read from
+ * @size: Access size of read
+ * Return: Value obtained
+ */
 unsigned long sandbox_read(const void *addr, enum sandboxio_size_t size);
+
+/**
+ * sandbox_write() - Perform a memory write
+ *
+ * @addr: Pointer to write to
+ * @val: Value to write
+ * @size: Access size of write
+ */
 void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size);
 
 #define readb(addr) ({ u8 __v = sandbox_read((const void *)addr, SB_SIZE_8); 
__v; })
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index 9dea0980bfc..582d8fa21a5 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -6,11 +6,14 @@
 #ifndef __SANDBOX_STATE_H
 #define __SANDBOX_STATE_H
 
+#include <alist.h>
 #include <sysreset.h>
 #include <stdbool.h>
 #include <linux/list.h>
 #include <linux/stringify.h>
 
+enum sandboxio_size_t;
+
 /**
  * Selects the behavior of the serial terminal.
  *
@@ -64,6 +67,69 @@ struct sandbox_mapmem_entry {
        struct list_head sibling_node;
 };
 
+/**
+ * sandbox_read() - Read function for sandbox_mmio
+ *
+ * @addr: Pointer to read from
+ * @size: Access size of read
+ * Return: Value obtained
+ */
+typedef long (*sandbox_mmio_read_func)(void *ctx, const void *addr,
+                                      enum sandboxio_size_t size);
+
+/**
+ * sandbox_write() - Write function for sandbox_mmio
+ *
+ * @addr: Pointer to write to
+ * @val: Value to write
+ * @size: Access size of write
+ */
+typedef void (*sandbox_mmio_write_func)(void *ctx, void *addr, unsigned int 
val,
+                                       enum sandboxio_size_t size);
+
+/**
+ * sandbox_mmio_add() - Add a new MMIO region
+ *
+ * Register a new set of read/write functions to be called for a particular
+ *     memory region
+ *
+ * @base: Base pointer for region
+ * @size: Size of region
+ * @h_read: Read handler
+ * @h_write: Write handler
+ * @ctx: Context pointer to passed to read/write functions
+ */
+int sandbox_mmio_add(void *base, ulong size, sandbox_mmio_read_func h_read,
+                    sandbox_mmio_write_func h_write, void *ctx);
+
+/**
+ * sandbox_mmio_remove() - Remove an MMIO region
+ *
+ * All regions with the given @ctx are removed
+ *
+ * @ctx: Context to search for
+ */
+void sandbox_mmio_remove(void *ctx);
+
+/**
+ * struct sandbox_mmio - defines a region of memory-mapped I/O
+ *
+ * This allows accesses to a region of memory to go through provided functions
+ *
+ * @base: Base pointer of region
+ * @size: Size of region
+ * @h_read: Read handler
+ * @h_write: Write handler
+ * @ctx: Context pointer provided when registering
+ */
+struct sandbox_mmio {
+       void *base;
+       ulong size;
+       sandbox_mmio_read_func h_read;
+       sandbox_mmio_write_func h_write;
+       void *ctx;
+};
+
 /* The complete state of the test system */
 struct sandbox_state {
        const char *cmd;                /* Command to execute */
@@ -119,6 +185,7 @@ struct sandbox_state {
        void *other_fdt_buf;            /* 'other' FDT blob used by tests */
        int other_size;                 /* size of other FDT blob */
 
+       struct alist mmio;              /* list of struct sandbox_mmio */
        /*
         * This struct is getting large.
         *
-- 
2.43.0

Reply via email to