1739 lines
39 KiB
C
1739 lines
39 KiB
C
/**************************************************************************
|
|
* *
|
|
* Copyright (C) 1996, Silicon Graphics, Inc. *
|
|
* *
|
|
* These coded instructions, statements, and computer programs contain *
|
|
* unpublished proprietary information of Silicon Graphics, Inc., and *
|
|
* are protected by Federal copyright law. They may not be disclosed *
|
|
* to third parties or copied or duplicated in any form, in whole or *
|
|
* in part, without the prior written consent of Silicon Graphics, Inc. *
|
|
* *
|
|
**************************************************************************/
|
|
|
|
#if defined(IP30)
|
|
|
|
#include <arcs/types.h>
|
|
#include <sys/cpu.h>
|
|
#include <sys/mips_addrspace.h>
|
|
#include <parser.h>
|
|
#include <libsc.h>
|
|
#include <libsk.h>
|
|
#include <ctype.h>
|
|
#include <sys/RACER/sflash.h>
|
|
#include <sys/RACER/IP30nvram.h>
|
|
|
|
#include "flash_prom_cmd.h"
|
|
|
|
static int _fl_copy(__psunsigned_t src, __psunsigned_t dst, int len);
|
|
|
|
#define FCMD_CHECK 0x1
|
|
|
|
/*
|
|
* command structure
|
|
*/
|
|
typedef struct flash_cmd flash_cmd_t;
|
|
|
|
struct flash_cmd {
|
|
char *cmd;
|
|
int (*func)(int, char **, flash_cmd_t *);
|
|
char *usage;
|
|
unsigned flags;
|
|
};
|
|
|
|
#define FLASH_USAGE(_p) FPR_PR(("flash %s %s\n", (_p)->cmd, (_p)->usage))
|
|
SETUP_TIME
|
|
|
|
#ifdef FDEBUG
|
|
unsigned long long
|
|
_cksum64(unsigned long long *lp, int len, unsigned long long sum)
|
|
{
|
|
len &= ~0x7; /* trucate to mod(8)==0 */
|
|
while (len) {
|
|
sum = sum + *lp++;
|
|
len -= sizeof (*lp);
|
|
}
|
|
return(sum);
|
|
}
|
|
#endif
|
|
|
|
static ulong
|
|
running_prom(void)
|
|
{
|
|
ulong pc, ppc;
|
|
extern ulong get_pc(void);
|
|
|
|
pc = get_pc();
|
|
if (IS_COMPAT_PHYS(pc))
|
|
ppc = COMPAT_TO_PHYS(pc);
|
|
else
|
|
ppc = KDM_TO_PHYS(pc);
|
|
|
|
return(IS_PROM_PADDR(ppc)?ppc:0);
|
|
}
|
|
|
|
static unsigned
|
|
running_rprom(void)
|
|
{
|
|
ulong ppc = running_prom();
|
|
return((ppc >= SFLASH_RPROM_PADDR &&
|
|
ppc < (SFLASH_RPROM_PADDR + SFLASH_RPROM_SIZE)));
|
|
}
|
|
|
|
static unsigned
|
|
running_fprom(void)
|
|
{
|
|
ulong ppc = running_prom();
|
|
return((ppc >= SFLASH_FPROM_PADDR &&
|
|
ppc < (SFLASH_FPROM_PADDR + SFLASH_FPROM_SIZE)));
|
|
}
|
|
/******************************************************************/
|
|
#include <arcs/errno.h>
|
|
#include <arcs/eiob.h>
|
|
|
|
extern MEMORYDESCRIPTOR *mem_contains(unsigned long, unsigned long);
|
|
extern MEMORYDESCRIPTOR *mem_getblock(void);
|
|
extern void mem_list(void);
|
|
|
|
int
|
|
_fl_get( char *path,
|
|
__psunsigned_t *get_buf,
|
|
int *get_size)
|
|
{
|
|
#define READ_SIZE (16 * 1024)
|
|
|
|
MEMORYDESCRIPTOR *m;
|
|
__psunsigned_t bufp, ptr, buf_lim;
|
|
ULONG fd, cnt, total;
|
|
LONG err;
|
|
|
|
if (!(m = mem_getblock())) {
|
|
FPR_ERR(("No free memory descriptors available.\n"));
|
|
mem_list();
|
|
return(ENOMEM);
|
|
}
|
|
|
|
FPR_HI((" memblock base=%#x count=%ld\n",
|
|
arcs_ptob(m->BasePage), arcs_ptob(m->PageCount)));
|
|
bufp = arcs_ptob(m->BasePage);
|
|
bufp = PHYS_TO_K0(bufp);
|
|
|
|
err = Open(path, OpenReadOnly, &fd);
|
|
if (err) {
|
|
FPR_ERR(("Open error %ld for %s\n", err, path));
|
|
return(err);
|
|
}
|
|
|
|
cnt = 0;
|
|
total = 0;
|
|
ptr = bufp;
|
|
buf_lim = bufp + arcs_ptob(m->PageCount);
|
|
|
|
do {
|
|
err = Read(fd, (void *)ptr, READ_SIZE, &cnt);
|
|
if (err != ESUCCESS) {
|
|
FPR_ERR(("Read error %ld for %s\n", err, path));
|
|
goto bail;
|
|
}
|
|
total += cnt;
|
|
ptr += cnt;
|
|
if (ptr > buf_lim) {
|
|
FPR_ERR(("File too big > %d\n", arcs_ptob(m->PageCount)));
|
|
err = EBADF;
|
|
goto bail;
|
|
}
|
|
} while (cnt);
|
|
|
|
*get_buf = bufp;
|
|
*get_size = total;
|
|
bail:
|
|
Close(fd);
|
|
return(err);
|
|
}
|
|
|
|
#ifdef FDEBUG
|
|
#include <elf.h>
|
|
extern int load_elf_struct64(char *, ULONG *, int, int, void *);
|
|
|
|
union commonhdr {
|
|
Elf64_Ehdr elfhdr64;
|
|
};
|
|
|
|
/*
|
|
* load the pgm section into load_buf and add a ~_cksum_fl16 at end
|
|
*/
|
|
static int
|
|
_fl_load( char *path,
|
|
__psunsigned_t exe_base,
|
|
__psunsigned_t *load_buf,
|
|
int *load_size)
|
|
{
|
|
__psunsigned_t bufp, boffset;
|
|
MEMORYDESCRIPTOR *m;
|
|
ULONG fd, cnt;
|
|
LONG err;
|
|
union commonhdr *commonhdr = 0;
|
|
Elf64_Ehdr *elfhdr;
|
|
Elf64_Phdr *pgmhdr = 0;
|
|
unsigned int size;
|
|
#ifdef XXX
|
|
Elf64_Shdr *shdr;
|
|
#endif
|
|
|
|
/* XXX */
|
|
if (!(m = mem_getblock())) {
|
|
FPR_ERR(("No free memory descriptors available.\n"));
|
|
mem_list();
|
|
return(FL_ERR);
|
|
}
|
|
FPR_HI((" memblock base=%#x count=%ld\n",
|
|
arcs_ptob(m->BasePage), arcs_ptob(m->PageCount)));
|
|
/*
|
|
* use the memory from the top
|
|
*/
|
|
bufp = arcs_ptob(m->BasePage + m->PageCount);
|
|
bufp = PHYS_TO_K0(bufp - SFLASH_MAX_SIZE);
|
|
/*
|
|
* initialize possbile holes with all 1's
|
|
*/
|
|
{
|
|
int64_t *lp = (int64_t*) bufp;
|
|
|
|
cnt = SFLASH_RPROM_SIZE + FLASH_HEADER_SIZE;
|
|
while (cnt) {
|
|
*lp++ = -1;
|
|
cnt -= sizeof(int64_t);
|
|
}
|
|
}
|
|
|
|
/* load */
|
|
err = Open(path, OpenReadOnly, &fd);
|
|
if (err) {
|
|
FPR_ERR(("Open error %ld for %s\n", err, path));
|
|
return(err);
|
|
}
|
|
commonhdr = dmabuf_malloc(sizeof(union commonhdr));
|
|
if (commonhdr == 0) {
|
|
Close(fd);
|
|
FPR_ERR(("cant dmabuf_malloc commondr (%d)\n",
|
|
sizeof(union commonhdr)));
|
|
return(FL_ERR);
|
|
}
|
|
elfhdr = &(commonhdr->elfhdr64);
|
|
err = load_elf_struct64(path, &fd, sizeof(Elf64_Ehdr), 0, elfhdr);
|
|
if (err != ESUCCESS) {
|
|
FPR_ERR(("%s: cant read elf64 header err=%i\n", err));
|
|
goto bail;
|
|
}
|
|
if (!IS_ELF(commonhdr->elfhdr64) ||
|
|
commonhdr->elfhdr64.e_ident[EI_CLASS] != ELFCLASS64) {
|
|
FPR_ERR(("Not elf class 64\n"));
|
|
goto bail;
|
|
}
|
|
FPR_HI(("file fd %li, Elf 64\n", fd));
|
|
|
|
FPR_HI((" type %#x mach %#x version %u\n",
|
|
elfhdr->e_type,
|
|
elfhdr->e_machine,
|
|
elfhdr->e_version));
|
|
FPR_HI((" entry-addr %#x hsize %u flg %#x\n",
|
|
elfhdr->e_entry,
|
|
elfhdr->e_ehsize,
|
|
elfhdr->e_flags));
|
|
FPR_HI((" program off %#llx size %#x num %#x\n",
|
|
elfhdr->e_phoff,
|
|
elfhdr->e_phentsize,
|
|
elfhdr->e_phnum));
|
|
FPR_HI((" section off %#llx size %#x num %#x\n\n",
|
|
elfhdr->e_shoff,
|
|
elfhdr->e_shentsize,
|
|
elfhdr->e_shnum));
|
|
size = elfhdr->e_phentsize * elfhdr->e_phnum;
|
|
if (size > 0) {
|
|
FPR_HI(("about to load program headers\n"));
|
|
pgmhdr = (Elf64_Phdr *) dmabuf_malloc(size);
|
|
if (pgmhdr == 0) {
|
|
FPR_ERR(("cant alloc pgmhdr, size=%d\n", size));
|
|
goto bail;
|
|
}
|
|
err = load_elf_struct64(path, &fd, size, elfhdr->e_phoff, pgmhdr);
|
|
if (err != ESUCCESS) {
|
|
FPR_ERR(("load_elf_struct() failed err=%d\n", err));
|
|
goto bail;
|
|
}
|
|
/* dump program headers */
|
|
FPR_HI(("\nheader entry size %d\n", elfhdr->e_phentsize));
|
|
FPR_HI(("%d entries in file\n", elfhdr->e_phnum));
|
|
for(cnt = 0; cnt < elfhdr->e_phnum; cnt++) {
|
|
FPR_MSG(("program %d: size %d vaddr %x\n",
|
|
cnt, pgmhdr[cnt].p_memsz, pgmhdr[cnt].p_vaddr));
|
|
FPR_HI((" type %x, offset %llx",
|
|
pgmhdr[cnt].p_type,
|
|
pgmhdr[cnt].p_offset));
|
|
FPR_HI((" file size %llx, mem size %llx, "
|
|
" flags %x, align %llx\n",
|
|
pgmhdr[cnt].p_filesz,
|
|
pgmhdr[cnt].p_memsz,
|
|
pgmhdr[cnt].p_flags,
|
|
pgmhdr[cnt].p_align));
|
|
}
|
|
} else {
|
|
FPR_ERR(("no program header!\n"));
|
|
goto bail;
|
|
}
|
|
for(size = 0, cnt = 0; cnt < elfhdr->e_phnum; cnt++) {
|
|
__psunsigned_t boffset, beg_paddr;
|
|
|
|
/* check PT_LOAD type */
|
|
if (pgmhdr[cnt].p_type != PT_LOAD)
|
|
continue;
|
|
|
|
if (IS_COMPAT_PHYS(pgmhdr[cnt].p_vaddr))
|
|
beg_paddr = COMPAT_TO_PHYS(pgmhdr[cnt].p_vaddr);
|
|
else
|
|
beg_paddr = KDM_TO_PHYS(pgmhdr[cnt].p_vaddr);
|
|
/* check vaddr+memsz range */
|
|
if (!IS_PROM_PADDR(beg_paddr) &&
|
|
!IS_PROM_PADDR(beg_paddr+pgmhdr[cnt].p_memsz-2))
|
|
continue;
|
|
if (beg_paddr < exe_base) {
|
|
FPR_ERR(("Bad (p_vaddr=0x%llx paddr=0x%x) < exe_base=0x%x\n",
|
|
pgmhdr[cnt].p_vaddr, beg_paddr, exe_base));
|
|
err = ENOMEM;
|
|
goto bail;
|
|
}
|
|
boffset = (beg_paddr - exe_base);
|
|
err = load_elf_struct64(path, &fd, pgmhdr[cnt].p_filesz,
|
|
pgmhdr[cnt].p_offset, (void *)(bufp + boffset));
|
|
if (err != ESUCCESS)
|
|
goto bail;
|
|
/* size must be begin of bufp to all loaded pgms */
|
|
if (boffset + pgmhdr[cnt].p_filesz > size)
|
|
size = boffset + pgmhdr[cnt].p_filesz;
|
|
}
|
|
|
|
#ifdef XXX
|
|
/*
|
|
* dump section headers
|
|
*/
|
|
size = elfhdr->e_shentsize * elfhdr->e_shnum;
|
|
if (size > 0) {
|
|
FPR_MSG(("about to load section headers size=%#x\n", size));
|
|
shdr = (Elf64_Shdr *) dmabuf_malloc(size);
|
|
if (shdr == 0) {
|
|
FPR_ERR(("cant alloc shdr, size=%d\n", size));
|
|
goto bail;
|
|
}
|
|
err = load_elf_struct64(path, &fd, size, elfhdr->e_shoff, shdr);
|
|
if (err != ESUCCESS) {
|
|
FPR_ERR(("load_elf_struct() failed err=%d\n", err));
|
|
goto bail;
|
|
}
|
|
FPR_MSG(("section entry size %#d\n", elfhdr->e_shentsize));
|
|
FPR_MSG(("%#d entries in file\n", elfhdr->e_shnum));
|
|
for(cnt = 0; cnt < elfhdr->e_shnum; cnt++) {
|
|
printf("[%d]\n", cnt);
|
|
dump_bytes((char *)&shdr[cnt], sizeof(Elf64_Shdr), 1);
|
|
FPR_MSG(("\n"));
|
|
FPR_MSG(("%d: %#x type %#x, offset %#llx, vaddr %#llx, "
|
|
"section size %#llx, align %#llx, entsize %#llx, "
|
|
"flags %#llx\n",
|
|
cnt,
|
|
shdr[cnt].sh_name,
|
|
shdr[cnt].sh_type,
|
|
shdr[cnt].sh_offset,
|
|
shdr[cnt].sh_addr,
|
|
shdr[cnt].sh_size,
|
|
shdr[cnt].sh_addralign,
|
|
shdr[cnt].sh_entsize,
|
|
shdr[cnt].sh_flags));
|
|
}
|
|
dmabuf_free(shdr);
|
|
}
|
|
#endif /* FDEBUG */
|
|
if (elfhdr->e_type != ET_EXEC) {
|
|
FPR_MSG(("%s: not executable!\n", path));
|
|
goto bail;
|
|
}
|
|
if (size & 1)
|
|
size += 1;
|
|
|
|
*load_size = size;
|
|
*load_buf = bufp;
|
|
bail:
|
|
if (commonhdr) dmabuf_free(commonhdr);
|
|
if (pgmhdr) dmabuf_free(pgmhdr);
|
|
if (fd) Close(fd);
|
|
return(err);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl load [<file>] -
|
|
*/
|
|
static int
|
|
fl_load(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
__psunsigned_t ld_buf;
|
|
int rv, ld_sz;
|
|
char *path;
|
|
|
|
FPR_LO(("load: \n"));
|
|
if (argc <= 0) {
|
|
/* no path, try env variables */
|
|
/* XXX for now hardcode is some stuff */
|
|
path = "bootp()femto.engr:i2/prom";
|
|
} else
|
|
path = argv[0];
|
|
FPR_LO(("path=%s\n", path));
|
|
ld_sz = 0;
|
|
ld_buf = 0;
|
|
rv = _fl_load(path, SFLASH_EXE_BASE, &ld_buf, &ld_sz);
|
|
if (rv != ESUCCESS || !ld_sz || !ld_buf)
|
|
FPR_ERR(("No text/data in %s to load\n", path));
|
|
|
|
FPR_MSG(("\n%s loaded @0x%x, actual size %d, flash rdup size %d\n",
|
|
path, ld_buf, ld_sz, SFLASH_RDUP(ld_sz)));
|
|
return(rv);
|
|
}
|
|
|
|
|
|
/*
|
|
* erase segments from beg_seg to end_seg inclusive
|
|
*/
|
|
static int
|
|
_fl_erase(unsigned beg_seg, unsigned end_seg)
|
|
{
|
|
unsigned seg;
|
|
flash_err_t frv;
|
|
|
|
if (end_seg - beg_seg >= SFLASH_MAX_SEGS)
|
|
return(1);
|
|
for (seg = beg_seg; seg <= end_seg; seg++) {
|
|
frv = flash_erase(seg);
|
|
if (frv) {
|
|
flash_print_err(frv);
|
|
return(1);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl get [<file>] -
|
|
*/
|
|
static int
|
|
fl_get(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
__psunsigned_t get_buf;
|
|
int rv, get_sz;
|
|
char *path;
|
|
|
|
if (argc <= 0) {
|
|
/* no path, try env variables */
|
|
/* XXX for now hardcode is some stuff */
|
|
path = "bootp()femto.engr:i2/prom";
|
|
} else
|
|
path = argv[0];
|
|
FPR_PR(("get: %s\n", path));
|
|
get_sz = 0;
|
|
get_buf = 0;
|
|
rv = _fl_get(path, &get_buf, &get_sz);
|
|
if (rv)
|
|
return(rv);
|
|
FPR_PR(("%d bytes read to 0x%x, sum -r:\n", get_sz, get_buf));
|
|
FPR_PR(("%05u %d\n", flash_cksum_r((void *)get_buf, get_sz, 0), (get_sz + 511)/512));
|
|
return(0);
|
|
}
|
|
#endif
|
|
|
|
#define PROM_CMD_OPT_f 0
|
|
#define PROM_CMD_OPT_R 1
|
|
#define PROM_CMD_OPT_r 2
|
|
#define PROM_CMD_OPT_Force 3
|
|
/*
|
|
* syntax: fl prom [-r|-R] <file> -
|
|
*/
|
|
static int
|
|
fl_prom(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
char *path;
|
|
char *data;
|
|
flash_header_t *hdr;
|
|
__psunsigned_t ld_buf = 0;
|
|
int ld_sz = 0;
|
|
int flash_n_reset_fprom = running_fprom();
|
|
int opt = PROM_CMD_OPT_f;
|
|
int rv;
|
|
|
|
FPR_LO(("prom:\n"));
|
|
|
|
if (argc) {
|
|
if (!strcmp(argv[0], "-r")) {
|
|
opt = PROM_CMD_OPT_r;
|
|
argc--;
|
|
argv++;
|
|
} else if (!strcmp(argv[0], "-R")) {
|
|
opt = PROM_CMD_OPT_R;
|
|
argc--;
|
|
argv++;
|
|
} else if (!strcmp(argv[0], "-Force")) {
|
|
opt = PROM_CMD_OPT_Force;
|
|
argc--;
|
|
argv++;
|
|
}
|
|
}
|
|
|
|
if (argc <= 0) {
|
|
FPR_ERR(("no file specified\n"));
|
|
return(1);
|
|
} else
|
|
path = argv[0];
|
|
|
|
rv = _fl_get(path, &ld_buf, &ld_sz);
|
|
if (rv) {
|
|
return(1);
|
|
}
|
|
FPR_MSG(("%d bytes loaded to mem @ 0x%x\n", ld_sz, ld_buf));
|
|
|
|
if (opt == PROM_CMD_OPT_Force) {
|
|
FPR_PR(("Program loaded data to base of flash\n"));
|
|
goto force_flash;
|
|
}
|
|
|
|
rv = _fl_check_bin_image((char*)ld_buf, ld_sz);
|
|
switch (rv) {
|
|
|
|
case IP30PROM_BIN_FORMAT: { /* rprom.bin format */
|
|
/*
|
|
* we will be running fprom or dprom, rprom will not
|
|
* use this fct
|
|
*/
|
|
if (opt == PROM_CMD_OPT_R || opt == PROM_CMD_OPT_r) {
|
|
FPR_PR(("Programming Rprom\n"));
|
|
rv = _fl_prom((uint16_t *)ld_buf,
|
|
0,
|
|
SFLASH_RPROM_SEG,
|
|
SFLASH_RPROM_SIZE);
|
|
if (rv)
|
|
goto rprom_failed;
|
|
}
|
|
/*
|
|
* make sure the rprom is good before attempting to
|
|
* re-flash the fprom section
|
|
*/
|
|
if (flash_prom_ok((char *)SFLASH_RPROM_ADDR,
|
|
SFLASH_RPROM_HDR_ADDR) == 0)
|
|
goto bad_rprom;
|
|
|
|
if (opt != PROM_CMD_OPT_r) {
|
|
FPR_PR(("Programming Fprom\n"));
|
|
rv = _fl_prom((uint16_t *)(ld_buf + SFLASH_RPROM_SIZE),
|
|
flash_n_reset_fprom,
|
|
SFLASH_FPROM_SEG,
|
|
ld_sz - SFLASH_RPROM_SIZE);
|
|
if (rv)
|
|
goto fprom_failed;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FPROM_BIN_FORMAT: { /* fprom.bin format */
|
|
|
|
if (opt != PROM_CMD_OPT_f) {
|
|
FPR_ERR(("bad option %s\n", argv[-1]));
|
|
return(1);
|
|
}
|
|
/*
|
|
* make sure the rprom is good before attempting to
|
|
* re-flash the fprom section
|
|
*/
|
|
if (flash_prom_ok((char *)SFLASH_RPROM_ADDR,
|
|
SFLASH_RPROM_HDR_ADDR) == 0)
|
|
goto bad_rprom;
|
|
|
|
FPR_PR(("Programming Fprom\n"));
|
|
rv = _fl_prom((uint16_t *)ld_buf,
|
|
flash_n_reset_fprom,
|
|
SFLASH_FPROM_SEG,
|
|
ld_sz);
|
|
if (rv)
|
|
goto fprom_failed;
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
if (!yes("Unrecognized binary image, program anyway"));
|
|
return(1);
|
|
force_flash:
|
|
if (!yes("This is VERY risky! Are you REALLY REALLY sure"))
|
|
return(1);
|
|
|
|
rv = _fl_prom((uint16_t *)ld_buf,
|
|
flash_n_reset_fprom,
|
|
SFLASH_RPROM_SEG,
|
|
MIN(ld_sz, SFLASH_MAX_SIZE));
|
|
if (rv)
|
|
goto force_failed;
|
|
break;
|
|
}
|
|
} /* switch */
|
|
return(0);
|
|
|
|
rprom_failed:
|
|
FPR_ERR(("Programming Rprom failed\n"));
|
|
return(1);
|
|
fprom_failed:
|
|
FPR_ERR(("Programming Fprom failed\n"));
|
|
return(1);
|
|
force_failed:
|
|
FPR_ERR(("Programming Flash failed\n"));
|
|
return(1);
|
|
bad_rprom:
|
|
FPR_ERR(("Rprom section is bad cannot proceed\n"));
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl log [inval] [<entry_offset>]
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_log(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
flash_pds_ent_t *ent = 0;
|
|
char *data;
|
|
int invalidate = 0;
|
|
int len, i;
|
|
int hoffset;
|
|
|
|
while (argc--) {
|
|
if ( !strcmp("inval", *argv)) {
|
|
invalidate = 1;
|
|
} else {
|
|
hoffset = atoi(*argv)/sizeof(vu_short);
|
|
ent = (flash_pds_ent_t *)(SFLASH_PDS_ADDR + hoffset);
|
|
}
|
|
argv++;
|
|
}
|
|
|
|
/*
|
|
* ent returned is the next entry but data and len
|
|
* is from the current log entry
|
|
*/
|
|
i = 0;
|
|
data = 0;
|
|
do {
|
|
ent = flash_pds_get_log(ent, &data, &len, invalidate);
|
|
if (!data)
|
|
break;
|
|
FPR_PR(("[0x%04x] ",
|
|
((__psint_t)data&0xffff)-FPDS_ENT_DATA_OFFS*sizeof(vu_short)));
|
|
flash_print_log((void *)data, len);
|
|
if ((++i % 16) == 0) {
|
|
if (!yes("more"))
|
|
return(0);
|
|
}
|
|
} while (ent);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* key=0 ==> first data entry starting from ent
|
|
* ent=0 ==> start searching from begin of PDS
|
|
*/
|
|
static flash_pds_ent_t *
|
|
fl_pds_get_data(char *key, flash_pds_ent_t *ent)
|
|
{
|
|
char *buf;
|
|
int len;
|
|
u_short cksum;
|
|
flash_pds_da0_t *da0;
|
|
|
|
ent = flash_pds_find_data(key, ent);
|
|
if (!ent)
|
|
return(0);
|
|
da0 = (flash_pds_da0_t *)ent->data;
|
|
key = (char *)(da0 + 1); /* in case key was 0 */
|
|
buf = malloc(da0->datalen + 8); /* datalen and some pad */
|
|
if (buf == 0) {
|
|
FPR_ERR(("cant malloc %d bytes\n", da0->datalen));
|
|
return(0);
|
|
}
|
|
len = flash_pds_copy_data(key, buf, 0);
|
|
cksum = flash_cksum_r(buf, len, 0);
|
|
|
|
FPR_PR(("PDS DATA key=%s: cksum 0x%x (%d bytes) is %s (actual 0x%x)\n",
|
|
key, da0->datasum, da0->datalen,
|
|
(da0->datasum != cksum)?"BAD":"OK", cksum));
|
|
free(buf);
|
|
return(ent);
|
|
}
|
|
|
|
#define DATA_CMD_OPT_def 0
|
|
#define DATA_CMD_OPT_d 1
|
|
#define DATA_CMD_OPT_f 2
|
|
#define DATA_CMD_OPT_m 3
|
|
#define DATA_CMD_OPT_r 4
|
|
/*
|
|
* "[[-d|-f|-m] <key> [<file>|<range>]]"
|
|
*/
|
|
static int
|
|
fl_data(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int opt = DATA_CMD_OPT_def;
|
|
int len;
|
|
char *key, *file, *buf;
|
|
struct range rg;
|
|
flash_pds_ent_t *ent;
|
|
flash_err_t frv;
|
|
|
|
if (argc) {
|
|
opt = DATA_CMD_OPT_r;
|
|
|
|
if (!strcmp(argv[0], "-d")) {
|
|
opt = DATA_CMD_OPT_d;
|
|
argc--;
|
|
argv++;
|
|
} else if (!strcmp(argv[0], "-f")) {
|
|
opt = DATA_CMD_OPT_f;
|
|
argc--;
|
|
argv++;
|
|
} else if (!strcmp(argv[0], "-m")) {
|
|
opt = DATA_CMD_OPT_m;
|
|
argc--;
|
|
argv++;
|
|
}
|
|
}
|
|
|
|
key = argv[0];
|
|
argc--;
|
|
argv++;
|
|
|
|
switch (opt) {
|
|
case DATA_CMD_OPT_d: /* delete option */
|
|
flash_pds_inval_data(key);
|
|
break;
|
|
|
|
case DATA_CMD_OPT_f: /* add from file option */
|
|
if (argc == 0) {
|
|
FLASH_USAGE(fcmdp);
|
|
return(-1);
|
|
}
|
|
frv = _fl_get(argv[0], (__psunsigned_t *)&buf, &len);
|
|
if (frv)
|
|
break;
|
|
frv = flash_pds_set_data(key, buf, len);
|
|
if (frv)
|
|
flash_print_err(frv);
|
|
break;
|
|
|
|
case DATA_CMD_OPT_m: /* add from memory option */
|
|
if (argc == 1 && !parse_range(argv[0], 1, &rg)) {
|
|
FLASH_USAGE(fcmdp);
|
|
return(-1);
|
|
}
|
|
frv = flash_pds_set_data(key, (char *)rg.ra_base, rg.ra_count);
|
|
if (frv)
|
|
flash_print_err(frv);
|
|
break;
|
|
|
|
case DATA_CMD_OPT_r: /* read <key> option */
|
|
fl_pds_get_data(key, 0);
|
|
break;
|
|
|
|
default: /* read all option */
|
|
ent = 0;
|
|
while (ent = fl_pds_get_data(0, ent))
|
|
;
|
|
break;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax:
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_resetpds(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
/* call flash_pds_init with resetpds flag on */
|
|
flash_pds_init(1);
|
|
return(0);
|
|
}
|
|
|
|
static struct reg_desc rprom_flags_desc[] = {
|
|
{ RPROM_FLG_TEST, 0, "RPROM TEST", NULL, NULL },
|
|
{ RPROM_FLG_DBG_MSK, -4, "Debug", "0x%x", NULL },
|
|
{ RPROM_FLG_FVP, 0, "FPROM Valid Pend",NULL,NULL },
|
|
{ RPROM_FLG_VRB_MSK, 0, "Verbose", "0x%x", NULL },
|
|
{0,0,NULL,NULL,NULL}
|
|
};
|
|
/*
|
|
* syntax: <16 bit flag>
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_rpromflg(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
ushort oval, nval;
|
|
|
|
if (argc) {
|
|
nval = atoi(*argv);
|
|
}
|
|
|
|
oval = flash_get_nv_rpromflg();
|
|
FPR_PR(("Current flag=%R\n", oval, rprom_flags_desc));
|
|
|
|
if (!argc)
|
|
return(0);
|
|
|
|
/* call flash_pds_init with resetpds flag on */
|
|
flash_set_nv_rpromflg(nval);
|
|
|
|
FPR_PR(("New flag=%R\n", nval, rprom_flags_desc));
|
|
return(0);
|
|
}
|
|
|
|
#ifdef FDEBUG
|
|
/*
|
|
* syntax: fl setenv var [str]
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_senv(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
flash_err_t rv;
|
|
short zero = 0;
|
|
char *str = (char *)&zero;
|
|
|
|
if (argc > 2 || !argc)
|
|
return(1);
|
|
if (argc == 2)
|
|
str = argv[1];
|
|
FPR_LO(("senv: var %s str %s\n", argv[0], str));
|
|
|
|
START_TIME;
|
|
rv = flash_setenv(argv[0], str);
|
|
STOP_TIME("setenv ")
|
|
|
|
FPR_PR(("rv=0x%x\n",rv));
|
|
return(rv);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl unsetenv var
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_uenv(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int rv;
|
|
|
|
if (argc != 1)
|
|
return(1);
|
|
|
|
/*
|
|
* 0 for string entry implies unset
|
|
*/
|
|
START_TIME;
|
|
rv = flash_setenv(argv[0], 0);
|
|
STOP_TIME("unsetenv ");
|
|
|
|
FPR_PR(("rv=0x%x\n",rv));
|
|
return(rv);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl getenv var
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_genv(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
flash_pds_ent_t *p;
|
|
|
|
if (argc != 1)
|
|
return(1);
|
|
FPR_LO(("genv: var %s\n", argv[0]));
|
|
|
|
START_TIME;
|
|
p = flash_findenv(0, argv[0]);
|
|
STOP_TIME("getenv ");
|
|
|
|
if (p)
|
|
FPR_PR(("%s\n", p->data));
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
syntax: fl pds [all | env | log]
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_pds(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
u_short filter = FPDS_FILTER_VALID;
|
|
flash_pds_ent_t *ent = 0;
|
|
int len;
|
|
char msg[514];
|
|
|
|
FPR_PDS(("fl_pds:\n"));
|
|
if (argc >= 1) {
|
|
if (!strcmp(argv[0], "all"))
|
|
filter = FPDS_FILTER_ALL;
|
|
else if (!strcmp(argv[0], "env"))
|
|
filter = FPDS_ENT_ENV_TYPE;
|
|
else if (!strcmp(argv[0], "log"))
|
|
filter = FPDS_ENT_LOG_TYPE;
|
|
else if (!strcmp(argv[0], "data"))
|
|
filter = FPDS_ENT_DAT_TYPE;
|
|
else if (!strcmp(argv[0], "compress")) {
|
|
vu_short *rv;
|
|
|
|
rv = flash_pds_compress(0);
|
|
FPR_PR(("flash_pds_compress rv = 0x%x\n", rv));
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
while (ent = flash_pds_ent_next(ent, filter)) {
|
|
__psunsigned_t offset;
|
|
|
|
len = ent->pds_hlen*sizeof(uint16_t);
|
|
bcopy((void *)ent->data, msg, len);
|
|
msg[len] = 0;
|
|
|
|
offset = ((__psunsigned_t)ent - (__psunsigned_t)SFLASH_PDS_ADDR);
|
|
switch (FPDS_ENT_TYPE(ent)) {
|
|
case FPDS_ENT_ENV_TYPE: {
|
|
printf("env: offs 0x%06x: %s: len %d: %s\n",
|
|
0xffffff&offset,
|
|
(ent->valid==FPDS_ENT_VALID)?"VAL":"INV",
|
|
len, msg);
|
|
break;
|
|
}
|
|
case FPDS_ENT_LOG_TYPE: {
|
|
printf("log: offs 0x%06x: %s: len %d:\n",
|
|
0xffffff&offset,
|
|
(ent->valid==FPDS_ENT_VALID)?"VAL":"INV",
|
|
len);
|
|
flash_print_log((void *)msg, len);
|
|
break;
|
|
}
|
|
case FPDS_ENT_DA0_TYPE: {
|
|
flash_pds_da0_t *da0 = (flash_pds_da0_t *)ent->data;
|
|
printf("da0: offs 0x%06x: %s: len %d:\n",
|
|
0xffffff&offset,
|
|
(ent->valid==FPDS_ENT_VALID)?"VAL":"INV",
|
|
len);
|
|
printf(" len %d, cksum %d (0x%x): key %s\n",
|
|
da0->datalen, da0->datasum, da0->datasum,
|
|
(char *)(da0 + 1));
|
|
break;
|
|
}
|
|
case FPDS_ENT_DA1_TYPE: {
|
|
printf("da1: offs 0x%06x: %s: len %d:\n",
|
|
0xffffff&offset,
|
|
(ent->valid==FPDS_ENT_VALID)?"VAL":"INV",
|
|
len);
|
|
break;
|
|
}
|
|
default: {
|
|
printf("unknown: offs 0x%06x: %s: type 0x%x (%d bytes):\n",
|
|
0xffffff&offset,
|
|
(ent->valid==FPDS_ENT_VALID)?"VAL":"INV",
|
|
ent->pds_type_len & FPDS_ENT_TYPE_MASK,
|
|
ent->pds_hlen * sizeof(uint16_t));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* syntax: fl erase (<SEG> | all) [<END_SEG>]
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_erase(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
unsigned beg_seg, end_seg;
|
|
|
|
if (argc == 1) {
|
|
if (!strcmp(argv[0], "all")) {
|
|
beg_seg = 0;
|
|
end_seg = SFLASH_MAX_SEGS - 1;
|
|
FPR_PR(("flash: erase all segments"));
|
|
} else {
|
|
beg_seg = atoi(argv[0]);
|
|
end_seg = beg_seg;
|
|
FPR_PR(("flash: erase segment %d @%#x",
|
|
beg_seg, SFLASH_SEG_ADDR(beg_seg)));
|
|
}
|
|
} else if (argc == 2) {
|
|
beg_seg = atoi(argv[0]);
|
|
end_seg = atoi(argv[1]);
|
|
FPR_PR(("flash: erase segments %d - %d", beg_seg, end_seg));
|
|
} else {
|
|
FLASH_USAGE(fcmdp);
|
|
return(0);
|
|
}
|
|
if (!yes(""))
|
|
return(1);
|
|
|
|
if (_fl_erase(beg_seg, end_seg))
|
|
FPR_ERR(("Error: unable to complete erase\n"));
|
|
else
|
|
FPR_MSG(("Erase completed\n"));
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl fprom [<SEG> [wd-pattern]]
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_writest(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int seg = 2, n;
|
|
unsigned *u1, test=0;
|
|
unsigned short *fp, *src_buf, *tp = (unsigned short *)&test;
|
|
flash_err_t frv;
|
|
|
|
if (argc >= 1)
|
|
seg = atoi(argv[0]);
|
|
if (argc >= 2)
|
|
test = (unsigned)atoi(argv[1]);
|
|
|
|
src_buf = (unsigned short *)malloc(SFLASH_SEG_SIZE);
|
|
if (!src_buf) {
|
|
FPR_ERR(("flash: src buffer alloc failed\n"));
|
|
return(0);
|
|
}
|
|
n = SFLASH_SEG_SIZE/2;
|
|
while (n--)
|
|
src_buf[n] = tp[n&1];
|
|
|
|
fp = (unsigned short *)SFLASH_SEG_ADDR(seg);
|
|
FPR_PR((" write segment %d@%#x from %#x with %#x",
|
|
seg, fp, src_buf, test));
|
|
if (!yes(""))
|
|
return(1);
|
|
|
|
START_TIME;
|
|
frv = flash_cp(src_buf, fp, SFLASH_SEG_SIZE/2);
|
|
STOP_TIME("\tsegment write");
|
|
if (frv)
|
|
flash_print_err(frv);
|
|
|
|
n = SFLASH_SEG_SIZE/4;
|
|
u1 = (unsigned *)src_buf;
|
|
START_TIME;
|
|
while (n--) {
|
|
if (*u1++ == test)
|
|
continue;
|
|
FPR_ERR(("flash: memory write failure @ %#x\n", u1-1));
|
|
free(src_buf);
|
|
return(0);
|
|
}
|
|
STOP_TIME("\tmemory buffer K1 read/test");
|
|
|
|
n = SFLASH_SEG_SIZE/4;
|
|
u1 = (unsigned *)SFLASH_SEG_ADDR(seg);
|
|
START_TIME;
|
|
while (n--) {
|
|
if (*u1++ == test)
|
|
continue;
|
|
FPR_ERR(("flash: segment write failure @ %#x\n", u1-1));
|
|
free(src_buf);
|
|
return(0);
|
|
}
|
|
STOP_TIME("\tflash segment K1 read/test");
|
|
|
|
free(src_buf);
|
|
return(0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
_fl_copy(__psunsigned_t src, __psunsigned_t dst, int hlen)
|
|
{
|
|
int n;
|
|
long long lsum;
|
|
unsigned short *sp, *dp, sum;
|
|
long long *lsp = (long long *)src;
|
|
long long *ldp = (long long *)dst;
|
|
flash_err_t frv;
|
|
|
|
n = hlen;
|
|
START_TIME;
|
|
frv = flash_cp((uint16_t *)src, (vu_short *)dst, hlen);
|
|
STOP_TIME("flash copy ");
|
|
if (frv)
|
|
flash_print_err(frv);
|
|
|
|
/* verify the copy */
|
|
n = hlen;
|
|
|
|
START_TIME;
|
|
while (n > 3) {
|
|
n -= 4;
|
|
if (*lsp++ == *ldp++)
|
|
continue;
|
|
FPR_ERR((" lcompare failure src/dst %04x(%#x)/%04x(%#x)\n",
|
|
*(lsp-1), lsp-1, *(ldp-1), ldp-1));
|
|
return(0);
|
|
}
|
|
if (n) { /* we have some odd hwds, 1,2, or 3 */
|
|
sp = (unsigned short *)lsp;
|
|
dp = (unsigned short *)ldp;
|
|
|
|
while (n--) {
|
|
if (*sp++ == *dp++)
|
|
continue;
|
|
FPR_ERR((" hcompare failure src/dst %04x(%#x)/%04x(%#x)\n",
|
|
*(sp-1), sp-1, *(dp-1), dp-1));
|
|
return(0);
|
|
}
|
|
}
|
|
STOP_TIME("src/dst cmp ");
|
|
|
|
START_TIME;
|
|
sum = 0xffff & ~_cksum1((void *)src, hlen*2, 0);
|
|
STOP_TIME("in_cksum src");
|
|
printf(" in_cksum src=%#x\n", sum);
|
|
START_TIME;
|
|
sum = 0xffff & ~_cksum1((void *)dst, hlen*2, 0);
|
|
STOP_TIME("in_cksum dst");
|
|
printf(" in_cksum dst=%#x\n", sum);
|
|
START_TIME;
|
|
lsum = _cksum64((void *)src, hlen*2, 0);
|
|
STOP_TIME("cksum64 src");
|
|
printf("cksum64 src=%#llx\n", lsum);
|
|
START_TIME;
|
|
lsum = _cksum64((void *)dst, hlen*2, 0);
|
|
STOP_TIME("cksum64 dst");
|
|
printf("cksum64 dst=%#llx\n", lsum);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl copy <SRC> <DST> <len>
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_copy(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int len;
|
|
long long lsum;
|
|
__psint_t src, dst;
|
|
|
|
if (argc != 3) {
|
|
FLASH_USAGE(fcmdp);
|
|
return(0);
|
|
}
|
|
|
|
/* switch over to command parser for addr/RANGE parsing*/
|
|
atob_ptr(argv[0], &src);
|
|
atob_ptr(argv[1], &dst);
|
|
len = atoi(argv[2]);
|
|
if (!IS_KSEGDM(src) || !IS_KSEGDM(src+len)) {
|
|
FPR_ERR(("src addr %#x not K0/1\n", src));
|
|
return(0);
|
|
}
|
|
if (!IS_FLASH_ADDR(dst) || !IS_FLASH_ADDR(dst + len - 2)) {
|
|
FPR_ERR(("dst addr %#x len %d not flash\n", dst, len));
|
|
return(0);
|
|
}
|
|
if (len & 1) {
|
|
FPR_ERR(("len not even bytes, flash is 16bit device\n"));
|
|
}
|
|
|
|
FPR_PR(("flash: copy %#x -> %#x for %d bytes",
|
|
src, dst, len));
|
|
if (!yes(""))
|
|
return(1);
|
|
return(_fl_copy(src, dst, len/2));
|
|
}
|
|
|
|
/*
|
|
* syntax: fl dump [<SEG> | <ADDR>]
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_dump(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
static __psint_t addr;
|
|
static int len;
|
|
static int addr_flg = 1;
|
|
|
|
if (argc >= 3)
|
|
addr_flg = 0;
|
|
if (argc >= 2)
|
|
len = atoi(argv[1]);
|
|
if (!len)
|
|
len = 0x80;
|
|
if (argc >= 1)
|
|
atob_ptr(argv[0], &addr);
|
|
if (addr >= 0 && addr < SFLASH_MAX_SEGS)
|
|
addr = (__psint_t)SFLASH_SEG_ADDR(addr);
|
|
else if (!IS_KSEGDM(addr) && !IS_COMPAT_PHYS(addr)) {
|
|
FPR_ERR(("Bad addr: %#x\n", addr));
|
|
return(0);
|
|
}
|
|
dump_bytes((char *)addr, len, addr_flg);
|
|
addr += len;
|
|
printf("\n");
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl 1fe
|
|
* set the flash_mem_base to 1fe
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_1fe(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
flash_mem_base = FLASH_MEM_ALT_BASE;
|
|
|
|
FPR_PR(("flash_mem_base set to 0x%x\n", flash_mem_base));
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl 1fc
|
|
* set the flash_mem_base to 1fc
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_1fc(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
flash_mem_base = FLASH_MEM_BASE;
|
|
FPR_PR(("flash_mem_base set to 0x%x\n", flash_mem_base));
|
|
|
|
if (running_rprom() || running_fprom())
|
|
FPR_PR(("CAUTION: You can toast the prom you are executing!!!\n"));
|
|
return(0);
|
|
}
|
|
/*
|
|
* syntax: fl time <usecs>
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_time(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int i = atoi(argv[0]);
|
|
ulong t10k, t10k_ns, ns;
|
|
vu_long hticks;
|
|
#ifdef US_DELAY_DEBUG
|
|
__uint32_t before, after;
|
|
#endif
|
|
extern __uint32_t us_before, us_after;
|
|
extern ulong decinsperloop, uc_decinsperloop;
|
|
extern ulong _ticksper1024inst(void);
|
|
extern ulong delay_calibrate(void);
|
|
|
|
FPR_PR(("time: us_delay(%d): ", i));
|
|
START_TIME;
|
|
us_delay(i);
|
|
SAMPLE_TICKS(hticks);
|
|
#ifdef IP30
|
|
ns = hticks * HEART_COUNT_NSECS;
|
|
#else
|
|
ns = hticks * 100;
|
|
#endif
|
|
#ifdef US_DELAY_DEBUG
|
|
before = us_before;
|
|
after = us_after;
|
|
FPR_PR(("C0_COUNT: took a little less than 0x%x - 0x%x = "
|
|
"%u ticks.\n",
|
|
(__psunsigned_t)before,(__psunsigned_t)after,
|
|
after-before));
|
|
#endif
|
|
FPR_PR(("took %d,%03d,%03d nsecs hticks=%u\n",
|
|
ns/1000000, (ns%1000000)/1000, (ns%1000000)%1000, hticks));
|
|
FPR_PR(("uc_decinsperloop=%u decinsperloop=%u\n",
|
|
uc_decinsperloop, decinsperloop));
|
|
|
|
START_TIME;
|
|
t10k = _ticksper1024inst();
|
|
SAMPLE_TICKS(hticks);
|
|
#ifdef IP30
|
|
ns = hticks * HEART_COUNT_NSECS;
|
|
t10k_ns = t10k * HEART_COUNT_NSECS;
|
|
#else
|
|
ns = hticks * 100;
|
|
t10k_ns = t10k * 100;
|
|
#endif
|
|
FPR_PR(("_ticksper1024inst took %d,%03d,%03d nsecs hticks=%u\n",
|
|
ns/1000000, (ns%1000000)/1000, (ns%1000000)%1000, hticks));
|
|
FPR_PR(("_ticksper1024inst=%u ticks, %u secs\n",
|
|
t10k, t10k_ns));
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl cksum [(<seg> | <addr>) [len]]
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_cksum(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int len = 0x80000; /* default is 512K*/
|
|
int cksum, n;
|
|
__psint_t data = 0;
|
|
long long llsum;
|
|
|
|
if (argc >= 1) {
|
|
atob_ptr(argv[0], &data);
|
|
len = SFLASH_SEG_SIZE;
|
|
}
|
|
if (argc >= 2)
|
|
len = atoi(argv[1]);
|
|
|
|
if (data >= 0 && data < SFLASH_MAX_SEGS)
|
|
data = (__psint_t)SFLASH_SEG_ADDR(data);
|
|
else if (!IS_KSEGDM(data) || !IS_KSEGDM(data+len)) {
|
|
FPR_ERR(("Bad addr/len: %#x/%#x\n", data/len));
|
|
return(0);
|
|
}
|
|
#if NOT
|
|
START_TIME;
|
|
cksum = flash_cksum_r((char *)data, len, 0);
|
|
STOP_TIME("sum ");
|
|
FPR_PR(("sum -r %d bytes @%#x\n", len, data));
|
|
FPR_PR(("%05u %d\n", cksum, (len+511)/512));
|
|
|
|
START_TIME;
|
|
isum = _cksum32_16((void *)data, len, 0);
|
|
STOP_TIME("cksum32_16 ");
|
|
START_TIME;
|
|
llsum = _cksum64_16((void *)data, len, 0);
|
|
STOP_TIME("cksum64_16 ");
|
|
FPR_PR((" 32bit %#x 64bit %#llx by 16 bit access\n", isum, llsum));
|
|
START_TIME;
|
|
isum = _cksum32((void *)data, len, 0);
|
|
STOP_TIME("cksum32 ");
|
|
#endif
|
|
FPR_PR(("%d bytes @%#x:\n", len, data));
|
|
START_TIME;
|
|
cksum = 0xffff & ~_cksum1((void *)data, len, 0);
|
|
STOP_TIME("in_cksum ");
|
|
FPR_PR(("in_cksum %#x\n", cksum));
|
|
|
|
START_TIME;
|
|
llsum = _cksum64((void *)data, len, 0);
|
|
STOP_TIME("cksum64 ");
|
|
FPR_PR(("cksum64 %#llx\n", llsum));
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* syntax: fl sum-r <addr> <len>
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_sum_r(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int cksum, len, n;
|
|
__psint_t data = 0;
|
|
long long llsum;
|
|
|
|
if (argc < 2) {
|
|
FLASH_USAGE(fcmdp);
|
|
return(0);
|
|
}
|
|
|
|
atob_ptr(argv[0], &data);
|
|
len = atoi(argv[1]);
|
|
|
|
if (data >= 0 && data < SFLASH_MAX_SEGS)
|
|
data = (__psint_t)SFLASH_SEG_ADDR(data);
|
|
else if (!IS_KSEGDM(data) || !IS_KSEGDM(data+len)) {
|
|
FPR_ERR(("Bad addr/len: %#x/%#x\n", data/len));
|
|
return(0);
|
|
}
|
|
START_TIME;
|
|
cksum = flash_cksum_r((char *)data, len, 0);
|
|
STOP_TIME("sum ");
|
|
FPR_PR(("sum -r %d bytes @%#x\n", len, data));
|
|
FPR_PR(("%05u %d\n", cksum, (len+511)/512));
|
|
FPR_PR(("0x%x\n", cksum));
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int
|
|
fl_log_test(int argc, char **argv, flash_cmd_t *f)
|
|
{
|
|
char buf[128];
|
|
char *str;
|
|
int n = 0;
|
|
|
|
if (argc)
|
|
str = argv[0];
|
|
else
|
|
str = "flash log test";
|
|
if (argc == 2) {
|
|
TIMEINFO t;
|
|
|
|
START_TIME;
|
|
cpu_get_tod(&t);
|
|
STOP_TIME("get tod ");
|
|
|
|
n = atoi(argv[1]);
|
|
}
|
|
START_TIME;
|
|
flash_pds_log(str);
|
|
STOP_TIME("log test ");
|
|
START_TIME;
|
|
flash_pds_prf("flash_pds_prf: string test %s=0x%x %s=%d", "A", 0xA, "B", 2);
|
|
STOP_TIME("log1 write ");
|
|
START_TIME;
|
|
flash_pds_write_log(PDS_LOG_TYPE2, 0xa, 0xb, 0xc, 0xd);
|
|
STOP_TIME("log2 write ");
|
|
|
|
START_TIME;
|
|
while (n--) {
|
|
flash_pds_prf("%s %8d", str, n);
|
|
}
|
|
STOP_TIME("logN write ");
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* test power en-dis able fct by toggling it
|
|
*/
|
|
static int
|
|
fl_power(int argc, char **argv, flash_cmd_t *f)
|
|
{
|
|
static int off_state;
|
|
|
|
if (off_state) {
|
|
ip30_setup_power();
|
|
off_state = 0;
|
|
FPR_MSG(("Power ints are ON\n"));
|
|
} else {
|
|
ip30_disable_power();
|
|
off_state = 1;
|
|
FPR_MSG(("Power ints are OFF\n"));
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
#define ERASED_UINT64 0xffffffffffffffff
|
|
static __psunsigned_t
|
|
erase_chk(int seg)
|
|
{
|
|
uint64_t *fdp = (uint64_t *)SFLASH_SEG_ADDR(seg);
|
|
uint64_t *fdp_end = (uint64_t *)SFLASH_SEG_ADDR(seg+1);
|
|
|
|
while (fdp < fdp_end) {
|
|
if (*fdp++ == ERASED_UINT64)
|
|
continue;
|
|
return((__psunsigned_t)(fdp - 1));
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
#define BITSPERSHORT 16
|
|
static flash_err_t
|
|
ttf_extra(int seg, int sl)
|
|
{
|
|
vu_short *fp = SFLASH_SEG_ADDR(seg);
|
|
vu_short *seg_endp = SFLASH_SEG_ADDR(seg + 1);
|
|
int i, ii;
|
|
vu_short test, actual;
|
|
flash_err_t rv;
|
|
|
|
for (i=0; fp < seg_endp; i++) {
|
|
test = 0xffff;
|
|
for (ii=0; ii < BITSPERSHORT; ii++) {
|
|
if (sl)
|
|
test <<= 1;
|
|
else
|
|
test >>= 1;
|
|
rv = flash_cp((void *)&test, fp, 1);
|
|
actual = *fp;
|
|
if (rv || test != actual)
|
|
goto failed;
|
|
}
|
|
fp++;
|
|
}
|
|
return(rv);
|
|
failed:
|
|
printf("ttf_extfa: failed fp=0x%x i=%d ii=%d\n", fp, i, ii);
|
|
if (rv)
|
|
flash_print_err(rv);
|
|
printf(" test=0x%x actual=0x%x\n", test, actual);
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* test time-to-failure of a segment
|
|
*/
|
|
static int
|
|
fl_ttf(int argc, char **argv, flash_cmd_t *f)
|
|
{
|
|
int extra = 0, erase_only = 0, set_count = 0, fcnt;
|
|
unsigned n, count = 1;
|
|
__psunsigned_t echk;
|
|
flash_err_t frv;
|
|
char *bufp = 0;
|
|
|
|
|
|
while (argc--) {
|
|
if ( !strcmp("extra", *argv)) {
|
|
extra = 1;
|
|
} else if ( !strcmp("erase_only", *argv)) {
|
|
erase_only = 1;
|
|
} else if ( !strcmp("set_count", *argv)) {
|
|
set_count = 1;
|
|
} else {
|
|
count = (unsigned) atoi(*argv);
|
|
}
|
|
argv++;
|
|
}
|
|
|
|
if (set_count) {
|
|
fcnt = count;
|
|
fcnt += flash_get_nv_cnt(SFLASH_FPROM_SEG);
|
|
flash_set_nv_cnt(SFLASH_FPROM_SEG, &fcnt);
|
|
printf("new count %d\n", fcnt);
|
|
return(0);
|
|
}
|
|
|
|
if (!extra) {
|
|
bufp = (char *)align_malloc(SFLASH_SEG_SIZE, sizeof(__uint64_t));
|
|
if (!bufp) {
|
|
printf("no mem for %d size\n", SFLASH_SEG_SIZE);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
printf("flash erase-to-failure test of segment 14,\n"
|
|
" %d loops extra=%d erase_only=%d: ",
|
|
count, extra, erase_only);
|
|
|
|
if (!yes("continue"))
|
|
return(0);
|
|
|
|
for (n = 0; n < count; n++) {
|
|
printf(" n = %8d: ", n);
|
|
if (extra) {
|
|
START_TIME;
|
|
if (ttf_extra(14, n & 1))
|
|
break;
|
|
STOP_TIME("ttf_extra ");
|
|
} else if (!erase_only) {
|
|
START_TIME;
|
|
bcopy((void *)SFLASH_SEG_ADDR(n&0x7), bufp, SFLASH_SEG_SIZE);
|
|
/* fill the buffer */
|
|
frv = flash_cp((void *)bufp,
|
|
SFLASH_SEG_ADDR(14),
|
|
SFLASH_SEG_SIZE/sizeof(uint16_t));
|
|
STOP_TIME("segfill ");
|
|
if (frv) {
|
|
flash_print_err(frv);
|
|
break;
|
|
}
|
|
}
|
|
frv = flash_erase(14);
|
|
if (frv) {
|
|
flash_print_err(frv);
|
|
break;
|
|
}
|
|
fcnt = flash_get_nv_cnt(SFLASH_FPROM_SEG) + 1;
|
|
flash_set_nv_cnt(SFLASH_FPROM_SEG, &fcnt);
|
|
echk = erase_chk(14);
|
|
if (echk) {
|
|
printf("erase failure at 0x%x\n", echk);
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (bufp)
|
|
align_free(bufp);
|
|
return(0);
|
|
}
|
|
#endif /* FDEBUG */
|
|
|
|
/*ARGSUSED*/
|
|
/*
|
|
* repeat flash cmds
|
|
*/
|
|
static int
|
|
fl_repeat(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
int flash_cmd(int argc, char **argv, char **envp);
|
|
int count;
|
|
|
|
if (argc < 2) {
|
|
FLASH_USAGE(fcmdp);
|
|
return(0);
|
|
}
|
|
count = atoi(argv[0]);
|
|
if (count <= 0) {
|
|
FLASH_USAGE(fcmdp);
|
|
return(0);
|
|
}
|
|
argc--;
|
|
argv++;
|
|
while (count--) {
|
|
flash_cmd(argc, argv, 0);
|
|
flash_pds_prf("%s: rep count %d", argv[0], count);
|
|
}
|
|
return(0);
|
|
|
|
}
|
|
|
|
/*
|
|
* syntax: fl info
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_info(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
unsigned short mfgid, devid;
|
|
int seg = 0, status;
|
|
|
|
if (argc >= 1)
|
|
seg = atoi(argv[0]);
|
|
flash_id(&mfgid, &devid);
|
|
FPR_PR(("Flash Base=0x%x ID(mfg %#x dev %#x)\n",
|
|
flash_mem_base, mfgid, devid));
|
|
/* check mfg and dev and give appropriate confirm/warning */
|
|
if (mfgid != SFLASH_MFG_ID)
|
|
FPR_PR(("Warning: unknown mfg id 0x%x, expected 0x%x\n",
|
|
mfgid, SFLASH_MFG_ID));
|
|
if (devid != SFLASH_DEV_ID)
|
|
FPR_PR(("Warning: unknown device id 0x%x, expected 0x%x\n",
|
|
devid, SFLASH_DEV_ID));
|
|
flash_print_status(seg);
|
|
|
|
FPR_PR(("\n"));
|
|
FPR_PR(("RPROM "));
|
|
flash_print_prom_info(SFLASH_RPROM_HDR_ADDR,
|
|
(u_short *)SFLASH_RPROM_ADDR);
|
|
FPR_PR(("\n"));
|
|
FPR_PR(("FPROM "));
|
|
flash_print_prom_info(SFLASH_FPROM_HDR_ADDR,
|
|
(u_short *)SFLASH_FPROM_ADDR +
|
|
FLASH_HEADER_SIZE/sizeof(uint16_t));
|
|
FPR_PR(("\n"));
|
|
/*
|
|
* if seg is non-zero it will be used as flag to check the
|
|
* pds usage data structs
|
|
*/
|
|
flash_print_pds_status(seg);
|
|
return(0);
|
|
}
|
|
|
|
#define FCMD_PROM_USAGE "[-r|-R] <file>"
|
|
#define FCMD_LOG_USAGE "[inval] [<entry_offset>]"
|
|
#define FCMD_DATA_USAGE "[[-d|-f|-m] <key> [<file>|<range>]]"
|
|
#define FCMD_RESETPDS_USAGE ""
|
|
#define FCMD_RPROMFLG_USAGE "<16-bit flag>"
|
|
#define FCMD_INFO_USAGE ""
|
|
#define FCMD_HELP_USAGE ""
|
|
|
|
#ifdef FDEBUG
|
|
#define FCMD_SENV_USAGE "<var> [<string>]"
|
|
#define FCMD_GENV_USAGE "<var>"
|
|
#define FCMD_UENV_USAGE "<var>"
|
|
#define FCMD_GET_USAGE "[<file>]"
|
|
#define FCMD_LOAD_USAGE "[<file>]"
|
|
#define FCMD_ERASE_USAGE "(<SEG> [<END_SEG>] | all)"
|
|
#define FCMD_PDS_USAGE "[all | env | log | compress ]"
|
|
#define FCMD_1FC_USAGE ""
|
|
#define FCMD_1FE_USAGE ""
|
|
#define FCMD_WRITEST_USAGE "[<SEG> [<wd-pattern>]]"
|
|
#define FCMD_COPY_USAGE "<SRC> <DST> <len>"
|
|
#define FCMD_DUMP_USAGE "[(<SEG> | <ADDR>) [<len> [<pr_addr>]]"
|
|
#define FCMD_TIME_USAGE "<usecs>"
|
|
#define FCMD_CKSUM_USAGE "[(<SEG> | <ADDR>) [<len>]]"
|
|
#define FCMD_SUM_R_USAGE "<ADDR> <len>"
|
|
#define FCMD_LOG_TEST_USAGE "[<string> [<iteration>]]"
|
|
#endif /* FDEBUG */
|
|
|
|
static int fl_usage(int, char **, flash_cmd_t *);
|
|
|
|
/*
|
|
* flash commands
|
|
*/
|
|
static flash_cmd_t fl_cmds[] = {
|
|
{"prom", fl_prom, FCMD_PROM_USAGE, FCMD_CHECK},
|
|
{"log", fl_log, FCMD_LOG_USAGE, FCMD_CHECK},
|
|
{"data", fl_data, FCMD_DATA_USAGE, FCMD_CHECK},
|
|
{"resetpds",fl_resetpds,FCMD_RESETPDS_USAGE, FCMD_CHECK},
|
|
{"rpromflg",fl_rpromflg,FCMD_RPROMFLG_USAGE, 0},
|
|
{"info", fl_info, FCMD_INFO_USAGE, 0},
|
|
{"?", fl_usage, FCMD_HELP_USAGE, 0},
|
|
{"help", fl_usage, FCMD_HELP_USAGE, 0},
|
|
#ifdef FDEBUG
|
|
{"setenv", fl_senv, FCMD_SENV_USAGE, FCMD_CHECK},
|
|
{"unsetenv",fl_uenv, FCMD_UENV_USAGE, FCMD_CHECK},
|
|
{"getenv", fl_genv, FCMD_GENV_USAGE, FCMD_CHECK},
|
|
{"load", fl_load, FCMD_LOAD_USAGE, 0},
|
|
{"get", fl_get, FCMD_GET_USAGE, 0},
|
|
{"erase", fl_erase, FCMD_ERASE_USAGE, FCMD_CHECK},
|
|
{"pds", fl_pds, FCMD_PDS_USAGE, FCMD_CHECK},
|
|
{"writest", fl_writest, FCMD_WRITEST_USAGE, FCMD_CHECK},
|
|
{"copy", fl_copy, FCMD_COPY_USAGE, FCMD_CHECK},
|
|
{"1fc", fl_1fc, FCMD_1FC_USAGE, 0},
|
|
{"1fe", fl_1fe, FCMD_1FE_USAGE, 0},
|
|
{"dump", fl_dump, FCMD_DUMP_USAGE, 0},
|
|
{"time", fl_time, FCMD_TIME_USAGE, 0},
|
|
{"cksum", fl_cksum, FCMD_CKSUM_USAGE, 0},
|
|
{"sum-r", fl_sum_r, FCMD_SUM_R_USAGE, 0},
|
|
{"log_test",fl_log_test,FCMD_LOG_TEST_USAGE, 0},
|
|
{"power", fl_power, "power", 0},
|
|
{"ttf", fl_ttf, "[extra | erase_only] [<count>]", 0},
|
|
#endif /* FDEBUG */
|
|
{"repeat", fl_repeat, "repeat count flash cmd ...", 0},
|
|
{ 0 },
|
|
};
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
fl_usage(int argc, char **argv, flash_cmd_t *fcmdp)
|
|
{
|
|
for (fcmdp = fl_cmds; fcmdp->cmd; fcmdp++)
|
|
FLASH_USAGE(fcmdp);
|
|
return(0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
flash_cmd(int argc, char **argv, char **envp)
|
|
{
|
|
flash_cmd_t *fcmdp = fl_cmds;
|
|
|
|
if (argc < 2)
|
|
goto err;
|
|
|
|
for (; fcmdp->cmd; fcmdp++) {
|
|
if ( !strcmp(fcmdp->cmd, argv[1])) {
|
|
if (fcmdp->flags & FCMD_CHECK) {
|
|
if (!flash_ok()) {
|
|
FPR_ERR(("flash: flash part not found at 0x%x\n",
|
|
flash_mem_base));
|
|
return(0);
|
|
}
|
|
}
|
|
argc -= 2;
|
|
argv += 2;
|
|
(void)(*fcmdp->func)(argc, argv, fcmdp);
|
|
return(0);
|
|
}
|
|
}
|
|
FPR_ERR(("unknown flash command\n"));
|
|
err:
|
|
return(fl_usage(argc, argv, fl_cmds));
|
|
}
|
|
#endif /* defined(IP30) */
|