aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikunj A. Dadhania <nikunj@linux.vnet.ibm.com>2012-10-16 11:49:51 +0530
committerDavid Gibson <david@gibson.dropbear.id.au>2012-10-17 16:30:58 +1100
commit0ad10f26c94a86a0c9c3970e53f9a9f6a744055d (patch)
tree40b0d9d2ba55512071a9e713bd2db55b84a65ef6 /lib
parent7000cbc4e14aa891adbfdcc07b157e8c9ebb026c (diff)
downloadSLOF-qemu-slof-20121018.zip
SLOF-qemu-slof-20121018.tar.gz
SLOF-qemu-slof-20121018.tar.bz2
SLOF: Support PAPR NVRAM RTAS callsqemu-slof-20121018
BenH still need to ACK this though. From: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> * Determines size of the flash using device tree. * Provides nvram access functions for RTAS_NVRAM * Allocates temporary buffer of nvram in SLOF code and use that in C. (sbrk not available) * NVRAM_LENGTH is used at various places, make sure it is well guarded and also use dynamically determined size once an RTAS-NVRAM is found. * Use NVRAM_LENGTH as a variable in case of RTAS_NVRAM, not very elegant though Signed-off-by: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> -- Changelog from v1: * #define cleanups suggested by Thomas/Benh * Fix makefile which missed passing $FLAG for building llfw * renamed vio-nvram.fs as rtas-nvram.fs
Diffstat (limited to 'lib')
-rw-r--r--lib/libbases/libbases.code2
-rw-r--r--lib/libbootmsg/bootmsg_lvl.S5
-rw-r--r--lib/libhvcall/libhvcall.h14
-rw-r--r--lib/libnvram/libnvram.code10
-rw-r--r--lib/libnvram/libnvram.in1
-rw-r--r--lib/libnvram/nvram.c88
-rw-r--r--lib/libnvram/nvram.h3
7 files changed, 111 insertions, 12 deletions
diff --git a/lib/libbases/libbases.code b/lib/libbases/libbases.code
index 7dc941d..45312e2 100644
--- a/lib/libbases/libbases.code
+++ b/lib/libbases/libbases.code
@@ -20,7 +20,7 @@ MIRP
// : get-nvram-size ( -- size )
PRIM(get_X2d_nvram_X2d_size)
PUSH;
- TOS.u = NVRAM_LENGTH;
+ TOS.u = get_nvram_size();
MIRP
// : get-flash-base ( -- base )
diff --git a/lib/libbootmsg/bootmsg_lvl.S b/lib/libbootmsg/bootmsg_lvl.S
index 65cf0c3..2e4c135 100644
--- a/lib/libbootmsg/bootmsg_lvl.S
+++ b/lib/libbootmsg/bootmsg_lvl.S
@@ -158,7 +158,8 @@ ENTRY(bootmsg_setlevel)
andi. r3, r3, 0x7F
add r6,r3,r6 // address |
stb r4,0(r6) // store level |_ stwbrx r4,r3,r6
-#ifndef DISABLE_NVRAM
+
+#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM)
LOAD64(r6, SB_NVRAM_FWONLY_adr + 8 )
add r6,r6,r3
stb r4,0(r6)
@@ -167,7 +168,7 @@ ENTRY(bootmsg_setlevel)
blr
ENTRY(bootmsg_nvupdate)
-#ifndef DISABLE_NVRAM
+#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM)
mflr r10
LOAD64(r3, SB_NVRAM_FWONLY_adr)
lwz r4, 0(r3)
diff --git a/lib/libhvcall/libhvcall.h b/lib/libhvcall/libhvcall.h
index 302e2a3..6e418ba 100644
--- a/lib/libhvcall/libhvcall.h
+++ b/lib/libhvcall/libhvcall.h
@@ -70,6 +70,20 @@ static inline long h_add_logical_lan_buffer(unsigned long unit_address,
return hv_generic(H_ADD_LOGICAL_LAN_BUFFER, unit_address, buffer);
}
+#define HV_RTAS_MAX_ARGRET 5
+
+struct hv_rtas_call {
+ uint32_t token;
+ uint32_t nargs;
+ uint32_t nrets;
+ uint32_t argret[HV_RTAS_MAX_ARGRET];
+};
+
+static inline unsigned long h_rtas(struct hv_rtas_call *rtas_buf)
+{
+ return hv_generic(KVMPPC_H_RTAS, (unsigned long)rtas_buf);
+}
+
extern unsigned long hv_logical_ci_load(unsigned long size, unsigned long addr);
extern unsigned long hv_logical_ci_store(unsigned long size, unsigned long addr,
unsigned long value);
diff --git a/lib/libnvram/libnvram.code b/lib/libnvram/libnvram.code
index f1fd414..723941d 100644
--- a/lib/libnvram/libnvram.code
+++ b/lib/libnvram/libnvram.code
@@ -276,4 +276,12 @@ PRIM(delete_X2d_nvram_X2d_partition)
MIRP
-
+// ( fetch_token store_token size nvram-addr -- )
+PRIM(internal_X2d_nvram_X2d_init)
+ void *nvram_addr = TOS.a; POP;
+ uint32_t nvram_size = TOS.u; POP;
+ uint32_t store_token = TOS.u; POP;
+ long fetch_token = TOS.u; POP;
+
+ nvram_init(fetch_token, store_token, nvram_size, nvram_addr);
+MIRP
diff --git a/lib/libnvram/libnvram.in b/lib/libnvram/libnvram.in
index 33ab3bc..bbb20a8 100644
--- a/lib/libnvram/libnvram.in
+++ b/lib/libnvram/libnvram.in
@@ -39,3 +39,4 @@ cod(internal-add-env)
cod(internal-del-env)
cod(internal-set-env)
+cod(internal-nvram-init)
diff --git a/lib/libnvram/nvram.c b/lib/libnvram/nvram.c
index 048ec0f..2cb83dc 100644
--- a/lib/libnvram/nvram.c
+++ b/lib/libnvram/nvram.c
@@ -12,6 +12,7 @@
#include "cache.h"
#include "nvram.h"
+#include "../libhvcall/libhvcall.h"
#include <stdio.h>
#include <stdarg.h>
@@ -20,9 +21,38 @@
#include <nvramlog.h>
#include <byteorder.h>
+#ifdef RTAS_NVRAM
+static uint32_t fetch_token;
+static uint32_t store_token;
+static uint32_t NVRAM_LENGTH;
+static char *nvram_buffer; /* use buffer allocated by SLOF code */
+#else
#ifndef NVRAM_LENGTH
#define NVRAM_LENGTH 0x10000
#endif
+/*
+ * This is extremely ugly, but still better than implementing
+ * another sbrk() around it.
+ */
+static char nvram_buffer[NVRAM_LENGTH];
+#endif
+
+static uint8_t nvram_buffer_locked=0x00;
+
+void nvram_init(uint32_t _fetch_token, uint32_t _store_token,
+ long _nvram_length, void* nvram_addr)
+{
+#ifdef RTAS_NVRAM
+ fetch_token = _fetch_token;
+ store_token = _store_token;
+ NVRAM_LENGTH = _nvram_length;
+ nvram_buffer = nvram_addr;
+
+ printf("\nNVRAM: size=%d, fetch=%x, store=%x\n",
+ NVRAM_LENGTH, fetch_token, store_token);
+#endif
+}
+
void asm_cout(long Character,long UART,long NVRAM);
@@ -48,6 +78,46 @@ static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */
*pos = data; \
}
+#elif defined(RTAS_NVRAM)
+
+static inline void nvram_fetch(unsigned int offset, void *buf, unsigned int len)
+{
+ struct hv_rtas_call rtas = {
+ .token = fetch_token,
+ .nargs = 3,
+ .nrets = 2,
+ .argret = { offset, (uint32_t)(unsigned long)buf, len },
+ };
+ h_rtas(&rtas);
+}
+
+static inline void nvram_store(unsigned int offset, void *buf, unsigned int len)
+{
+ struct hv_rtas_call rtas = {
+ .token = store_token,
+ .nargs = 3,
+ .nrets = 2,
+ .argret = { offset, (uint32_t)(unsigned long)buf, len },
+ };
+ h_rtas(&rtas);
+}
+
+#define nvram_access(type,size,name) \
+ type nvram_read_##name(unsigned int offset) \
+ { \
+ type val; \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return 0; \
+ nvram_fetch(offset, &val, size / 8); \
+ return val; \
+ } \
+ void nvram_write_##name(unsigned int offset, type data) \
+ { \
+ if (offset > (NVRAM_LENGTH - sizeof(type))) \
+ return; \
+ nvram_store(offset, &data, size / 8); \
+ }
+
#else /* DISABLE_NVRAM */
static volatile uint8_t *nvram = (volatile uint8_t *)SB_NVRAM_adr;
@@ -83,12 +153,7 @@ nvram_access(uint16_t, 16, word)
nvram_access(uint32_t, 32, dword)
nvram_access(uint64_t, 64, qword)
-/*
- * This is extremely ugly, but still better than implementing
- * another sbrk() around it.
- */
-static char nvram_buffer[NVRAM_LENGTH];
-static uint8_t nvram_buffer_locked=0x00;
+
/**
* This function is a minimal abstraction for our temporary
@@ -184,7 +249,7 @@ static char * get_partition_name(int offset)
for (i=0; i<12; i++)
name[i]=nvram_read_byte(offset+4+i);
- // DEBUG("name: \"%s\"\n", name);
+ DEBUG("name: \"%s\"\n", name);
return name;
}
@@ -217,7 +282,7 @@ static int calc_used_nvram_space(void)
}
len=get_partition_len(walk);
- // DEBUG("... part len=%x, %x\n", len, len*16);
+ DEBUG("... part len=%x, %x\n", len, len*16);
if(!len) {
/* If there's a partition type but no len, bail out.
@@ -546,6 +611,13 @@ void reset_nvram(void)
void nvram_debug(void)
{
+#ifndef RTAS_NVRAM
printf("\nNVRAM_BASE: %p\n", nvram);
printf("NVRAM_LEN: 0x%x\n", NVRAM_LENGTH);
+#endif
+}
+
+unsigned int get_nvram_size(void)
+{
+ return NVRAM_LENGTH;
}
diff --git a/lib/libnvram/nvram.h b/lib/libnvram/nvram.h
index 1324809..fa6bdd4 100644
--- a/lib/libnvram/nvram.h
+++ b/lib/libnvram/nvram.h
@@ -60,6 +60,9 @@ int delete_nvram_partition(partition_t part);
void reset_nvram(void);
void wipe_nvram(void);
void nvram_debug(void);
+void nvram_init(uint32_t store_token, uint32_t fetch_token,
+ long nv_size, void* nvram_addr);
+unsigned int get_nvram_size(void);
/* envvar.c */
char *get_env(partition_t part, char *envvar);