diff options
author | Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com> | 2012-10-16 11:49:51 +0530 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2012-10-17 16:30:58 +1100 |
commit | 0ad10f26c94a86a0c9c3970e53f9a9f6a744055d (patch) | |
tree | 40b0d9d2ba55512071a9e713bd2db55b84a65ef6 /lib | |
parent | 7000cbc4e14aa891adbfdcc07b157e8c9ebb026c (diff) | |
download | SLOF-0ad10f26c94a86a0c9c3970e53f9a9f6a744055d.zip SLOF-0ad10f26c94a86a0c9c3970e53f9a9f6a744055d.tar.gz SLOF-0ad10f26c94a86a0c9c3970e53f9a9f6a744055d.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.code | 2 | ||||
-rw-r--r-- | lib/libbootmsg/bootmsg_lvl.S | 5 | ||||
-rw-r--r-- | lib/libhvcall/libhvcall.h | 14 | ||||
-rw-r--r-- | lib/libnvram/libnvram.code | 10 | ||||
-rw-r--r-- | lib/libnvram/libnvram.in | 1 | ||||
-rw-r--r-- | lib/libnvram/nvram.c | 88 | ||||
-rw-r--r-- | lib/libnvram/nvram.h | 3 |
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); |