/* SPDX-License-Identifier: Apache-2.0 */ /* Copyright (C) 2018 IBM Corp. */ /* Copyright (C) 2018 Evan Lojewski. */ #ifndef BACKEND_H #define BACKEND_H #include #include #include #include #include #define FLASH_DIRTY 0x00 #define FLASH_ERASED 0x01 /* Estimate as to how long (milliseconds) it takes to access a MB from flash */ #define FLASH_ACCESS_MS_PER_MB 8000 enum backend_reset_mode { reset_lpc_flash, reset_lpc_memory }; struct backend_ops; struct backend { const struct backend_ops *ops; /* Backend private data */ void *priv; /* Flash size from command line (bytes) */ uint32_t flash_size; /* Erase size (as a shift) */ uint32_t erase_size_shift; /* Block size (as a shift) */ uint32_t block_size_shift; }; struct backend_ops { /* * init() - Main initialization function for backing device * @context: The backend context pointer * @data: Additional backend-implementation-specifc data * Return: Zero on success, otherwise negative error */ int (*init)(struct backend *backend, void *data); /* * free() - Main teardown function for backing device * @context: The backend context pointer */ void (*free)(struct backend *backend); /* * copy() - Copy data from the flash device into a provided buffer * @context: The mbox context pointer * @offset: The flash offset to copy from (bytes) * @mem: The buffer to copy into (must be of atleast 'size' bytes) * @size: The number of bytes to copy * Return: Number of bytes copied on success, otherwise negative error * code. flash_copy will copy at most 'size' bytes, but it may * copy less. */ int64_t (*copy)(struct backend *backend, uint32_t offset, void *mem, uint32_t size); /* * set_bytemap() - Set the flash erased bytemap * @context: The mbox context pointer * @offset: The flash offset to set (bytes) * @count: Number of bytes to set * @val: Value to set the bytemap to * * The flash bytemap only tracks the erased status at the erase block level so * this will update the erased state for an (or many) erase blocks * * Return: 0 if success otherwise negative error code */ int (*set_bytemap)(struct backend *backend, uint32_t offset, uint32_t count, uint8_t val); /* * erase() - Erase the flash * @context: The backend context pointer * @offset: The flash offset to erase (bytes) * @size: The number of bytes to erase * * Return: 0 on success otherwise negative error code */ int (*erase)(struct backend *backend, uint32_t offset, uint32_t count); /* * write() - Write the flash from a provided buffer * @context: The backend context pointer * @offset: The flash offset to write to (bytes) * @buf: The buffer to write from (must be of atleast size) * @size: The number of bytes to write * * Return: 0 on success otherwise negative error code */ int (*write)(struct backend *backend, uint32_t offset, void *buf, uint32_t count); /* * validate() - Validates a requested window * @context: The backend context pointer * @offset: The requested flash offset * @size: The requested region size * @ro: The requested access type: True for read-only, false * for read-write * * Return: 0 on valid otherwise negative error code */ int (*validate)(struct backend *backend, uint32_t offset, uint32_t size, bool ro); /* * reset() - Ready the reserved memory for host startup * @context: The backend context pointer * @buf: The LPC reserved memory pointer * @count The size of the LPC reserved memory region * * Return: 0 on success otherwise negative error code */ int (*reset)(struct backend *backend, void *buf, uint32_t count); }; /* Make this better */ static inline int backend_init(struct backend *master, struct backend *with, void *data) { int rc; assert(master); /* FIXME: A bit hacky? */ with->flash_size = master->flash_size; *master = *with; #ifndef NDEBUG /* Set some poison values to ensure backends init properly */ master->erase_size_shift = 33; master->block_size_shift = 34; #endif if (!master->ops->init) return -ENOTSUP; rc = master->ops->init(master, data); if (rc < 0) return rc; assert(master->erase_size_shift < 32); assert(master->block_size_shift < 32); return 0; } static inline void backend_free(struct backend *backend) { assert(backend); if (backend->ops->free) backend->ops->free(backend); } static inline int64_t backend_copy(struct backend *backend, uint32_t offset, void *mem, uint32_t size) { assert(backend); assert(backend->ops->copy); return backend->ops->copy(backend, offset, mem, size); } static inline int backend_set_bytemap(struct backend *backend, uint32_t offset, uint32_t count, uint8_t val) { assert(backend); if (backend->ops->set_bytemap) return backend->ops->set_bytemap(backend, offset, count, val); return 0; } static inline int backend_erase(struct backend *backend, uint32_t offset, uint32_t count) { assert(backend); if (backend->ops->erase) return backend->ops->erase(backend, offset, count); return 0; } static inline int backend_write(struct backend *backend, uint32_t offset, void *buf, uint32_t count) { assert(backend); assert(backend->ops->write); return backend->ops->write(backend, offset, buf, count); } static inline int backend_validate(struct backend *backend, uint32_t offset, uint32_t size, bool ro) { assert(backend); if (backend->ops->validate) return backend->ops->validate(backend, offset, size, ro); return 0; } static inline int backend_reset(struct backend *backend, void *buf, uint32_t count) { assert(backend); assert(backend->ops->reset); return backend->ops->reset(backend, buf, count); } struct backend backend_get_mtd(void); int backend_probe_mtd(struct backend *master, const char *path); struct backend backend_get_file(void); int backend_probe_file(struct backend *master, const char *path); /* Avoid dependency on vpnor/mboxd_pnor_partition_table.h */ struct vpnor_partition_paths; #ifdef VIRTUAL_PNOR_ENABLED struct backend backend_get_vpnor(void); int backend_probe_vpnor(struct backend *master, const struct vpnor_partition_paths *paths); #else static inline struct backend backend_get_vpnor(void) { struct backend be = { 0 }; return be; } static inline int backend_probe_vpnor(struct backend *master, const struct vpnor_partition_paths *paths) { return -ENOTSUP; } #endif #endif /* BACKEND_H */