Refactored NVM data structures and functions
This commit is contained in:
parent
031eda1d7e
commit
5b9cc789b9
|
|
@ -25,16 +25,65 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a byte-aligned read operation on an NVM area.
|
* Perform a byte-aligned read operation on a nonvolatile memory.
|
||||||
*
|
*
|
||||||
* @param area: pointer to the NVM are descriptor.
|
* @param dev: NVM device number.
|
||||||
* @param address: start address for the read operation.
|
* @param part: partition number, -1 for direct device access.
|
||||||
|
* @param address: offset for the read operation.
|
||||||
* @param data: pointer to a buffer where to store the data read.
|
* @param data: pointer to a buffer where to store the data read.
|
||||||
* @param len: number of bytes to read.
|
* @param len: number of bytes to read.
|
||||||
* @return zero on success, a negative error code otherwise.
|
* @return zero on success, a negative error code otherwise.
|
||||||
*/
|
*/
|
||||||
int nvmArea_read(const struct nvmArea *area, uint32_t address, void *data, size_t len);
|
int nvm_read(const uint32_t dev, const int part, uint32_t offset, void *data,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a write operation on a nonvolatile memory.
|
||||||
|
*
|
||||||
|
* @param dev: NVM device number.
|
||||||
|
* @param part: partition number, -1 for direct device access.
|
||||||
|
* @param offset: offset for the write operation.
|
||||||
|
* @param data: pointer to a buffer containing the data to write.
|
||||||
|
* @param len: number of bytes to write.
|
||||||
|
* @return zero on success, a negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int nvm_write(const uint32_t dev, const int part, uint32_t offset, const void *data,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an erase operation on a nonvolatile memory. Acceptable offset and
|
||||||
|
* size depend on characteristics of the underlying device.
|
||||||
|
*
|
||||||
|
* @param dev: NVM device number.
|
||||||
|
* @param part: partition number, -1 for direct device access.
|
||||||
|
* @param offset: offset for the erase operation.
|
||||||
|
* @param size: size of the area to be erased.
|
||||||
|
* @return zero on success, a negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int nvm_erase(const uint32_t dev, const int part, uint32_t offset, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a byte-aligned read operation on an NVM area.
|
||||||
|
*
|
||||||
|
* @param area: pointer to the NVM are descriptor.
|
||||||
|
* @param offset: offset for the read operation.
|
||||||
|
* @param data: pointer to a buffer where to store the data read.
|
||||||
|
* @param len: number of bytes to read.
|
||||||
|
* @return zero on success, a negative error code otherwise.
|
||||||
|
*/
|
||||||
|
static inline int nvm_devRead(const struct nvmDevice *dev, uint32_t offset,
|
||||||
|
void *data, size_t len)
|
||||||
|
{
|
||||||
|
if((offset + len) > dev->size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return dev->ops->read(dev, offset, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a byte-aligned write operation on an NVM area. If the underlying
|
* Perform a byte-aligned write operation on an NVM area. If the underlying
|
||||||
|
|
@ -42,98 +91,51 @@ int nvmArea_read(const struct nvmArea *area, uint32_t address, void *data, size_
|
||||||
* the write.
|
* the write.
|
||||||
*
|
*
|
||||||
* @param area: pointer to the NVM are descriptor.
|
* @param area: pointer to the NVM are descriptor.
|
||||||
* @param address: start address for the write operation.
|
* @param offset: offset for the write operation.
|
||||||
* @param data: pointer to a buffer containing the data to write.
|
* @param data: pointer to a buffer containing the data to write.
|
||||||
* @param len: number of bytes to write.
|
* @param len: number of bytes to write.
|
||||||
* @return zero on success, a negative error code otherwise.
|
* @return zero on success, a negative error code otherwise.
|
||||||
*/
|
*/
|
||||||
int nvmArea_write(const struct nvmArea *area, uint32_t address, const void *data,
|
static inline int nvm_devWrite(const struct nvmDevice *dev, uint32_t offset,
|
||||||
size_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform an erase operation on an NVM area. Acceptable start address and size
|
|
||||||
* depend on the NVM device the area belongs to.
|
|
||||||
*
|
|
||||||
* @param area: pointer to the NVM are descriptor.
|
|
||||||
* @param address: start address for the erase operation.
|
|
||||||
* @param size: size of the area to be erased.
|
|
||||||
* @return zero on success, a negative error code otherwise.
|
|
||||||
*/
|
|
||||||
int nvmArea_erase(const struct nvmArea *area, uint32_t address, size_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the parameters of the NVM device associated to a memory area.
|
|
||||||
*
|
|
||||||
* @param area: pointer to the NVM are descriptor.
|
|
||||||
* @return pointer to the device parameters' data structure.
|
|
||||||
*/
|
|
||||||
static inline const struct nvmParams *nvmArea_params(const struct nvmArea *area)
|
|
||||||
{
|
|
||||||
const struct nvmDevice *dev = area->dev;
|
|
||||||
|
|
||||||
return dev->api->params(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a byte-aligned read operation on an NVM area partition.
|
|
||||||
*
|
|
||||||
* @param area: pointer to the NVM are descriptor.
|
|
||||||
* @param pNum: partition number.
|
|
||||||
* @param address: start address for the read operation.
|
|
||||||
* @param data: pointer to a buffer where to store the data read.
|
|
||||||
* @param len: number of bytes to read.
|
|
||||||
* @return zero on success, a negative error code otherwise.
|
|
||||||
*/
|
|
||||||
static inline int nvmArea_readPartition(const struct nvmArea *area,
|
|
||||||
const uint32_t pNum, uint32_t offset,
|
|
||||||
void *data, size_t len)
|
|
||||||
{
|
|
||||||
const struct nvmPartition *partition = &(area->partitions[pNum]);
|
|
||||||
const size_t startAddr = area->startAddr + partition->offset + offset;
|
|
||||||
|
|
||||||
return nvmArea_read(area, startAddr, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a byte-aligned write operation on an NVM area partition. If the
|
|
||||||
* underlying device requires state syncing, a sync operation is performed at
|
|
||||||
* the end of the write.
|
|
||||||
*
|
|
||||||
* @param area: pointer to the NVM are descriptor.
|
|
||||||
* @param pNum: partition number.
|
|
||||||
* @param address: start address for the write operation.
|
|
||||||
* @param data: pointer to a buffer containing the data to write.
|
|
||||||
* @param len: number of bytes to write.
|
|
||||||
* @return zero on success, a negative error code otherwise.
|
|
||||||
*/
|
|
||||||
static inline int nvmArea_writePartition(const struct nvmArea *area,
|
|
||||||
const uint32_t pNum, uint32_t offset,
|
|
||||||
const void *data, size_t len)
|
const void *data, size_t len)
|
||||||
{
|
{
|
||||||
const struct nvmPartition *partition = &(area->partitions[pNum]);
|
if(dev->ops->write == NULL)
|
||||||
const size_t startAddr = area->startAddr + partition->offset + offset;
|
return -ENOTSUP;
|
||||||
|
|
||||||
return nvmArea_write(area, startAddr, data, len);
|
if((offset + len) > dev->size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return dev->ops->write(dev, offset, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform an erase operation on an NVM area partition. Acceptable start address
|
* Perform an erase operation on an NVM area. Acceptable offset and size depend
|
||||||
* and size depend on the NVM device the area belongs to.
|
* on the NVM device the area belongs to.
|
||||||
*
|
*
|
||||||
* @param area: pointer to the NVM are descriptor.
|
* @param area: pointer to the NVM are descriptor.
|
||||||
* @param pNum: partition number.
|
* @param offset: offset for the erase operation.
|
||||||
* @param address: start address for the erase operation.
|
|
||||||
* @param size: size of the area to be erased.
|
* @param size: size of the area to be erased.
|
||||||
* @return zero on success, a negative error code otherwise.
|
* @return zero on success, a negative error code otherwise.
|
||||||
*/
|
*/
|
||||||
static inline int nvmArea_erasePartition(const struct nvmArea *area,
|
int nvm_devErase(const struct nvmDevice *dev, uint32_t offset, size_t size);
|
||||||
const uint32_t pNum, uint32_t offset,
|
|
||||||
size_t size)
|
|
||||||
{
|
|
||||||
const struct nvmPartition *partition = &(area->partitions[pNum]);
|
|
||||||
const size_t startAddr = area->startAddr + partition->offset + offset;
|
|
||||||
|
|
||||||
return nvmArea_erase(area, startAddr, size);
|
/**
|
||||||
|
* Sync device cache and state to its underlying hardware.
|
||||||
|
* If the device does not support sync this function pointer is set to NULL.
|
||||||
|
*
|
||||||
|
* @param dev: pointer to NVM device descriptor.
|
||||||
|
* @return 0 on success, negative errno code on fail.
|
||||||
|
*/
|
||||||
|
static inline int nvm_devSync(const struct nvmDevice *dev)
|
||||||
|
{
|
||||||
|
if(dev->ops->sync == NULL)
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
|
return dev->ops->sync(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -41,23 +41,33 @@ enum nvmType
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nonvolatile memory device parameters. The content of this data structure is
|
* Enumeration field for nonvolatile memory properties.
|
||||||
* filled by the device driver and then kept constant.
|
|
||||||
*/
|
*/
|
||||||
struct nvmParams
|
enum nvmProperties
|
||||||
|
{
|
||||||
|
NVM_WRITE = 0x100, ///< Device allows write access
|
||||||
|
NVM_BITWRITE = 0x200, ///< Device allows to change the value of single bits
|
||||||
|
NVM_ERASE = 0x400, ///< Device memory needs to be erased before writing
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonvolatile memory device information block. The content of this data structure
|
||||||
|
* is defined by the device driver and remains constant.
|
||||||
|
*/
|
||||||
|
struct nvmInfo
|
||||||
{
|
{
|
||||||
size_t write_size; ///< Minimum write size (write unit)
|
size_t write_size; ///< Minimum write size (write unit)
|
||||||
size_t erase_size; ///< Minimum erase size (erase unit)
|
size_t erase_size; ///< Minimum erase size (erase unit)
|
||||||
size_t erase_cycles; ///< Maximum allowed erase cycles of a block
|
size_t erase_cycles; ///< Maximum allowed erase cycles of a block
|
||||||
uint8_t type; ///< Device type
|
uint32_t device_info; ///< Device type and flags
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nvmDevice;
|
struct nvmDevice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard API for nonvolatile memory driver.
|
* Nonvolatile memory device driver.
|
||||||
*/
|
*/
|
||||||
struct nvmApi
|
struct nvmOps
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Read data from nonvolatile memory device.
|
* Read data from nonvolatile memory device.
|
||||||
|
|
@ -104,29 +114,19 @@ struct nvmApi
|
||||||
* @return 0 on success, negative errno code on fail.
|
* @return 0 on success, negative errno code on fail.
|
||||||
*/
|
*/
|
||||||
int (*sync)(const struct nvmDevice *dev);
|
int (*sync)(const struct nvmDevice *dev);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get device parameters.
|
|
||||||
*
|
|
||||||
* @param dev: pointer to NVM device descriptor.
|
|
||||||
* @return pointer to the device parameters' data structure.
|
|
||||||
*/
|
|
||||||
const struct nvmParams *(*params)(const struct nvmDevice *dev);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Nonvolatile memory device driver.
|
|
||||||
*/
|
|
||||||
struct nvmDevice
|
struct nvmDevice
|
||||||
{
|
{
|
||||||
const struct nvmApi *api; ///< Driver API
|
const void *priv; ///< Device driver private data
|
||||||
const void *config; ///< Driver configuration data
|
const struct nvmOps *ops; ///< Device operations
|
||||||
void *const priv; ///< Driver runtime data
|
const struct nvmInfo *info; ///< Device info
|
||||||
|
const size_t size; ///< Device size
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data structure representing a partition of a NVM area. The offset of the
|
* Data structure representing a partition of a nonvolatile memory. The offset
|
||||||
* partition is referred to the beginning of the area itself.
|
* of the partition is referred to the beginning of the memory area.
|
||||||
*/
|
*/
|
||||||
struct nvmPartition
|
struct nvmPartition
|
||||||
{
|
{
|
||||||
|
|
@ -135,17 +135,16 @@ struct nvmPartition
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nonvolatile memory area descriptor. This data structure contains all the data
|
* Nonvolatile memory descriptor. This data structure contains all the data
|
||||||
* relative to an area of nonvolatile memory with a fixed size, managed by a
|
* relative to an area of nonvolatile memory with a fixed size, managed by a
|
||||||
* given device and with zero or more partition.
|
* given device and with zero or more partition.
|
||||||
*/
|
*/
|
||||||
struct nvmArea
|
struct nvmDescriptor
|
||||||
{
|
{
|
||||||
const char *name; ///< Area name
|
const char *name; ///< Name
|
||||||
const struct nvmDevice *dev; ///< Device driver to manage the area
|
const struct nvmDevice *dev; ///< Associated device driver
|
||||||
const size_t startAddr; ///< Start address of the area from the beginning of the device
|
const size_t partNum; ///< Number of partitions
|
||||||
const size_t size; ///< Size of the area, in bytes
|
const struct nvmPartition *partitions; ///< Partion table
|
||||||
const struct nvmPartition *partitions; ///< List of partitions
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -160,12 +159,13 @@ void nvm_init();
|
||||||
void nvm_terminate();
|
void nvm_terminate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of the available nonvolatile memory areas of the device.
|
* Obtain the descriptor of a given nonvolatile memory.
|
||||||
*
|
*
|
||||||
* @param list: pointer where to store the pointer to the list head.
|
* @param index: index of the nonvolatile memory.
|
||||||
* @return number of elements in the list.
|
* @return a pointer to the memory descriptor or NULL if the requested descriptor
|
||||||
|
* does not exist.
|
||||||
*/
|
*/
|
||||||
size_t nvm_getMemoryAreas(const struct nvmArea **list);
|
const struct nvmDescriptor *nvm_getDesc(const size_t index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load calibration data from nonvolatile memory.
|
* Load calibration data from nonvolatile memory.
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include <interfaces/nvmem.h>
|
#include <interfaces/nvmem.h>
|
||||||
|
#include <nvmem_access.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -26,60 +27,99 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \internal
|
* \internal
|
||||||
* Check if a read/write/erase operation is within the bounds of a given NVM
|
* Compute the absolute offset from the beginning of an NVM device, given the
|
||||||
* area.
|
* device descriptor and the partition number. If the partition number is set
|
||||||
|
* to -1, the offset is considered from the beginning of the device.
|
||||||
|
* This function performs also a bound check to guarantee that the following
|
||||||
|
* operation stays within the limits of the partition (if any).
|
||||||
*
|
*
|
||||||
* @param area: pointer to the NVM area descriptor
|
* @param nvm: pointer to NVM descriptor.
|
||||||
* @param addr: start address of the read/write/erase operation
|
* @param part: partition number.
|
||||||
* @param len: size of the read/write/erase operation
|
* @param offset: pointer to the offset.
|
||||||
* @return true if the operation is within the NVM area bounds
|
* @param len: lenght of the read/write/erase operation.
|
||||||
|
* @return a negative error code or zero.
|
||||||
*/
|
*/
|
||||||
static inline bool checkBounds(const struct nvmArea *area, uint32_t addr, size_t len)
|
static inline int getAbsOffset(const struct nvmDescriptor *nvm, const int part,
|
||||||
|
uint32_t *offset, size_t len)
|
||||||
{
|
{
|
||||||
return (addr >= area->startAddr)
|
const struct nvmPartition *np;
|
||||||
&& ((addr + len) < (area->startAddr + area->size));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Offset is relative to a partition
|
||||||
int nvmArea_read(const struct nvmArea *area, uint32_t address, void *data, size_t len)
|
if(part >= 0)
|
||||||
{
|
{
|
||||||
const struct nvmDevice *dev = area->dev;
|
if((size_t) part >= nvm->partNum)
|
||||||
|
|
||||||
if(checkBounds(area, address, len) == false)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return dev->api->read(dev, address, data, len);
|
np = &nvm->partitions[part];
|
||||||
}
|
|
||||||
|
|
||||||
int nvmArea_write(const struct nvmArea *area, uint32_t address, void *data, size_t len)
|
if((*offset + len) > np->size)
|
||||||
{
|
|
||||||
const struct nvmDevice *dev = area->dev;
|
|
||||||
|
|
||||||
if(checkBounds(area, address, len) == false)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if(dev->api->write == NULL)
|
*offset += np->offset;
|
||||||
return -ENOTSUP;
|
}
|
||||||
|
|
||||||
int ret = dev->api->write(dev, address, data, len);
|
|
||||||
if(ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if(dev->api->sync != NULL)
|
|
||||||
dev->api->sync(dev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nvmArea_erase(const struct nvmArea *area, uint32_t address, size_t size)
|
|
||||||
{
|
|
||||||
const struct nvmDevice *dev = area->dev;
|
|
||||||
|
|
||||||
if(checkBounds(area, address, size) == false)
|
int nvm_read(const uint32_t dev, const int part, uint32_t offset, void *data,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
const struct nvmDescriptor *nvm = nvm_getDesc(dev);
|
||||||
|
if(nvm == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if(dev->api->erase == NULL)
|
int ret = getAbsOffset(nvm, part, &offset, len);
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return nvm_devRead(nvm->dev, offset, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvm_write(const uint32_t dev, const int part, uint32_t offset, const void *data,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
const struct nvmDescriptor *nvm = nvm_getDesc(dev);
|
||||||
|
if(nvm == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
int ret = getAbsOffset(nvm, part, &offset, len);
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return nvm_devWrite(nvm->dev, offset, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvm_erase(const uint32_t dev, const int part, uint32_t offset, size_t size)
|
||||||
|
{
|
||||||
|
const struct nvmDescriptor *nvm = nvm_getDesc(dev);
|
||||||
|
if(nvm == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
int ret = getAbsOffset(nvm, part, &offset, size);
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return nvm_devErase(nvm->dev, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvm_devErase(const struct nvmDevice *dev, uint32_t offset, size_t size)
|
||||||
|
{
|
||||||
|
// Erase operation is allowed
|
||||||
|
if(dev->ops->erase == NULL)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|
||||||
return dev->api->erase(dev, address, size);
|
// Out-of-bounds check
|
||||||
|
if((offset + size) > dev->size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
// Start offset must be aligned to the erase size
|
||||||
|
if((offset % dev->info->erase_size) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
// Total size must be aligned to the erase size
|
||||||
|
if((size % dev->info->erase_size) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return dev->ops->erase(dev, offset, size);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue