kopia lustrzana https://github.com/OpenRTX/OpenRTX
Refactored NVM data structures and functions
rodzic
d43dd57031
commit
d18bcbc59f
|
@ -26,15 +26,60 @@
|
|||
#include <errno.h>
|
||||
|
||||
/**
|
||||
* 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 address: start address for the read operation.
|
||||
* @param dev: NVM device number.
|
||||
* @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 len: number of bytes to read.
|
||||
* @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
|
||||
|
@ -42,98 +87,47 @@ int nvmArea_read(const struct nvmArea *area, uint32_t address, void *data, size_
|
|||
* the write.
|
||||
*
|
||||
* @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 len: number of bytes to write.
|
||||
* @return zero on success, a negative error code otherwise.
|
||||
*/
|
||||
int nvmArea_write(const struct nvmArea *area, uint32_t address, const void *data,
|
||||
size_t len);
|
||||
static inline int nvm_devWrite(const struct nvmDevice *dev, uint32_t offset,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
if(dev->ops->write == NULL)
|
||||
return -ENOTSUP;
|
||||
|
||||
if((offset + len) > dev->size)
|
||||
return -EINVAL;
|
||||
|
||||
return dev->ops->write(dev, offset, data, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an erase operation on an NVM area. Acceptable start address and size
|
||||
* depend on the NVM device the area belongs to.
|
||||
* Perform an erase operation on an NVM area. Acceptable offset 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 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 nvmArea_erase(const struct nvmArea *area, uint32_t address, size_t size);
|
||||
int nvm_devErase(const struct nvmDevice *dev, uint32_t offset, size_t size);
|
||||
|
||||
/**
|
||||
* Get the parameters of the NVM device associated to a memory area.
|
||||
* Sync device cache and state to its underlying hardware.
|
||||
* If the device does not support sync this function pointer is set to NULL.
|
||||
*
|
||||
* @param area: pointer to the NVM are descriptor.
|
||||
* @return pointer to the device parameters' data structure.
|
||||
* @param dev: pointer to NVM device descriptor.
|
||||
* @return 0 on success, negative errno code on fail.
|
||||
*/
|
||||
static inline const struct nvmParams *nvmArea_params(const struct nvmArea *area)
|
||||
static inline int nvm_devSync(const struct nvmDevice *dev)
|
||||
{
|
||||
const struct nvmDevice *dev = area->dev;
|
||||
if(dev->ops->sync == NULL)
|
||||
return -ENOTSUP;
|
||||
|
||||
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 struct nvmPartition *partition = &(area->partitions[pNum]);
|
||||
const size_t startAddr = area->startAddr + partition->offset + offset;
|
||||
|
||||
return nvmArea_write(area, startAddr, data, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an erase operation on an NVM area partition. Acceptable start address
|
||||
* and size depend on the NVM device the area belongs to.
|
||||
*
|
||||
* @param area: pointer to the NVM are descriptor.
|
||||
* @param pNum: partition number.
|
||||
* @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.
|
||||
*/
|
||||
static inline int nvmArea_erasePartition(const struct nvmArea *area,
|
||||
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);
|
||||
return dev->ops->sync(dev);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,23 +41,33 @@ enum nvmType
|
|||
};
|
||||
|
||||
/**
|
||||
* Nonvolatile memory device parameters. The content of this data structure is
|
||||
* filled by the device driver and then kept constant.
|
||||
* Enumeration field for nonvolatile memory properties.
|
||||
*/
|
||||
struct nvmParams
|
||||
enum nvmProperties
|
||||
{
|
||||
size_t write_size; ///< Minimum write size (write unit)
|
||||
size_t erase_size; ///< Minimum erase size (erase unit)
|
||||
size_t erase_cycles; ///< Maximum allowed erase cycles of a block
|
||||
uint8_t type; ///< Device type
|
||||
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 erase_size; ///< Minimum erase size (erase unit)
|
||||
size_t erase_cycles; ///< Maximum allowed erase cycles of a block
|
||||
uint32_t device_info; ///< Device type and flags
|
||||
};
|
||||
|
||||
struct nvmDevice;
|
||||
|
||||
/**
|
||||
* Standard API for nonvolatile memory driver.
|
||||
* Nonvolatile memory device driver.
|
||||
*/
|
||||
struct nvmApi
|
||||
struct nvmOps
|
||||
{
|
||||
/**
|
||||
* Read data from nonvolatile memory device.
|
||||
|
@ -104,29 +114,18 @@ struct nvmApi
|
|||
* @return 0 on success, negative errno code on fail.
|
||||
*/
|
||||
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
|
||||
{
|
||||
const struct nvmApi *api; ///< Driver API
|
||||
const void *config; ///< Driver configuration data
|
||||
void *const priv; ///< Driver runtime data
|
||||
const struct nvmOps *ops; ///< Device operations
|
||||
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
|
||||
* partition is referred to the beginning of the area itself.
|
||||
* Data structure representing a partition of a nonvolatile memory. The offset
|
||||
* of the partition is referred to the beginning of the memory area.
|
||||
*/
|
||||
struct nvmPartition
|
||||
{
|
||||
|
@ -135,17 +134,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
|
||||
* given device and with zero or more partition.
|
||||
*/
|
||||
struct nvmArea
|
||||
struct nvmDescriptor
|
||||
{
|
||||
const char *name; ///< Area name
|
||||
const struct nvmDevice *dev; ///< Device driver to manage the area
|
||||
const size_t startAddr; ///< Start address of the area from the beginning of the device
|
||||
const size_t size; ///< Size of the area, in bytes
|
||||
const struct nvmPartition *partitions; ///< List of partitions
|
||||
const char *name; ///< Name
|
||||
const struct nvmDevice *dev; ///< Associated device driver
|
||||
const size_t partNum; ///< Number of partitions
|
||||
const struct nvmPartition *partitions; ///< Partion table
|
||||
};
|
||||
|
||||
|
||||
|
@ -160,12 +158,13 @@ void nvm_init();
|
|||
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.
|
||||
* @return number of elements in the list.
|
||||
* @param index: index of the nonvolatile memory.
|
||||
* @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.
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
***************************************************************************/
|
||||
|
||||
#include <interfaces/nvmem.h>
|
||||
#include <nvmem_access.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
@ -26,60 +27,99 @@
|
|||
|
||||
/**
|
||||
* \internal
|
||||
* Check if a read/write/erase operation is within the bounds of a given NVM
|
||||
* area.
|
||||
* Compute the absolute offset from the beginning of an NVM device, given the
|
||||
* 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 addr: start address of the read/write/erase operation
|
||||
* @param len: size of the read/write/erase operation
|
||||
* @return true if the operation is within the NVM area bounds
|
||||
* @param nvm: pointer to NVM descriptor.
|
||||
* @param part: partition number.
|
||||
* @param offset: pointer to the offset.
|
||||
* @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)
|
||||
&& ((addr + len) < (area->startAddr + area->size));
|
||||
}
|
||||
const struct nvmPartition *np;
|
||||
|
||||
// Offset is relative to a partition
|
||||
if(part >= 0)
|
||||
{
|
||||
if((size_t) part >= nvm->partNum)
|
||||
return -EINVAL;
|
||||
|
||||
int nvmArea_read(const struct nvmArea *area, uint32_t address, void *data, size_t len)
|
||||
{
|
||||
const struct nvmDevice *dev = area->dev;
|
||||
np = &nvm->partitions[part];
|
||||
|
||||
if(checkBounds(area, address, len) == false)
|
||||
return -EINVAL;
|
||||
if((*offset + len) > np->size)
|
||||
return -EINVAL;
|
||||
|
||||
return dev->api->read(dev, address, data, len);
|
||||
}
|
||||
|
||||
int nvmArea_write(const struct nvmArea *area, uint32_t address, void *data, size_t len)
|
||||
{
|
||||
const struct nvmDevice *dev = area->dev;
|
||||
|
||||
if(checkBounds(area, address, len) == false)
|
||||
return -EINVAL;
|
||||
|
||||
if(dev->api->write == NULL)
|
||||
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);
|
||||
*offset += np->offset;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue