18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PS3 System Manager. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Sony Computer Entertainment Inc. 68c2ecf20Sopenharmony_ci * Copyright 2007 Sony Corp. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 128c2ecf20Sopenharmony_ci#include <linux/reboot.h> 138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/firmware.h> 168c2ecf20Sopenharmony_ci#include <asm/lv1call.h> 178c2ecf20Sopenharmony_ci#include <asm/ps3.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "vuart.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/** 228c2ecf20Sopenharmony_ci * ps3_sys_manager - PS3 system manager driver. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * The system manager provides an asynchronous system event notification 258c2ecf20Sopenharmony_ci * mechanism for reporting events like thermal alert and button presses to 268c2ecf20Sopenharmony_ci * guests. It also provides support to control system shutdown and startup. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * The actual system manager is implemented as an application running in the 298c2ecf20Sopenharmony_ci * system policy module in lpar_1. Guests communicate with the system manager 308c2ecf20Sopenharmony_ci * through port 2 of the vuart using a simple packet message protocol. 318c2ecf20Sopenharmony_ci * Messages are comprised of a fixed field header followed by a message 328c2ecf20Sopenharmony_ci * specific payload. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * struct ps3_sys_manager_header - System manager message header. 378c2ecf20Sopenharmony_ci * @version: Header version, currently 1. 388c2ecf20Sopenharmony_ci * @size: Header size in bytes, currently 16. 398c2ecf20Sopenharmony_ci * @payload_size: Message payload size in bytes. 408c2ecf20Sopenharmony_ci * @service_id: Message type, one of enum ps3_sys_manager_service_id. 418c2ecf20Sopenharmony_ci * @request_tag: Unique number to identify reply. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct ps3_sys_manager_header { 458c2ecf20Sopenharmony_ci /* version 1 */ 468c2ecf20Sopenharmony_ci u8 version; 478c2ecf20Sopenharmony_ci u8 size; 488c2ecf20Sopenharmony_ci u16 reserved_1; 498c2ecf20Sopenharmony_ci u32 payload_size; 508c2ecf20Sopenharmony_ci u16 service_id; 518c2ecf20Sopenharmony_ci u16 reserved_2; 528c2ecf20Sopenharmony_ci u32 request_tag; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__) 568c2ecf20Sopenharmony_cistatic void __maybe_unused _dump_sm_header( 578c2ecf20Sopenharmony_ci const struct ps3_sys_manager_header *h, const char *func, int line) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci pr_debug("%s:%d: version: %xh\n", func, line, h->version); 608c2ecf20Sopenharmony_ci pr_debug("%s:%d: size: %xh\n", func, line, h->size); 618c2ecf20Sopenharmony_ci pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size); 628c2ecf20Sopenharmony_ci pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id); 638c2ecf20Sopenharmony_ci pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. 688c2ecf20Sopenharmony_ci * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Currently all messages received from the system manager are either 718c2ecf20Sopenharmony_ci * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header 728c2ecf20Sopenharmony_ci * + 16 bytes payload = 32 bytes). This knowledge is used to simplify 738c2ecf20Sopenharmony_ci * the logic. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cienum { 778c2ecf20Sopenharmony_ci PS3_SM_RX_MSG_LEN_MIN = 24, 788c2ecf20Sopenharmony_ci PS3_SM_RX_MSG_LEN_MAX = 32, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * enum ps3_sys_manager_service_id - Message header service_id. 838c2ecf20Sopenharmony_ci * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. 848c2ecf20Sopenharmony_ci * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. 858c2ecf20Sopenharmony_ci * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. 868c2ecf20Sopenharmony_ci * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. 878c2ecf20Sopenharmony_ci * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. 888c2ecf20Sopenharmony_ci * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. 898c2ecf20Sopenharmony_ci * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a 928c2ecf20Sopenharmony_ci * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when 938c2ecf20Sopenharmony_ci * a REQUEST message is sent at the wrong time. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cienum ps3_sys_manager_service_id { 978c2ecf20Sopenharmony_ci /* version 1 */ 988c2ecf20Sopenharmony_ci PS3_SM_SERVICE_ID_REQUEST = 1, 998c2ecf20Sopenharmony_ci PS3_SM_SERVICE_ID_RESPONSE = 2, 1008c2ecf20Sopenharmony_ci PS3_SM_SERVICE_ID_COMMAND = 3, 1018c2ecf20Sopenharmony_ci PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, 1028c2ecf20Sopenharmony_ci PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, 1038c2ecf20Sopenharmony_ci PS3_SM_SERVICE_ID_REQUEST_ERROR = 6, 1048c2ecf20Sopenharmony_ci PS3_SM_SERVICE_ID_SET_ATTR = 8, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * enum ps3_sys_manager_attr - Notification attribute (bit position mask). 1098c2ecf20Sopenharmony_ci * @PS3_SM_ATTR_POWER: Power button. 1108c2ecf20Sopenharmony_ci * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. 1118c2ecf20Sopenharmony_ci * @PS3_SM_ATTR_THERMAL: System thermal alert. 1128c2ecf20Sopenharmony_ci * @PS3_SM_ATTR_CONTROLLER: Remote controller event. 1138c2ecf20Sopenharmony_ci * @PS3_SM_ATTR_ALL: Logical OR of all. 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * The guest tells the system manager which events it is interested in receiving 1168c2ecf20Sopenharmony_ci * notice of by sending the system manager a logical OR of notification 1178c2ecf20Sopenharmony_ci * attributes via the ps3_sys_manager_send_attr() routine. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cienum ps3_sys_manager_attr { 1218c2ecf20Sopenharmony_ci /* version 1 */ 1228c2ecf20Sopenharmony_ci PS3_SM_ATTR_POWER = 1, 1238c2ecf20Sopenharmony_ci PS3_SM_ATTR_RESET = 2, 1248c2ecf20Sopenharmony_ci PS3_SM_ATTR_THERMAL = 4, 1258c2ecf20Sopenharmony_ci PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */ 1268c2ecf20Sopenharmony_ci PS3_SM_ATTR_ALL = 0x0f, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/** 1308c2ecf20Sopenharmony_ci * enum ps3_sys_manager_event - External event type, reported by system manager. 1318c2ecf20Sopenharmony_ci * @PS3_SM_EVENT_POWER_PRESSED: payload.value = 1328c2ecf20Sopenharmony_ci * enum ps3_sys_manager_button_event. 1338c2ecf20Sopenharmony_ci * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. 1348c2ecf20Sopenharmony_ci * @PS3_SM_EVENT_RESET_PRESSED: payload.value = 1358c2ecf20Sopenharmony_ci * enum ps3_sys_manager_button_event. 1368c2ecf20Sopenharmony_ci * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. 1378c2ecf20Sopenharmony_ci * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. 1388c2ecf20Sopenharmony_ci * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cienum ps3_sys_manager_event { 1428c2ecf20Sopenharmony_ci /* version 1 */ 1438c2ecf20Sopenharmony_ci PS3_SM_EVENT_POWER_PRESSED = 3, 1448c2ecf20Sopenharmony_ci PS3_SM_EVENT_POWER_RELEASED = 4, 1458c2ecf20Sopenharmony_ci PS3_SM_EVENT_RESET_PRESSED = 5, 1468c2ecf20Sopenharmony_ci PS3_SM_EVENT_RESET_RELEASED = 6, 1478c2ecf20Sopenharmony_ci PS3_SM_EVENT_THERMAL_ALERT = 7, 1488c2ecf20Sopenharmony_ci PS3_SM_EVENT_THERMAL_CLEARED = 8, 1498c2ecf20Sopenharmony_ci /* no info on controller events */ 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/** 1538c2ecf20Sopenharmony_ci * enum ps3_sys_manager_button_event - Button event payload values. 1548c2ecf20Sopenharmony_ci * @PS3_SM_BUTTON_EVENT_HARD: Hardware generated event. 1558c2ecf20Sopenharmony_ci * @PS3_SM_BUTTON_EVENT_SOFT: Software generated event. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cienum ps3_sys_manager_button_event { 1598c2ecf20Sopenharmony_ci PS3_SM_BUTTON_EVENT_HARD = 0, 1608c2ecf20Sopenharmony_ci PS3_SM_BUTTON_EVENT_SOFT = 1, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/** 1648c2ecf20Sopenharmony_ci * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cienum ps3_sys_manager_next_op { 1688c2ecf20Sopenharmony_ci /* version 3 */ 1698c2ecf20Sopenharmony_ci PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, 1708c2ecf20Sopenharmony_ci PS3_SM_NEXT_OP_SYS_REBOOT = 2, 1718c2ecf20Sopenharmony_ci PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/** 1758c2ecf20Sopenharmony_ci * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). 1768c2ecf20Sopenharmony_ci * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button. 1778c2ecf20Sopenharmony_ci * @PS3_SM_WAKE_W_O_L: Ether or wireless LAN. 1788c2ecf20Sopenharmony_ci * @PS3_SM_WAKE_P_O_R: Power on reset. 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. 1818c2ecf20Sopenharmony_ci * The system will always wake from the PS3_SM_WAKE_DEFAULT sources. 1828c2ecf20Sopenharmony_ci * Sources listed here are the only ones available to guests in the 1838c2ecf20Sopenharmony_ci * other-os lpar. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cienum ps3_sys_manager_wake_source { 1878c2ecf20Sopenharmony_ci /* version 3 */ 1888c2ecf20Sopenharmony_ci PS3_SM_WAKE_DEFAULT = 0, 1898c2ecf20Sopenharmony_ci PS3_SM_WAKE_W_O_L = 0x00000400, 1908c2ecf20Sopenharmony_ci PS3_SM_WAKE_P_O_R = 0x80000000, 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/** 1948c2ecf20Sopenharmony_ci * user_wake_sources - User specified wakeup sources. 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * Logical OR of enum ps3_sys_manager_wake_source types. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic u32 user_wake_sources = PS3_SM_WAKE_DEFAULT; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * enum ps3_sys_manager_cmd - Command from system manager to guest. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * The guest completes the actions needed, then acks or naks the command via 2058c2ecf20Sopenharmony_ci * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, 2068c2ecf20Sopenharmony_ci * the guest must be fully prepared for a system poweroff prior to acking the 2078c2ecf20Sopenharmony_ci * command. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cienum ps3_sys_manager_cmd { 2118c2ecf20Sopenharmony_ci /* version 1 */ 2128c2ecf20Sopenharmony_ci PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/** 2168c2ecf20Sopenharmony_ci * ps3_sm_force_power_off - Poweroff helper. 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * A global variable used to force a poweroff when the power button has 2198c2ecf20Sopenharmony_ci * been pressed irrespective of how init handles the ctrl_alt_del signal. 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic unsigned int ps3_sm_force_power_off; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/** 2268c2ecf20Sopenharmony_ci * ps3_sys_manager_write - Helper to write a two part message to the vuart. 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int ps3_sys_manager_write(struct ps3_system_bus_device *dev, 2318c2ecf20Sopenharmony_ci const struct ps3_sys_manager_header *header, const void *payload) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int result; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci BUG_ON(header->version != 1); 2368c2ecf20Sopenharmony_ci BUG_ON(header->size != 16); 2378c2ecf20Sopenharmony_ci BUG_ON(header->payload_size != 8 && header->payload_size != 16); 2388c2ecf20Sopenharmony_ci BUG_ON(header->service_id > 8); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci result = ps3_vuart_write(dev, header, 2418c2ecf20Sopenharmony_ci sizeof(struct ps3_sys_manager_header)); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!result) 2448c2ecf20Sopenharmony_ci result = ps3_vuart_write(dev, payload, header->payload_size); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return result; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/** 2508c2ecf20Sopenharmony_ci * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev, 2558c2ecf20Sopenharmony_ci enum ps3_sys_manager_attr attr) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct ps3_sys_manager_header header; 2588c2ecf20Sopenharmony_ci struct { 2598c2ecf20Sopenharmony_ci u8 version; 2608c2ecf20Sopenharmony_ci u8 reserved_1[3]; 2618c2ecf20Sopenharmony_ci u32 attribute; 2628c2ecf20Sopenharmony_ci } payload; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(payload) != 8); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci memset(&header, 0, sizeof(header)); 2698c2ecf20Sopenharmony_ci header.version = 1; 2708c2ecf20Sopenharmony_ci header.size = 16; 2718c2ecf20Sopenharmony_ci header.payload_size = 16; 2728c2ecf20Sopenharmony_ci header.service_id = PS3_SM_SERVICE_ID_SET_ATTR; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 2758c2ecf20Sopenharmony_ci payload.version = 1; 2768c2ecf20Sopenharmony_ci payload.attribute = attr; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return ps3_sys_manager_write(dev, &header, &payload); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/** 2828c2ecf20Sopenharmony_ci * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci * Tell the system manager what to do after this lpar is destroyed. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev, 2888c2ecf20Sopenharmony_ci enum ps3_sys_manager_next_op op, 2898c2ecf20Sopenharmony_ci enum ps3_sys_manager_wake_source wake_source) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct ps3_sys_manager_header header; 2928c2ecf20Sopenharmony_ci struct { 2938c2ecf20Sopenharmony_ci u8 version; 2948c2ecf20Sopenharmony_ci u8 type; 2958c2ecf20Sopenharmony_ci u8 gos_id; 2968c2ecf20Sopenharmony_ci u8 reserved_1; 2978c2ecf20Sopenharmony_ci u32 wake_source; 2988c2ecf20Sopenharmony_ci u8 reserved_2[8]; 2998c2ecf20Sopenharmony_ci } payload; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(payload) != 16); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci memset(&header, 0, sizeof(header)); 3068c2ecf20Sopenharmony_ci header.version = 1; 3078c2ecf20Sopenharmony_ci header.size = 16; 3088c2ecf20Sopenharmony_ci header.payload_size = 16; 3098c2ecf20Sopenharmony_ci header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 3128c2ecf20Sopenharmony_ci payload.version = 3; 3138c2ecf20Sopenharmony_ci payload.type = op; 3148c2ecf20Sopenharmony_ci payload.gos_id = 3; /* other os */ 3158c2ecf20Sopenharmony_ci payload.wake_source = wake_source; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return ps3_sys_manager_write(dev, &header, &payload); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/** 3218c2ecf20Sopenharmony_ci * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * The guest sends this message to request an operation or action of the system 3248c2ecf20Sopenharmony_ci * manager. The reply is a command message from the system manager. In the 3258c2ecf20Sopenharmony_ci * command handler the guest performs the requested operation. The result of 3268c2ecf20Sopenharmony_ci * the command is then communicated back to the system manager with a response 3278c2ecf20Sopenharmony_ci * message. 3288c2ecf20Sopenharmony_ci * 3298c2ecf20Sopenharmony_ci * Currently, the only supported request is the 'shutdown self' request. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int ps3_sys_manager_send_request_shutdown( 3338c2ecf20Sopenharmony_ci struct ps3_system_bus_device *dev) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct ps3_sys_manager_header header; 3368c2ecf20Sopenharmony_ci struct { 3378c2ecf20Sopenharmony_ci u8 version; 3388c2ecf20Sopenharmony_ci u8 type; 3398c2ecf20Sopenharmony_ci u8 gos_id; 3408c2ecf20Sopenharmony_ci u8 reserved_1[13]; 3418c2ecf20Sopenharmony_ci } payload; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(payload) != 16); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci memset(&header, 0, sizeof(header)); 3488c2ecf20Sopenharmony_ci header.version = 1; 3498c2ecf20Sopenharmony_ci header.size = 16; 3508c2ecf20Sopenharmony_ci header.payload_size = 16; 3518c2ecf20Sopenharmony_ci header.service_id = PS3_SM_SERVICE_ID_REQUEST; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 3548c2ecf20Sopenharmony_ci payload.version = 1; 3558c2ecf20Sopenharmony_ci payload.type = 1; /* shutdown */ 3568c2ecf20Sopenharmony_ci payload.gos_id = 0; /* self */ 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return ps3_sys_manager_write(dev, &header, &payload); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci/** 3628c2ecf20Sopenharmony_ci * ps3_sys_manager_send_response - Send a 'response' to the system manager. 3638c2ecf20Sopenharmony_ci * @status: zero = success, others fail. 3648c2ecf20Sopenharmony_ci * 3658c2ecf20Sopenharmony_ci * The guest sends this message to the system manager to acnowledge success or 3668c2ecf20Sopenharmony_ci * failure of a command sent by the system manager. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev, 3708c2ecf20Sopenharmony_ci u64 status) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct ps3_sys_manager_header header; 3738c2ecf20Sopenharmony_ci struct { 3748c2ecf20Sopenharmony_ci u8 version; 3758c2ecf20Sopenharmony_ci u8 reserved_1[3]; 3768c2ecf20Sopenharmony_ci u8 status; 3778c2ecf20Sopenharmony_ci u8 reserved_2[11]; 3788c2ecf20Sopenharmony_ci } payload; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(payload) != 16); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 3838c2ecf20Sopenharmony_ci (status ? "nak" : "ack")); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci memset(&header, 0, sizeof(header)); 3868c2ecf20Sopenharmony_ci header.version = 1; 3878c2ecf20Sopenharmony_ci header.size = 16; 3888c2ecf20Sopenharmony_ci header.payload_size = 16; 3898c2ecf20Sopenharmony_ci header.service_id = PS3_SM_SERVICE_ID_RESPONSE; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 3928c2ecf20Sopenharmony_ci payload.version = 1; 3938c2ecf20Sopenharmony_ci payload.status = status; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return ps3_sys_manager_write(dev, &header, &payload); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci/** 3998c2ecf20Sopenharmony_ci * ps3_sys_manager_handle_event - Second stage event msg handler. 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci int result; 4068c2ecf20Sopenharmony_ci struct { 4078c2ecf20Sopenharmony_ci u8 version; 4088c2ecf20Sopenharmony_ci u8 type; 4098c2ecf20Sopenharmony_ci u8 reserved_1[2]; 4108c2ecf20Sopenharmony_ci u32 value; 4118c2ecf20Sopenharmony_ci u8 reserved_2[8]; 4128c2ecf20Sopenharmony_ci } event; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(event) != 16); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci result = ps3_vuart_read(dev, &event, sizeof(event)); 4178c2ecf20Sopenharmony_ci BUG_ON(result && "need to retry here"); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (event.version != 1) { 4208c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", 4218c2ecf20Sopenharmony_ci __func__, __LINE__, event.version); 4228c2ecf20Sopenharmony_ci return -EIO; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci switch (event.type) { 4268c2ecf20Sopenharmony_ci case PS3_SM_EVENT_POWER_PRESSED: 4278c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: POWER_PRESSED (%s)\n", 4288c2ecf20Sopenharmony_ci __func__, __LINE__, 4298c2ecf20Sopenharmony_ci (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 4308c2ecf20Sopenharmony_ci : "hard")); 4318c2ecf20Sopenharmony_ci ps3_sm_force_power_off = 1; 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * A memory barrier is use here to sync memory since 4348c2ecf20Sopenharmony_ci * ps3_sys_manager_final_restart() could be called on 4358c2ecf20Sopenharmony_ci * another cpu. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci wmb(); 4388c2ecf20Sopenharmony_ci kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci case PS3_SM_EVENT_POWER_RELEASED: 4418c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", 4428c2ecf20Sopenharmony_ci __func__, __LINE__, event.value); 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci case PS3_SM_EVENT_RESET_PRESSED: 4458c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: RESET_PRESSED (%s)\n", 4468c2ecf20Sopenharmony_ci __func__, __LINE__, 4478c2ecf20Sopenharmony_ci (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 4488c2ecf20Sopenharmony_ci : "hard")); 4498c2ecf20Sopenharmony_ci ps3_sm_force_power_off = 0; 4508c2ecf20Sopenharmony_ci /* 4518c2ecf20Sopenharmony_ci * A memory barrier is use here to sync memory since 4528c2ecf20Sopenharmony_ci * ps3_sys_manager_final_restart() could be called on 4538c2ecf20Sopenharmony_ci * another cpu. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ci wmb(); 4568c2ecf20Sopenharmony_ci kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci case PS3_SM_EVENT_RESET_RELEASED: 4598c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n", 4608c2ecf20Sopenharmony_ci __func__, __LINE__, event.value); 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci case PS3_SM_EVENT_THERMAL_ALERT: 4638c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", 4648c2ecf20Sopenharmony_ci __func__, __LINE__, event.value); 4658c2ecf20Sopenharmony_ci pr_info("PS3 Thermal Alert Zone %u\n", event.value); 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case PS3_SM_EVENT_THERMAL_CLEARED: 4688c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", 4698c2ecf20Sopenharmony_ci __func__, __LINE__, event.value); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci default: 4728c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", 4738c2ecf20Sopenharmony_ci __func__, __LINE__, event.type); 4748c2ecf20Sopenharmony_ci return -EIO; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci/** 4808c2ecf20Sopenharmony_ci * ps3_sys_manager_handle_cmd - Second stage command msg handler. 4818c2ecf20Sopenharmony_ci * 4828c2ecf20Sopenharmony_ci * The system manager sends this in reply to a 'request' message from the guest. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci int result; 4888c2ecf20Sopenharmony_ci struct { 4898c2ecf20Sopenharmony_ci u8 version; 4908c2ecf20Sopenharmony_ci u8 type; 4918c2ecf20Sopenharmony_ci u8 reserved_1[14]; 4928c2ecf20Sopenharmony_ci } cmd; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(cmd) != 16); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); 4998c2ecf20Sopenharmony_ci BUG_ON(result && "need to retry here"); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (result) 5028c2ecf20Sopenharmony_ci return result; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (cmd.version != 1) { 5058c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", 5068c2ecf20Sopenharmony_ci __func__, __LINE__, cmd.version); 5078c2ecf20Sopenharmony_ci return -EIO; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (cmd.type != PS3_SM_CMD_SHUTDOWN) { 5118c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", 5128c2ecf20Sopenharmony_ci __func__, __LINE__, cmd.type); 5138c2ecf20Sopenharmony_ci return -EIO; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci ps3_sys_manager_send_response(dev, 0); 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/** 5218c2ecf20Sopenharmony_ci * ps3_sys_manager_handle_msg - First stage msg handler. 5228c2ecf20Sopenharmony_ci * 5238c2ecf20Sopenharmony_ci * Can be called directly to manually poll vuart and pump message handler. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci int result; 5298c2ecf20Sopenharmony_ci struct ps3_sys_manager_header header; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci result = ps3_vuart_read(dev, &header, 5328c2ecf20Sopenharmony_ci sizeof(struct ps3_sys_manager_header)); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (result) 5358c2ecf20Sopenharmony_ci return result; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (header.version != 1) { 5388c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", 5398c2ecf20Sopenharmony_ci __func__, __LINE__, header.version); 5408c2ecf20Sopenharmony_ci dump_sm_header(&header); 5418c2ecf20Sopenharmony_ci goto fail_header; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(header) != 16); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (header.size != 16 || (header.payload_size != 8 5478c2ecf20Sopenharmony_ci && header.payload_size != 16)) { 5488c2ecf20Sopenharmony_ci dump_sm_header(&header); 5498c2ecf20Sopenharmony_ci BUG(); 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci switch (header.service_id) { 5538c2ecf20Sopenharmony_ci case PS3_SM_SERVICE_ID_EXTERN_EVENT: 5548c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); 5558c2ecf20Sopenharmony_ci return ps3_sys_manager_handle_event(dev); 5568c2ecf20Sopenharmony_ci case PS3_SM_SERVICE_ID_COMMAND: 5578c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); 5588c2ecf20Sopenharmony_ci return ps3_sys_manager_handle_cmd(dev); 5598c2ecf20Sopenharmony_ci case PS3_SM_SERVICE_ID_REQUEST_ERROR: 5608c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__, 5618c2ecf20Sopenharmony_ci __LINE__); 5628c2ecf20Sopenharmony_ci dump_sm_header(&header); 5638c2ecf20Sopenharmony_ci break; 5648c2ecf20Sopenharmony_ci default: 5658c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", 5668c2ecf20Sopenharmony_ci __func__, __LINE__, header.service_id); 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci goto fail_id; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cifail_header: 5728c2ecf20Sopenharmony_ci ps3_vuart_clear_rx_bytes(dev, 0); 5738c2ecf20Sopenharmony_ci return -EIO; 5748c2ecf20Sopenharmony_cifail_id: 5758c2ecf20Sopenharmony_ci ps3_vuart_clear_rx_bytes(dev, header.payload_size); 5768c2ecf20Sopenharmony_ci return -EIO; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic void ps3_sys_manager_fin(struct ps3_system_bus_device *dev) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci ps3_sys_manager_send_request_shutdown(dev); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci pr_emerg("System Halted, OK to turn off power\n"); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci while (ps3_sys_manager_handle_msg(dev)) { 5868c2ecf20Sopenharmony_ci /* pause until next DEC interrupt */ 5878c2ecf20Sopenharmony_ci lv1_pause(0); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci while (1) { 5918c2ecf20Sopenharmony_ci /* pause, ignoring DEC interrupt */ 5928c2ecf20Sopenharmony_ci lv1_pause(1); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci/** 5978c2ecf20Sopenharmony_ci * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. 5988c2ecf20Sopenharmony_ci * 5998c2ecf20Sopenharmony_ci * This routine never returns. The routine disables asynchronous vuart reads 6008c2ecf20Sopenharmony_ci * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 6018c2ecf20Sopenharmony_ci * the shutdown command sent from the system manager. Soon after the 6028c2ecf20Sopenharmony_ci * acknowledgement is sent the lpar is destroyed by the HV. This routine 6038c2ecf20Sopenharmony_ci * should only be called from ps3_power_off() through 6048c2ecf20Sopenharmony_ci * ps3_sys_manager_ops.power_off. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci BUG_ON(!dev); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ps3_vuart_cancel_async(dev); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, 6168c2ecf20Sopenharmony_ci user_wake_sources); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci ps3_sys_manager_fin(dev); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci/** 6228c2ecf20Sopenharmony_ci * ps3_sys_manager_final_restart - The final platform machine_restart routine. 6238c2ecf20Sopenharmony_ci * 6248c2ecf20Sopenharmony_ci * This routine never returns. The routine disables asynchronous vuart reads 6258c2ecf20Sopenharmony_ci * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 6268c2ecf20Sopenharmony_ci * the shutdown command sent from the system manager. Soon after the 6278c2ecf20Sopenharmony_ci * acknowledgement is sent the lpar is destroyed by the HV. This routine 6288c2ecf20Sopenharmony_ci * should only be called from ps3_restart() through ps3_sys_manager_ops.restart. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci BUG_ON(!dev); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* Check if we got here via a power button event. */ 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (ps3_sm_force_power_off) { 6408c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: forcing poweroff\n", 6418c2ecf20Sopenharmony_ci __func__, __LINE__); 6428c2ecf20Sopenharmony_ci ps3_sys_manager_final_power_off(dev); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci ps3_vuart_cancel_async(dev); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci ps3_sys_manager_send_attr(dev, 0); 6488c2ecf20Sopenharmony_ci ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_REBOOT, 6498c2ecf20Sopenharmony_ci user_wake_sources); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci ps3_sys_manager_fin(dev); 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci/** 6558c2ecf20Sopenharmony_ci * ps3_sys_manager_get_wol - Get wake-on-lan setting. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ciint ps3_sys_manager_get_wol(void) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci pr_debug("%s:%d\n", __func__, __LINE__); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return (user_wake_sources & PS3_SM_WAKE_W_O_L) != 0; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_sys_manager_get_wol); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci/** 6678c2ecf20Sopenharmony_ci * ps3_sys_manager_set_wol - Set wake-on-lan setting. 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_civoid ps3_sys_manager_set_wol(int state) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci static DEFINE_MUTEX(mutex); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci mutex_lock(&mutex); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci pr_debug("%s:%d: %d\n", __func__, __LINE__, state); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (state) 6798c2ecf20Sopenharmony_ci user_wake_sources |= PS3_SM_WAKE_W_O_L; 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci user_wake_sources &= ~PS3_SM_WAKE_W_O_L; 6828c2ecf20Sopenharmony_ci mutex_unlock(&mutex); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_sys_manager_set_wol); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci/** 6878c2ecf20Sopenharmony_ci * ps3_sys_manager_work - Asynchronous read handler. 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic void ps3_sys_manager_work(struct ps3_system_bus_device *dev) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci ps3_sys_manager_handle_msg(dev); 6958c2ecf20Sopenharmony_ci ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci int result; 7018c2ecf20Sopenharmony_ci struct ps3_sys_manager_ops ops; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ops.power_off = ps3_sys_manager_final_power_off; 7068c2ecf20Sopenharmony_ci ops.restart = ps3_sys_manager_final_restart; 7078c2ecf20Sopenharmony_ci ops.dev = dev; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* ps3_sys_manager_register_ops copies ops. */ 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci ps3_sys_manager_register_ops(&ops); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); 7148c2ecf20Sopenharmony_ci BUG_ON(result); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 7178c2ecf20Sopenharmony_ci BUG_ON(result); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return result; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int ps3_sys_manager_remove(struct ps3_system_bus_device *dev) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic struct ps3_vuart_port_driver ps3_sys_manager = { 7348c2ecf20Sopenharmony_ci .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER, 7358c2ecf20Sopenharmony_ci .core.core.name = "ps3_sys_manager", 7368c2ecf20Sopenharmony_ci .probe = ps3_sys_manager_probe, 7378c2ecf20Sopenharmony_ci .remove = ps3_sys_manager_remove, 7388c2ecf20Sopenharmony_ci .shutdown = ps3_sys_manager_shutdown, 7398c2ecf20Sopenharmony_ci .work = ps3_sys_manager_work, 7408c2ecf20Sopenharmony_ci}; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int __init ps3_sys_manager_init(void) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 7458c2ecf20Sopenharmony_ci return -ENODEV; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci return ps3_vuart_port_driver_register(&ps3_sys_manager); 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cimodule_init(ps3_sys_manager_init); 7518c2ecf20Sopenharmony_ci/* Module remove not supported. */ 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sony Corporation"); 7548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 7558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PS3 System Manager"); 7568c2ecf20Sopenharmony_ciMODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER); 757