#include <sys/types.h>
#include <sys/param.h>
#include "common/common.h"
#include "common/t4_regs.h"
#include "cudbg.h"
#include "cudbg_lib_common.h"
int write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size);
int read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
u32 start_address);
void
update_skip_size(struct cudbg_flash_sec_info *sec_info, u32 size)
{
sec_info->skip_size += size;
}
static
void set_sector_availability(struct adapter *adap,
struct cudbg_flash_sec_info *sec_info, int sector_nu, int avail)
{
int start = t4_flash_loc_start(adap, FLASH_LOC_CUDBG, NULL);
sector_nu -= start / SF_SEC_SIZE;;
if (avail)
set_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
else
reset_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
}
static int
find_empty_sec(struct adapter *adap, struct cudbg_flash_sec_info *sec_info)
{
int i, index, bit;
unsigned int len = 0;
int start = t4_flash_loc_start(adap, FLASH_LOC_CUDBG, &len);
start /= SF_SEC_SIZE;
len /= SF_SEC_SIZE;
for (i = start; i < start + len; i++) {
index = (i - start) / 8;
bit = (i - start) % 8;
if (!(sec_info->sec_bitmap[index] & (1 << bit)))
return i;
}
return CUDBG_STATUS_FLASH_FULL;
}
static void update_headers(void *handle, struct cudbg_buffer *dbg_buff,
u64 timestamp, u32 cur_entity_hdr_offset,
u32 start_offset, u32 ext_size)
{
struct cudbg_private *priv = handle;
struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
void *sec_hdr;
struct cudbg_hdr *cudbg_hdr;
struct cudbg_flash_hdr *flash_hdr;
struct cudbg_entity_hdr *entity_hdr;
u32 hdr_offset;
u32 data_hdr_size;
u32 total_hdr_size;
u32 sec_hdr_start_addr;
data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
sizeof(struct cudbg_hdr);
total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
sec_hdr_start_addr = SF_SEC_SIZE - total_hdr_size;
sec_hdr = sec_info->sec_data + sec_hdr_start_addr;
flash_hdr = (struct cudbg_flash_hdr *)(sec_hdr);
cudbg_hdr = (struct cudbg_hdr *)dbg_buff->data;
if ((start_offset - sec_info->skip_size) == data_hdr_size) {
flash_hdr->signature = CUDBG_FL_SIGNATURE;
flash_hdr->major_ver = CUDBG_FL_MAJOR_VERSION;
flash_hdr->minor_ver = CUDBG_FL_MINOR_VERSION;
flash_hdr->build_ver = CUDBG_FL_BUILD_VERSION;
flash_hdr->hdr_len = sizeof(struct cudbg_flash_hdr);
hdr_offset = sizeof(struct cudbg_flash_hdr);
memcpy((void *)((char *)sec_hdr + hdr_offset),
(void *)((char *)dbg_buff->data), data_hdr_size);
} else
memcpy((void *)((char *)sec_hdr +
sizeof(struct cudbg_flash_hdr) +
cur_entity_hdr_offset),
(void *)((char *)dbg_buff->data +
cur_entity_hdr_offset),
sizeof(struct cudbg_entity_hdr));
hdr_offset = data_hdr_size + sizeof(struct cudbg_flash_hdr);
flash_hdr->data_len = cudbg_hdr->data_len - sec_info->skip_size;
flash_hdr->timestamp = timestamp;
entity_hdr = (struct cudbg_entity_hdr *)((char *)sec_hdr +
sizeof(struct cudbg_flash_hdr) +
cur_entity_hdr_offset);
entity_hdr->start_offset -= sec_info->skip_size;
cudbg_hdr = (struct cudbg_hdr *)((char *)sec_hdr +
sizeof(struct cudbg_flash_hdr));
cudbg_hdr->data_len = flash_hdr->data_len;
flash_hdr->data_len += ext_size;
}
int cudbg_write_flash(void *handle, u64 timestamp, void *data,
u32 start_offset, u32 cur_entity_hdr_offset,
u32 cur_entity_size,
u32 ext_size)
{
struct cudbg_private *priv = handle;
struct cudbg_init *cudbg_init = &priv->dbg_init;
struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
struct adapter *adap = cudbg_init->adap;
struct cudbg_flash_hdr *flash_hdr = NULL;
struct cudbg_buffer *dbg_buff = (struct cudbg_buffer *)data;
u32 data_hdr_size;
u32 total_hdr_size;
u32 tmp_size;
u32 sec_data_offset;
u32 sec_hdr_start_addr;
u32 sec_data_size;
u32 space_left;
int rc = 0;
int sec;
unsigned int cudbg_max_size = 0;
t4_flash_loc_start(adap, FLASH_LOC_CUDBG, &cudbg_max_size);
data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
sizeof(struct cudbg_hdr);
total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
sec_hdr_start_addr = SF_SEC_SIZE - total_hdr_size;
sec_data_size = sec_hdr_start_addr;
cudbg_init->print("\tWriting %u bytes to flash\n", cur_entity_size);
update_headers(handle, dbg_buff, timestamp,
cur_entity_hdr_offset,
start_offset, ext_size);
if (ext_size) {
cur_entity_size += sizeof(struct cudbg_entity_hdr);
start_offset = dbg_buff->offset - cur_entity_size;
}
flash_hdr = (struct cudbg_flash_hdr *)(sec_info->sec_data +
sec_hdr_start_addr);
if (flash_hdr->data_len > cudbg_max_size) {
rc = CUDBG_STATUS_FLASH_FULL;
goto out;
}
space_left = cudbg_max_size - flash_hdr->data_len;
if (cur_entity_size > space_left) {
rc = CUDBG_STATUS_FLASH_FULL;
goto out;
}
while (cur_entity_size > 0) {
sec = find_empty_sec(adap, sec_info);
if (sec_info->par_sec) {
sec_data_offset = sec_info->par_sec_offset;
set_sector_availability(adap, sec_info,
sec_info->par_sec, 0);
sec_info->par_sec = 0;
sec_info->par_sec_offset = 0;
} else {
sec_info->cur_seq_no++;
flash_hdr->sec_seq_no = sec_info->cur_seq_no;
sec_data_offset = 0;
}
if (cur_entity_size + sec_data_offset > sec_data_size) {
tmp_size = sec_data_size - sec_data_offset;
} else {
tmp_size = cur_entity_size;
sec_info->par_sec = sec;
sec_info->par_sec_offset = cur_entity_size +
sec_data_offset;
}
memcpy((void *)((char *)sec_info->sec_data + sec_data_offset),
(void *)((char *)dbg_buff->data + start_offset),
tmp_size);
rc = write_flash(adap, sec, sec_info->sec_data, SF_SEC_SIZE);
if (rc)
goto out;
cur_entity_size -= tmp_size;
set_sector_availability(adap, sec_info, sec, 1);
start_offset += tmp_size;
}
out:
return rc;
}
int write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size)
{
unsigned int addr;
unsigned int i, n;
int rc = 0;
u8 *ptr = (u8 *)data;
addr = start_sec * SF_SEC_SIZE;
i = DIV_ROUND_UP(size, SF_SEC_SIZE);
rc = t4_flash_erase_sectors(adap, start_sec, start_sec + i - 1);
if (rc || size == 0)
goto out;
for (i = 0; i < size; i += SF_PAGE_SIZE) {
if ((size - i) < SF_PAGE_SIZE)
n = size - i;
else
n = SF_PAGE_SIZE;
rc = t4_write_flash(adap, addr, n, ptr, 0);
if (rc)
goto out;
addr += n;
ptr += n;
}
return 0;
out:
return rc;
}
int cudbg_read_flash_details(void *handle, struct cudbg_flash_hdr *data)
{
int rc;
rc = cudbg_read_flash(handle, (void *)data,
sizeof(struct cudbg_flash_hdr), 0);
return rc;
}
int cudbg_read_flash_data(void *handle, void *buf, u32 buf_size)
{
int rc;
u32 total_hdr_size, data_header_size;
void *payload = NULL;
u32 payload_size = 0;
data_header_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
sizeof(struct cudbg_hdr);
total_hdr_size = data_header_size + sizeof(struct cudbg_flash_hdr);
rc = cudbg_read_flash(handle, buf, total_hdr_size, 0);
if (rc != 0)
goto out;
payload = (char *)buf + total_hdr_size;
payload_size = buf_size - total_hdr_size;
rc = cudbg_read_flash(handle, payload, payload_size, 1);
if (rc != 0)
goto out;
out:
return rc;
}
int cudbg_read_flash(void *handle, void *data, u32 size, int data_flag)
{
struct cudbg_private *priv = handle;
struct cudbg_init *cudbg_init = &priv->dbg_init;
struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
struct adapter *adap = cudbg_init->adap;
struct cudbg_flash_hdr flash_hdr;
u32 total_hdr_size;
u32 data_hdr_size;
u32 sec_hdr_start_addr;
u32 tmp_size;
u32 data_offset = 0;
u32 i, j;
int rc;
unsigned int cudbg_len = 0;
int cudbg_start_sec = t4_flash_loc_start(adap, FLASH_LOC_CUDBG,
&cudbg_len) / SF_SEC_SIZE;
rc = t4_get_flash_params(adap);
if (rc) {
cudbg_init->print("\nGet flash params failed."
"Try Again...readflash\n\n");
return rc;
}
data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
sizeof(struct cudbg_hdr);
total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
sec_hdr_start_addr = SF_SEC_SIZE - total_hdr_size;
if (!data_flag) {
if (!sec_info->max_timestamp) {
memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
rc = read_flash(adap, cudbg_start_sec, &flash_hdr,
sizeof(struct cudbg_flash_hdr),
sec_hdr_start_addr);
if (flash_hdr.signature == CUDBG_FL_SIGNATURE) {
sec_info->max_timestamp = flash_hdr.timestamp;
} else {
rc = read_flash(adap, cudbg_start_sec + 1,
&flash_hdr,
sizeof(struct cudbg_flash_hdr),
sec_hdr_start_addr);
if (flash_hdr.signature == CUDBG_FL_SIGNATURE)
sec_info->max_timestamp =
flash_hdr.timestamp;
else {
cudbg_init->print("\n\tNo cudbg dump "\
"found in flash\n\n");
return CUDBG_STATUS_NO_SIGNATURE;
}
}
for (i = cudbg_start_sec; i < cudbg_start_sec +
cudbg_len / SF_SEC_SIZE; i++) {
memset(&flash_hdr, 0,
sizeof(struct cudbg_flash_hdr));
rc = read_flash(adap, i, &flash_hdr,
sizeof(struct cudbg_flash_hdr),
sec_hdr_start_addr);
if (flash_hdr.signature == CUDBG_FL_SIGNATURE &&
sec_info->max_timestamp ==
flash_hdr.timestamp &&
sec_info->max_seq_no <=
flash_hdr.sec_seq_no) {
if (sec_info->max_seq_no ==
flash_hdr.sec_seq_no) {
if (sec_info->hdr_data_len <
flash_hdr.data_len)
sec_info->max_seq_sec = i;
} else {
sec_info->max_seq_sec = i;
sec_info->hdr_data_len =
flash_hdr.data_len;
}
sec_info->max_seq_no = flash_hdr.sec_seq_no;
}
}
}
rc = read_flash(adap, sec_info->max_seq_sec,
(struct cudbg_flash_hdr *)data,
size, sec_hdr_start_addr);
if (rc)
cudbg_init->print("Read flash header failed, rc %d\n",
rc);
return rc;
}
for (i = 1; i <= sec_info->max_seq_no; i++) {
for (j = cudbg_start_sec; j < cudbg_start_sec +
cudbg_len / SF_SEC_SIZE; j++) {
memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
rc = read_flash(adap, j, &flash_hdr,
sizeof(struct cudbg_flash_hdr),
sec_hdr_start_addr);
if (flash_hdr.signature ==
CUDBG_FL_SIGNATURE &&
sec_info->max_timestamp ==
flash_hdr.timestamp &&
flash_hdr.sec_seq_no == i) {
if (size + total_hdr_size > SF_SEC_SIZE)
tmp_size = SF_SEC_SIZE - total_hdr_size;
else
tmp_size = size;
if ((i != sec_info->max_seq_no) ||
(i == sec_info->max_seq_no &&
j == sec_info->max_seq_sec)){
rc = read_flash(adap, j,
(void *)((char *)data +
data_offset),
tmp_size, 0);
data_offset += (tmp_size);
size -= (tmp_size);
break;
}
}
}
}
return rc;
}
int read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
u32 start_address)
{
unsigned int addr, i, n;
int rc;
u32 *ptr = (u32 *)data;
addr = start_sec * SF_SEC_SIZE + start_address;
size = size / 4;
for (i = 0; i < size; i += SF_PAGE_SIZE) {
if ((size - i) < SF_PAGE_SIZE)
n = size - i;
else
n = SF_PAGE_SIZE;
rc = t4_read_flash(adap, addr, n, ptr, 0);
if (rc)
goto out;
addr = addr + (n*4);
ptr += n;
}
return 0;
out:
return rc;
}