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

