blob: 2a206c8be27855cd2fccd1b791792a16aed9e32a [file] [log] [blame]
/* Copyright 2013-2016 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 <skiboot.h>
#include <opal.h>
#include <console.h>
#include <timebase.h>
#include <cpu.h>
#include <chip.h>
#include <xscom.h>
#include <errorlog.h>
#include <bt.h>
#include <nvram.h>
#include <platforms/astbmc/astbmc.h>
bool manufacturing_mode = false;
struct platform platform;
DEFINE_LOG_ENTRY(OPAL_RC_ABNORMAL_REBOOT, OPAL_PLATFORM_ERR_EVT, OPAL_CEC,
OPAL_CEC_HARDWARE, OPAL_PREDICTIVE_ERR_FAULT_RECTIFY_REBOOT,
OPAL_ABNORMAL_POWER_OFF);
/*
* Various wrappers for platform functions
*/
static int64_t opal_cec_power_down(uint64_t request)
{
prlog(PR_NOTICE, "OPAL: Shutdown request type 0x%llx...\n", request);
console_complete_flush();
if (platform.cec_power_down)
return platform.cec_power_down(request);
return OPAL_SUCCESS;
}
opal_call(OPAL_CEC_POWER_DOWN, opal_cec_power_down, 1);
static int64_t opal_cec_reboot(void)
{
prlog(PR_NOTICE, "OPAL: Reboot request...\n");
console_complete_flush();
/* Try a fast reset first, if enabled */
if (nvram_query_eq("experimental-fast-reset","feeling-lucky"))
fast_reboot();
if (platform.cec_reboot)
return platform.cec_reboot();
return OPAL_SUCCESS;
}
opal_call(OPAL_CEC_REBOOT, opal_cec_reboot, 0);
static int64_t opal_cec_reboot2(uint32_t reboot_type, char *diag)
{
struct errorlog *buf;
switch (reboot_type) {
case OPAL_REBOOT_NORMAL:
return opal_cec_reboot();
case OPAL_REBOOT_PLATFORM_ERROR:
prlog(PR_EMERG,
"OPAL: Reboot requested due to Platform error.\n");
buf = opal_elog_create(&e_info(OPAL_RC_ABNORMAL_REBOOT), 0);
if (buf) {
log_append_msg(buf,
"OPAL: Reboot requested due to Platform error.");
if (diag) {
/* Add user section "DESC" */
log_add_section(buf, 0x44455350);
log_append_data(buf, diag, strlen(diag));
log_commit(buf);
}
} else {
prerror("OPAL: failed to log an error\n");
}
disable_fast_reboot("Reboot due to Platform Error");
return xscom_trigger_xstop();
case OPAL_REBOOT_FULL_IPL:
disable_fast_reboot("full IPL reboot requested");
return opal_cec_reboot();
default:
prlog(PR_NOTICE, "OPAL: Unsupported reboot request %d\n", reboot_type);
return OPAL_UNSUPPORTED;
break;
}
return OPAL_SUCCESS;
}
opal_call(OPAL_CEC_REBOOT2, opal_cec_reboot2, 2);
static bool generic_platform_probe(void)
{
if (dt_find_by_path(dt_root, "bmc")) {
/* We appear to have a BMC... so let's cross our fingers
* and see if we can do anything!
*/
prlog(PR_ERR, "GENERIC BMC PLATFORM: **GUESSING** that there's "
"*maybe* a BMC we can talk to.\n");
prlog(PR_ERR, "THIS IS ****UNSUPPORTED****, BRINGUP USE ONLY.\n");
astbmc_early_init();
} else {
uart_init();
}
return true;
}
static void generic_platform_init(void)
{
if (uart_enabled())
set_opal_console(&uart_opal_con);
if (dt_find_by_path(dt_root, "bmc")) {
prlog(PR_ERR, "BMC-GUESSWORK: Here be dragons with a taste for human flesh\n");
astbmc_init();
} else {
/* Otherwise we go down the ultra-minimal path */
/* Enable a BT interface if we find one too */
bt_init();
}
/* Fake a real time clock */
fake_rtc_init();
}
static int64_t generic_cec_power_down(uint64_t request __unused)
{
return OPAL_UNSUPPORTED;
}
static int generic_resource_loaded(enum resource_id id, uint32_t subid)
{
if (dt_find_by_path(dt_root, "bmc"))
return flash_resource_loaded(id, subid);
return OPAL_EMPTY;
}
static int generic_start_preload_resource(enum resource_id id, uint32_t subid,
void *buf, size_t *len)
{
if (dt_find_by_path(dt_root, "bmc"))
return flash_start_preload_resource(id, subid, buf, len);
return OPAL_EMPTY;
}
static struct bmc_platform generic_bmc = {
.name = "generic",
};
static struct platform generic_platform = {
.name = "generic",
.bmc = &generic_bmc,
.probe = generic_platform_probe,
.init = generic_platform_init,
.nvram_info = fake_nvram_info,
.nvram_start_read = fake_nvram_start_read,
.nvram_write = fake_nvram_write,
.cec_power_down = generic_cec_power_down,
.start_preload_resource = generic_start_preload_resource,
.resource_loaded = generic_resource_loaded,
};
const struct bmc_platform *bmc_platform = &generic_bmc;
void set_bmc_platform(const struct bmc_platform *bmc)
{
if (bmc)
prlog(PR_NOTICE, "PLAT: Detected BMC platform %s\n", bmc->name);
else
bmc = &generic_bmc;
bmc_platform = bmc;
}
void probe_platform(void)
{
struct platform *platforms = &__platforms_start;
unsigned int i;
/* Detect Manufacturing mode */
if (dt_find_property(dt_root, "ibm,manufacturing-mode")) {
/**
* @fwts-label ManufacturingMode
* @fwts-advice You are running in manufacturing mode.
* This mode should only be enabled in a factory during
* manufacturing.
*/
prlog(PR_NOTICE, "PLAT: Manufacturing mode ON\n");
manufacturing_mode = true;
}
for (i = 0; &platforms[i] < &__platforms_end; i++) {
if (platforms[i].probe && platforms[i].probe()) {
platform = platforms[i];
break;
}
}
if (!platform.name) {
platform = generic_platform;
if (platform.probe)
platform.probe();
}
prlog(PR_NOTICE, "PLAT: Detected %s platform\n", platform.name);
set_bmc_platform(platform.bmc);
}
int start_preload_resource(enum resource_id id, uint32_t subid,
void *buf, size_t *len)
{
if (!platform.start_preload_resource)
return OPAL_UNSUPPORTED;
return platform.start_preload_resource(id, subid, buf, len);
}
int resource_loaded(enum resource_id id, uint32_t idx)
{
if (!platform.resource_loaded)
return OPAL_SUCCESS;
return platform.resource_loaded(id, idx);
}
int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
{
int r = resource_loaded(id, idx);
int waited = 0;
while(r == OPAL_BUSY) {
opal_run_pollers();
r = resource_loaded(id, idx);
if (r != OPAL_BUSY)
break;
time_wait_ms_nopoll(5);
waited+=5;
}
prlog(PR_TRACE, "PLATFORM: wait_for_resource_loaded %x/%x %u ms\n",
id, idx, waited);
return r;
}