summaryrefslogtreecommitdiffstats
path: root/core/hostservices.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/hostservices.c')
-rw-r--r--core/hostservices.c826
1 files changed, 826 insertions, 0 deletions
diff --git a/core/hostservices.c b/core/hostservices.c
new file mode 100644
index 00000000..85e62e31
--- /dev/null
+++ b/core/hostservices.c
@@ -0,0 +1,826 @@
+/* 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)
+
+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)
+{
+ prerror("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);
+ printf("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;
+
+ printf("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;
+
+ printf("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);
+}
+
+static int hservice_lid_load(uint32_t lid, void **buf, size_t *len)
+{
+ int rc;
+ static void *lid_cache;
+ static size_t lid_cache_len;
+ static uint32_t lid_cache_id;
+
+ printf("HBRT: LID load request for 0x%08x\n", lid);
+
+ /* Adjust LID side first or we get a cache mismatch */
+ lid = fsp_adjust_lid_side(lid);
+
+ /* Check for cache */
+ if (lid_cache && lid_cache_id == lid) {
+ *buf = lid_cache;
+ *len = lid_cache_len;
+ printf("HBRT: Serviced from cache, len=0x%lx\n", lid_cache_len);
+ return 0;
+ }
+
+ /* Cache mismatch, discard old one */
+ if (lid_cache) {
+ printf("HBRT: Cache mismatch, discarding old 0x%08x\n",
+ lid_cache_id);
+ free(lid_cache);
+ lid_cache = NULL;
+ }
+
+ /* Allocate a new buffer and load the LID into it */
+ *buf = malloc(HBRT_LOAD_LID_SIZE);
+ *len = HBRT_LOAD_LID_SIZE;
+ rc = fsp_fetch_data(0, FSP_DATASET_NONSP_LID, lid, 0, *buf, len);
+ if (rc != 0)
+ /* Take advantage of realloc corner case here. */
+ *len = 0;
+ *buf = realloc(*buf, *len);
+
+ /* We managed, let's cache it */
+ if (rc == 0 && *len) {
+ lid_cache = *buf;
+ lid_cache_len = *len;
+ lid_cache_id = lid;
+
+ printf("HBRT: LID 0x%08x successfully loaded and cached"
+ ", len=0x%lx\n", lid, lid_cache_len);
+ }
+
+ return rc;
+}
+
+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)
+ prerror("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(&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 neccessary
+ */
+ 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();
+ printf("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 neccessary
+ */
+ 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 targetting)
+ */
+ 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;
+ printf("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;
+ printf("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 */
+ printf("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;
+
+ printf("HBRT: OCC Load requested\n");
+
+ if (!(hservice_runtime && hservice_runtime->loadOCC)) {
+ prerror("HBRT: No hservice_runtime->loadOCC\n");
+ return -ENOENT;
+ }
+
+ for_each_chip(chip) {
+
+ printf("HBRT: [%16lx] Calling loadOCC() homer %016llx, occ_common_area %016llx, "
+ "chip %04x\n",
+ mftb(),
+ 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();
+ printf("HBRT: [%16lx] -> rc = %d\n", mftb(), 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];
+
+ printf("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;
+ }
+
+ printf("HBRT: [%16lx] Calling startOCC() for IDs: ", mftb());
+ for (i = 0; i < nr_chips; i++)
+ printf("%04llx ", chipids[i]);
+ printf("\n");
+
+ /* Lets start all OCC */
+ rc = hservice_runtime->startOCCs(chipids, nr_chips);
+ hservice_mark();
+ printf("HBRT: [%16lx] -> rc = %d\n", mftb(), rc);
+ 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);
+
+ printf("HBRT: Chip %d HOMER base %016llx : %08llx "
+ "OCC common base %016llx : %08llx\n",
+ chip->id, chip->homer_base, chip->homer_size,
+ 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;
+ }
+
+ printf("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 = 0;
+
+ hbrt_init = (void *)&fdesc;
+
+ hservice_runtime = hbrt_init(&hinterface);
+ hservice_mark();
+ if (!hservice_runtime) {
+ prerror("HBRT: Host services init failed\n");
+ return false;
+ }
+
+ printf("HBRT: Interface version %llu\n",
+ hservice_runtime->interface_version);
+
+ return true;
+}
OpenPOWER on IntegriCloud