aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm/head.S10
-rw-r--r--include/skiboot.h5
-rw-r--r--platforms/ibm-fsp/hostservices.c125
3 files changed, 134 insertions, 6 deletions
diff --git a/asm/head.S b/asm/head.S
index fa8933b..e968ac6 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -1124,3 +1124,13 @@ start_kernel_secondary:
mtspr SPR_HSRR1,%r10
mfspr %r3,SPR_PIR
hrfid
+
+.global restore_cpu_ptr_r16
+restore_cpu_ptr_r16:
+ GET_CPU()
+ blr
+
+.global set_cpu_ptr_r16
+set_cpu_ptr_r16:
+ mr %r16,%r3
+ blr
diff --git a/include/skiboot.h b/include/skiboot.h
index df11934..4f4a005 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -163,6 +163,11 @@ extern void start_kernel32(uint64_t entry, void* fdt,
uint64_t mem_top) __noreturn;
extern void start_kernel_secondary(uint64_t entry) __noreturn;
+/* Re-set r16 register with CPU pointer, based on stack (r1) value */
+extern void restore_cpu_ptr_r16(void);
+/* Set r16 register with value in 'r16' parameter */
+extern void set_cpu_ptr_r16(uint64_t r16);
+
/* Get description of machine from HDAT and create device-tree */
extern int parse_hdat(bool is_opal);
diff --git a/platforms/ibm-fsp/hostservices.c b/platforms/ibm-fsp/hostservices.c
index accc098..1aab668 100644
--- a/platforms/ibm-fsp/hostservices.c
+++ b/platforms/ibm-fsp/hostservices.c
@@ -168,6 +168,27 @@ struct runtime_interfaces {
void (*reserved[32])(void);
};
+/*
+ * The host interfaces are called by hostboot, which considers r16 a regular
+ * non-volatile register that it may have used at the time of the call.
+ * Skiboot requires r16 to be set to the CPU pointer while it runs. So the
+ * host interface handlers must save HBRT's r16, switch r16 to the CPU pointer,
+ * do their thing, and then restore HBRT's r16 value before returning.
+ */
+static uint64_t host_interface_pre_fixup(void)
+{
+ uint64_t r16 = (uint64_t)__this_cpu;
+
+ restore_cpu_ptr_r16();
+
+ return r16;
+}
+
+static void host_interface_post_fixup(uint64_t r16)
+{
+ set_cpu_ptr_r16(r16);
+}
+
static struct runtime_interfaces *hservice_runtime;
static char *hbrt_con_buf = (char *)HBRT_CON_START;
@@ -187,6 +208,7 @@ static struct memcons hbrt_memcons __section(".data.memcons") = {
static void hservice_putc(char c)
{
+ uint64_t r16 = host_interface_pre_fixup();
uint32_t opos;
hbrt_con_buf[hbrt_con_pos++] = c;
@@ -207,15 +229,20 @@ static void hservice_putc(char c)
opos |= MEMCONS_OUT_POS_WRAP;
lwsync();
hbrt_memcons.out_pos = cpu_to_be32(opos);
+
+ host_interface_post_fixup(r16);
}
static void hservice_puts(const char *str)
{
+ uint64_t r16 = host_interface_pre_fixup();
char c;
while((c = *(str++)) != 0)
hservice_putc(c);
hservice_putc(10);
+
+ host_interface_post_fixup(r16);
}
static void hservice_mark(void)
@@ -226,28 +253,48 @@ static void hservice_mark(void)
static void hservice_assert(void)
{
+ uint64_t r16 = host_interface_pre_fixup();
+
/**
* @fwts-label HBRTassert
* @fwts-advice HBRT triggered assert: you need to debug HBRT
*/
prlog(PR_EMERG, "HBRT: Assertion from hostservices\n");
abort();
+ /* Should not be reached... */
+ host_interface_post_fixup(r16);
}
static void *hservice_malloc(size_t size)
{
- return malloc(size);
+ uint64_t r16 = host_interface_pre_fixup();
+ void *mem;
+
+ mem = malloc(size);
+
+ host_interface_post_fixup(r16);
+
+ return mem;
}
static void hservice_free(void *ptr)
{
+ uint64_t r16 = host_interface_pre_fixup();
free(ptr);
+ host_interface_post_fixup(r16);
}
static void *hservice_realloc(void *ptr, size_t size)
{
- return realloc(ptr, size);
+ uint64_t r16 = host_interface_pre_fixup();
+ void *mem;
+
+ mem = realloc(ptr, size);
+
+ host_interface_post_fixup(r16);
+
+ return mem;
}
struct hbrt_elog_ent {
@@ -319,6 +366,7 @@ static void hservice_start_elog_send(void)
int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data)
{
+ uint64_t r16 = host_interface_pre_fixup();
struct hbrt_elog_ent *ent;
void *abuf;
@@ -327,6 +375,9 @@ int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data)
/* We only know how to send error logs to FSP */
if (!fsp_present()) {
prerror("HBRT: Warning, error log from HBRT discarded !\n");
+
+ host_interface_post_fixup(r16);
+
return OPAL_UNSUPPORTED;
}
if (dsize > PSI_DMA_HBRT_LOG_WRITE_BUF_SZ) {
@@ -341,6 +392,9 @@ int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data)
ent = zalloc(sizeof(struct hbrt_elog_ent));
if (!ent) {
unlock(&hbrt_elog_lock);
+
+ host_interface_post_fixup(r16);
+
return OPAL_NO_MEM;
}
@@ -349,6 +403,9 @@ int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data)
if (!abuf) {
free(ent);
unlock(&hbrt_elog_lock);
+
+ host_interface_post_fixup(r16);
+
return OPAL_NO_MEM;
}
memset(abuf, 0, PSI_DMA_HBRT_LOG_WRITE_BUF_SZ);
@@ -361,21 +418,36 @@ int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data)
hservice_start_elog_send();
unlock(&hbrt_elog_lock);
+ host_interface_post_fixup(r16);
+
return 0;
}
static int hservice_scom_read(uint64_t chip_id, uint64_t addr, void *buf)
{
- return xscom_read(chip_id, addr, buf);
+ uint64_t r16 = host_interface_pre_fixup();
+ int ret;
+
+ ret = xscom_read(chip_id, addr, buf);
+
+ host_interface_post_fixup(r16);
+
+ return ret;
}
static int hservice_scom_write(uint64_t chip_id, uint64_t addr,
const void *buf)
{
+ uint64_t r16 = host_interface_pre_fixup();
uint64_t val;
+ int ret;
memcpy(&val, buf, sizeof(val));
- return xscom_write(chip_id, addr, val);
+ ret = xscom_write(chip_id, addr, val);
+
+ host_interface_post_fixup(r16);
+
+ return ret;
}
struct hbrt_lid {
@@ -475,6 +547,7 @@ void hservices_lid_preload(void)
static int hservice_lid_load(uint32_t lid, void **buf, size_t *len)
{
+ uint64_t r16 = host_interface_pre_fixup();
struct hbrt_lid *hlid;
prlog(PR_INFO, "HBRT: Lid load request for 0x%08x\n", lid);
@@ -494,14 +567,24 @@ static int hservice_lid_load(uint32_t lid, void **buf, size_t *len)
*len = hlid->len;
prlog(PR_DEBUG, "HBRT: LID Serviced from cache,"
" %x, len=0x%lx\n", hlid->id, hlid->len);
+
+ host_interface_post_fixup(r16);
+
return 0;
}
}
+
+ host_interface_post_fixup(r16);
+
return -ENOENT;
}
static int hservice_lid_unload(void *buf __unused)
{
+ uint64_t r16 = host_interface_pre_fixup();
+
+ host_interface_post_fixup(r16);
+
/* We do nothing as the LID is held in cache */
return 0;
}
@@ -526,15 +609,19 @@ static uint64_t hservice_get_reserved_mem(const char *name)
static void hservice_nanosleep(uint64_t i_seconds, uint64_t i_nano_seconds)
{
+ uint64_t r16 = host_interface_pre_fixup();
struct timespec ts;
ts.tv_sec = i_seconds;
ts.tv_nsec = i_nano_seconds;
nanosleep_nopoll(&ts, NULL);
+
+ host_interface_post_fixup(r16);
}
int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
{
+ uint64_t r16 = host_interface_pre_fixup();
struct cpu_thread *cpu;
int rc = OPAL_SUCCESS;
@@ -556,6 +643,8 @@ int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
i_core <<= 2;
break;
default:
+ host_interface_post_fixup(r16);
+
return OPAL_UNSUPPORTED;
}
@@ -563,32 +652,49 @@ int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
switch(i_mode) {
case 0: /* Assert special wakeup */
cpu = find_cpu_by_pir(i_core);
- if (!cpu)
+ if (!cpu) {
+ host_interface_post_fixup(r16);
+
return OPAL_PARAMETER;
+ }
prlog(PR_TRACE, "HBRT: Special wakeup assert for core 0x%x,"
" count=%d\n", i_core, cpu->hbrt_spec_wakeup);
if (cpu->hbrt_spec_wakeup == 0)
rc = dctl_set_special_wakeup(cpu);
if (rc == 0)
cpu->hbrt_spec_wakeup++;
+
+ host_interface_post_fixup(r16);
+
return rc;
+
case 1: /* Deassert special wakeup */
cpu = find_cpu_by_pir(i_core);
- if (!cpu)
+ if (!cpu) {
+ host_interface_post_fixup(r16);
+
return OPAL_PARAMETER;
+ }
prlog(PR_TRACE, "HBRT: Special wakeup release for core"
" 0x%x, count=%d\n", i_core, cpu->hbrt_spec_wakeup);
if (cpu->hbrt_spec_wakeup == 0) {
prerror("HBRT: Special wakeup clear"
" on core 0x%x with count=0\n",
i_core);
+
+ host_interface_post_fixup(r16);
+
return OPAL_WRONG_STATE;
}
/* What to do with count on errors ? */
cpu->hbrt_spec_wakeup--;
if (cpu->hbrt_spec_wakeup == 0)
rc = dctl_clear_special_wakeup(cpu);
+
+ host_interface_post_fixup(r16);
+
return rc;
+
case 2: /* Clear all special wakeups */
prlog(PR_DEBUG, "HBRT: Special wakeup release for all cores\n");
for_each_cpu(cpu) {
@@ -598,8 +704,15 @@ int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
dctl_clear_special_wakeup(cpu);
}
}
+
+ host_interface_post_fixup(r16);
+
return OPAL_SUCCESS;
+
default:
+
+ host_interface_post_fixup(r16);
+
return OPAL_PARAMETER;
}
}