Files
6CAR/middleware/fee/fee.c
2026-04-18 09:16:58 +08:00

1596 lines
57 KiB
C

/**
* @file fee.c
*
* Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*
* Description:
*
* Revision History:
* -----------------
*/
#include <debug.h>
#include <stdlib.h>
#include <string.h>
#include <param.h>
#include <types.h>
#include <stdarg.h>
#include <lib/list.h>
#include <fee/fee.h>
/* FEE BUFF */
#define FEE_BUFF_SIZE ((FEE_RECORD_BUFF_SIZE) * (FEE_BUFF_MAX))
static uint8_t record_buff[FEE_BUFF_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE) = {0};
//#define FEE_WRITE_CHECK 1
#ifdef FEE_WRITE_CHECK
#define FEE_WRITE_CHECK_SIZE 0x200
static uint8_t fee_write_check_buff[FEE_WRITE_CHECK_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE) = {0};
#endif
static int fee_disk_read(struct fee_dev *fee_dev, disk_addr_t addr,
uint8_t *dst, disk_size_t size)
{
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
if (!IS_ALIGNED(dst, disk_dev->mem_align_size)) {
ssdk_printf(SSDK_CRIT,
"fee_disk_read dst not aligned to disk_mem_align_size\n");
return -1;
}
if ((!IS_ALIGNED(addr, disk_dev->access_size))
|| (!IS_ALIGNED(size, disk_dev->access_size))) {
ssdk_printf(SSDK_CRIT,
"fee_disk_read addr or size not aligned to disk_access_size\n");
return -1;
}
return disk_dev->disk_read(disk_dev->disk_dev, dst, addr, size);
}
static int fee_disk_write(struct fee_dev *fee_dev, disk_addr_t addr,
const uint8_t *src, disk_size_t size)
{
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
if (!IS_ALIGNED(src, disk_dev->mem_align_size)) {
ssdk_printf(SSDK_CRIT,
"fee_disk_write src not aligned to disk_mem_align_size\n");
return -1;
}
if ((!IS_ALIGNED(addr, disk_dev->access_size))
|| (!IS_ALIGNED(size, disk_dev->access_size))) {
ssdk_printf(SSDK_CRIT,
"fee_disk_write addr or size not aligned to disk_access_size\n");
return -1;
}
#ifdef FEE_WRITE_CHECK
disk_size_t offset = 0;
disk_size_t rlen = 0;
uint8_t *check_buff = fee_write_check_buff;
int ret = 0;
ret = disk_dev->disk_write(disk_dev->disk_dev, src, addr, size);
if(ret) {
ssdk_printf(SSDK_CRIT,
"fee_disk_write write error, addr:%llx, size:%llx\n", addr, size);
return ret;
}
while(offset < size) {
rlen = MIN(FEE_WRITE_CHECK_SIZE, size - offset);
memset(check_buff, 0x0, rlen);
ret = disk_dev->disk_read(disk_dev->disk_dev, check_buff, addr + offset, rlen);
if(ret) {
ssdk_printf(SSDK_CRIT,
"fee_disk_write read error, addr:%llx, size:%llx\n", addr + offset, rlen);
return ret;
}
if(memcmp(check_buff, src + offset, rlen)) {
ssdk_printf(SSDK_CRIT, "*****************write data addr:%llx, size:%llx********************\n", addr + offset, rlen);
hexdump8_ex(src + offset, rlen,
(uint64_t)((addr_t)src + offset));
ssdk_printf(SSDK_CRIT, "*****************read data addr:%llx, size:%llx********************\n", addr + offset, rlen);
hexdump8_ex(check_buff, rlen,
(uint64_t)((addr_t)check_buff));
}
offset += rlen;
}
return 0;
#else
return disk_dev->disk_write(disk_dev->disk_dev, src, addr, size);
#endif
}
static int fee_disk_erase(struct fee_dev *fee_dev, disk_addr_t addr,
disk_size_t size)
{
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
if ((!IS_ALIGNED(addr, disk_dev->sector_size))
|| (!IS_ALIGNED(size, disk_dev->sector_size))) {
ssdk_printf(SSDK_CRIT,
"fee_disk_erase addr or size not aligned to disk_sector_size\n");
return -1;
}
return disk_dev->disk_erase(disk_dev->disk_dev, addr, size);
}
/* get sector_size record info based on sector_index */
static int fee_get_sector(struct fee_dev *fee_dev, uint16_t page_number,
uint16_t sector_index, uint8_t *sector)
{
return fee_disk_read(fee_dev,
fee_dev->page_info[page_number].page_addr + (sector_index *
fee_dev->record_buff_size), sector, fee_dev->record_buff_size);
}
/* configure page_status based on page_number */
static int fee_set_page_status(struct fee_dev *fee_dev, uint16_t page_number,
fee_page_status_t page_status)
{
fee_dev->page_info[page_number].page_status = page_status;
return fee_disk_write(fee_dev, fee_dev->page_info[page_number].page_addr,
(uint8_t *)&fee_dev->page_info[page_number].page_status,
sizeof(fee_page_status_t));
}
/* get page_status based on page_number */
static int fee_get_page_status(struct fee_dev *fee_dev, uint16_t page_number,
fee_page_status_t *page_status)
{
if (fee_disk_read(fee_dev, fee_dev->page_info[page_number].page_addr,
(uint8_t *)&fee_dev->page_info[page_number].page_status,
sizeof(fee_page_status_t)))
return -1;
*page_status = fee_dev->page_info[page_number].page_status;
return 0;
}
/* erases page based on page_number */
static int fee_erase_page(struct fee_dev *fee_dev, uint16_t page_number)
{
return fee_disk_erase(fee_dev, fee_dev->page_info[page_number].page_addr,
fee_dev->page_info[page_number].page_size);
}
/* displays complete page information based on page_number */
__UNUSED static int fee_page_dump(struct fee_dev *fee_dev, uint16_t page_number)
{
int ret = 0;
for (int i = 0; i < fee_dev->page_info[page_number].page_buff_num; i++) {
if (fee_get_sector(fee_dev, page_number, i,
(uint8_t *)fee_dev->record_data_buff))
return -1;
ssdk_printf(SSDK_INFO, "***************Page:%d sector:%d dump*******************\n",
page_number, i);
hexdump8_ex(fee_dev->record_data_buff, fee_dev->record_buff_size,
(uint64_t)((addr_t)fee_dev->record_data_buff));
}
return ret;
}
/* TODO:set/get block addr mask */
__UNUSED static int fee_block_addr_set(struct fee_dev *fee_dev, uint16_t page_number,
uint16_t block_number, uint16_t block_length)
{
int ret = 0;
return ret;
}
__UNUSED static int fee_block_addr_get(struct fee_dev *fee_dev, uint16_t page_number,
uint16_t block_number, uint32_t *block_addr)
{
int ret = 0;
return ret;
}
/* set record_status based on page_number and record_index */
static int fee_set_record_status(struct fee_dev *fee_dev, uint16_t page_number,
disk_size_t record_index_offset, fee_record_status_t record_status)
{
disk_addr_t addr = fee_dev->page_info[page_number].page_addr +
fee_dev->page_info[page_number].page_size;
addr -= (record_index_offset + 1) * sizeof(struct fee_record_info);
fee_dev->record_info.record_status = record_status;
return fee_disk_write(fee_dev, addr, (uint8_t *)&fee_dev->record_info.record_status,
sizeof(fee_record_status_t));
}
/* set record_info based on page_number and record_index */
static int fee_set_record_info(struct fee_dev *fee_dev, uint16_t page_number,
disk_size_t record_index_offset, struct fee_record_info *record_info)
{
disk_addr_t addr = fee_dev->page_info[page_number].page_addr +
fee_dev->page_info[page_number].page_size;
addr -= (record_index_offset + 1) * sizeof(struct fee_record_info);
return fee_disk_write(fee_dev, addr, (uint8_t *)record_info,
sizeof(struct fee_record_info));
}
/* get record_data_offset based on page_number and record_index_offset */
static int fee_get_record_data_offset(struct fee_dev *fee_dev,
uint16_t page_number, disk_size_t record_index_offset,
disk_size_t *record_data_offset)
{
int ret = 0;
uint32_t record_data_tmp = 0;
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
struct fee_record_info *record_info = (struct fee_record_info *)
fee_dev->record_data_offset_buff;
uint32_t sector_num = DIV_ROUND_UP(record_index_offset,
fee_dev->record_info_num);
uint32_t sector_index = fee_dev->page_info[page_number].page_buff_num -
sector_num;
uint32_t record_num = 0, record_index = 0;
for (int i = sector_index; i < sector_index + sector_num; i++) {
ret = fee_get_sector(fee_dev, page_number, i, (uint8_t *)record_info);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i);
return -1;
}
if ((!IS_ALIGNED(record_index_offset, fee_dev->record_info_num))
&& (i == sector_index))
record_num = record_index_offset % fee_dev->record_info_num;
else
record_num = fee_dev->record_info_num;
record_index = fee_dev->record_info_num - record_num;
for (int j = record_index; j < record_index + record_num; j++) {
ssdk_printf(SSDK_INFO, "sector_index:%d record_index:%d \n", i, j);
record_data_tmp += ROUNDUP(record_info[j].record_len,
disk_dev->access_size);
}
}
*record_data_offset = record_data_tmp;
return ret;
}
/* write record data based on page_number and record_data_offset */
static int fee_write_record_data(struct fee_dev *fee_dev, uint16_t page_number,
disk_size_t record_data_offset, const uint8_t *data_buffer, uint16_t length)
{
/* Address offset, start address + page information + block addr + used data offset */
disk_addr_t addr = fee_dev->page_info[page_number].page_addr +
FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset;
uint16_t rlen = 0;
uint8_t *buff = NULL;
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
while (length) {
/* length smaller than disk_access_size,added to disk_access_size */
if (length < disk_dev->access_size) {
buff = fee_dev->record_data_buff;
rlen = ROUNDUP(length, disk_dev->access_size);
memset(buff, 0xff, rlen);
memcpy(buff, data_buffer, MIN(rlen, length));
}
else {
/* mem address misaligned, data copy */
if (IS_ALIGNED(data_buffer, disk_dev->mem_align_size)) {
buff = (uint8_t *)data_buffer;
rlen = ROUNDDOWN(length, disk_dev->access_size);
}
else {
buff = fee_dev->record_data_buff;
rlen = MIN(ROUNDDOWN(length, disk_dev->access_size),
fee_dev->record_buff_size);
memcpy(buff, data_buffer, rlen);
}
}
if (fee_disk_write(fee_dev, addr, buff, rlen)) {
ssdk_printf(SSDK_CRIT,
"fee_write_record_data page_number %d record_data_offset %lld failure\n",
page_number, record_data_offset);
return -1;
}
data_buffer += MIN(rlen, length);
addr += MIN(rlen, length);
length -= MIN(rlen, length);
}
return 0;
}
/* read record data based on page_number and record_data_offset */
static int fee_read_record_data(struct fee_dev *fee_dev, uint16_t page_number,
disk_size_t record_data_offset, const uint8_t *data_buffer, uint16_t length)
{
/* Address offset, start address + page information + used data offset */
disk_addr_t addr = fee_dev->page_info[page_number].page_addr +
FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset;
uint16_t rlen = 0;
uint8_t *buff = NULL;
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
while (length) {
if (length < disk_dev->access_size) {
buff = fee_dev->record_data_buff;
rlen = ROUNDUP(length, disk_dev->access_size);
}
else {
if (IS_ALIGNED(data_buffer, disk_dev->mem_align_size)) {
buff = (uint8_t *)data_buffer;
rlen = ROUNDDOWN(length, disk_dev->access_size);
}
else {
buff = fee_dev->record_data_buff;
rlen = MIN(ROUNDDOWN(length, disk_dev->access_size),
fee_dev->record_buff_size);
}
}
if (fee_disk_read(fee_dev, addr, buff, rlen)) {
ssdk_printf(SSDK_CRIT,
"fee_read_record_data page_number %d record_data_offset %lld failure\n",
page_number, record_data_offset);
return -1;
}
if (buff != data_buffer) {
memcpy((void *)data_buffer, buff, MIN(rlen, length));
}
data_buffer += MIN(rlen, length);
addr += MIN(rlen, length);
length -= MIN(rlen, length);
}
return 0;
}
/* Based on page_number, write record */
static int fee_write_record(struct fee_dev *fee_dev, uint16_t page_number,
disk_size_t record_index_offset, uint16_t block_number,
disk_size_t record_data_offset, const uint8_t *data_buffer, uint16_t length)
{
int ret = 0;
ssdk_printf(SSDK_INFO,
"fee_write_record page_number:%d block_number:%x record_index_offset:%lld record_data_offset:%llx length:%x data_buffer:%x~%x\n",
page_number, block_number, record_index_offset, record_data_offset, length,
*data_buffer, *(data_buffer + length - 1));
/* Configuring record Information */
struct fee_record_info *record_info = (struct fee_record_info *)&fee_dev->record_info;
record_info->record_status = FEE_RECORD_INVALID;
record_info->record_num = block_number;
record_info->record_len = length;
ret = fee_set_record_info(fee_dev, page_number, record_index_offset,
record_info);
if (ret) {
ssdk_printf(SSDK_CRIT,
"fee_block_write set_record_info block_number %d failure\n", block_number);
return -1;
}
/* Write record data */
ret = fee_write_record_data(fee_dev, page_number, record_data_offset,
data_buffer, length);
if (ret) {
ssdk_printf(SSDK_CRIT,
"fee_block_write set_record_data block_number %d failure\n", block_number);
return -1;
}
/* Configure record valid */
ret = fee_set_record_status(fee_dev, page_number, record_index_offset,
FEE_RECORD_VALID);
if (ret) {
ssdk_printf(SSDK_CRIT,
"fee_block_write set_record_info FEE_RECORD_VALID status block_number %d failure\n",
block_number);
return -1;
}
return ret;
}
/* set the block address mask
block_number:The starting blocks
block_length:Block number */
static int fee_addr_mask_set(uint8_t *addr, uint16_t block_number,
uint16_t block_length)
{
int ret = 0;
uint32_t addr_mask = 0;
uint32_t addr_index = 0;
uint32_t left_offset = 0;
uint32_t rlen = 0;
ssdk_printf(SSDK_INFO, "fee_addr_mask_set block_number %d block_length %d\n",
block_number, block_length);
while (block_length) {
if (!IS_ALIGNED(block_number, FEE_CHAR_BIT)) {
left_offset = block_number - ROUNDDOWN(block_number, FEE_CHAR_BIT);
rlen = MIN(block_length, FEE_CHAR_BIT - left_offset);
addr_mask = ((0x1 << rlen) - 1) << left_offset;
addr_index = ROUNDDOWN(block_number, FEE_CHAR_BIT) / FEE_CHAR_BIT;
addr[addr_index] |= addr_mask;
ssdk_printf(SSDK_INFO,
"fee_addr_mask_set block_number not aligned part addr_index %d addr_mask %x\n",
addr_index, addr_mask);
block_number += rlen;
block_length -= rlen;
}
else if (block_length >= FEE_CHAR_BIT) {
rlen = ROUNDDOWN(block_length, FEE_CHAR_BIT);
addr_index = block_number / FEE_CHAR_BIT;
memset(addr + addr_index, 0xff, rlen / FEE_CHAR_BIT);
ssdk_printf(SSDK_INFO, "fee_addr_mask_set addr_index %d\n",
addr_index);
block_number += rlen;
block_length -= rlen;
}
else {
rlen = block_length;
addr_index = block_number / FEE_CHAR_BIT;
addr_mask = (0x1 << rlen) - 1;
addr[addr_index] |= addr_mask;
ssdk_printf(SSDK_INFO,
"fee_addr_mask_set block_length not aligned part addr_index %d addr_mask %x\n",
addr_index, addr_mask);
block_number += rlen;
block_length -= rlen;
}
}
return ret;
}
/* clear the block address mask
block_number:The starting blocks
block_length:Block number */
static int fee_addr_mask_clear(uint8_t *addr, uint16_t block_number,
uint16_t block_length)
{
int ret = 0;
uint32_t addr_mask = 0;
uint32_t addr_index = 0;
uint32_t left_offset = 0;
uint32_t rlen = 0;
ssdk_printf(SSDK_INFO, "fee_addr_mask_clear block_number %d block_length %d\n",
block_number, block_length);
while (block_length) {
if (!IS_ALIGNED(block_number, FEE_CHAR_BIT)) {
left_offset = block_number - ROUNDDOWN(block_number, FEE_CHAR_BIT);
rlen = MIN(block_length, FEE_CHAR_BIT - left_offset);
addr_mask = ~(((0x1 << rlen) - 1) << left_offset);
addr_index = ROUNDDOWN(block_number, FEE_CHAR_BIT) / FEE_CHAR_BIT;
addr[addr_index] &= addr_mask;
ssdk_printf(SSDK_INFO,
"fee_addr_mask_clear block_number not aligned part addr_index %d addr_mask %x\n",
addr_index, addr_mask);
block_number += rlen;
block_length -= rlen;
}
else if (block_length >= FEE_CHAR_BIT) {
rlen = ROUNDDOWN(block_length, FEE_CHAR_BIT);
addr_index = block_number / FEE_CHAR_BIT;
memset(addr + addr_index, 0x0, rlen / FEE_CHAR_BIT);
ssdk_printf(SSDK_INFO, "fee_addr_mask_clear addr_index %d\n",
addr_index);
block_number += rlen;
block_length -= rlen;
}
else {
rlen = block_length;
addr_index = block_number / FEE_CHAR_BIT;
addr_mask = ~((0x1 << rlen) - 1);
addr[addr_index] &= addr_mask;
ssdk_printf(SSDK_INFO,
"fee_addr_mask_clear block_length not aligned part addr_index %d addr_mask %x\n",
addr_index, addr_mask);
block_number += rlen;
block_length -= rlen;
}
}
return ret;
}
static int fee_addr_mask_and(uint8_t *addr_mask1, uint8_t *addr_mask2,
uint8_t *addr_mask3, uint16_t block_length)
{
for (int i = 0; i < block_length; i++) {
addr_mask3[i] = addr_mask1[i] & addr_mask2[i];
}
return 0;
}
__UNUSED static int fee_addr_mask_or(uint8_t *addr_mask1, uint8_t *addr_mask2,
uint8_t *addr_mask3, uint16_t block_length)
{
for (int i = 0; i < block_length; i++) {
addr_mask3[i] = addr_mask1[i] | addr_mask2[i];
}
return 0;
}
static int fee_addr_mask_empty(uint8_t *addr_mask, uint16_t block_length)
{
for (int i = 0; i < block_length; i++) {
if (addr_mask[i])
return 0;
}
return 1;
}
/* get the start block address and size based on the block address mask */
static int fee_addr_mask_block(uint8_t *addr_mask, uint32_t addr_size,
uint16_t *block_number, uint16_t *block_length)
{
int ret = 0;
uint32_t addr_block_index = 0;
uint32_t addr_index = 0;
uint32_t rlen = 0;
/* The first bit that is 1 is block_number */
for (int i = 0; i < addr_size; i++) {
if (addr_mask[i]) {
addr_block_index = i;
ssdk_printf(SSDK_INFO, "addr_block_index:%d \n", addr_block_index);
for (int j = 0; j < FEE_CHAR_BIT; j++) {
if ((addr_mask[addr_block_index] >> j) & 0x1) {
addr_index = j;
ssdk_printf(SSDK_INFO, "addr_index:%d \n", addr_index);
*block_number = DIVD_NUM(i, j, FEE_CHAR_BIT);
ssdk_printf(SSDK_INFO, "block_number:%d \n", *block_number);
goto match_num;
}
}
}
}
return -1;
match_num:
/* Offset back from block_number and calculate the length from the first 0 bit to block_length */
for (int i = addr_block_index; i < addr_size; i++) {
if (i != addr_block_index)
addr_index = 0;
for (int j = addr_index; j < FEE_CHAR_BIT; j++) {
if ((addr_mask[i] >> j) & 0x1) {
rlen++;
ssdk_printf(SSDK_INFO, "rlen:%d \n", rlen);
}
else
goto match_len;
}
}
match_len:
*block_length = rlen;
return ret;
}
/* fee initial power-on initialization */
static int fee_format(struct fee_dev *fee_dev)
{
/* Erase all pages */
int ret = 0;
for (int i = 0; i < fee_dev->page_number; i++) {
ret = fee_erase_page(fee_dev, i);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee_format erase page %d failure\n", i);
return ret;
}
}
/* configure Page 0 to FEE_PAGE_RECEIVE */
ret = fee_set_page_status(fee_dev, 0, FEE_PAGE_ACTIVE);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee_format set page 0 FEE_PAGE_RECEIVE failure\n");
return ret;
}
return ret;
}
/* get the current record_index based on page_number */
static int fee_get_page_record_index(struct fee_dev *fee_dev,
uint16_t page_number, disk_size_t *record_index_offset)
{
int ret = 0;
disk_size_t record_offset = 0;
uint8_t record_match = 0;
/* Get the latest record_info_offset(fee_record_info aligned) */
struct fee_record_info *record_info = (struct fee_record_info *)
fee_dev->record_info_buff;
uint32_t sector_index = fee_dev->page_info[page_number].page_buff_num - 1;
uint32_t record_index = 0;
/* Traversal from the last sector */
for (int i = sector_index; i >= 0 ; i--) {
ret = fee_get_sector(fee_dev, page_number, i, (uint8_t *)record_info);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i);
return -1;
}
/* Traversal from the last record */
record_index = fee_dev->record_info_num - 1;
for (int j = record_index; j >= 0; j--) {
if (record_info[j].record_status == FEE_RECORD_ERASED) {
ssdk_printf(SSDK_INFO, "sector_num:%d record_num:%d\n", sector_index - i,
record_index - j);
record_match = 1;
record_offset = DIVD_NUM(sector_index - i, record_index - j,
fee_dev->record_info_num);
break;
}
}
if (record_match)
break;
}
*record_index_offset = record_offset;
return ret;
}
/* Get the current page ADDR mask based on page_number and record_index */
static int fee_set_record_addr_mask(struct fee_dev *fee_dev,
uint16_t page_number, disk_size_t record_index_offset, uint8_t *addr_mask)
{
int ret = 0;
/* Traversal begins with the last sector */
uint32_t sector_num = DIV_ROUND_UP(record_index_offset,
fee_dev->record_info_num);
uint32_t sector_index = fee_dev->page_info[page_number].page_buff_num -
sector_num;
uint32_t record_num = 0, record_index = 0;
struct fee_record_info *record_info = (struct fee_record_info *)
fee_dev->record_info_buff;
uint16_t block_length = 0;
for (int i = sector_index; i < sector_index + sector_num; i++) {
ret = fee_get_sector(fee_dev, page_number, i, (uint8_t *)record_info);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i);
return -1;
}
if ((!IS_ALIGNED(record_index_offset, fee_dev->record_info_num))
&& (i == sector_index))
record_num = record_index_offset % fee_dev->record_info_num;
else
record_num = fee_dev->record_info_num;
record_index = fee_dev->record_info_num - record_num;
for (int j = record_index; j < record_index + record_num; j++) {
block_length = DIV_ROUND_UP(record_info[j].record_len, fee_dev->block_length);
ssdk_printf(SSDK_INFO, "block_number:%d block_length %d\n",
record_info[j].record_num, block_length);
fee_addr_mask_set(addr_mask, record_info[j].record_num, block_length);
}
}
return ret;
}
static int fee_swap_data(struct fee_dev *fee_dev, uint16_t src_page,
uint16_t dst_page, disk_size_t record_info_offset_dst,
struct fee_record_info *record_info, disk_size_t record_data_offset_src,
disk_size_t record_data_offset_dst)
{
int ret = 0;
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
ret = fee_set_record_info(fee_dev, dst_page, record_info_offset_dst,
record_info);
if (ret) {
ssdk_printf(SSDK_CRIT,
"fee_block_write set_record_info block_number %d failure\n",
record_info->record_num);
return -1;
}
fee_record_length_t record_len = 0, rlen = 0, addr_offset = 0;;
record_len = record_info->record_len;
disk_addr_t addr_src = fee_dev->page_info[src_page].page_addr +
FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset_src;
disk_addr_t addr_dst = fee_dev->page_info[dst_page].page_addr +
FEE_BLOCK_ADDR_BIT_SIZE + sizeof(struct fee_page_info) + record_data_offset_dst;
while (record_len) {
rlen = MIN(record_len, fee_dev->record_buff_size);
memset((void *)fee_dev->record_data_buff, 0xff, ROUNDUP(rlen,
disk_dev->access_size));
/* Read the data */
ret = fee_disk_read(fee_dev, addr_src + addr_offset, fee_dev->record_data_buff,
ROUNDUP(rlen, disk_dev->access_size));
if (ret) {
ssdk_printf(SSDK_CRIT, "fee fee_read_record_data failure\n");
return -1;
}
/* Write data */
ret = fee_disk_write(fee_dev, addr_dst + addr_offset, fee_dev->record_data_buff,
ROUNDUP(rlen, disk_dev->access_size));
if (ret) {
ssdk_printf(SSDK_CRIT, "fee fee_write_record failure\n");
return -1;
}
addr_offset += rlen;
record_len -= rlen;
}
/* Configure record valid */
ret = fee_set_record_status(fee_dev, dst_page, record_info_offset_dst,
FEE_RECORD_VALID);
if (ret) {
ssdk_printf(SSDK_CRIT,
"fee_block_write set_record_info FEE_RECORD_VALID status block_number %d failure\n",
record_info->record_num);
return -1;
}
return ret;
}
/* Two page swaps */
static int fee_page_swap_multiple(struct fee_dev *fee_dev, uint16_t active_page,
uint16_t erase_page)
{
int ret = 0;
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
/* Setting page Status */
if (fee_set_page_status(fee_dev, active_page, FEE_PAGE_VALID))
return -1;
if (fee_set_page_status(fee_dev, erase_page, FEE_PAGE_RECEIVE))
return -1;
/* Record information */
disk_size_t record_info_offset_active = fee_dev->record_info_offset;
disk_size_t record_info_offset_erase = 0;
disk_size_t record_data_offset_erase = 0;
disk_size_t record_info_offset_record = 0;
disk_size_t record_data_offset_record = 0;
uint16_t match_block = 0;
uint16_t match_len = 0;
disk_size_t record_addr_offset = 0;
disk_size_t record_addr_len = 0;
/* block address space */
uint8_t *block_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_BLOCK, fee_dev->block_addr_size);
uint8_t *record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_RECORD, fee_dev->block_addr_size);
uint8_t *current_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_RECORD_CURRENT, fee_dev->block_addr_size);
uint8_t *tmp_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_RECORD_TMP, fee_dev->block_addr_size);
/* copy data information */
memset(record_mask, 0x0, fee_dev->block_addr_size);
memcpy(record_mask, block_mask, fee_dev->block_addr_size);
/* Traversal begins with the last sector */
struct fee_record_info *record_info = (struct fee_record_info *)
fee_dev->record_info_buff;
uint32_t sector_num = DIV_ROUND_UP(record_info_offset_active,
fee_dev->record_info_num);
uint32_t sector_index = fee_dev->page_info[active_page].page_buff_num -
sector_num;
uint32_t record_num = 0, record_index = 0;
for (int i = sector_index; i < sector_index + sector_num; i++) {
ret = fee_get_sector(fee_dev, active_page, i, (uint8_t *)record_info);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i);
return -1;
}
if ((!IS_ALIGNED(record_info_offset_active, fee_dev->record_info_num))
&& (i == sector_index))
record_num = record_info_offset_active % fee_dev->record_info_num;
else
record_num = fee_dev->record_info_num;
record_index = fee_dev->record_info_num - record_num;
for (int j = record_index; j < record_index + record_num; j++) {
/* Record the effective */
if (record_info[j].record_status == FEE_RECORD_VALID) {
/* Judge the matching of record and block_mask, and swap the consistent parts */
memset(current_record_mask, 0x0, fee_dev->block_addr_size);
fee_addr_mask_set(current_record_mask, record_info[j].record_num,
DIV_ROUND_UP(record_info[j].record_len, fee_dev->block_length));
memset(tmp_record_mask, 0x0, fee_dev->block_addr_size);
fee_addr_mask_and(current_record_mask, record_mask, tmp_record_mask,
fee_dev->block_addr_size);
/* When the matching part is not empty */
while (!fee_addr_mask_empty(tmp_record_mask, fee_dev->block_addr_size)) {
/* Matches block & length */
fee_addr_mask_block(tmp_record_mask, fee_dev->block_addr_size, &match_block,
&match_len);
/* Clears matching blocks */
fee_addr_mask_clear(tmp_record_mask, match_block, match_len);
fee_addr_mask_clear(record_mask, match_block, match_len);
/* Get record data */
record_info_offset_record = DIVD_NUM(
fee_dev->page_info[active_page].page_buff_num - 1 - i,
fee_dev->record_info_num - 1 - j, fee_dev->record_info_num);
if (fee_get_record_data_offset(fee_dev, active_page, record_info_offset_record,
&record_data_offset_record))
return -1;
/* Calculate the data offset and matching address length of the matching part and record */
record_addr_offset = (match_block - record_info[j].record_num) *
fee_dev->block_length;
record_addr_len = match_len * fee_dev->block_length;
/* Configuring record Information */
struct fee_record_info *record_info_erase = (struct fee_record_info *)&fee_dev->record_info;
record_info_erase->record_status = FEE_RECORD_INVALID;
record_info_erase->record_num = match_block;
record_info_erase->record_len = record_addr_len;
ret = fee_swap_data(fee_dev, active_page, erase_page, record_info_offset_erase,
record_info_erase, record_data_offset_record + record_addr_offset,
record_data_offset_erase);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee_swap_data block_num %d failure\n",
record_info[j].record_num);
return -1;
}
record_info_offset_erase++;
record_data_offset_erase += ROUNDUP(record_addr_len, disk_dev->access_size);
}
}
if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size))
break;
}
if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size))
break;
}
/* Updated fee_dev information */
fee_dev->current_page = erase_page;
fee_dev->record_info_offset = record_info_offset_erase;
fee_dev->record_data_offset = record_data_offset_erase;
memset(block_mask, 0x0, fee_dev->block_addr_size);
ret = fee_set_record_addr_mask(fee_dev, erase_page, fee_dev->record_info_offset,
block_mask);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee set_record_addr_mask error\n");
return ret;
}
/* TODO:configure block mask info */
/* Setting page Status */
if (fee_set_page_status(fee_dev, erase_page, FEE_PAGE_ACTIVE))
return -1;
if (fee_set_page_status(fee_dev, active_page, FEE_PAGE_ERASING))
return -1;
if (fee_erase_page(fee_dev, active_page))
return -1;
return ret;
}
/* TODO:Two page swaps singel block */
static int fee_page_swap_single(struct fee_dev *fee_dev, uint16_t active_page,
uint16_t erase_page)
{
int ret = 0;
return ret;
}
/* Two page swaps */
static int fee_page_swap(struct fee_dev *fee_dev, uint16_t active_page,
uint16_t erase_page)
{
switch (fee_dev->page_mode) {
case FEE_PAGE_BLOCK:
return fee_page_swap_single(fee_dev, active_page, erase_page);
case FEE_PAGE_EEPROM:
return fee_page_swap_multiple(fee_dev, active_page, erase_page);
default:
ssdk_printf(SSDK_CRIT, "fee_page_swap page mode error\n");
return -1;
}
}
/* get the current page based on page information */
static int fee_page_set_two(struct fee_dev *fee_dev)
{
int ret = 0;
fee_page_status_t page0_status = 0;
fee_page_status_t page1_status = 0;
/* Getting page state */
ret = fee_get_page_status(fee_dev, 0, &page0_status);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get page0 status error\n");
return ret;
}
ret = fee_get_page_status(fee_dev, 1, &page1_status);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get page1 status error\n");
return ret;
}
ssdk_printf(SSDK_INFO, "get current page: page0_status %x page1_status %x\n",
page0_status, page1_status);
switch (page0_status) {
case FEE_PAGE_ERASED:
switch (page1_status) {
case FEE_PAGE_ERASED:
fee_dev->current_page = 0;
break;
case FEE_PAGE_ACTIVE:
case FEE_PAGE_VALID:
fee_dev->current_page = 1;
break;
default:
goto error;
}
break;
case FEE_PAGE_RECEIVE:
switch (page1_status) {
case FEE_PAGE_VALID:
fee_dev->current_page = 1;
break;
default:
goto error;
}
break;
case FEE_PAGE_ACTIVE:
switch (page1_status) {
case FEE_PAGE_ERASED:
case FEE_PAGE_VALID:
case FEE_PAGE_ERASING:
fee_dev->current_page = 0;
break;
default:
goto error;
}
break;
case FEE_PAGE_VALID:
switch (page1_status) {
case FEE_PAGE_ERASED:
case FEE_PAGE_RECEIVE:
fee_dev->current_page = 0;
break;
case FEE_PAGE_ACTIVE:
fee_dev->current_page = 1;
break;
default:
goto error;
}
break;
case FEE_PAGE_ERASING:
switch (page1_status) {
case FEE_PAGE_ACTIVE:
fee_dev->current_page = 1;
break;
default:
goto error;
}
break;
default:
goto error;
}
return ret;
error:
ssdk_printf(SSDK_CRIT,
"fee_page_set_two page0_status %x page1_status %x failure\n",
page0_status, page1_status);
return -1;
}
/* Page state information detection */
static int fee_page_check_two(struct fee_dev *fee_dev)
{
int ret = 0;
fee_page_status_t page0_status = 0;
fee_page_status_t page1_status = 0;
/* Getting page state */
ret = fee_get_page_status(fee_dev, 0, &page0_status);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get page0 status error\n");
return ret;
}
ret = fee_get_page_status(fee_dev, 1, &page1_status);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get page1 status error\n");
return ret;
}
ssdk_printf(SSDK_CRIT, "two page: page0_status %x page1_status %x\n",
page0_status, page1_status);
switch (page0_status) {
case FEE_PAGE_ERASED:
switch (page1_status) {
case FEE_PAGE_ERASED:
ssdk_printf(SSDK_INFO,
"fee dev is initialized for the first time,fee_format\n");
/* Power on for the first time */
return fee_format(fee_dev);
case FEE_PAGE_ACTIVE:
ssdk_printf(SSDK_INFO, "fee page information is normal\n");
/* Normal boot */
break;
case FEE_PAGE_VALID:
/* Page1 data is exchanged to Page0 */
ssdk_printf(SSDK_INFO, "fee page1 data is full, exchange data to page0\n");
return fee_page_swap(fee_dev, 1, 0);
default:
goto error;
}
break;
case FEE_PAGE_RECEIVE:
switch (page1_status) {
case FEE_PAGE_VALID:
/* Page1 data is exchanged to Page0 */
ssdk_printf(SSDK_INFO,
"fee page1 data is full, erase page0 & exchange data to page0\n");
if (fee_erase_page(fee_dev, 0))
goto error;
return fee_page_swap(fee_dev, 1, 0);
default:
goto error;
}
break;
case FEE_PAGE_ACTIVE:
switch (page1_status) {
case FEE_PAGE_ERASED:
ssdk_printf(SSDK_INFO, "fee page information is normal\n");
/* Normal boot */
break;
case FEE_PAGE_VALID:
fee_set_page_status(fee_dev, 1, FEE_PAGE_ERASING);
case FEE_PAGE_ERASING:
ssdk_printf(SSDK_INFO, "fee erase page1\n");
/* Erase the page1 */
return fee_erase_page(fee_dev, 1);
default:
goto error;
}
break;
case FEE_PAGE_VALID:
switch (page1_status) {
case FEE_PAGE_ERASED:
ssdk_printf(SSDK_INFO, "fee page0 data is full, exchange data to page1\n");
/* Page0 Data is exchanged to page1 */
return fee_page_swap(fee_dev, 0, 1);
case FEE_PAGE_RECEIVE:
/* Page0 Data is exchanged to page1 */
ssdk_printf(SSDK_INFO,
"fee page0 data is full, erase page1 & exchange data to page1\n");
if (fee_erase_page(fee_dev, 1))
goto error;
return fee_page_swap(fee_dev, 0, 1);
case FEE_PAGE_ACTIVE:
ssdk_printf(SSDK_INFO, "fee erase page0\n");
fee_set_page_status(fee_dev, 0, FEE_PAGE_ERASING);
/* Erase the page1 */
return fee_erase_page(fee_dev, 0);
default:
goto error;
}
break;
case FEE_PAGE_ERASING:
switch (page1_status) {
case FEE_PAGE_ACTIVE:
ssdk_printf(SSDK_INFO, "fee erase page0\n");
/* Erase the page0 */
return fee_erase_page(fee_dev, 0);
default:
goto error;
}
break;
default:
goto error;
}
return ret;
error:
ssdk_printf(SSDK_CRIT, "page0_status %x page1_status %x failure\n",
page0_status, page1_status);
return -1;
}
int fee_init(struct fee_dev *fee_dev)
{
int ret = 0;
disk_size_t page_size = 0;
/* Configure basic page information */
fee_dev->page_number = FEE_PAGE_NUMBER;
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
if (!IS_ALIGNED(disk_dev->addr, disk_dev->sector_size)) {
ssdk_printf(SSDK_CRIT, "fee disk addr:%lld not aligned to sector_size %d\n",
disk_dev->addr, disk_dev->sector_size);
goto error;
}
if (!IS_ALIGNED(disk_dev->size,
disk_dev->sector_size * fee_dev->page_number)) {
ssdk_printf(SSDK_CRIT, "fee size:%lld not aligned to (sector_size * %d):%d\n",
disk_dev->size, fee_dev->page_number,
disk_dev->sector_size * fee_dev->page_number);
goto error;
}
page_size = disk_dev->size / fee_dev->page_number;
ssdk_printf(SSDK_INFO,
"nor flash Flash EEPROM Emulation addr:%llx size:%llx\n",
disk_dev->addr, disk_dev->size);
for (int i = 0; i < fee_dev->page_number; i++) {
fee_dev->page_info[i].page_addr = disk_dev->addr + (page_size * i);
fee_dev->page_info[i].page_size = page_size;
fee_dev->page_info[i].page_sector_num = fee_dev->page_info[i].page_size /
disk_dev->sector_size;
ssdk_printf(SSDK_CRIT, "page %d addr:%llx size:%llx page_sector_num:%d\n",
i, fee_dev->page_info[i].page_addr, fee_dev->page_info[i].page_size,
fee_dev->page_info[i].page_sector_num);
}
/* set current page */
switch (fee_dev->page_number) {
case FEE_PAGE_NUMBER_TWO:
ret = fee_page_set_two(fee_dev);
if (ret < 0) {
ssdk_printf(SSDK_CRIT, "two page mode set current page error \n");
goto error;
}
break;
default:
ssdk_printf(SSDK_CRIT, "page mode not support \n");
ret = -1;
goto error;
}
ssdk_printf(SSDK_CRIT, "set current page %d\n", fee_dev->current_page);
fee_dev->record_buff_size = FEE_RECORD_BUFF_SIZE;
for (int i = 0; i < fee_dev->page_number; i++) {
fee_dev->page_info[i].page_buff_num = fee_dev->page_info[i].page_size /
fee_dev->record_buff_size;
ssdk_printf(SSDK_CRIT, "page %d record_buff_size:%x page_buff_num:%d\n",
i, fee_dev->record_buff_size, fee_dev->page_info[i].page_buff_num);
}
fee_dev->record_info_buff = FEE_ADDR_MASK_PRT(record_buff, FEE_INFO_BUFF, fee_dev->record_buff_size);
fee_dev->record_data_buff = FEE_ADDR_MASK_PRT(record_buff, FEE_DATA_BUFF, fee_dev->record_buff_size);
fee_dev->record_data_offset_buff = FEE_ADDR_MASK_PRT(record_buff, FEE_DATA_OFFSET_BUFF, fee_dev->record_buff_size);
/* Verify that the Record INFO is aligned to the sector */
if (!IS_ALIGNED(fee_dev->record_buff_size, sizeof(struct fee_record_info))) {
ssdk_printf(SSDK_CRIT,
"fee record_buff_size %x not aligned to fee_record_info size %d\n",
fee_dev->record_buff_size, sizeof(struct fee_record_info));
goto error;
}
fee_dev->record_info_num = fee_dev->record_buff_size / sizeof(
struct fee_record_info);
ret = fee_get_page_record_index(fee_dev, fee_dev->current_page,
&fee_dev->record_info_offset);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get_page_record_index error\n");
goto error;
}
ret = fee_get_record_data_offset(fee_dev, fee_dev->current_page,
fee_dev->record_info_offset, &fee_dev->record_data_offset);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get_record_data_offset error\n");
goto error;
}
ssdk_printf(SSDK_INFO, "record_info_offset %lld record_data_offset:%lld\n",
fee_dev->record_info_offset, fee_dev->record_data_offset);
memset(fee_dev->block_addr_mask, 0x0,
fee_dev->block_addr_size * FEE_ADDR_MASK_MAX);
ret = fee_set_record_addr_mask(fee_dev, fee_dev->current_page,
fee_dev->record_info_offset, fee_dev->block_addr_mask);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee set_record_addr_mask error\n");
goto error;
}
/* Check status information based on page mode */
switch (fee_dev->page_number) {
case FEE_PAGE_NUMBER_TWO:
ret = fee_page_check_two(fee_dev);
if (ret < 0) {
ssdk_printf(SSDK_CRIT, "two page mode check error \n");
goto error;
}
break;
default:
ssdk_printf(SSDK_CRIT, "page mode not support \n");
ret = -1;
goto error;
}
/* One final page was FEE_PAGE_ACTIVE and the rest were FEE_PAGE_ERASE */
fee_page_status_t page_status;
for (int i = 0; i < fee_dev->page_number; i++) {
if (fee_get_page_status(fee_dev, i, &page_status))
goto error;
if (page_status == FEE_PAGE_ACTIVE) {
fee_dev->current_page = i;
break;
}
}
if (fee_get_page_status(fee_dev, fee_dev->current_page, &page_status))
goto error;
if (page_status != FEE_PAGE_ACTIVE) {
ssdk_printf(SSDK_CRIT, "page mode check FEE_PAGE_ACTIVE failure\n");
goto error;
}
for (int i = 0; i < fee_dev->page_number; i++) {
if (fee_get_page_status(fee_dev, i, &page_status))
goto error;
if ((i != fee_dev->current_page) && page_status != FEE_PAGE_ERASED) {
ssdk_printf(SSDK_CRIT, "page mode check FEE_PAGE_ERASED failure\n");
goto error;
}
}
return ret;
error:
return -1;
}
int fee_exit(struct fee_dev *fee_dev)
{
int ret = 0;
return ret;
}
static int fee_page_check_size(struct fee_dev *fee_dev, uint16_t page_number,
uint16_t length)
{
/* Fee Residual space detection */
/* One more record info space must be reserved for initial use of the record index offset */
disk_size_t used_size = sizeof(struct fee_page_info) + FEE_BLOCK_ADDR_BIT_SIZE +
fee_dev->record_data_offset + (fee_dev->record_info_offset * sizeof(
struct fee_record_info) + sizeof(struct fee_record_info));
if ((fee_dev->page_info[page_number].page_size - used_size) < length)
return 0;
else
return 1;
}
/* Based on page_number, write record */
static int fee_write_record_block(struct fee_dev *fee_dev,
uint16_t block_number,
uint8_t *data_buffer, uint16_t length)
{
int ret = 0;
struct disk_dev_info *disk_dev = fee_dev->disk_dev;
if (!fee_page_check_size(fee_dev, fee_dev->current_page,
length + sizeof(struct fee_record_info))) {
ssdk_printf(SSDK_INFO,
"******************%d full page size %lld target size %d,swap page****************\n",
block_number, fee_dev->page_info[fee_dev->current_page].page_size,
length + sizeof(struct fee_record_info));
uint16_t swap_page = 0;
if (fee_dev->current_page == fee_dev->page_number - 1)
swap_page = 0;
else
swap_page = fee_dev->current_page + 1;
ret = fee_page_swap(fee_dev, fee_dev->current_page, swap_page);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee fee_page_swap error\n");
return -1;
}
if (!fee_page_check_size(fee_dev, fee_dev->current_page,
length + sizeof(struct fee_record_info))) {
ssdk_printf(SSDK_EMERG, "swap page end, still not enough space\n");
return -1;
}
}
/* Actually writing record */
ret = fee_write_record(fee_dev, fee_dev->current_page,
fee_dev->record_info_offset, block_number, fee_dev->record_data_offset,
data_buffer, length);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee fee_write_record error\n");
return -1;
}
/* Update Status Information */
fee_dev->record_info_offset++;
fee_dev->record_data_offset += ROUNDUP(length, disk_dev->access_size);
fee_addr_mask_set(fee_dev->block_addr_mask, block_number, ROUNDUP(length,
fee_dev->block_length));
/* TODO:set block addr mask */
return ret;
}
/* Based on page_number, write record */
int fee_write_record_multiple(struct fee_dev *fee_dev, uint16_t block_number,
uint8_t *data_buffer, uint16_t length)
{
return fee_write_record_block(fee_dev, block_number, data_buffer, length);
}
/* Read the record based on page_number */
int fee_read_record_multiple(struct fee_dev *fee_dev, uint16_t block_number,
uint8_t *data_buffer, uint16_t length)
{
int ret = 0;
/* block address space */
uint8_t *block_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_BLOCK, fee_dev->block_addr_size);
uint8_t *record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_RECORD, fee_dev->block_addr_size);
uint8_t *current_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_RECORD_CURRENT, fee_dev->block_addr_size);
uint8_t *tmp_record_mask = FEE_ADDR_MASK_PRT(fee_dev->block_addr_mask,
FEE_ADDR_MASK_RECORD_TMP, fee_dev->block_addr_size);
/* record info offset */
disk_size_t record_info_offset_record = 0;
disk_size_t record_data_offset_record = 0;
/* match block */
uint16_t match_block = 0;
uint16_t match_len = 0;
/* data information */
disk_size_t record_addr_offset = 0;
disk_size_t record_addr_len = 0;
uint32_t data_addr_offset = 0;
/* Matches the record part and the block part */
memset(record_mask, 0x0, fee_dev->block_addr_size);
fee_addr_mask_set(record_mask, block_number, length / fee_dev->block_length);
fee_addr_mask_and(block_mask, record_mask, record_mask,
fee_dev->block_addr_size);
/* Traversal begins with the last sector */
struct fee_record_info *record_info = (struct fee_record_info *)
fee_dev->record_info_buff;
uint32_t sector_num = DIV_ROUND_UP(fee_dev->record_info_offset,
fee_dev->record_info_num);
uint32_t sector_index =
fee_dev->page_info[fee_dev->current_page].page_buff_num - sector_num;
uint32_t record_num = 0, record_index = 0;
for (int i = sector_index; i < sector_index + sector_num; i++) {
ret = fee_get_sector(fee_dev, fee_dev->current_page, i, (uint8_t *)record_info);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee get record info %d failure\n", i);
return -1;
}
if ((!IS_ALIGNED(fee_dev->record_info_offset, fee_dev->record_info_num))
&& (i == sector_index))
record_num = fee_dev->record_info_offset % fee_dev->record_info_num;
else
record_num = fee_dev->record_info_num;
record_index = fee_dev->record_info_num - record_num;
for (int j = record_index; j < record_index + record_num; j++) {
if (record_info[j].record_status == FEE_RECORD_VALID) {
/* block_number and block_length of the current record */
memset(current_record_mask, 0x0, fee_dev->block_addr_size);
fee_addr_mask_set(current_record_mask, record_info[j].record_num,
record_info[j].record_len / fee_dev->block_length);
/* matches the matching parts of current_record_mask and record_mask */
memset(tmp_record_mask, 0x0, fee_dev->block_addr_size);
fee_addr_mask_and(current_record_mask, record_mask, tmp_record_mask,
fee_dev->block_addr_size);
while (!fee_addr_mask_empty(tmp_record_mask, fee_dev->block_addr_size)) {
/* Matches block & length */
fee_addr_mask_block(tmp_record_mask, fee_dev->block_addr_size, &match_block,
&match_len);
/* Clears matching blocks */
fee_addr_mask_clear(tmp_record_mask, match_block, match_len);
fee_addr_mask_clear(record_mask, match_block, match_len);
/* Get record data information */
record_info_offset_record = DIVD_NUM(
fee_dev->page_info[fee_dev->current_page].page_buff_num - 1 - i,
fee_dev->record_info_num - 1 - j, fee_dev->record_info_num);
if (fee_get_record_data_offset(fee_dev, fee_dev->current_page,
record_info_offset_record, &record_data_offset_record))
return -1;
/* Calculate the data offset and matching address length of the matching part and record */
record_addr_offset = (match_block - record_info[j].record_num) *
fee_dev->block_length;
record_addr_len = match_len * fee_dev->block_length;
data_addr_offset = (match_block - block_number) * fee_dev->block_length;
/* Read the data */
ret = fee_read_record_data(fee_dev, fee_dev->current_page,
record_data_offset_record + record_addr_offset, data_buffer + data_addr_offset,
record_addr_len);
if (ret) {
ssdk_printf(SSDK_CRIT, "fee fee_read_record_data failure\n");
return -1;
}
}
if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size))
break;
}
if (fee_addr_mask_empty(record_mask, fee_dev->block_addr_size))
break;
}
}
return 0;
}
/* TODO:write/read singel block */
int fee_write_record_single(struct fee_dev *fee_dev, uint16_t block_number,
uint8_t *data_buffer, uint16_t length)
{
int ret = 0;
return ret;
}
int fee_read_record_single(struct fee_dev *fee_dev, uint16_t block_number,
uint16_t block_offset, uint8_t *data_buffer, uint16_t length)
{
int ret = 0;
return ret;
}