blob: d1f6fda7ceadf764fec7a0e5d184093a22a1cec1 [file] [log] [blame]
/* Copyright 2013-2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <lock.h>
#include <device.h>
#include <compiler.h>
#include <hostservices.h>
#include <mem_region.h>
#include <xscom.h>
#include <fsp.h>
#include <chip.h>
#include <console.h>
#include <mem-map.h>
#include <timebase.h>
#define HOSTBOOT_RUNTIME_INTERFACE_VERSION 1
struct host_interfaces {
/** Interface version. */
uint64_t interface_version;
/** Put a string to the console. */
void (*puts)(const char*);
/** Critical failure in runtime execution. */
void (*assert)(void);
/** OPTIONAL. Hint to environment that the page may be executed. */
int (*set_page_execute)(void*);
/** malloc */
void *(*malloc)(size_t);
/** free */
void (*free)(void*);
/** realloc */
void *(*realloc)(void*, size_t);
/** sendErrorLog
* @param[in] plid Platform Log identifier
* @param[in] data size in bytes
* @param[in] pointer to data
* @return 0 on success else error code
*/
int (*send_error_log)(uint32_t,uint32_t,void *);
/** Scan communication read
* @param[in] chip_id (based on devtree defn)
* @param[in] address
* @param[in] pointer to 8-byte data buffer
* @return 0 on success else return code
*/
int (*scom_read)(uint64_t, uint64_t, void*);
/** Scan communication write
* @param[in] chip_id (based on devtree defn)
* @param[in] address
* @param[in] pointer to 8-byte data buffer
* @return 0 on success else return code
*/
int (*scom_write)(uint64_t, uint64_t, const void *);
/** lid_load
* Load a LID from PNOR, FSP, etc.
*
* @param[in] LID number.
* @param[out] Allocated buffer for LID.
* @param[out] Size of LID (in bytes).
*
* @return 0 on success, else RC.
*/
int (*lid_load)(uint32_t lid, void **buf, size_t *len);
/** lid_unload
* Release memory from previously loaded LID.
*
* @param[in] Allocated buffer for LID to release.
*
* @return 0 on success, else RC.
*/
int (*lid_unload)(void *buf);
/** Get the address of a reserved memory region by its devtree name.
*
* @param[in] Devtree name (ex. "ibm,hbrt-vpd-image")
* @return physical address of region (or NULL).
**/
uint64_t (*get_reserved_mem)(const char*);
/**
* @brief Force a core to be awake, or clear the force
* @param[in] i_core Core to wake up (pid)
* @param[in] i_mode 0=force awake
* 1=clear force
* 2=clear all previous forces
* @return rc non-zero on error
*/
int (*wakeup)( uint32_t i_core, uint32_t i_mode );
/**
* @brief Delay/sleep for at least the time given
* @param[in] seconds
* @param[in] nano seconds
*/
void (*nanosleep)(uint64_t i_seconds, uint64_t i_nano_seconds);
// Reserve some space for future growth.
void (*reserved[32])(void);
};
struct runtime_interfaces {
/** Interface version. */
uint64_t interface_version;
/** Execute CxxTests that may be contained in the image.
*
* @param[in] - Pointer to CxxTestStats structure for results reporting.
*/
void (*cxxtestExecute)(void *);
/** Get a list of lids numbers of the lids known to HostBoot
*
* @param[out] o_num - the number of lids in the list
* @return a pointer to the list
*/
const uint32_t * (*get_lid_list)(size_t * o_num);
/** Load OCC Image and common data into mainstore, also setup OCC BARSs
*
* @param[in] i_homer_addr_phys - The physical mainstore address of the
* start of the HOMER image
* @param[in] i_homer_addr_va - Virtual memory address of the HOMER image
* @param[in] i_common_addr_phys - The physical mainstore address of the
* OCC common area.
* @param[in] i_common_addr_va - Virtual memory address of the common area
* @param[in] i_chip - The HW chip id (XSCOM chip ID)
* @return 0 on success else return code
*/
int(*loadOCC)(uint64_t i_homer_addr_phys,
uint64_t i_homer_addr_va,
uint64_t i_common_addr_phys,
uint64_t i_common_addr_va,
uint64_t i_chip);
/** Start OCC on all chips, by module
*
* @param[in] i_chip - Array of functional HW chip ids
* @Note The caller must include a complete modules worth of chips
* @param[in] i_num_chips - Number of chips in the array
* @return 0 on success else return code
*/
int (*startOCCs)(uint64_t* i_chip,
size_t i_num_chips);
/** Stop OCC hold OCCs in reset
*
* @param[in] i_chip - Array of functional HW chip ids
* @Note The caller must include a complete modules worth of chips
* @param[in] i_num_chips - Number of chips in the array
* @return 0 on success else return code
*/
int (*stopOCCs)(uint64_t* i_chip,
size_t i_num_chips);
/* Reserve some space for future growth. */
void (*reserved[32])(void);
};
static struct runtime_interfaces *hservice_runtime;
static char *hbrt_con_buf = (char *)HBRT_CON_START;
static size_t hbrt_con_pos;
static bool hbrt_con_wrapped;
#define HBRT_CON_IN_LEN 0
#define HBRT_CON_OUT_LEN (HBRT_CON_LEN - HBRT_CON_IN_LEN)
static struct memcons hbrt_memcons __section(".data.memcons") = {
.magic = MEMCONS_MAGIC,
.obuf_phys = HBRT_CON_START,
.ibuf_phys = HBRT_CON_START + HBRT_CON_OUT_LEN,
.obuf_size = HBRT_CON_OUT_LEN,
.ibuf_size = HBRT_CON_IN_LEN,
};
static void hservice_putc(char c)
{
uint32_t opos;
hbrt_con_buf[hbrt_con_pos++] = c;
if (hbrt_con_pos >= HBRT_CON_OUT_LEN) {
hbrt_con_pos = 0;
hbrt_con_wrapped = true;
}
/*
* We must always re-generate memcons.out_pos because
* under some circumstances, the console script will
* use a broken putmemproc that does RMW on the full
* 8 bytes containing out_pos and in_prod, thus corrupting
* out_pos
*/
opos = hbrt_con_pos;
if (hbrt_con_wrapped)
opos |= MEMCONS_OUT_POS_WRAP;
lwsync();
hbrt_memcons.out_pos = opos;
}
static void hservice_puts(const char *str)
{
char c;
while((c = *(str++)) != 0)
hservice_putc(c);
hservice_putc(10);
}
static void hservice_mark(void)
{
hservice_puts("--------------------------------------------------"
"--------------------------------------------------\n");
}
static void hservice_assert(void)
{
/**
* @fwts-label HBRTassert
* @fwts-advice HBRT triggered assert: you need to debug HBRT
*/
prlog(PR_EMERG, "HBRT: Assertion from hostservices\n");
abort();
}
static void *hservice_malloc(size_t size)
{
return malloc(size);
}
static void hservice_free(void *ptr)
{
free(ptr);
}
static void *hservice_realloc(void *ptr, size_t size)
{
return realloc(ptr, size);
}
struct hbrt_elog_ent {
void *buf;
unsigned int size;
unsigned int plid;
struct list_node link;
};
static LIST_HEAD(hbrt_elogs);
static struct lock hbrt_elog_lock = LOCK_UNLOCKED;
static bool hbrt_elog_sending;
static void hservice_start_elog_send(void);
static void hservice_elog_write_complete(struct fsp_msg *msg)
{
struct hbrt_elog_ent *ent = msg->user_data;
lock(&hbrt_elog_lock);
prlog(PR_DEBUG, "HBRT: Completed send of PLID 0x%08x\n", ent->plid);
hbrt_elog_sending = false;
fsp_tce_unmap(PSI_DMA_HBRT_LOG_WRITE_BUF,
PSI_DMA_HBRT_LOG_WRITE_BUF_SZ);
free(ent->buf);
free(ent);
fsp_freemsg(msg);
hservice_start_elog_send();
unlock(&hbrt_elog_lock);
}
static void hservice_start_elog_send(void)
{
struct fsp_msg *msg;
struct hbrt_elog_ent *ent;
again:
if (list_empty(&hbrt_elogs))
return;
ent = list_pop(&hbrt_elogs, struct hbrt_elog_ent, link);
hbrt_elog_sending = true;
prlog(PR_DEBUG, "HBRT: Starting send of PLID 0x%08x\n", ent->plid);
fsp_tce_map(PSI_DMA_HBRT_LOG_WRITE_BUF, ent->buf,
PSI_DMA_HBRT_LOG_WRITE_BUF_SZ);
msg = fsp_mkmsg(FSP_CMD_WRITE_SP_DATA, 6, FSP_DATASET_HBRT_BLOB,
0, 0, 0, PSI_DMA_HBRT_LOG_WRITE_BUF,
ent->size);
if (!msg) {
prerror("HBRT: Failed to create error msg log to FSP\n");
goto error;
}
msg->user_data = ent;
if (!fsp_queue_msg(msg, hservice_elog_write_complete))
return;
prerror("FSP: Error queueing elog update\n");
error:
if (msg)
fsp_freemsg(msg);
fsp_tce_unmap(PSI_DMA_HBRT_LOG_WRITE_BUF,
PSI_DMA_HBRT_LOG_WRITE_BUF_SZ);
free(ent->buf);
free(ent);
hbrt_elog_sending = false;
goto again;
}
static int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data)
{
struct hbrt_elog_ent *ent;
void *abuf;
prlog(PR_ERR, "HBRT: Error log generated with plid 0x%08x\n", plid);
/* We only know how to send error logs to FSP */
if (!fsp_present()) {
prerror("HBRT: Warning, error log from HBRT discarded !\n");
return OPAL_UNSUPPORTED;
}
if (dsize > PSI_DMA_HBRT_LOG_WRITE_BUF_SZ) {
prerror("HBRT: Warning, error log from HBRT too big (%d) !\n",
dsize);
dsize = PSI_DMA_HBRT_LOG_WRITE_BUF_SZ;
}
lock(&hbrt_elog_lock);
/* Create and populate a tracking structure */
ent = zalloc(sizeof(struct hbrt_elog_ent));
if (!ent) {
unlock(&hbrt_elog_lock);
return OPAL_NO_MEM;
}
/* Grab a 4k aligned page */
abuf = memalign(0x1000, PSI_DMA_HBRT_LOG_WRITE_BUF_SZ);
if (!abuf) {
free(ent);
unlock(&hbrt_elog_lock);
return OPAL_NO_MEM;
}
memset(abuf, 0, PSI_DMA_HBRT_LOG_WRITE_BUF_SZ);
memcpy(abuf, data, dsize);
ent->buf = abuf;
ent->size = dsize;
ent->plid = plid;
list_add_tail(&hbrt_elogs, &ent->link);
if (!hbrt_elog_sending)
hservice_start_elog_send();
unlock(&hbrt_elog_lock);
return 0;
}
static int hservice_scom_read(uint64_t chip_id, uint64_t addr, void *buf)
{
return xscom_read(chip_id, addr, buf);
}
static int hservice_scom_write(uint64_t chip_id, uint64_t addr,
const void *buf)
{
uint64_t val;
memcpy(&val, buf, sizeof(val));
return xscom_write(chip_id, addr, val);
}
struct hbrt_lid {
void *load_addr;
size_t len;
uint32_t id;
struct list_node link;
};
static LIST_HEAD(hbrt_lid_list);
static bool hbrt_lid_preload_complete = false;
bool hservices_lid_preload_complete(void)
{
return hbrt_lid_preload_complete;
}
/* TODO: Few of the following routines can be generalized */
static int __hservice_lid_load(uint32_t lid, void **buf, size_t *len)
{
int rc;
/* Adjust LID side first or we get a cache mismatch */
lid = fsp_adjust_lid_side(lid);
/*
* Allocate a new buffer and load the LID into it
* XXX: We currently use the same size for each HBRT lid.
*/
*buf = malloc(HBRT_LOAD_LID_SIZE);
*len = HBRT_LOAD_LID_SIZE;
rc = fsp_preload_lid(lid, *buf, len);
rc = fsp_wait_lid_loaded(lid);
if (rc != 0)
/* Take advantage of realloc corner case here. */
*len = 0;
*buf = realloc(*buf, *len);
prlog(PR_DEBUG, "HBRT: LID 0x%08x successfully loaded, len=0x%lx\n",
lid, (unsigned long)len);
return rc;
}
static int __hservice_lid_preload(const uint32_t lid)
{
struct hbrt_lid *hlid;
void *buf;
size_t len;
int rc;
hlid = zalloc(sizeof(struct hbrt_lid));
if (!hlid) {
prerror("HBRT: Could not allocate struct hbrt_lid\n");
return OPAL_NO_MEM;
}
rc = __hservice_lid_load(lid, &buf, &len);
if (rc) {
free(hlid);
return rc;
}
hlid->load_addr = buf;
hlid->len = len;
hlid->id = lid;
list_add_tail(&hbrt_lid_list, &hlid->link);
return 0;
}
/* Find and preload all lids needed by hostservices */
void hservices_lid_preload(void)
{
const uint32_t *lid_list = NULL;
size_t num_lids;
int i;
if (!hservice_runtime)
return;
lid_list = (const uint32_t *)hservice_runtime->get_lid_list(&num_lids);
if (!lid_list) {
prerror("HBRT: get_lid_list() returned NULL\n");
return;
}
prlog(PR_INFO, "HBRT: %d lids to load\n", (int)num_lids);
/* Currently HBRT needs only one (OCC) lid */
for (i = 0; i < num_lids; i++)
__hservice_lid_preload(lid_list[i]);
hbrt_lid_preload_complete = true;
occ_poke_load_queue();
}
static int hservice_lid_load(uint32_t lid, void **buf, size_t *len)
{
struct hbrt_lid *hlid;
prlog(PR_INFO, "HBRT: Lid load request for 0x%08x\n", lid);
if (list_empty(&hbrt_lid_list)) { /* Should not happen */
/**
* @fwts-label HBRTlidLoadFail
* @fwts-advice Firmware should have aborted boot
*/
prlog(PR_CRIT, "HBRT: LID Load failed\n");
abort();
}
list_for_each(&hbrt_lid_list, hlid, link) {
if (hlid->id == lid) {
*buf = hlid->load_addr;
*len = hlid->len;
prlog(PR_DEBUG, "HBRT: LID Serviced from cache,"
" %x, len=0x%lx\n", hlid->id, hlid->len);
return 0;
}
}
return -ENOENT;
}
static int hservice_lid_unload(void *buf __unused)
{
/* We do nothing as the LID is held in cache */
return 0;
}
static uint64_t hservice_get_reserved_mem(const char *name)
{
struct mem_region *region;
uint64_t ret;
/* We assume it doesn't change after we've unlocked it, but
* lock ensures list is safe to walk. */
lock(&mem_region_lock);
region = find_mem_region(name);
ret = region ? region->start : 0;
unlock(&mem_region_lock);
if (!ret)
prlog(PR_WARNING, "HBRT: Mem region '%s' not found !\n", name);
return ret;
}
static void hservice_nanosleep(uint64_t i_seconds, uint64_t i_nano_seconds)
{
struct timespec ts;
ts.tv_sec = i_seconds;
ts.tv_nsec = i_nano_seconds;
nanosleep_nopoll(&ts, NULL);
}
static int hservice_set_special_wakeup(struct cpu_thread *cpu)
{
uint64_t val, core_id, poll_target, stamp;
int rc;
/*
* Note: HWP checks for checkstops, but I assume we don't need to
* as we wouldn't be running if one was present
*/
/* Grab core ID once */
core_id = pir_to_core_id(cpu->pir);
/*
* The original HWp reads the XSCOM first but ignores the result
* and error, let's do the same until I know for sure that is
* not necessary
*/
xscom_read(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
&val);
/* Then we write special wakeup */
rc = xscom_write(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id,
EX_PM_SPECIAL_WAKEUP_PHYP),
PPC_BIT(0));
if (rc) {
prerror("HBRT: XSCOM error %d asserting special"
" wakeup on 0x%x\n", rc, cpu->pir);
return rc;
}
/*
* HWP uses the history for Perf register here, dunno why it uses
* that one instead of the pHyp one, maybe to avoid clobbering it...
*
* In any case, it does that to check for run/nap vs.sleep/winkle/other
* to decide whether to poll on checkstop or not. Since we don't deal
* with checkstop conditions here, we ignore that part.
*/
/*
* Now poll for completion of special wakeup. The HWP is nasty here,
* it will poll at 5ms intervals for up to 200ms. This is not quite
* acceptable for us at runtime, at least not until we have the
* ability to "context switch" HBRT. In practice, because we don't
* winkle, it will never take that long, so we increase the polling
* frequency to 1us per poll. However we do have to keep the same
* timeout.
*
* We don't use time_wait_ms() either for now as we don't want to
* poll the FSP here.
*/
stamp = mftb();
poll_target = stamp + msecs_to_tb(200);
val = 0;
while (!(val & EX_PM_GP0_SPECIAL_WAKEUP_DONE)) {
/* Wait 1 us */
hservice_nanosleep(0, 1000);
/* Read PM state */
rc = xscom_read(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_GP0),
&val);
if (rc) {
prerror("HBRT: XSCOM error %d reading PM state on"
" 0x%x\n", rc, cpu->pir);
return rc;
}
/* Check timeout */
if (mftb() > poll_target)
break;
}
/* Success ? */
if (val & EX_PM_GP0_SPECIAL_WAKEUP_DONE) {
uint64_t now = mftb();
prlog(PR_TRACE, "HBRT: Special wakeup complete after %ld us\n",
tb_to_usecs(now - stamp));
return 0;
}
/*
* We timed out ...
*
* HWP has a complex workaround for HW255321 which affects
* Murano DD1 and Venice DD1. Ignore that for now
*
* Instead we just dump some XSCOMs for error logging
*/
prerror("HBRT: Timeout on special wakeup of 0x%0x\n", cpu->pir);
prerror("HBRT: PM0 = 0x%016llx\n", val);
val = -1;
xscom_read(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
&val);
prerror("HBRT: SPC_WKUP = 0x%016llx\n", val);
val = -1;
xscom_read(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id,
EX_PM_IDLE_STATE_HISTORY_PHYP),
&val);
prerror("HBRT: HISTORY = 0x%016llx\n", val);
return OPAL_HARDWARE;
}
static int hservice_clr_special_wakeup(struct cpu_thread *cpu)
{
uint64_t val, core_id;
int rc;
/*
* Note: HWP checks for checkstops, but I assume we don't need to
* as we wouldn't be running if one was present
*/
/* Grab core ID once */
core_id = pir_to_core_id(cpu->pir);
/*
* The original HWp reads the XSCOM first but ignores the result
* and error, let's do the same until I know for sure that is
* not necessary
*/
xscom_read(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
&val);
/* Then we write special wakeup */
rc = xscom_write(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id,
EX_PM_SPECIAL_WAKEUP_PHYP), 0);
if (rc) {
prerror("HBRT: XSCOM error %d deasserting"
" special wakeup on 0x%x\n", rc, cpu->pir);
return rc;
}
/*
* The original HWp reads the XSCOM again with the comment
* "This puts an inherent delay in the propagation of the reset
* transition"
*/
xscom_read(cpu->chip_id,
XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
&val);
return 0;
}
static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
{
struct cpu_thread *cpu;
int rc = OPAL_SUCCESS;
/*
* Mask out the top nibble of i_core since it may contain
* 0x4 (which we use for XSCOM targeting)
*/
i_core &= 0x0fffffff;
/* What do we need to do ? */
switch(i_mode) {
case 0: /* Assert special wakeup */
/* XXX Assume P8 */
cpu = find_cpu_by_pir(i_core << 3);
if (!cpu)
return OPAL_PARAMETER;
prlog(PR_DEBUG, "HBRT: Special wakeup assert for core 0x%x,"
" count=%d\n", i_core, cpu->hbrt_spec_wakeup);
if (cpu->hbrt_spec_wakeup == 0)
rc = hservice_set_special_wakeup(cpu);
if (rc == 0)
cpu->hbrt_spec_wakeup++;
return rc;
case 1: /* Deassert special wakeup */
/* XXX Assume P8 */
cpu = find_cpu_by_pir(i_core << 3);
if (!cpu)
return OPAL_PARAMETER;
prlog(PR_DEBUG, "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);
return OPAL_WRONG_STATE;
}
/* What to do with count on errors ? */
cpu->hbrt_spec_wakeup--;
if (cpu->hbrt_spec_wakeup == 0)
rc = hservice_clr_special_wakeup(cpu);
return rc;
case 2: /* Clear all special wakeups */
prlog(PR_DEBUG, "HBRT: Special wakeup release for all cores\n");
for_each_cpu(cpu) {
if (cpu->hbrt_spec_wakeup) {
cpu->hbrt_spec_wakeup = 0;
/* What to do on errors ? */
hservice_clr_special_wakeup(cpu);
}
}
return OPAL_SUCCESS;
default:
return OPAL_PARAMETER;
}
}
static struct host_interfaces hinterface = {
.interface_version = HOSTBOOT_RUNTIME_INTERFACE_VERSION,
.puts = hservice_puts,
.assert = hservice_assert,
.malloc = hservice_malloc,
.free = hservice_free,
.realloc = hservice_realloc,
.send_error_log = hservice_send_error_log,
.scom_read = hservice_scom_read,
.scom_write = hservice_scom_write,
.lid_load = hservice_lid_load,
.lid_unload = hservice_lid_unload,
.get_reserved_mem = hservice_get_reserved_mem,
.wakeup = hservice_wakeup,
.nanosleep = hservice_nanosleep,
};
int host_services_occ_load(void)
{
struct proc_chip *chip;
int rc = 0;
prlog(PR_DEBUG, "HBRT: OCC Load requested\n");
if (!(hservice_runtime && hservice_runtime->loadOCC)) {
prerror("HBRT: No hservice_runtime->loadOCC\n");
return -ENOENT;
}
for_each_chip(chip) {
prlog(PR_DEBUG, "HBRT: Calling loadOCC() homer"
" %016llx, occ_common_area %016llx, chip %04x\n",
chip->homer_base,
chip->occ_common_base,
chip->id);
rc = hservice_runtime->loadOCC(chip->homer_base,
chip->homer_base,
chip->occ_common_base,
chip->occ_common_base,
chip->id);
hservice_mark();
prlog(PR_DEBUG, "HBRT: -> rc = %d\n", rc);
}
return rc;
}
int host_services_occ_start(void)
{
struct proc_chip *chip;
int i, rc = 0, nr_chips=0;
uint64_t chipids[MAX_CHIPS];
prlog(PR_INFO, "HBRT: OCC Start requested\n");
if (!(hservice_runtime && hservice_runtime->startOCCs)) {
prerror("HBRT: No hservice_runtime->startOCCs\n");
return -ENOENT;
}
for_each_chip(chip) {
chipids[nr_chips++] = chip->id;
}
for (i = 0; i < nr_chips; i++)
prlog(PR_TRACE, "HBRT: Calling startOCC() for %04llx\n",
chipids[i]);
/* Lets start all OCC */
rc = hservice_runtime->startOCCs(chipids, nr_chips);
hservice_mark();
prlog(PR_DEBUG, "HBRT: startOCCs() rc = %d\n", rc);
return rc;
}
int host_services_occ_stop(void)
{
int i, rc = 0, nr_slaves = 0, nr_masters = 0;
uint64_t *master_chipids = NULL, *slave_chipids = NULL;
prlog(PR_INFO, "HBRT: OCC Stop requested\n");
if (!(hservice_runtime && hservice_runtime->stopOCCs)) {
prerror("HBRT: No hservice_runtime->stopOCCs\n");
return -ENOENT;
}
rc = find_master_and_slave_occ(&master_chipids, &slave_chipids,
&nr_masters, &nr_slaves);
if (rc)
goto out;
for (i = 0; i < nr_slaves; i++)
prlog(PR_TRACE, "HBRT: Calling stopOCC() for %04llx ",
slave_chipids[i]);
if (!nr_slaves)
goto master;
/* Lets STOP all the slave OCC */
rc = hservice_runtime->stopOCCs(slave_chipids, nr_slaves);
prlog(PR_DEBUG, "HBRT: stopOCCs() slave rc = %d\n", rc);
master:
for (i = 0; i < nr_masters; i++)
prlog(PR_TRACE, "HBRT: Calling stopOCC() for %04llx ",
master_chipids[i]);
/* Lets STOP all the master OCC */
rc = hservice_runtime->stopOCCs(master_chipids, nr_masters);
hservice_mark();
prlog(PR_DEBUG, "HBRT: stopOCCs() master rc = %d\n", rc);
out:
free(master_chipids);
free(slave_chipids);
return rc;
}
void host_services_occ_base_setup(void)
{
struct proc_chip *chip;
uint64_t occ_common;
chip = next_chip(NULL); /* Frist chip */
occ_common = (uint64_t) local_alloc(chip->id, OCC_COMMON_SIZE, OCC_COMMON_SIZE);
for_each_chip(chip) {
chip->occ_common_base = occ_common;
chip->occ_common_size = OCC_COMMON_SIZE;
chip->homer_base = (uint64_t) local_alloc(chip->id, HOMER_IMAGE_SIZE,
HOMER_IMAGE_SIZE);
chip->homer_size = HOMER_IMAGE_SIZE;
memset((void *)chip->homer_base, 0, chip->homer_size);
prlog(PR_DEBUG, "HBRT: Chip %d HOMER base %016llx : %08llx\n",
chip->id, chip->homer_base, chip->homer_size);
prlog(PR_DEBUG, "HBRT: OCC common base %016llx : %08llx\n",
chip->occ_common_base, chip->occ_common_size);
}
}
bool hservices_init(void)
{
void *code = NULL;
struct runtime_interfaces *(*hbrt_init)(struct host_interfaces *);
struct function_descriptor {
void *addr;
void *toc;
} fdesc;
code = (void *)hservice_get_reserved_mem("ibm,hbrt-code-image");
if (!code) {
prerror("HBRT: No ibm,hbrt-code-image found.\n");
return false;
}
if (memcmp(code, "HBRTVERS", 8) != 0) {
prerror("HBRT: Bad eyecatcher for ibm,hbrt-code-image!\n");
return false;
}
prlog(PR_INFO, "HBRT: Found HostBoot Runtime version %llu\n",
((u64 *)code)[1]);
/* We enter at 0x100 into the image. */
fdesc.addr = code + 0x100;
/* It doesn't care about TOC */
fdesc.toc = NULL;
hbrt_init = (void *)&fdesc;
hservice_runtime = hbrt_init(&hinterface);
hservice_mark();
if (!hservice_runtime) {
prerror("HBRT: Host services init failed\n");
return false;
}
prlog(PR_INFO, "HBRT: Interface version %llu\n",
hservice_runtime->interface_version);
return true;
}