165 lines
4.6 KiB
C
165 lines
4.6 KiB
C
/* 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.
|
|
*/
|
|
|
|
/* FSP DPO (Delayed Power Off) event support */
|
|
|
|
#define pr_fmt(fmt) "FSP-DPO: " fmt
|
|
|
|
#include <skiboot.h>
|
|
#include <fsp.h>
|
|
#include <stdio.h>
|
|
#include <timebase.h>
|
|
#include <opal.h>
|
|
#include <opal-msg.h>
|
|
|
|
#define DPO_CMD_SGN_BYTE0 0xf4 /* Byte[0] signature */
|
|
#define DPO_CMD_SGN_BYTE1 0x20 /* Byte[1] signature */
|
|
#define DPO_TIMEOUT 2700 /* 45 minutes in seconds */
|
|
|
|
bool fsp_dpo_pending;
|
|
static unsigned long fsp_dpo_init_tb;
|
|
|
|
/*
|
|
* OPAL DPO interface
|
|
*
|
|
* Returns zero if DPO is not active, positive value indicating number
|
|
* of seconds remaining for a forced system shutdown. This will enable
|
|
* the host to schedule for shutdown voluntarily before timeout occurs.
|
|
*/
|
|
static int64_t fsp_opal_get_dpo_status(int64_t *dpo_timeout)
|
|
{
|
|
if (!fsp_dpo_pending) {
|
|
*dpo_timeout = 0;
|
|
return OPAL_WRONG_STATE;
|
|
}
|
|
|
|
*dpo_timeout = DPO_TIMEOUT - tb_to_secs(mftb() - fsp_dpo_init_tb);
|
|
return OPAL_SUCCESS;
|
|
}
|
|
|
|
/* Process FSP DPO init message */
|
|
static void fsp_process_dpo(struct fsp_msg *msg)
|
|
{
|
|
struct fsp_msg *resp;
|
|
u32 cmd = FSP_RSP_INIT_DPO;
|
|
int rc;
|
|
|
|
/* DPO message does not have the correct signatures */
|
|
if ((msg->data.bytes[0] != DPO_CMD_SGN_BYTE0)
|
|
|| (msg->data.bytes[1] != DPO_CMD_SGN_BYTE1)) {
|
|
prerror("Message signatures did not match\n");
|
|
cmd |= FSP_STATUS_INVALID_CMD;
|
|
resp = fsp_mkmsg(cmd, 0);
|
|
if (resp == NULL) {
|
|
prerror("%s : Message allocation failed\n", __func__);
|
|
return;
|
|
}
|
|
if (fsp_queue_msg(resp, fsp_freemsg)) {
|
|
fsp_freemsg(resp);
|
|
prerror("%s : Failed to queue response "
|
|
"message\n", __func__);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* OPAL is already in "DPO pending" state */
|
|
if (fsp_dpo_pending) {
|
|
prlog(PR_INFO, "OPAL already in DPO pending state\n");
|
|
cmd |= FSP_STATUS_INVALID_DPOSTATE;
|
|
resp = fsp_mkmsg(cmd, 0);
|
|
if (resp == NULL) {
|
|
prerror("%s : Message allocation failed\n", __func__);
|
|
return;
|
|
}
|
|
if (fsp_queue_msg(resp, fsp_freemsg)) {
|
|
fsp_freemsg(resp);
|
|
prerror("%s : Failed to queue response "
|
|
"message\n", __func__);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/* Inform the host about DPO */
|
|
rc = opal_queue_msg(OPAL_MSG_DPO, NULL, NULL);
|
|
if (rc) {
|
|
prerror("OPAL message queuing failed\n");
|
|
cmd |= FSP_STATUS_GENERIC_ERROR;
|
|
resp = fsp_mkmsg(cmd, 0);
|
|
if (resp == NULL) {
|
|
prerror("%s : Message allocation failed\n", __func__);
|
|
return;
|
|
}
|
|
if (fsp_queue_msg(resp, fsp_freemsg)) {
|
|
fsp_freemsg(resp);
|
|
prerror("%s : Failed to queue response "
|
|
"message\n", __func__);
|
|
}
|
|
return;
|
|
} else
|
|
prlog(PR_INFO, "Notified host about DPO event\n");
|
|
|
|
/* Acknowledge the FSP on DPO */
|
|
resp = fsp_mkmsg(cmd, 0);
|
|
if (resp == NULL) {
|
|
prerror("%s : Message allocation failed\n", __func__);
|
|
return;
|
|
}
|
|
if (fsp_queue_msg(resp, fsp_freemsg)) {
|
|
fsp_freemsg(resp);
|
|
prerror("%s : Failed to queue response message\n", __func__);
|
|
return;
|
|
}
|
|
|
|
/* Record DPO init time and set DPO pending flag */
|
|
fsp_dpo_init_tb = mftb();
|
|
fsp_dpo_pending = true;
|
|
|
|
/*
|
|
* OPAL is now in DPO pending state. After first detecting DPO
|
|
* condition from OPAL, the host will have 45 minutes to prepare
|
|
* the system for shutdown. The host must take all necessary actions
|
|
* required in that regard and at the end shutdown itself. The host
|
|
* shutdown sequence eventually will make the call OPAL_CEC_POWER_DOWN
|
|
* which in turn ask the FSP to shutdown the CEC. If the FSP does not
|
|
* receive the cec power down command from OPAL within 45 minutes,
|
|
* it will assume that the host and the OPAL has processed the DPO
|
|
* sequence successfully and hence force power off the system.
|
|
*/
|
|
}
|
|
|
|
/* Handle DPO sub-command from FSP */
|
|
static bool fsp_dpo_message(u32 cmd_sub_mod, struct fsp_msg *msg)
|
|
{
|
|
if (cmd_sub_mod == FSP_CMD_INIT_DPO) {
|
|
prlog(PR_INFO, "Delayed Power Off (DPO) notification received\n");
|
|
fsp_process_dpo(msg);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static struct fsp_client fsp_dpo_client = {
|
|
.message = fsp_dpo_message,
|
|
};
|
|
|
|
void fsp_dpo_init(void)
|
|
{
|
|
fsp_register_client(&fsp_dpo_client, FSP_MCLASS_SERVICE);
|
|
opal_register(OPAL_GET_DPO_STATUS, fsp_opal_get_dpo_status, 1);
|
|
prlog(PR_INFO, "FSP DPO support initialized\n");
|
|
}
|