1
0
Files
irix-657m-src/stand/arcs/lib/libsk/ml/IP30nvram.c
2022-09-29 17:59:04 +03:00

395 lines
8.4 KiB
C

/* IP30 nvram code */
#ident "$Revision: 1.22 $"
#include <sys/types.h>
#include <sys/immu.h>
#include <sys/cpu.h>
#include <sys/ds1687clk.h>
#include <sys/RACER/IP30nvram.h>
#include <libsk.h>
#include <libsc.h>
#include <sys/RACER/sflash.h>
void ip30_init_cpu_disable(void);
static uchar_t nvram_content[NVLEN_MAX];
static int nvram_read;
/* nvchecksum calculates the checksum for the nvram */
static uchar_t
nvchecksum(void)
{
/*
* seed the checksum so all-zeroes (all-ones) nvram doesn't have a zero
* (all-ones) checksum
*/
char bitbucket[2]; /* extra byte for NULL */
uchar_t checksum = 0xa5;
int i;
/* read the whole nvram into memory */
if (!nvram_read)
cpu_get_nvram_buf(NVOFF_CHECKSUM, NVLEN_CHECKSUM, bitbucket);
/* NVOFF_REVISION must be the first checksummed offset, with
* NVOFF_CHECKSUM before it.
*/
for (i = NVOFF_REVISION; i < NVLEN_MAX; i++) {
checksum ^= nvram_content[i];
/* rotate checksum */
checksum = (checksum << 1) | (checksum >> 7);
}
return checksum;
}
/*
* cpu_get_nvram_buf is the same as cpu_get_nvram_offset() except putting
* the read string in the given buffer
*/
void
cpu_get_nvram_buf(int nv_off, int nv_len, char buf[])
{
int i;
extern int nic_get_eaddr(__int32_t *, __int32_t *, char *);
int nv_last = nv_off + nv_len;
if (nv_off == NVOFF_ENET && nv_len == NVLEN_ENET) {
(void)nic_get_eaddr(
(__int32_t *)(IOC3_PCI_DEVIO_K1PTR + IOC3_MCR),
(__int32_t *)(IOC3_PCI_DEVIO_K1PTR + IOC3_GPCR_S),
buf);
buf[6] = 0;
return;
}
/* variable is a PDS variable. Ignore it. */
if (nv_off == NVOFF_PDSVAR) {
buf[0] = 0;
return;
}
/* save all nvram variables in memory for speed */
if (!nvram_read) {
ioc3reg_t old;
old = slow_ioc3_sio();
/* access the first 2 sets of nvram variables through bank 0 */
WR_DS1687_RTC(RTC_CTRL_A, RTC_OSCILLATOR_ON);
for (i = NVRAM_SET_0_MIN; i <= NVRAM_SET_1_MAX; i++)
nvram_content[i - NVRAM_REG_OFFSET] = RD_DS1687_RTC(i);
/* must access the last set of nvram variables through bank 1 */
WR_DS1687_RTC(RTC_CTRL_A,
RTC_SELECT_BANK_1 | RTC_OSCILLATOR_ON);
for (i = NVRAM_SET_2_MIN; i <= NVRAM_SET_2_MAX; i++) {
WR_DS1687_RTC(RTC_X_RAM_ADDR, i & 0x7f);
nvram_content[i - NVRAM_REG_OFFSET] =
RD_DS1687_RTC(RTC_X_RAM_DATA);
}
restore_ioc3_sio(old);
nvram_read = 1;
}
if (nv_last > NVLEN_MAX)
nv_last = NVLEN_MAX;
for (i = nv_off; i < nv_last; i++)
*buf++ = nvram_content[i];
*buf = 0;
}
/*
* cpu_get_nvram reads a string with the given length from the nvram
* starting at the specified byte offset
*/
char *
cpu_get_nvram_offset(int nv_off, int nv_len)
{
/* add 1 for the NULL terminator */
static char buf[NVLEN_MAX + 1];
cpu_get_nvram_buf(nv_off, nv_len, buf);
return buf;
}
/*
* cpu_set_nvram_offset writes the specified string with the given length to
* the nvram starting at the specified byte offset
*/
int
cpu_set_nvram_offset(int nv_off, int nv_len, char *string)
{
uchar_t checksum;
int i;
int nv_last = nv_off + nv_len - 1;
ioc3reg_t old;
if (nv_last >= NVLEN_MAX) /* covers PDS case */
return -1;
nv_off += NVRAM_REG_OFFSET;
nv_last += NVRAM_REG_OFFSET;
old = slow_ioc3_sio();
/* access the first 2 sets of nvram variables through bank 0 */
if (nv_off <= NVRAM_SET_1_MAX)
WR_DS1687_RTC(RTC_CTRL_A, RTC_OSCILLATOR_ON);
while (nv_off <= nv_last && nv_off <= NVRAM_SET_1_MAX) {
WR_DS1687_RTC(nv_off, *string);
nvram_content[nv_off - NVRAM_REG_OFFSET] = *string;
nv_off++;
string++;
}
/* must access the last set of nvram variables through bank 1 */
if (nv_off <= nv_last)
WR_DS1687_RTC(RTC_CTRL_A,
RTC_SELECT_BANK_1 | RTC_OSCILLATOR_ON);
while (nv_off <= nv_last && nv_off <= NVRAM_SET_2_MAX) {
WR_DS1687_RTC(RTC_X_RAM_ADDR, nv_off & 0x7f);
WR_DS1687_RTC(RTC_X_RAM_DATA, *string);
nvram_content[nv_off - NVRAM_REG_OFFSET] = *string;
nv_off++;
string++;
}
checksum = nvchecksum();
WR_DS1687_RTC(NVOFF_CHECKSUM + NVRAM_REG_OFFSET, checksum);
restore_ioc3_sio(old);
return 0;
}
/*
* cpu_set_nvram sets the nvram string identified by 'match' to the
* string identified by 'newstring'
*/
int
cpu_set_nvram(char *match, char *newstring)
{
/* Most systems only let the prom do this. It's only libsk programs,
* and symmon stubs everything, so this lets us set variables from
* ide, which we need for the mfg process.
*/
return setenv_nvram(match, newstring);
}
/* cpu_is_nvvalid returns 1 if the nvram is valid, 0 otherwise */
static int
rev_is_nvvalid(unsigned char revision)
{
uchar_t checksum;
char byte;
checksum = *cpu_get_nvram_offset(NVOFF_CHECKSUM, NVLEN_CHECKSUM);
if (checksum != nvchecksum()) {
/* Check if only cpumask is incorrect -- may happen on a
* failed bootstrap -> NMI with diagmode hook.
*/
if (!(nvram_content[NVOFF_CPUDISABLE+1] & CPU_DISABLE_INVALID))
return 0;
nvram_content[NVOFF_CPUDISABLE+1] ^= CPU_DISABLE_INVALID;
if (checksum != nvchecksum())
return 0;
printf("Clearing CPU disable mask with diagmode NMI hook.\n");
cpu_set_nvram_offset(NVOFF_BOOTMASTER,NVLEN_BOOTMASTER,"");
ip30_init_cpu_disable(); /* enable everything */
}
if ((uchar_t)*cpu_get_nvram_offset(NVOFF_REVISION, NVLEN_REVISION) !=
revision) {
return 0;
}
return 1;
}
int
cpu_is_nvvalid(void)
{
return rev_is_nvvalid(NV_CURRENT_REV);
}
/*ARGSUSED*/
void
cpu_get_nvram_persist(int (*putstr)(char *,char *,struct string_list *),
struct string_list *env)
{
flash_loadenv(putstr, env);
}
/*ARGSUSED*/
void
cpu_set_nvram_persist(char *a,char *b)
{
(void)flash_setenv(a, b);
}
static void
init_nv_counters(void)
{
int val;
char *cp = (char *)&val;
/*
* initialize with values from flash headers
* if flash hdr is bad we will get 0
*/
val = flash_get_nflashed(SFLASH_RPROM_SEG);
cpu_set_nvram_offset(NVOFF_NFLASHEDRP,NVLEN_NFLASHEDRP,cp);
val = flash_get_nflashed(SFLASH_FPROM_SEG);
cpu_set_nvram_offset(NVOFF_NFLASHEDFP,NVLEN_NFLASHEDFP,cp);
val = flash_get_nflashed(SFLASH_PDS_SEG);
cpu_set_nvram_offset(NVOFF_NFLASHEDPDS,NVLEN_NFLASHEDPDS,cp);
val = 0;
cpu_set_nvram_offset(NVOFF_UPTIME,NVLEN_UPTIME,cp);
}
/*
* cpu_set_nvvalid validates the nvram by updating the revision and checksum
* entries
*/
void
cpu_set_nvvalid(void (*delstr)(char *,struct string_list *),
struct string_list *env)
{
char c;
/* cpu_set_nvram_offset() will generate the correct checksum too */
c = (uchar_t)NV_CURRENT_REV;
cpu_set_nvram_offset(NVOFF_REVISION, NVLEN_REVISION, &c);
}
/* cpu_nv_lock locks the nvram if lock==1, unlocks otherwise */
void
cpu_nv_lock(int lock)
{
}
/* nvram_is_protected returns 1 if the nvram is protected, 0 otherwise */
int
nvram_is_protected(void)
{
return 0;
}
void
ip30_init_cpu_disable(void)
{
char buf[2];
buf[0] = CPU_DISABLE_MAGIC >> 8;
buf[1] = CPU_DISABLE_MAGIC & 0xff;
cpu_set_nvram_offset(NVOFF_CPUDISABLE,NVLEN_CPUDISABLE,buf);
}
static int oldrev;
int
cpu_is_oldnvram(void)
{
int rc = 0;
oldrev = 0;
if (rev_is_nvvalid(2)) {
oldrev = 2;
rc = 1;
}
else if (rev_is_nvvalid(3)) {
oldrev = 3;
rc = 1;
}
else if (rev_is_nvvalid(4)) {
oldrev = 4;
rc = 1;
}
else if (rev_is_nvvalid(5)) {
oldrev = 5;
rc = 1;
}
else if (rev_is_nvvalid(6)) {
oldrev = 6;
rc = 1;
}
/* always reset cpu mask when nvram checksum is wrong */
ip30_init_cpu_disable();
/* bad checksum and we dont recognize the version, init counters */
if (rc == 0)
init_nv_counters();
return rc;
}
void
cpu_update_nvram(void)
{
void initialize_envstrs(void);
if (oldrev == 0) return;
/* no compat hook for rev 0 -> rev 1 */
if (oldrev <= 2) {
cpu_set_nvram_offset(NVOFF_BOOTMASTER,NVLEN_BOOTMASTER,"\000");
}
if (oldrev <= 3) {
cpu_set_nvram_offset(NVOFF_AUTOPOWER,NVLEN_AUTOPOWER,"y");
}
if (oldrev <= 4) {
init_nv_counters();
}
if (oldrev <= 5) {
cpu_set_nvram_offset(NVOFF_UNCACHEDPROM,NVLEN_UNCACHEDPROM,"");
}
if (oldrev <= 6) {
unsigned short zero = 0;
char *cp = (char *)&zero;
cpu_set_nvram_offset(NVOFF_RPROMFLAGS,NVLEN_RPROMFLAGS,cp);
/*
* boottune is not being added but most of systems have
* systems with garbage in them so take this chance to
* set initial values to it
*/
cpu_set_nvram_offset(NVOFF_BOOTTUNE,NVLEN_BOOTTUNE,"1");
}
oldrev = 0;
initialize_envstrs(); /* normal env set-up */
}
void
cpu_resetenv(void)
{
/* always clear processor disable mask for saftey */
ip30_init_cpu_disable();
/* XXX validate dallas flash/uptime variables (may be corrupt) */
/* clear Flash PDS env vars */
flash_resetenv();
}