1*873e65bcSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 224828550SGeert Uytterhoeven /* 324828550SGeert Uytterhoeven * PS3 System Manager. 424828550SGeert Uytterhoeven * 524828550SGeert Uytterhoeven * Copyright (C) 2007 Sony Computer Entertainment Inc. 624828550SGeert Uytterhoeven * Copyright 2007 Sony Corp. 724828550SGeert Uytterhoeven */ 824828550SGeert Uytterhoeven 924828550SGeert Uytterhoeven #include <linux/kernel.h> 1024828550SGeert Uytterhoeven #include <linux/module.h> 1124828550SGeert Uytterhoeven #include <linux/workqueue.h> 1224828550SGeert Uytterhoeven #include <linux/reboot.h> 133f07c014SIngo Molnar #include <linux/sched/signal.h> 1424828550SGeert Uytterhoeven 1524828550SGeert Uytterhoeven #include <asm/firmware.h> 16ca052f79SGeert Uytterhoeven #include <asm/lv1call.h> 1724828550SGeert Uytterhoeven #include <asm/ps3.h> 1824828550SGeert Uytterhoeven 1924828550SGeert Uytterhoeven #include "vuart.h" 2024828550SGeert Uytterhoeven 2124828550SGeert Uytterhoeven /** 2224828550SGeert Uytterhoeven * ps3_sys_manager - PS3 system manager driver. 2324828550SGeert Uytterhoeven * 2424828550SGeert Uytterhoeven * The system manager provides an asynchronous system event notification 2524828550SGeert Uytterhoeven * mechanism for reporting events like thermal alert and button presses to 2624828550SGeert Uytterhoeven * guests. It also provides support to control system shutdown and startup. 2724828550SGeert Uytterhoeven * 2824828550SGeert Uytterhoeven * The actual system manager is implemented as an application running in the 2924828550SGeert Uytterhoeven * system policy module in lpar_1. Guests communicate with the system manager 3024828550SGeert Uytterhoeven * through port 2 of the vuart using a simple packet message protocol. 3124828550SGeert Uytterhoeven * Messages are comprised of a fixed field header followed by a message 3224828550SGeert Uytterhoeven * specific payload. 3324828550SGeert Uytterhoeven */ 3424828550SGeert Uytterhoeven 3524828550SGeert Uytterhoeven /** 3624828550SGeert Uytterhoeven * struct ps3_sys_manager_header - System manager message header. 3724828550SGeert Uytterhoeven * @version: Header version, currently 1. 38af901ca1SAndré Goddard Rosa * @size: Header size in bytes, currently 16. 3924828550SGeert Uytterhoeven * @payload_size: Message payload size in bytes. 4024828550SGeert Uytterhoeven * @service_id: Message type, one of enum ps3_sys_manager_service_id. 4124828550SGeert Uytterhoeven * @request_tag: Unique number to identify reply. 4224828550SGeert Uytterhoeven */ 4324828550SGeert Uytterhoeven 4424828550SGeert Uytterhoeven struct ps3_sys_manager_header { 4524828550SGeert Uytterhoeven /* version 1 */ 4624828550SGeert Uytterhoeven u8 version; 4724828550SGeert Uytterhoeven u8 size; 4824828550SGeert Uytterhoeven u16 reserved_1; 4924828550SGeert Uytterhoeven u32 payload_size; 5024828550SGeert Uytterhoeven u16 service_id; 5124828550SGeert Uytterhoeven u16 reserved_2; 5224828550SGeert Uytterhoeven u32 request_tag; 5324828550SGeert Uytterhoeven }; 5424828550SGeert Uytterhoeven 5524828550SGeert Uytterhoeven #define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__) 5624828550SGeert Uytterhoeven static void __maybe_unused _dump_sm_header( 5724828550SGeert Uytterhoeven const struct ps3_sys_manager_header *h, const char *func, int line) 5824828550SGeert Uytterhoeven { 5924828550SGeert Uytterhoeven pr_debug("%s:%d: version: %xh\n", func, line, h->version); 6024828550SGeert Uytterhoeven pr_debug("%s:%d: size: %xh\n", func, line, h->size); 6124828550SGeert Uytterhoeven pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size); 6224828550SGeert Uytterhoeven pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id); 6324828550SGeert Uytterhoeven pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag); 6424828550SGeert Uytterhoeven } 6524828550SGeert Uytterhoeven 6624828550SGeert Uytterhoeven /** 6724828550SGeert Uytterhoeven * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. 6824828550SGeert Uytterhoeven * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. 6924828550SGeert Uytterhoeven * 7024828550SGeert Uytterhoeven * Currently all messages received from the system manager are either 7124828550SGeert Uytterhoeven * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header 7225985edcSLucas De Marchi * + 16 bytes payload = 32 bytes). This knowledge is used to simplify 7324828550SGeert Uytterhoeven * the logic. 7424828550SGeert Uytterhoeven */ 7524828550SGeert Uytterhoeven 7624828550SGeert Uytterhoeven enum { 7724828550SGeert Uytterhoeven PS3_SM_RX_MSG_LEN_MIN = 24, 7824828550SGeert Uytterhoeven PS3_SM_RX_MSG_LEN_MAX = 32, 7924828550SGeert Uytterhoeven }; 8024828550SGeert Uytterhoeven 8124828550SGeert Uytterhoeven /** 8224828550SGeert Uytterhoeven * enum ps3_sys_manager_service_id - Message header service_id. 8324828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. 8424828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. 8524828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. 8624828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. 8724828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. 8824828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. 8924828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. 9024828550SGeert Uytterhoeven * 9124828550SGeert Uytterhoeven * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a 9224828550SGeert Uytterhoeven * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when 9324828550SGeert Uytterhoeven * a REQUEST message is sent at the wrong time. 9424828550SGeert Uytterhoeven */ 9524828550SGeert Uytterhoeven 9624828550SGeert Uytterhoeven enum ps3_sys_manager_service_id { 9724828550SGeert Uytterhoeven /* version 1 */ 9824828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_REQUEST = 1, 9924828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_RESPONSE = 2, 10024828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_COMMAND = 3, 10124828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, 10224828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, 10324828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_REQUEST_ERROR = 6, 10424828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_SET_ATTR = 8, 10524828550SGeert Uytterhoeven }; 10624828550SGeert Uytterhoeven 10724828550SGeert Uytterhoeven /** 10824828550SGeert Uytterhoeven * enum ps3_sys_manager_attr - Notification attribute (bit position mask). 10924828550SGeert Uytterhoeven * @PS3_SM_ATTR_POWER: Power button. 11024828550SGeert Uytterhoeven * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. 11188393161SThomas Weber * @PS3_SM_ATTR_THERMAL: System thermal alert. 11224828550SGeert Uytterhoeven * @PS3_SM_ATTR_CONTROLLER: Remote controller event. 11324828550SGeert Uytterhoeven * @PS3_SM_ATTR_ALL: Logical OR of all. 11424828550SGeert Uytterhoeven * 11524828550SGeert Uytterhoeven * The guest tells the system manager which events it is interested in receiving 11624828550SGeert Uytterhoeven * notice of by sending the system manager a logical OR of notification 11724828550SGeert Uytterhoeven * attributes via the ps3_sys_manager_send_attr() routine. 11824828550SGeert Uytterhoeven */ 11924828550SGeert Uytterhoeven 12024828550SGeert Uytterhoeven enum ps3_sys_manager_attr { 12124828550SGeert Uytterhoeven /* version 1 */ 12224828550SGeert Uytterhoeven PS3_SM_ATTR_POWER = 1, 12324828550SGeert Uytterhoeven PS3_SM_ATTR_RESET = 2, 12424828550SGeert Uytterhoeven PS3_SM_ATTR_THERMAL = 4, 12524828550SGeert Uytterhoeven PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */ 12624828550SGeert Uytterhoeven PS3_SM_ATTR_ALL = 0x0f, 12724828550SGeert Uytterhoeven }; 12824828550SGeert Uytterhoeven 12924828550SGeert Uytterhoeven /** 13024828550SGeert Uytterhoeven * enum ps3_sys_manager_event - External event type, reported by system manager. 131ea24608fSGeoff Levand * @PS3_SM_EVENT_POWER_PRESSED: payload.value = 132ea24608fSGeoff Levand * enum ps3_sys_manager_button_event. 13324828550SGeert Uytterhoeven * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. 134ea24608fSGeoff Levand * @PS3_SM_EVENT_RESET_PRESSED: payload.value = 135ea24608fSGeoff Levand * enum ps3_sys_manager_button_event. 13624828550SGeert Uytterhoeven * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. 13724828550SGeert Uytterhoeven * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. 13824828550SGeert Uytterhoeven * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. 13924828550SGeert Uytterhoeven */ 14024828550SGeert Uytterhoeven 14124828550SGeert Uytterhoeven enum ps3_sys_manager_event { 14224828550SGeert Uytterhoeven /* version 1 */ 14324828550SGeert Uytterhoeven PS3_SM_EVENT_POWER_PRESSED = 3, 14424828550SGeert Uytterhoeven PS3_SM_EVENT_POWER_RELEASED = 4, 14524828550SGeert Uytterhoeven PS3_SM_EVENT_RESET_PRESSED = 5, 14624828550SGeert Uytterhoeven PS3_SM_EVENT_RESET_RELEASED = 6, 14724828550SGeert Uytterhoeven PS3_SM_EVENT_THERMAL_ALERT = 7, 14824828550SGeert Uytterhoeven PS3_SM_EVENT_THERMAL_CLEARED = 8, 14924828550SGeert Uytterhoeven /* no info on controller events */ 15024828550SGeert Uytterhoeven }; 15124828550SGeert Uytterhoeven 15224828550SGeert Uytterhoeven /** 153ea24608fSGeoff Levand * enum ps3_sys_manager_button_event - Button event payload values. 154ea24608fSGeoff Levand * @PS3_SM_BUTTON_EVENT_HARD: Hardware generated event. 155ea24608fSGeoff Levand * @PS3_SM_BUTTON_EVENT_SOFT: Software generated event. 156ea24608fSGeoff Levand */ 157ea24608fSGeoff Levand 158ea24608fSGeoff Levand enum ps3_sys_manager_button_event { 159ea24608fSGeoff Levand PS3_SM_BUTTON_EVENT_HARD = 0, 160ea24608fSGeoff Levand PS3_SM_BUTTON_EVENT_SOFT = 1, 161ea24608fSGeoff Levand }; 162ea24608fSGeoff Levand 163ea24608fSGeoff Levand /** 16424828550SGeert Uytterhoeven * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. 16524828550SGeert Uytterhoeven */ 16624828550SGeert Uytterhoeven 16724828550SGeert Uytterhoeven enum ps3_sys_manager_next_op { 16824828550SGeert Uytterhoeven /* version 3 */ 16924828550SGeert Uytterhoeven PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, 17024828550SGeert Uytterhoeven PS3_SM_NEXT_OP_SYS_REBOOT = 2, 17124828550SGeert Uytterhoeven PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, 17224828550SGeert Uytterhoeven }; 17324828550SGeert Uytterhoeven 17424828550SGeert Uytterhoeven /** 17524828550SGeert Uytterhoeven * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). 1765442381cSGeoff Levand * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button. 1771c43d265SGeoff Levand * @PS3_SM_WAKE_W_O_L: Ether or wireless LAN. 17824828550SGeert Uytterhoeven * @PS3_SM_WAKE_P_O_R: Power on reset. 17924828550SGeert Uytterhoeven * 18024828550SGeert Uytterhoeven * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. 18150dad902SGeoff Levand * The system will always wake from the PS3_SM_WAKE_DEFAULT sources. 18250dad902SGeoff Levand * Sources listed here are the only ones available to guests in the 18350dad902SGeoff Levand * other-os lpar. 18424828550SGeert Uytterhoeven */ 18524828550SGeert Uytterhoeven 18624828550SGeert Uytterhoeven enum ps3_sys_manager_wake_source { 18724828550SGeert Uytterhoeven /* version 3 */ 18824828550SGeert Uytterhoeven PS3_SM_WAKE_DEFAULT = 0, 1891c43d265SGeoff Levand PS3_SM_WAKE_W_O_L = 0x00000400, 19050dad902SGeoff Levand PS3_SM_WAKE_P_O_R = 0x80000000, 19124828550SGeert Uytterhoeven }; 19224828550SGeert Uytterhoeven 19324828550SGeert Uytterhoeven /** 1941c43d265SGeoff Levand * user_wake_sources - User specified wakeup sources. 1951c43d265SGeoff Levand * 1961c43d265SGeoff Levand * Logical OR of enum ps3_sys_manager_wake_source types. 1971c43d265SGeoff Levand */ 1981c43d265SGeoff Levand 1991c43d265SGeoff Levand static u32 user_wake_sources = PS3_SM_WAKE_DEFAULT; 2001c43d265SGeoff Levand 2011c43d265SGeoff Levand /** 20224828550SGeert Uytterhoeven * enum ps3_sys_manager_cmd - Command from system manager to guest. 20324828550SGeert Uytterhoeven * 20424828550SGeert Uytterhoeven * The guest completes the actions needed, then acks or naks the command via 20524828550SGeert Uytterhoeven * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, 20624828550SGeert Uytterhoeven * the guest must be fully prepared for a system poweroff prior to acking the 20724828550SGeert Uytterhoeven * command. 20824828550SGeert Uytterhoeven */ 20924828550SGeert Uytterhoeven 21024828550SGeert Uytterhoeven enum ps3_sys_manager_cmd { 21124828550SGeert Uytterhoeven /* version 1 */ 21224828550SGeert Uytterhoeven PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ 21324828550SGeert Uytterhoeven }; 21424828550SGeert Uytterhoeven 21524828550SGeert Uytterhoeven /** 21624828550SGeert Uytterhoeven * ps3_sm_force_power_off - Poweroff helper. 21724828550SGeert Uytterhoeven * 21824828550SGeert Uytterhoeven * A global variable used to force a poweroff when the power button has 21924828550SGeert Uytterhoeven * been pressed irrespective of how init handles the ctrl_alt_del signal. 22024828550SGeert Uytterhoeven * 22124828550SGeert Uytterhoeven */ 22224828550SGeert Uytterhoeven 22324828550SGeert Uytterhoeven static unsigned int ps3_sm_force_power_off; 22424828550SGeert Uytterhoeven 22524828550SGeert Uytterhoeven /** 22624828550SGeert Uytterhoeven * ps3_sys_manager_write - Helper to write a two part message to the vuart. 22724828550SGeert Uytterhoeven * 22824828550SGeert Uytterhoeven */ 22924828550SGeert Uytterhoeven 23024828550SGeert Uytterhoeven static int ps3_sys_manager_write(struct ps3_system_bus_device *dev, 23124828550SGeert Uytterhoeven const struct ps3_sys_manager_header *header, const void *payload) 23224828550SGeert Uytterhoeven { 23324828550SGeert Uytterhoeven int result; 23424828550SGeert Uytterhoeven 23524828550SGeert Uytterhoeven BUG_ON(header->version != 1); 23624828550SGeert Uytterhoeven BUG_ON(header->size != 16); 23724828550SGeert Uytterhoeven BUG_ON(header->payload_size != 8 && header->payload_size != 16); 23824828550SGeert Uytterhoeven BUG_ON(header->service_id > 8); 23924828550SGeert Uytterhoeven 24024828550SGeert Uytterhoeven result = ps3_vuart_write(dev, header, 24124828550SGeert Uytterhoeven sizeof(struct ps3_sys_manager_header)); 24224828550SGeert Uytterhoeven 24324828550SGeert Uytterhoeven if (!result) 24424828550SGeert Uytterhoeven result = ps3_vuart_write(dev, payload, header->payload_size); 24524828550SGeert Uytterhoeven 24624828550SGeert Uytterhoeven return result; 24724828550SGeert Uytterhoeven } 24824828550SGeert Uytterhoeven 24924828550SGeert Uytterhoeven /** 25024828550SGeert Uytterhoeven * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. 25124828550SGeert Uytterhoeven * 25224828550SGeert Uytterhoeven */ 25324828550SGeert Uytterhoeven 25424828550SGeert Uytterhoeven static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev, 25524828550SGeert Uytterhoeven enum ps3_sys_manager_attr attr) 25624828550SGeert Uytterhoeven { 25724828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 25824828550SGeert Uytterhoeven struct { 25924828550SGeert Uytterhoeven u8 version; 26024828550SGeert Uytterhoeven u8 reserved_1[3]; 26124828550SGeert Uytterhoeven u32 attribute; 26224828550SGeert Uytterhoeven } payload; 26324828550SGeert Uytterhoeven 26424828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 8); 26524828550SGeert Uytterhoeven 26624828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); 26724828550SGeert Uytterhoeven 26824828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 26924828550SGeert Uytterhoeven header.version = 1; 27024828550SGeert Uytterhoeven header.size = 16; 27124828550SGeert Uytterhoeven header.payload_size = 16; 27224828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_SET_ATTR; 27324828550SGeert Uytterhoeven 27424828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 27524828550SGeert Uytterhoeven payload.version = 1; 27624828550SGeert Uytterhoeven payload.attribute = attr; 27724828550SGeert Uytterhoeven 27824828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 27924828550SGeert Uytterhoeven } 28024828550SGeert Uytterhoeven 28124828550SGeert Uytterhoeven /** 28224828550SGeert Uytterhoeven * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. 28324828550SGeert Uytterhoeven * 28424828550SGeert Uytterhoeven * Tell the system manager what to do after this lpar is destroyed. 28524828550SGeert Uytterhoeven */ 28624828550SGeert Uytterhoeven 28724828550SGeert Uytterhoeven static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev, 28824828550SGeert Uytterhoeven enum ps3_sys_manager_next_op op, 28924828550SGeert Uytterhoeven enum ps3_sys_manager_wake_source wake_source) 29024828550SGeert Uytterhoeven { 29124828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 29224828550SGeert Uytterhoeven struct { 29324828550SGeert Uytterhoeven u8 version; 29424828550SGeert Uytterhoeven u8 type; 29524828550SGeert Uytterhoeven u8 gos_id; 29624828550SGeert Uytterhoeven u8 reserved_1; 29724828550SGeert Uytterhoeven u32 wake_source; 29824828550SGeert Uytterhoeven u8 reserved_2[8]; 29924828550SGeert Uytterhoeven } payload; 30024828550SGeert Uytterhoeven 30124828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 30224828550SGeert Uytterhoeven 30324828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); 30424828550SGeert Uytterhoeven 30524828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 30624828550SGeert Uytterhoeven header.version = 1; 30724828550SGeert Uytterhoeven header.size = 16; 30824828550SGeert Uytterhoeven header.payload_size = 16; 30924828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP; 31024828550SGeert Uytterhoeven 31124828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 31224828550SGeert Uytterhoeven payload.version = 3; 31324828550SGeert Uytterhoeven payload.type = op; 31424828550SGeert Uytterhoeven payload.gos_id = 3; /* other os */ 31524828550SGeert Uytterhoeven payload.wake_source = wake_source; 31624828550SGeert Uytterhoeven 31724828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 31824828550SGeert Uytterhoeven } 31924828550SGeert Uytterhoeven 32024828550SGeert Uytterhoeven /** 32124828550SGeert Uytterhoeven * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. 32224828550SGeert Uytterhoeven * 32324828550SGeert Uytterhoeven * The guest sends this message to request an operation or action of the system 32424828550SGeert Uytterhoeven * manager. The reply is a command message from the system manager. In the 32524828550SGeert Uytterhoeven * command handler the guest performs the requested operation. The result of 32624828550SGeert Uytterhoeven * the command is then communicated back to the system manager with a response 32724828550SGeert Uytterhoeven * message. 32824828550SGeert Uytterhoeven * 32924828550SGeert Uytterhoeven * Currently, the only supported request is the 'shutdown self' request. 33024828550SGeert Uytterhoeven */ 33124828550SGeert Uytterhoeven 33224828550SGeert Uytterhoeven static int ps3_sys_manager_send_request_shutdown( 33324828550SGeert Uytterhoeven struct ps3_system_bus_device *dev) 33424828550SGeert Uytterhoeven { 33524828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 33624828550SGeert Uytterhoeven struct { 33724828550SGeert Uytterhoeven u8 version; 33824828550SGeert Uytterhoeven u8 type; 33924828550SGeert Uytterhoeven u8 gos_id; 34024828550SGeert Uytterhoeven u8 reserved_1[13]; 34124828550SGeert Uytterhoeven } payload; 34224828550SGeert Uytterhoeven 34324828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 34424828550SGeert Uytterhoeven 34524828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 34624828550SGeert Uytterhoeven 34724828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 34824828550SGeert Uytterhoeven header.version = 1; 34924828550SGeert Uytterhoeven header.size = 16; 35024828550SGeert Uytterhoeven header.payload_size = 16; 35124828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_REQUEST; 35224828550SGeert Uytterhoeven 35324828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 35424828550SGeert Uytterhoeven payload.version = 1; 35524828550SGeert Uytterhoeven payload.type = 1; /* shutdown */ 35624828550SGeert Uytterhoeven payload.gos_id = 0; /* self */ 35724828550SGeert Uytterhoeven 35824828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 35924828550SGeert Uytterhoeven } 36024828550SGeert Uytterhoeven 36124828550SGeert Uytterhoeven /** 36224828550SGeert Uytterhoeven * ps3_sys_manager_send_response - Send a 'response' to the system manager. 36324828550SGeert Uytterhoeven * @status: zero = success, others fail. 36424828550SGeert Uytterhoeven * 36524828550SGeert Uytterhoeven * The guest sends this message to the system manager to acnowledge success or 36624828550SGeert Uytterhoeven * failure of a command sent by the system manager. 36724828550SGeert Uytterhoeven */ 36824828550SGeert Uytterhoeven 36924828550SGeert Uytterhoeven static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev, 37024828550SGeert Uytterhoeven u64 status) 37124828550SGeert Uytterhoeven { 37224828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 37324828550SGeert Uytterhoeven struct { 37424828550SGeert Uytterhoeven u8 version; 37524828550SGeert Uytterhoeven u8 reserved_1[3]; 37624828550SGeert Uytterhoeven u8 status; 37724828550SGeert Uytterhoeven u8 reserved_2[11]; 37824828550SGeert Uytterhoeven } payload; 37924828550SGeert Uytterhoeven 38024828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 38124828550SGeert Uytterhoeven 38224828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 38324828550SGeert Uytterhoeven (status ? "nak" : "ack")); 38424828550SGeert Uytterhoeven 38524828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 38624828550SGeert Uytterhoeven header.version = 1; 38724828550SGeert Uytterhoeven header.size = 16; 38824828550SGeert Uytterhoeven header.payload_size = 16; 38924828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_RESPONSE; 39024828550SGeert Uytterhoeven 39124828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 39224828550SGeert Uytterhoeven payload.version = 1; 39324828550SGeert Uytterhoeven payload.status = status; 39424828550SGeert Uytterhoeven 39524828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 39624828550SGeert Uytterhoeven } 39724828550SGeert Uytterhoeven 39824828550SGeert Uytterhoeven /** 39924828550SGeert Uytterhoeven * ps3_sys_manager_handle_event - Second stage event msg handler. 40024828550SGeert Uytterhoeven * 40124828550SGeert Uytterhoeven */ 40224828550SGeert Uytterhoeven 40324828550SGeert Uytterhoeven static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) 40424828550SGeert Uytterhoeven { 40524828550SGeert Uytterhoeven int result; 40624828550SGeert Uytterhoeven struct { 40724828550SGeert Uytterhoeven u8 version; 40824828550SGeert Uytterhoeven u8 type; 40924828550SGeert Uytterhoeven u8 reserved_1[2]; 41024828550SGeert Uytterhoeven u32 value; 41124828550SGeert Uytterhoeven u8 reserved_2[8]; 41224828550SGeert Uytterhoeven } event; 41324828550SGeert Uytterhoeven 41424828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(event) != 16); 41524828550SGeert Uytterhoeven 41624828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &event, sizeof(event)); 41724828550SGeert Uytterhoeven BUG_ON(result && "need to retry here"); 41824828550SGeert Uytterhoeven 41924828550SGeert Uytterhoeven if (event.version != 1) { 42024828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", 42124828550SGeert Uytterhoeven __func__, __LINE__, event.version); 42224828550SGeert Uytterhoeven return -EIO; 42324828550SGeert Uytterhoeven } 42424828550SGeert Uytterhoeven 42524828550SGeert Uytterhoeven switch (event.type) { 42624828550SGeert Uytterhoeven case PS3_SM_EVENT_POWER_PRESSED: 427ea24608fSGeoff Levand dev_dbg(&dev->core, "%s:%d: POWER_PRESSED (%s)\n", 428ea24608fSGeoff Levand __func__, __LINE__, 429ea24608fSGeoff Levand (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 430ea24608fSGeoff Levand : "hard")); 43124828550SGeert Uytterhoeven ps3_sm_force_power_off = 1; 43224828550SGeert Uytterhoeven /* 43324828550SGeert Uytterhoeven * A memory barrier is use here to sync memory since 43424828550SGeert Uytterhoeven * ps3_sys_manager_final_restart() could be called on 43524828550SGeert Uytterhoeven * another cpu. 43624828550SGeert Uytterhoeven */ 43724828550SGeert Uytterhoeven wmb(); 43824828550SGeert Uytterhoeven kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 43924828550SGeert Uytterhoeven break; 44024828550SGeert Uytterhoeven case PS3_SM_EVENT_POWER_RELEASED: 44124828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", 44224828550SGeert Uytterhoeven __func__, __LINE__, event.value); 44324828550SGeert Uytterhoeven break; 44424828550SGeert Uytterhoeven case PS3_SM_EVENT_RESET_PRESSED: 445ea24608fSGeoff Levand dev_dbg(&dev->core, "%s:%d: RESET_PRESSED (%s)\n", 446ea24608fSGeoff Levand __func__, __LINE__, 447ea24608fSGeoff Levand (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 448ea24608fSGeoff Levand : "hard")); 44924828550SGeert Uytterhoeven ps3_sm_force_power_off = 0; 45024828550SGeert Uytterhoeven /* 45124828550SGeert Uytterhoeven * A memory barrier is use here to sync memory since 45224828550SGeert Uytterhoeven * ps3_sys_manager_final_restart() could be called on 45324828550SGeert Uytterhoeven * another cpu. 45424828550SGeert Uytterhoeven */ 45524828550SGeert Uytterhoeven wmb(); 45624828550SGeert Uytterhoeven kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 45724828550SGeert Uytterhoeven break; 45824828550SGeert Uytterhoeven case PS3_SM_EVENT_RESET_RELEASED: 45924828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n", 46024828550SGeert Uytterhoeven __func__, __LINE__, event.value); 46124828550SGeert Uytterhoeven break; 46224828550SGeert Uytterhoeven case PS3_SM_EVENT_THERMAL_ALERT: 46324828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", 46424828550SGeert Uytterhoeven __func__, __LINE__, event.value); 465eff56c92SGeert Uytterhoeven pr_info("PS3 Thermal Alert Zone %u\n", event.value); 46624828550SGeert Uytterhoeven break; 46724828550SGeert Uytterhoeven case PS3_SM_EVENT_THERMAL_CLEARED: 46824828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", 46924828550SGeert Uytterhoeven __func__, __LINE__, event.value); 47024828550SGeert Uytterhoeven break; 47124828550SGeert Uytterhoeven default: 47224828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", 47324828550SGeert Uytterhoeven __func__, __LINE__, event.type); 47424828550SGeert Uytterhoeven return -EIO; 47524828550SGeert Uytterhoeven } 47624828550SGeert Uytterhoeven 47724828550SGeert Uytterhoeven return 0; 47824828550SGeert Uytterhoeven } 47924828550SGeert Uytterhoeven /** 48024828550SGeert Uytterhoeven * ps3_sys_manager_handle_cmd - Second stage command msg handler. 48124828550SGeert Uytterhoeven * 48224828550SGeert Uytterhoeven * The system manager sends this in reply to a 'request' message from the guest. 48324828550SGeert Uytterhoeven */ 48424828550SGeert Uytterhoeven 48524828550SGeert Uytterhoeven static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev) 48624828550SGeert Uytterhoeven { 48724828550SGeert Uytterhoeven int result; 48824828550SGeert Uytterhoeven struct { 48924828550SGeert Uytterhoeven u8 version; 49024828550SGeert Uytterhoeven u8 type; 49124828550SGeert Uytterhoeven u8 reserved_1[14]; 49224828550SGeert Uytterhoeven } cmd; 49324828550SGeert Uytterhoeven 49424828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(cmd) != 16); 49524828550SGeert Uytterhoeven 49624828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 49724828550SGeert Uytterhoeven 49824828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); 49924828550SGeert Uytterhoeven BUG_ON(result && "need to retry here"); 50024828550SGeert Uytterhoeven 50124828550SGeert Uytterhoeven if (result) 50224828550SGeert Uytterhoeven return result; 50324828550SGeert Uytterhoeven 50424828550SGeert Uytterhoeven if (cmd.version != 1) { 50524828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", 50624828550SGeert Uytterhoeven __func__, __LINE__, cmd.version); 50724828550SGeert Uytterhoeven return -EIO; 50824828550SGeert Uytterhoeven } 50924828550SGeert Uytterhoeven 51024828550SGeert Uytterhoeven if (cmd.type != PS3_SM_CMD_SHUTDOWN) { 51124828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", 51224828550SGeert Uytterhoeven __func__, __LINE__, cmd.type); 51324828550SGeert Uytterhoeven return -EIO; 51424828550SGeert Uytterhoeven } 51524828550SGeert Uytterhoeven 51624828550SGeert Uytterhoeven ps3_sys_manager_send_response(dev, 0); 51724828550SGeert Uytterhoeven return 0; 51824828550SGeert Uytterhoeven } 51924828550SGeert Uytterhoeven 52024828550SGeert Uytterhoeven /** 52124828550SGeert Uytterhoeven * ps3_sys_manager_handle_msg - First stage msg handler. 52224828550SGeert Uytterhoeven * 52324828550SGeert Uytterhoeven * Can be called directly to manually poll vuart and pump message handler. 52424828550SGeert Uytterhoeven */ 52524828550SGeert Uytterhoeven 52624828550SGeert Uytterhoeven static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev) 52724828550SGeert Uytterhoeven { 52824828550SGeert Uytterhoeven int result; 52924828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 53024828550SGeert Uytterhoeven 53124828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &header, 53224828550SGeert Uytterhoeven sizeof(struct ps3_sys_manager_header)); 53324828550SGeert Uytterhoeven 53424828550SGeert Uytterhoeven if (result) 53524828550SGeert Uytterhoeven return result; 53624828550SGeert Uytterhoeven 53724828550SGeert Uytterhoeven if (header.version != 1) { 53824828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", 53924828550SGeert Uytterhoeven __func__, __LINE__, header.version); 54024828550SGeert Uytterhoeven dump_sm_header(&header); 54124828550SGeert Uytterhoeven goto fail_header; 54224828550SGeert Uytterhoeven } 54324828550SGeert Uytterhoeven 54424828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(header) != 16); 54524828550SGeert Uytterhoeven 54624828550SGeert Uytterhoeven if (header.size != 16 || (header.payload_size != 8 54724828550SGeert Uytterhoeven && header.payload_size != 16)) { 54824828550SGeert Uytterhoeven dump_sm_header(&header); 54924828550SGeert Uytterhoeven BUG(); 55024828550SGeert Uytterhoeven } 55124828550SGeert Uytterhoeven 55224828550SGeert Uytterhoeven switch (header.service_id) { 55324828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_EXTERN_EVENT: 55424828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); 55524828550SGeert Uytterhoeven return ps3_sys_manager_handle_event(dev); 55624828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_COMMAND: 55724828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); 55824828550SGeert Uytterhoeven return ps3_sys_manager_handle_cmd(dev); 55924828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_REQUEST_ERROR: 56024828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__, 56124828550SGeert Uytterhoeven __LINE__); 56224828550SGeert Uytterhoeven dump_sm_header(&header); 56324828550SGeert Uytterhoeven break; 56424828550SGeert Uytterhoeven default: 56524828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", 56624828550SGeert Uytterhoeven __func__, __LINE__, header.service_id); 56724828550SGeert Uytterhoeven break; 56824828550SGeert Uytterhoeven } 56924828550SGeert Uytterhoeven goto fail_id; 57024828550SGeert Uytterhoeven 57124828550SGeert Uytterhoeven fail_header: 57224828550SGeert Uytterhoeven ps3_vuart_clear_rx_bytes(dev, 0); 57324828550SGeert Uytterhoeven return -EIO; 57424828550SGeert Uytterhoeven fail_id: 57524828550SGeert Uytterhoeven ps3_vuart_clear_rx_bytes(dev, header.payload_size); 57624828550SGeert Uytterhoeven return -EIO; 57724828550SGeert Uytterhoeven } 57824828550SGeert Uytterhoeven 579ca052f79SGeert Uytterhoeven static void ps3_sys_manager_fin(struct ps3_system_bus_device *dev) 580ca052f79SGeert Uytterhoeven { 581ca052f79SGeert Uytterhoeven ps3_sys_manager_send_request_shutdown(dev); 582ca052f79SGeert Uytterhoeven 583ca052f79SGeert Uytterhoeven pr_emerg("System Halted, OK to turn off power\n"); 584ca052f79SGeert Uytterhoeven 585ca052f79SGeert Uytterhoeven while (ps3_sys_manager_handle_msg(dev)) { 586ca052f79SGeert Uytterhoeven /* pause until next DEC interrupt */ 587ca052f79SGeert Uytterhoeven lv1_pause(0); 588ca052f79SGeert Uytterhoeven } 589ca052f79SGeert Uytterhoeven 590ca052f79SGeert Uytterhoeven while (1) { 591ca052f79SGeert Uytterhoeven /* pause, ignoring DEC interrupt */ 592ca052f79SGeert Uytterhoeven lv1_pause(1); 593ca052f79SGeert Uytterhoeven } 594ca052f79SGeert Uytterhoeven } 595ca052f79SGeert Uytterhoeven 59624828550SGeert Uytterhoeven /** 59724828550SGeert Uytterhoeven * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. 59824828550SGeert Uytterhoeven * 59924828550SGeert Uytterhoeven * This routine never returns. The routine disables asynchronous vuart reads 60024828550SGeert Uytterhoeven * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 60124828550SGeert Uytterhoeven * the shutdown command sent from the system manager. Soon after the 60224828550SGeert Uytterhoeven * acknowledgement is sent the lpar is destroyed by the HV. This routine 60324828550SGeert Uytterhoeven * should only be called from ps3_power_off() through 60424828550SGeert Uytterhoeven * ps3_sys_manager_ops.power_off. 60524828550SGeert Uytterhoeven */ 60624828550SGeert Uytterhoeven 60724828550SGeert Uytterhoeven static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev) 60824828550SGeert Uytterhoeven { 60924828550SGeert Uytterhoeven BUG_ON(!dev); 61024828550SGeert Uytterhoeven 61124828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 61224828550SGeert Uytterhoeven 61324828550SGeert Uytterhoeven ps3_vuart_cancel_async(dev); 61424828550SGeert Uytterhoeven 61524828550SGeert Uytterhoeven ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, 6161c43d265SGeoff Levand user_wake_sources); 61724828550SGeert Uytterhoeven 618ca052f79SGeert Uytterhoeven ps3_sys_manager_fin(dev); 61924828550SGeert Uytterhoeven } 62024828550SGeert Uytterhoeven 62124828550SGeert Uytterhoeven /** 62224828550SGeert Uytterhoeven * ps3_sys_manager_final_restart - The final platform machine_restart routine. 62324828550SGeert Uytterhoeven * 62424828550SGeert Uytterhoeven * This routine never returns. The routine disables asynchronous vuart reads 62524828550SGeert Uytterhoeven * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 62624828550SGeert Uytterhoeven * the shutdown command sent from the system manager. Soon after the 62724828550SGeert Uytterhoeven * acknowledgement is sent the lpar is destroyed by the HV. This routine 62824828550SGeert Uytterhoeven * should only be called from ps3_restart() through ps3_sys_manager_ops.restart. 62924828550SGeert Uytterhoeven */ 63024828550SGeert Uytterhoeven 63124828550SGeert Uytterhoeven static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) 63224828550SGeert Uytterhoeven { 63324828550SGeert Uytterhoeven BUG_ON(!dev); 63424828550SGeert Uytterhoeven 63524828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 63624828550SGeert Uytterhoeven 63724828550SGeert Uytterhoeven /* Check if we got here via a power button event. */ 63824828550SGeert Uytterhoeven 63924828550SGeert Uytterhoeven if (ps3_sm_force_power_off) { 64024828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: forcing poweroff\n", 64124828550SGeert Uytterhoeven __func__, __LINE__); 64224828550SGeert Uytterhoeven ps3_sys_manager_final_power_off(dev); 64324828550SGeert Uytterhoeven } 64424828550SGeert Uytterhoeven 64524828550SGeert Uytterhoeven ps3_vuart_cancel_async(dev); 64624828550SGeert Uytterhoeven 64724828550SGeert Uytterhoeven ps3_sys_manager_send_attr(dev, 0); 64875ffe88dSGeoff Levand ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_REBOOT, 6491c43d265SGeoff Levand user_wake_sources); 65024828550SGeert Uytterhoeven 651ca052f79SGeert Uytterhoeven ps3_sys_manager_fin(dev); 65224828550SGeert Uytterhoeven } 65324828550SGeert Uytterhoeven 65424828550SGeert Uytterhoeven /** 6551c43d265SGeoff Levand * ps3_sys_manager_get_wol - Get wake-on-lan setting. 6561c43d265SGeoff Levand */ 6571c43d265SGeoff Levand 6581c43d265SGeoff Levand int ps3_sys_manager_get_wol(void) 6591c43d265SGeoff Levand { 6601c43d265SGeoff Levand pr_debug("%s:%d\n", __func__, __LINE__); 6611c43d265SGeoff Levand 6621c43d265SGeoff Levand return (user_wake_sources & PS3_SM_WAKE_W_O_L) != 0; 6631c43d265SGeoff Levand } 6641c43d265SGeoff Levand EXPORT_SYMBOL_GPL(ps3_sys_manager_get_wol); 6651c43d265SGeoff Levand 6661c43d265SGeoff Levand /** 6671c43d265SGeoff Levand * ps3_sys_manager_set_wol - Set wake-on-lan setting. 6681c43d265SGeoff Levand */ 6691c43d265SGeoff Levand 6701c43d265SGeoff Levand void ps3_sys_manager_set_wol(int state) 6711c43d265SGeoff Levand { 6721c43d265SGeoff Levand static DEFINE_MUTEX(mutex); 6731c43d265SGeoff Levand 6741c43d265SGeoff Levand mutex_lock(&mutex); 6751c43d265SGeoff Levand 6761c43d265SGeoff Levand pr_debug("%s:%d: %d\n", __func__, __LINE__, state); 6771c43d265SGeoff Levand 6781c43d265SGeoff Levand if (state) 6791c43d265SGeoff Levand user_wake_sources |= PS3_SM_WAKE_W_O_L; 6801c43d265SGeoff Levand else 6811c43d265SGeoff Levand user_wake_sources &= ~PS3_SM_WAKE_W_O_L; 6821c43d265SGeoff Levand mutex_unlock(&mutex); 6831c43d265SGeoff Levand } 6841c43d265SGeoff Levand EXPORT_SYMBOL_GPL(ps3_sys_manager_set_wol); 6851c43d265SGeoff Levand 6861c43d265SGeoff Levand /** 68724828550SGeert Uytterhoeven * ps3_sys_manager_work - Asynchronous read handler. 68824828550SGeert Uytterhoeven * 68924828550SGeert Uytterhoeven * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port. 69024828550SGeert Uytterhoeven */ 69124828550SGeert Uytterhoeven 69224828550SGeert Uytterhoeven static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) 69324828550SGeert Uytterhoeven { 69424828550SGeert Uytterhoeven ps3_sys_manager_handle_msg(dev); 69524828550SGeert Uytterhoeven ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 69624828550SGeert Uytterhoeven } 69724828550SGeert Uytterhoeven 6980fe763c5SGreg Kroah-Hartman static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) 69924828550SGeert Uytterhoeven { 70024828550SGeert Uytterhoeven int result; 70124828550SGeert Uytterhoeven struct ps3_sys_manager_ops ops; 70224828550SGeert Uytterhoeven 70324828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 70424828550SGeert Uytterhoeven 70524828550SGeert Uytterhoeven ops.power_off = ps3_sys_manager_final_power_off; 70624828550SGeert Uytterhoeven ops.restart = ps3_sys_manager_final_restart; 70724828550SGeert Uytterhoeven ops.dev = dev; 70824828550SGeert Uytterhoeven 70924828550SGeert Uytterhoeven /* ps3_sys_manager_register_ops copies ops. */ 71024828550SGeert Uytterhoeven 71124828550SGeert Uytterhoeven ps3_sys_manager_register_ops(&ops); 71224828550SGeert Uytterhoeven 71324828550SGeert Uytterhoeven result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); 71424828550SGeert Uytterhoeven BUG_ON(result); 71524828550SGeert Uytterhoeven 71624828550SGeert Uytterhoeven result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 71724828550SGeert Uytterhoeven BUG_ON(result); 71824828550SGeert Uytterhoeven 71924828550SGeert Uytterhoeven return result; 72024828550SGeert Uytterhoeven } 72124828550SGeert Uytterhoeven 72224828550SGeert Uytterhoeven static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev) 72324828550SGeert Uytterhoeven { 72424828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 72524828550SGeert Uytterhoeven return 0; 72624828550SGeert Uytterhoeven } 72724828550SGeert Uytterhoeven 72824828550SGeert Uytterhoeven static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev) 72924828550SGeert Uytterhoeven { 73024828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 73124828550SGeert Uytterhoeven } 73224828550SGeert Uytterhoeven 73324828550SGeert Uytterhoeven static struct ps3_vuart_port_driver ps3_sys_manager = { 73424828550SGeert Uytterhoeven .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER, 73524828550SGeert Uytterhoeven .core.core.name = "ps3_sys_manager", 73624828550SGeert Uytterhoeven .probe = ps3_sys_manager_probe, 73724828550SGeert Uytterhoeven .remove = ps3_sys_manager_remove, 73824828550SGeert Uytterhoeven .shutdown = ps3_sys_manager_shutdown, 73924828550SGeert Uytterhoeven .work = ps3_sys_manager_work, 74024828550SGeert Uytterhoeven }; 74124828550SGeert Uytterhoeven 74224828550SGeert Uytterhoeven static int __init ps3_sys_manager_init(void) 74324828550SGeert Uytterhoeven { 74424828550SGeert Uytterhoeven if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 74524828550SGeert Uytterhoeven return -ENODEV; 74624828550SGeert Uytterhoeven 74724828550SGeert Uytterhoeven return ps3_vuart_port_driver_register(&ps3_sys_manager); 74824828550SGeert Uytterhoeven } 74924828550SGeert Uytterhoeven 75024828550SGeert Uytterhoeven module_init(ps3_sys_manager_init); 75124828550SGeert Uytterhoeven /* Module remove not supported. */ 75224828550SGeert Uytterhoeven 75350dad902SGeoff Levand MODULE_AUTHOR("Sony Corporation"); 75450dad902SGeoff Levand MODULE_LICENSE("GPL v2"); 75550dad902SGeoff Levand MODULE_DESCRIPTION("PS3 System Manager"); 75624828550SGeert Uytterhoeven MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER); 757