// SPDX-License-Identifier: GPL-2.0-only /* * PS3 System Manager. * * Copyright (C) 2007 Sony Computer Entertainment Inc. * Copyright 2007 Sony Corp.
*/
/** * ps3_sys_manager - PS3 system manager driver. * * The system manager provides an asynchronous system event notification * mechanism for reporting events like thermal alert and button presses to * guests. It also provides support to control system shutdown and startup. * * The actual system manager is implemented as an application running in the * system policy module in lpar_1. Guests communicate with the system manager * through port 2 of the vuart using a simple packet message protocol. * Messages are comprised of a fixed field header followed by a message * specific payload.
*/
/** * struct ps3_sys_manager_header - System manager message header. * @version: Header version, currently 1. * @size: Header size in bytes, currently 16. * @payload_size: Message payload size in bytes. * @service_id: Message type, one of enum ps3_sys_manager_service_id. * @request_tag: Unique number to identify reply.
*/
/** * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. * * Currently all messages received from the system manager are either * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header * + 16 bytes payload = 32 bytes). This knowledge is used to simplify * the logic.
*/
/** * enum ps3_sys_manager_service_id - Message header service_id. * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. * * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when * a REQUEST message is sent at the wrong time.
*/
/** * enum ps3_sys_manager_attr - Notification attribute (bit position mask). * @PS3_SM_ATTR_POWER: Power button. * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. * @PS3_SM_ATTR_THERMAL: System thermal alert. * @PS3_SM_ATTR_CONTROLLER: Remote controller event. * @PS3_SM_ATTR_ALL: Logical OR of all. * * The guest tells the system manager which events it is interested in receiving * notice of by sending the system manager a logical OR of notification * attributes via the ps3_sys_manager_send_attr() routine.
*/
/** * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button. * @PS3_SM_WAKE_W_O_L: Ether or wireless LAN. * @PS3_SM_WAKE_P_O_R: Power on reset. * * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. * The system will always wake from the PS3_SM_WAKE_DEFAULT sources. * Sources listed here are the only ones available to guests in the * other-os lpar.
*/
/** * enum ps3_sys_manager_cmd - Command from system manager to guest. * * The guest completes the actions needed, then acks or naks the command via * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, * the guest must be fully prepared for a system poweroff prior to acking the * command.
*/
enum ps3_sys_manager_cmd { /* version 1 */
PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */
};
/** * ps3_sm_force_power_off - Poweroff helper. * * A global variable used to force a poweroff when the power button has * been pressed irrespective of how init handles the ctrl_alt_del signal. *
*/
staticunsignedint ps3_sm_force_power_off;
/** * ps3_sys_manager_write - Helper to write a two part message to the vuart. *
*/
/** * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. * * Tell the system manager what to do after this lpar is destroyed.
*/
/** * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. * * The guest sends this message to request an operation or action of the system * manager. The reply is a command message from the system manager. In the * command handler the guest performs the requested operation. The result of * the command is then communicated back to the system manager with a response * message. * * Currently, the only supported request is the 'shutdown self' request.
*/
/** * ps3_sys_manager_send_response - Send a 'response' to the system manager. * @status: zero = success, others fail. * * The guest sends this message to the system manager to acknowledge success or * failure of a command sent by the system manager.
*/
result = ps3_vuart_read(dev, &event, sizeof(event));
BUG_ON(result && "need to retry here");
if (event.version != 1) {
dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n",
__func__, __LINE__, event.version); return -EIO;
}
switch (event.type) { case PS3_SM_EVENT_POWER_PRESSED:
dev_dbg(&dev->core, "%s:%d: POWER_PRESSED (%s)\n",
__func__, __LINE__,
(event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft"
: "hard"));
ps3_sm_force_power_off = 1; /* * A memory barrier is use here to sync memory since * ps3_sys_manager_final_restart() could be called on * another cpu.
*/
wmb();
kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ break; case PS3_SM_EVENT_POWER_RELEASED:
dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n",
__func__, __LINE__, event.value); break; case PS3_SM_EVENT_RESET_PRESSED:
dev_dbg(&dev->core, "%s:%d: RESET_PRESSED (%s)\n",
__func__, __LINE__,
(event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft"
: "hard"));
ps3_sm_force_power_off = 0; /* * A memory barrier is use here to sync memory since * ps3_sys_manager_final_restart() could be called on * another cpu.
*/
wmb();
kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ break; case PS3_SM_EVENT_RESET_RELEASED:
dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n",
__func__, __LINE__, event.value); break; case PS3_SM_EVENT_THERMAL_ALERT:
dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
__func__, __LINE__, event.value);
pr_info("PS3 Thermal Alert Zone %u\n", event.value); break; case PS3_SM_EVENT_THERMAL_CLEARED:
dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n",
__func__, __LINE__, event.value); break; default:
dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n",
__func__, __LINE__, event.type); return -EIO;
}
return 0;
} /** * ps3_sys_manager_handle_cmd - Second stage command msg handler. * * The system manager sends this in reply to a 'request' message from the guest.
*/
pr_emerg("System Halted, OK to turn off power\n");
while (ps3_sys_manager_handle_msg(dev)) { /* pause until next DEC interrupt */
lv1_pause(0);
}
while (1) { /* pause, ignoring DEC interrupt */
lv1_pause(1);
}
}
/** * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. * * This routine never returns. The routine disables asynchronous vuart reads * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge * the shutdown command sent from the system manager. Soon after the * acknowledgement is sent the lpar is destroyed by the HV. This routine * should only be called from ps3_power_off() through * ps3_sys_manager_ops.power_off.
*/
/** * ps3_sys_manager_final_restart - The final platform machine_restart routine. * * This routine never returns. The routine disables asynchronous vuart reads * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge * the shutdown command sent from the system manager. Soon after the * acknowledgement is sent the lpar is destroyed by the HV. This routine * should only be called from ps3_restart() through ps3_sys_manager_ops.restart.
*/