124828550SGeert Uytterhoeven /* 224828550SGeert Uytterhoeven * PS3 System Manager. 324828550SGeert Uytterhoeven * 424828550SGeert Uytterhoeven * Copyright (C) 2007 Sony Computer Entertainment Inc. 524828550SGeert Uytterhoeven * Copyright 2007 Sony Corp. 624828550SGeert Uytterhoeven * 724828550SGeert Uytterhoeven * This program is free software; you can redistribute it and/or modify 824828550SGeert Uytterhoeven * it under the terms of the GNU General Public License as published by 924828550SGeert Uytterhoeven * the Free Software Foundation; version 2 of the License. 1024828550SGeert Uytterhoeven * 1124828550SGeert Uytterhoeven * This program is distributed in the hope that it will be useful, 1224828550SGeert Uytterhoeven * but WITHOUT ANY WARRANTY; without even the implied warranty of 1324828550SGeert Uytterhoeven * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1424828550SGeert Uytterhoeven * GNU General Public License for more details. 1524828550SGeert Uytterhoeven * 1624828550SGeert Uytterhoeven * You should have received a copy of the GNU General Public License 1724828550SGeert Uytterhoeven * along with this program; if not, write to the Free Software 1824828550SGeert Uytterhoeven * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1924828550SGeert Uytterhoeven */ 2024828550SGeert Uytterhoeven 2124828550SGeert Uytterhoeven #include <linux/kernel.h> 2224828550SGeert Uytterhoeven #include <linux/module.h> 2324828550SGeert Uytterhoeven #include <linux/workqueue.h> 2424828550SGeert Uytterhoeven #include <linux/reboot.h> 2524828550SGeert Uytterhoeven 2624828550SGeert Uytterhoeven #include <asm/firmware.h> 27ca052f79SGeert Uytterhoeven #include <asm/lv1call.h> 2824828550SGeert Uytterhoeven #include <asm/ps3.h> 2924828550SGeert Uytterhoeven 3024828550SGeert Uytterhoeven #include "vuart.h" 3124828550SGeert Uytterhoeven 3224828550SGeert Uytterhoeven /** 3324828550SGeert Uytterhoeven * ps3_sys_manager - PS3 system manager driver. 3424828550SGeert Uytterhoeven * 3524828550SGeert Uytterhoeven * The system manager provides an asynchronous system event notification 3624828550SGeert Uytterhoeven * mechanism for reporting events like thermal alert and button presses to 3724828550SGeert Uytterhoeven * guests. It also provides support to control system shutdown and startup. 3824828550SGeert Uytterhoeven * 3924828550SGeert Uytterhoeven * The actual system manager is implemented as an application running in the 4024828550SGeert Uytterhoeven * system policy module in lpar_1. Guests communicate with the system manager 4124828550SGeert Uytterhoeven * through port 2 of the vuart using a simple packet message protocol. 4224828550SGeert Uytterhoeven * Messages are comprised of a fixed field header followed by a message 4324828550SGeert Uytterhoeven * specific payload. 4424828550SGeert Uytterhoeven */ 4524828550SGeert Uytterhoeven 4624828550SGeert Uytterhoeven /** 4724828550SGeert Uytterhoeven * struct ps3_sys_manager_header - System manager message header. 4824828550SGeert Uytterhoeven * @version: Header version, currently 1. 49af901ca1SAndré Goddard Rosa * @size: Header size in bytes, currently 16. 5024828550SGeert Uytterhoeven * @payload_size: Message payload size in bytes. 5124828550SGeert Uytterhoeven * @service_id: Message type, one of enum ps3_sys_manager_service_id. 5224828550SGeert Uytterhoeven * @request_tag: Unique number to identify reply. 5324828550SGeert Uytterhoeven */ 5424828550SGeert Uytterhoeven 5524828550SGeert Uytterhoeven struct ps3_sys_manager_header { 5624828550SGeert Uytterhoeven /* version 1 */ 5724828550SGeert Uytterhoeven u8 version; 5824828550SGeert Uytterhoeven u8 size; 5924828550SGeert Uytterhoeven u16 reserved_1; 6024828550SGeert Uytterhoeven u32 payload_size; 6124828550SGeert Uytterhoeven u16 service_id; 6224828550SGeert Uytterhoeven u16 reserved_2; 6324828550SGeert Uytterhoeven u32 request_tag; 6424828550SGeert Uytterhoeven }; 6524828550SGeert Uytterhoeven 6624828550SGeert Uytterhoeven #define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__) 6724828550SGeert Uytterhoeven static void __maybe_unused _dump_sm_header( 6824828550SGeert Uytterhoeven const struct ps3_sys_manager_header *h, const char *func, int line) 6924828550SGeert Uytterhoeven { 7024828550SGeert Uytterhoeven pr_debug("%s:%d: version: %xh\n", func, line, h->version); 7124828550SGeert Uytterhoeven pr_debug("%s:%d: size: %xh\n", func, line, h->size); 7224828550SGeert Uytterhoeven pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size); 7324828550SGeert Uytterhoeven pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id); 7424828550SGeert Uytterhoeven pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag); 7524828550SGeert Uytterhoeven } 7624828550SGeert Uytterhoeven 7724828550SGeert Uytterhoeven /** 7824828550SGeert Uytterhoeven * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. 7924828550SGeert Uytterhoeven * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. 8024828550SGeert Uytterhoeven * 8124828550SGeert Uytterhoeven * Currently all messages received from the system manager are either 8224828550SGeert Uytterhoeven * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header 8325985edcSLucas De Marchi * + 16 bytes payload = 32 bytes). This knowledge is used to simplify 8424828550SGeert Uytterhoeven * the logic. 8524828550SGeert Uytterhoeven */ 8624828550SGeert Uytterhoeven 8724828550SGeert Uytterhoeven enum { 8824828550SGeert Uytterhoeven PS3_SM_RX_MSG_LEN_MIN = 24, 8924828550SGeert Uytterhoeven PS3_SM_RX_MSG_LEN_MAX = 32, 9024828550SGeert Uytterhoeven }; 9124828550SGeert Uytterhoeven 9224828550SGeert Uytterhoeven /** 9324828550SGeert Uytterhoeven * enum ps3_sys_manager_service_id - Message header service_id. 9424828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. 9524828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. 9624828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. 9724828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. 9824828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. 9924828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. 10024828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. 10124828550SGeert Uytterhoeven * 10224828550SGeert Uytterhoeven * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a 10324828550SGeert Uytterhoeven * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when 10424828550SGeert Uytterhoeven * a REQUEST message is sent at the wrong time. 10524828550SGeert Uytterhoeven */ 10624828550SGeert Uytterhoeven 10724828550SGeert Uytterhoeven enum ps3_sys_manager_service_id { 10824828550SGeert Uytterhoeven /* version 1 */ 10924828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_REQUEST = 1, 11024828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_RESPONSE = 2, 11124828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_COMMAND = 3, 11224828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, 11324828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, 11424828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_REQUEST_ERROR = 6, 11524828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_SET_ATTR = 8, 11624828550SGeert Uytterhoeven }; 11724828550SGeert Uytterhoeven 11824828550SGeert Uytterhoeven /** 11924828550SGeert Uytterhoeven * enum ps3_sys_manager_attr - Notification attribute (bit position mask). 12024828550SGeert Uytterhoeven * @PS3_SM_ATTR_POWER: Power button. 12124828550SGeert Uytterhoeven * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. 12288393161SThomas Weber * @PS3_SM_ATTR_THERMAL: System thermal alert. 12324828550SGeert Uytterhoeven * @PS3_SM_ATTR_CONTROLLER: Remote controller event. 12424828550SGeert Uytterhoeven * @PS3_SM_ATTR_ALL: Logical OR of all. 12524828550SGeert Uytterhoeven * 12624828550SGeert Uytterhoeven * The guest tells the system manager which events it is interested in receiving 12724828550SGeert Uytterhoeven * notice of by sending the system manager a logical OR of notification 12824828550SGeert Uytterhoeven * attributes via the ps3_sys_manager_send_attr() routine. 12924828550SGeert Uytterhoeven */ 13024828550SGeert Uytterhoeven 13124828550SGeert Uytterhoeven enum ps3_sys_manager_attr { 13224828550SGeert Uytterhoeven /* version 1 */ 13324828550SGeert Uytterhoeven PS3_SM_ATTR_POWER = 1, 13424828550SGeert Uytterhoeven PS3_SM_ATTR_RESET = 2, 13524828550SGeert Uytterhoeven PS3_SM_ATTR_THERMAL = 4, 13624828550SGeert Uytterhoeven PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */ 13724828550SGeert Uytterhoeven PS3_SM_ATTR_ALL = 0x0f, 13824828550SGeert Uytterhoeven }; 13924828550SGeert Uytterhoeven 14024828550SGeert Uytterhoeven /** 14124828550SGeert Uytterhoeven * enum ps3_sys_manager_event - External event type, reported by system manager. 142ea24608fSGeoff Levand * @PS3_SM_EVENT_POWER_PRESSED: payload.value = 143ea24608fSGeoff Levand * enum ps3_sys_manager_button_event. 14424828550SGeert Uytterhoeven * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. 145ea24608fSGeoff Levand * @PS3_SM_EVENT_RESET_PRESSED: payload.value = 146ea24608fSGeoff Levand * enum ps3_sys_manager_button_event. 14724828550SGeert Uytterhoeven * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. 14824828550SGeert Uytterhoeven * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. 14924828550SGeert Uytterhoeven * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. 15024828550SGeert Uytterhoeven */ 15124828550SGeert Uytterhoeven 15224828550SGeert Uytterhoeven enum ps3_sys_manager_event { 15324828550SGeert Uytterhoeven /* version 1 */ 15424828550SGeert Uytterhoeven PS3_SM_EVENT_POWER_PRESSED = 3, 15524828550SGeert Uytterhoeven PS3_SM_EVENT_POWER_RELEASED = 4, 15624828550SGeert Uytterhoeven PS3_SM_EVENT_RESET_PRESSED = 5, 15724828550SGeert Uytterhoeven PS3_SM_EVENT_RESET_RELEASED = 6, 15824828550SGeert Uytterhoeven PS3_SM_EVENT_THERMAL_ALERT = 7, 15924828550SGeert Uytterhoeven PS3_SM_EVENT_THERMAL_CLEARED = 8, 16024828550SGeert Uytterhoeven /* no info on controller events */ 16124828550SGeert Uytterhoeven }; 16224828550SGeert Uytterhoeven 16324828550SGeert Uytterhoeven /** 164ea24608fSGeoff Levand * enum ps3_sys_manager_button_event - Button event payload values. 165ea24608fSGeoff Levand * @PS3_SM_BUTTON_EVENT_HARD: Hardware generated event. 166ea24608fSGeoff Levand * @PS3_SM_BUTTON_EVENT_SOFT: Software generated event. 167ea24608fSGeoff Levand */ 168ea24608fSGeoff Levand 169ea24608fSGeoff Levand enum ps3_sys_manager_button_event { 170ea24608fSGeoff Levand PS3_SM_BUTTON_EVENT_HARD = 0, 171ea24608fSGeoff Levand PS3_SM_BUTTON_EVENT_SOFT = 1, 172ea24608fSGeoff Levand }; 173ea24608fSGeoff Levand 174ea24608fSGeoff Levand /** 17524828550SGeert Uytterhoeven * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. 17624828550SGeert Uytterhoeven */ 17724828550SGeert Uytterhoeven 17824828550SGeert Uytterhoeven enum ps3_sys_manager_next_op { 17924828550SGeert Uytterhoeven /* version 3 */ 18024828550SGeert Uytterhoeven PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, 18124828550SGeert Uytterhoeven PS3_SM_NEXT_OP_SYS_REBOOT = 2, 18224828550SGeert Uytterhoeven PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, 18324828550SGeert Uytterhoeven }; 18424828550SGeert Uytterhoeven 18524828550SGeert Uytterhoeven /** 18624828550SGeert Uytterhoeven * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). 1875442381cSGeoff Levand * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button. 1881c43d265SGeoff Levand * @PS3_SM_WAKE_W_O_L: Ether or wireless LAN. 18924828550SGeert Uytterhoeven * @PS3_SM_WAKE_P_O_R: Power on reset. 19024828550SGeert Uytterhoeven * 19124828550SGeert Uytterhoeven * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. 19250dad902SGeoff Levand * The system will always wake from the PS3_SM_WAKE_DEFAULT sources. 19350dad902SGeoff Levand * Sources listed here are the only ones available to guests in the 19450dad902SGeoff Levand * other-os lpar. 19524828550SGeert Uytterhoeven */ 19624828550SGeert Uytterhoeven 19724828550SGeert Uytterhoeven enum ps3_sys_manager_wake_source { 19824828550SGeert Uytterhoeven /* version 3 */ 19924828550SGeert Uytterhoeven PS3_SM_WAKE_DEFAULT = 0, 2001c43d265SGeoff Levand PS3_SM_WAKE_W_O_L = 0x00000400, 20150dad902SGeoff Levand PS3_SM_WAKE_P_O_R = 0x80000000, 20224828550SGeert Uytterhoeven }; 20324828550SGeert Uytterhoeven 20424828550SGeert Uytterhoeven /** 2051c43d265SGeoff Levand * user_wake_sources - User specified wakeup sources. 2061c43d265SGeoff Levand * 2071c43d265SGeoff Levand * Logical OR of enum ps3_sys_manager_wake_source types. 2081c43d265SGeoff Levand */ 2091c43d265SGeoff Levand 2101c43d265SGeoff Levand static u32 user_wake_sources = PS3_SM_WAKE_DEFAULT; 2111c43d265SGeoff Levand 2121c43d265SGeoff Levand /** 21324828550SGeert Uytterhoeven * enum ps3_sys_manager_cmd - Command from system manager to guest. 21424828550SGeert Uytterhoeven * 21524828550SGeert Uytterhoeven * The guest completes the actions needed, then acks or naks the command via 21624828550SGeert Uytterhoeven * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, 21724828550SGeert Uytterhoeven * the guest must be fully prepared for a system poweroff prior to acking the 21824828550SGeert Uytterhoeven * command. 21924828550SGeert Uytterhoeven */ 22024828550SGeert Uytterhoeven 22124828550SGeert Uytterhoeven enum ps3_sys_manager_cmd { 22224828550SGeert Uytterhoeven /* version 1 */ 22324828550SGeert Uytterhoeven PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ 22424828550SGeert Uytterhoeven }; 22524828550SGeert Uytterhoeven 22624828550SGeert Uytterhoeven /** 22724828550SGeert Uytterhoeven * ps3_sm_force_power_off - Poweroff helper. 22824828550SGeert Uytterhoeven * 22924828550SGeert Uytterhoeven * A global variable used to force a poweroff when the power button has 23024828550SGeert Uytterhoeven * been pressed irrespective of how init handles the ctrl_alt_del signal. 23124828550SGeert Uytterhoeven * 23224828550SGeert Uytterhoeven */ 23324828550SGeert Uytterhoeven 23424828550SGeert Uytterhoeven static unsigned int ps3_sm_force_power_off; 23524828550SGeert Uytterhoeven 23624828550SGeert Uytterhoeven /** 23724828550SGeert Uytterhoeven * ps3_sys_manager_write - Helper to write a two part message to the vuart. 23824828550SGeert Uytterhoeven * 23924828550SGeert Uytterhoeven */ 24024828550SGeert Uytterhoeven 24124828550SGeert Uytterhoeven static int ps3_sys_manager_write(struct ps3_system_bus_device *dev, 24224828550SGeert Uytterhoeven const struct ps3_sys_manager_header *header, const void *payload) 24324828550SGeert Uytterhoeven { 24424828550SGeert Uytterhoeven int result; 24524828550SGeert Uytterhoeven 24624828550SGeert Uytterhoeven BUG_ON(header->version != 1); 24724828550SGeert Uytterhoeven BUG_ON(header->size != 16); 24824828550SGeert Uytterhoeven BUG_ON(header->payload_size != 8 && header->payload_size != 16); 24924828550SGeert Uytterhoeven BUG_ON(header->service_id > 8); 25024828550SGeert Uytterhoeven 25124828550SGeert Uytterhoeven result = ps3_vuart_write(dev, header, 25224828550SGeert Uytterhoeven sizeof(struct ps3_sys_manager_header)); 25324828550SGeert Uytterhoeven 25424828550SGeert Uytterhoeven if (!result) 25524828550SGeert Uytterhoeven result = ps3_vuart_write(dev, payload, header->payload_size); 25624828550SGeert Uytterhoeven 25724828550SGeert Uytterhoeven return result; 25824828550SGeert Uytterhoeven } 25924828550SGeert Uytterhoeven 26024828550SGeert Uytterhoeven /** 26124828550SGeert Uytterhoeven * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. 26224828550SGeert Uytterhoeven * 26324828550SGeert Uytterhoeven */ 26424828550SGeert Uytterhoeven 26524828550SGeert Uytterhoeven static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev, 26624828550SGeert Uytterhoeven enum ps3_sys_manager_attr attr) 26724828550SGeert Uytterhoeven { 26824828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 26924828550SGeert Uytterhoeven struct { 27024828550SGeert Uytterhoeven u8 version; 27124828550SGeert Uytterhoeven u8 reserved_1[3]; 27224828550SGeert Uytterhoeven u32 attribute; 27324828550SGeert Uytterhoeven } payload; 27424828550SGeert Uytterhoeven 27524828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 8); 27624828550SGeert Uytterhoeven 27724828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); 27824828550SGeert Uytterhoeven 27924828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 28024828550SGeert Uytterhoeven header.version = 1; 28124828550SGeert Uytterhoeven header.size = 16; 28224828550SGeert Uytterhoeven header.payload_size = 16; 28324828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_SET_ATTR; 28424828550SGeert Uytterhoeven 28524828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 28624828550SGeert Uytterhoeven payload.version = 1; 28724828550SGeert Uytterhoeven payload.attribute = attr; 28824828550SGeert Uytterhoeven 28924828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 29024828550SGeert Uytterhoeven } 29124828550SGeert Uytterhoeven 29224828550SGeert Uytterhoeven /** 29324828550SGeert Uytterhoeven * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. 29424828550SGeert Uytterhoeven * 29524828550SGeert Uytterhoeven * Tell the system manager what to do after this lpar is destroyed. 29624828550SGeert Uytterhoeven */ 29724828550SGeert Uytterhoeven 29824828550SGeert Uytterhoeven static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev, 29924828550SGeert Uytterhoeven enum ps3_sys_manager_next_op op, 30024828550SGeert Uytterhoeven enum ps3_sys_manager_wake_source wake_source) 30124828550SGeert Uytterhoeven { 30224828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 30324828550SGeert Uytterhoeven struct { 30424828550SGeert Uytterhoeven u8 version; 30524828550SGeert Uytterhoeven u8 type; 30624828550SGeert Uytterhoeven u8 gos_id; 30724828550SGeert Uytterhoeven u8 reserved_1; 30824828550SGeert Uytterhoeven u32 wake_source; 30924828550SGeert Uytterhoeven u8 reserved_2[8]; 31024828550SGeert Uytterhoeven } payload; 31124828550SGeert Uytterhoeven 31224828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 31324828550SGeert Uytterhoeven 31424828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); 31524828550SGeert Uytterhoeven 31624828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 31724828550SGeert Uytterhoeven header.version = 1; 31824828550SGeert Uytterhoeven header.size = 16; 31924828550SGeert Uytterhoeven header.payload_size = 16; 32024828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP; 32124828550SGeert Uytterhoeven 32224828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 32324828550SGeert Uytterhoeven payload.version = 3; 32424828550SGeert Uytterhoeven payload.type = op; 32524828550SGeert Uytterhoeven payload.gos_id = 3; /* other os */ 32624828550SGeert Uytterhoeven payload.wake_source = wake_source; 32724828550SGeert Uytterhoeven 32824828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 32924828550SGeert Uytterhoeven } 33024828550SGeert Uytterhoeven 33124828550SGeert Uytterhoeven /** 33224828550SGeert Uytterhoeven * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. 33324828550SGeert Uytterhoeven * 33424828550SGeert Uytterhoeven * The guest sends this message to request an operation or action of the system 33524828550SGeert Uytterhoeven * manager. The reply is a command message from the system manager. In the 33624828550SGeert Uytterhoeven * command handler the guest performs the requested operation. The result of 33724828550SGeert Uytterhoeven * the command is then communicated back to the system manager with a response 33824828550SGeert Uytterhoeven * message. 33924828550SGeert Uytterhoeven * 34024828550SGeert Uytterhoeven * Currently, the only supported request is the 'shutdown self' request. 34124828550SGeert Uytterhoeven */ 34224828550SGeert Uytterhoeven 34324828550SGeert Uytterhoeven static int ps3_sys_manager_send_request_shutdown( 34424828550SGeert Uytterhoeven struct ps3_system_bus_device *dev) 34524828550SGeert Uytterhoeven { 34624828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 34724828550SGeert Uytterhoeven struct { 34824828550SGeert Uytterhoeven u8 version; 34924828550SGeert Uytterhoeven u8 type; 35024828550SGeert Uytterhoeven u8 gos_id; 35124828550SGeert Uytterhoeven u8 reserved_1[13]; 35224828550SGeert Uytterhoeven } payload; 35324828550SGeert Uytterhoeven 35424828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 35524828550SGeert Uytterhoeven 35624828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 35724828550SGeert Uytterhoeven 35824828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 35924828550SGeert Uytterhoeven header.version = 1; 36024828550SGeert Uytterhoeven header.size = 16; 36124828550SGeert Uytterhoeven header.payload_size = 16; 36224828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_REQUEST; 36324828550SGeert Uytterhoeven 36424828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 36524828550SGeert Uytterhoeven payload.version = 1; 36624828550SGeert Uytterhoeven payload.type = 1; /* shutdown */ 36724828550SGeert Uytterhoeven payload.gos_id = 0; /* self */ 36824828550SGeert Uytterhoeven 36924828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 37024828550SGeert Uytterhoeven } 37124828550SGeert Uytterhoeven 37224828550SGeert Uytterhoeven /** 37324828550SGeert Uytterhoeven * ps3_sys_manager_send_response - Send a 'response' to the system manager. 37424828550SGeert Uytterhoeven * @status: zero = success, others fail. 37524828550SGeert Uytterhoeven * 37624828550SGeert Uytterhoeven * The guest sends this message to the system manager to acnowledge success or 37724828550SGeert Uytterhoeven * failure of a command sent by the system manager. 37824828550SGeert Uytterhoeven */ 37924828550SGeert Uytterhoeven 38024828550SGeert Uytterhoeven static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev, 38124828550SGeert Uytterhoeven u64 status) 38224828550SGeert Uytterhoeven { 38324828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 38424828550SGeert Uytterhoeven struct { 38524828550SGeert Uytterhoeven u8 version; 38624828550SGeert Uytterhoeven u8 reserved_1[3]; 38724828550SGeert Uytterhoeven u8 status; 38824828550SGeert Uytterhoeven u8 reserved_2[11]; 38924828550SGeert Uytterhoeven } payload; 39024828550SGeert Uytterhoeven 39124828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 39224828550SGeert Uytterhoeven 39324828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 39424828550SGeert Uytterhoeven (status ? "nak" : "ack")); 39524828550SGeert Uytterhoeven 39624828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 39724828550SGeert Uytterhoeven header.version = 1; 39824828550SGeert Uytterhoeven header.size = 16; 39924828550SGeert Uytterhoeven header.payload_size = 16; 40024828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_RESPONSE; 40124828550SGeert Uytterhoeven 40224828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 40324828550SGeert Uytterhoeven payload.version = 1; 40424828550SGeert Uytterhoeven payload.status = status; 40524828550SGeert Uytterhoeven 40624828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 40724828550SGeert Uytterhoeven } 40824828550SGeert Uytterhoeven 40924828550SGeert Uytterhoeven /** 41024828550SGeert Uytterhoeven * ps3_sys_manager_handle_event - Second stage event msg handler. 41124828550SGeert Uytterhoeven * 41224828550SGeert Uytterhoeven */ 41324828550SGeert Uytterhoeven 41424828550SGeert Uytterhoeven static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) 41524828550SGeert Uytterhoeven { 41624828550SGeert Uytterhoeven int result; 41724828550SGeert Uytterhoeven struct { 41824828550SGeert Uytterhoeven u8 version; 41924828550SGeert Uytterhoeven u8 type; 42024828550SGeert Uytterhoeven u8 reserved_1[2]; 42124828550SGeert Uytterhoeven u32 value; 42224828550SGeert Uytterhoeven u8 reserved_2[8]; 42324828550SGeert Uytterhoeven } event; 42424828550SGeert Uytterhoeven 42524828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(event) != 16); 42624828550SGeert Uytterhoeven 42724828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &event, sizeof(event)); 42824828550SGeert Uytterhoeven BUG_ON(result && "need to retry here"); 42924828550SGeert Uytterhoeven 43024828550SGeert Uytterhoeven if (event.version != 1) { 43124828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", 43224828550SGeert Uytterhoeven __func__, __LINE__, event.version); 43324828550SGeert Uytterhoeven return -EIO; 43424828550SGeert Uytterhoeven } 43524828550SGeert Uytterhoeven 43624828550SGeert Uytterhoeven switch (event.type) { 43724828550SGeert Uytterhoeven case PS3_SM_EVENT_POWER_PRESSED: 438ea24608fSGeoff Levand dev_dbg(&dev->core, "%s:%d: POWER_PRESSED (%s)\n", 439ea24608fSGeoff Levand __func__, __LINE__, 440ea24608fSGeoff Levand (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 441ea24608fSGeoff Levand : "hard")); 44224828550SGeert Uytterhoeven ps3_sm_force_power_off = 1; 44324828550SGeert Uytterhoeven /* 44424828550SGeert Uytterhoeven * A memory barrier is use here to sync memory since 44524828550SGeert Uytterhoeven * ps3_sys_manager_final_restart() could be called on 44624828550SGeert Uytterhoeven * another cpu. 44724828550SGeert Uytterhoeven */ 44824828550SGeert Uytterhoeven wmb(); 44924828550SGeert Uytterhoeven kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 45024828550SGeert Uytterhoeven break; 45124828550SGeert Uytterhoeven case PS3_SM_EVENT_POWER_RELEASED: 45224828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", 45324828550SGeert Uytterhoeven __func__, __LINE__, event.value); 45424828550SGeert Uytterhoeven break; 45524828550SGeert Uytterhoeven case PS3_SM_EVENT_RESET_PRESSED: 456ea24608fSGeoff Levand dev_dbg(&dev->core, "%s:%d: RESET_PRESSED (%s)\n", 457ea24608fSGeoff Levand __func__, __LINE__, 458ea24608fSGeoff Levand (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 459ea24608fSGeoff Levand : "hard")); 46024828550SGeert Uytterhoeven ps3_sm_force_power_off = 0; 46124828550SGeert Uytterhoeven /* 46224828550SGeert Uytterhoeven * A memory barrier is use here to sync memory since 46324828550SGeert Uytterhoeven * ps3_sys_manager_final_restart() could be called on 46424828550SGeert Uytterhoeven * another cpu. 46524828550SGeert Uytterhoeven */ 46624828550SGeert Uytterhoeven wmb(); 46724828550SGeert Uytterhoeven kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 46824828550SGeert Uytterhoeven break; 46924828550SGeert Uytterhoeven case PS3_SM_EVENT_RESET_RELEASED: 47024828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n", 47124828550SGeert Uytterhoeven __func__, __LINE__, event.value); 47224828550SGeert Uytterhoeven break; 47324828550SGeert Uytterhoeven case PS3_SM_EVENT_THERMAL_ALERT: 47424828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", 47524828550SGeert Uytterhoeven __func__, __LINE__, event.value); 476eff56c92SGeert Uytterhoeven pr_info("PS3 Thermal Alert Zone %u\n", event.value); 47724828550SGeert Uytterhoeven break; 47824828550SGeert Uytterhoeven case PS3_SM_EVENT_THERMAL_CLEARED: 47924828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", 48024828550SGeert Uytterhoeven __func__, __LINE__, event.value); 48124828550SGeert Uytterhoeven break; 48224828550SGeert Uytterhoeven default: 48324828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", 48424828550SGeert Uytterhoeven __func__, __LINE__, event.type); 48524828550SGeert Uytterhoeven return -EIO; 48624828550SGeert Uytterhoeven } 48724828550SGeert Uytterhoeven 48824828550SGeert Uytterhoeven return 0; 48924828550SGeert Uytterhoeven } 49024828550SGeert Uytterhoeven /** 49124828550SGeert Uytterhoeven * ps3_sys_manager_handle_cmd - Second stage command msg handler. 49224828550SGeert Uytterhoeven * 49324828550SGeert Uytterhoeven * The system manager sends this in reply to a 'request' message from the guest. 49424828550SGeert Uytterhoeven */ 49524828550SGeert Uytterhoeven 49624828550SGeert Uytterhoeven static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev) 49724828550SGeert Uytterhoeven { 49824828550SGeert Uytterhoeven int result; 49924828550SGeert Uytterhoeven struct { 50024828550SGeert Uytterhoeven u8 version; 50124828550SGeert Uytterhoeven u8 type; 50224828550SGeert Uytterhoeven u8 reserved_1[14]; 50324828550SGeert Uytterhoeven } cmd; 50424828550SGeert Uytterhoeven 50524828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(cmd) != 16); 50624828550SGeert Uytterhoeven 50724828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 50824828550SGeert Uytterhoeven 50924828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); 51024828550SGeert Uytterhoeven BUG_ON(result && "need to retry here"); 51124828550SGeert Uytterhoeven 51224828550SGeert Uytterhoeven if (result) 51324828550SGeert Uytterhoeven return result; 51424828550SGeert Uytterhoeven 51524828550SGeert Uytterhoeven if (cmd.version != 1) { 51624828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", 51724828550SGeert Uytterhoeven __func__, __LINE__, cmd.version); 51824828550SGeert Uytterhoeven return -EIO; 51924828550SGeert Uytterhoeven } 52024828550SGeert Uytterhoeven 52124828550SGeert Uytterhoeven if (cmd.type != PS3_SM_CMD_SHUTDOWN) { 52224828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", 52324828550SGeert Uytterhoeven __func__, __LINE__, cmd.type); 52424828550SGeert Uytterhoeven return -EIO; 52524828550SGeert Uytterhoeven } 52624828550SGeert Uytterhoeven 52724828550SGeert Uytterhoeven ps3_sys_manager_send_response(dev, 0); 52824828550SGeert Uytterhoeven return 0; 52924828550SGeert Uytterhoeven } 53024828550SGeert Uytterhoeven 53124828550SGeert Uytterhoeven /** 53224828550SGeert Uytterhoeven * ps3_sys_manager_handle_msg - First stage msg handler. 53324828550SGeert Uytterhoeven * 53424828550SGeert Uytterhoeven * Can be called directly to manually poll vuart and pump message handler. 53524828550SGeert Uytterhoeven */ 53624828550SGeert Uytterhoeven 53724828550SGeert Uytterhoeven static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev) 53824828550SGeert Uytterhoeven { 53924828550SGeert Uytterhoeven int result; 54024828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 54124828550SGeert Uytterhoeven 54224828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &header, 54324828550SGeert Uytterhoeven sizeof(struct ps3_sys_manager_header)); 54424828550SGeert Uytterhoeven 54524828550SGeert Uytterhoeven if (result) 54624828550SGeert Uytterhoeven return result; 54724828550SGeert Uytterhoeven 54824828550SGeert Uytterhoeven if (header.version != 1) { 54924828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", 55024828550SGeert Uytterhoeven __func__, __LINE__, header.version); 55124828550SGeert Uytterhoeven dump_sm_header(&header); 55224828550SGeert Uytterhoeven goto fail_header; 55324828550SGeert Uytterhoeven } 55424828550SGeert Uytterhoeven 55524828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(header) != 16); 55624828550SGeert Uytterhoeven 55724828550SGeert Uytterhoeven if (header.size != 16 || (header.payload_size != 8 55824828550SGeert Uytterhoeven && header.payload_size != 16)) { 55924828550SGeert Uytterhoeven dump_sm_header(&header); 56024828550SGeert Uytterhoeven BUG(); 56124828550SGeert Uytterhoeven } 56224828550SGeert Uytterhoeven 56324828550SGeert Uytterhoeven switch (header.service_id) { 56424828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_EXTERN_EVENT: 56524828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); 56624828550SGeert Uytterhoeven return ps3_sys_manager_handle_event(dev); 56724828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_COMMAND: 56824828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); 56924828550SGeert Uytterhoeven return ps3_sys_manager_handle_cmd(dev); 57024828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_REQUEST_ERROR: 57124828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__, 57224828550SGeert Uytterhoeven __LINE__); 57324828550SGeert Uytterhoeven dump_sm_header(&header); 57424828550SGeert Uytterhoeven break; 57524828550SGeert Uytterhoeven default: 57624828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", 57724828550SGeert Uytterhoeven __func__, __LINE__, header.service_id); 57824828550SGeert Uytterhoeven break; 57924828550SGeert Uytterhoeven } 58024828550SGeert Uytterhoeven goto fail_id; 58124828550SGeert Uytterhoeven 58224828550SGeert Uytterhoeven fail_header: 58324828550SGeert Uytterhoeven ps3_vuart_clear_rx_bytes(dev, 0); 58424828550SGeert Uytterhoeven return -EIO; 58524828550SGeert Uytterhoeven fail_id: 58624828550SGeert Uytterhoeven ps3_vuart_clear_rx_bytes(dev, header.payload_size); 58724828550SGeert Uytterhoeven return -EIO; 58824828550SGeert Uytterhoeven } 58924828550SGeert Uytterhoeven 590ca052f79SGeert Uytterhoeven static void ps3_sys_manager_fin(struct ps3_system_bus_device *dev) 591ca052f79SGeert Uytterhoeven { 592ca052f79SGeert Uytterhoeven ps3_sys_manager_send_request_shutdown(dev); 593ca052f79SGeert Uytterhoeven 594ca052f79SGeert Uytterhoeven pr_emerg("System Halted, OK to turn off power\n"); 595ca052f79SGeert Uytterhoeven 596ca052f79SGeert Uytterhoeven while (ps3_sys_manager_handle_msg(dev)) { 597ca052f79SGeert Uytterhoeven /* pause until next DEC interrupt */ 598ca052f79SGeert Uytterhoeven lv1_pause(0); 599ca052f79SGeert Uytterhoeven } 600ca052f79SGeert Uytterhoeven 601ca052f79SGeert Uytterhoeven while (1) { 602ca052f79SGeert Uytterhoeven /* pause, ignoring DEC interrupt */ 603ca052f79SGeert Uytterhoeven lv1_pause(1); 604ca052f79SGeert Uytterhoeven } 605ca052f79SGeert Uytterhoeven } 606ca052f79SGeert Uytterhoeven 60724828550SGeert Uytterhoeven /** 60824828550SGeert Uytterhoeven * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. 60924828550SGeert Uytterhoeven * 61024828550SGeert Uytterhoeven * This routine never returns. The routine disables asynchronous vuart reads 61124828550SGeert Uytterhoeven * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 61224828550SGeert Uytterhoeven * the shutdown command sent from the system manager. Soon after the 61324828550SGeert Uytterhoeven * acknowledgement is sent the lpar is destroyed by the HV. This routine 61424828550SGeert Uytterhoeven * should only be called from ps3_power_off() through 61524828550SGeert Uytterhoeven * ps3_sys_manager_ops.power_off. 61624828550SGeert Uytterhoeven */ 61724828550SGeert Uytterhoeven 61824828550SGeert Uytterhoeven static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev) 61924828550SGeert Uytterhoeven { 62024828550SGeert Uytterhoeven BUG_ON(!dev); 62124828550SGeert Uytterhoeven 62224828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 62324828550SGeert Uytterhoeven 62424828550SGeert Uytterhoeven ps3_vuart_cancel_async(dev); 62524828550SGeert Uytterhoeven 62624828550SGeert Uytterhoeven ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, 6271c43d265SGeoff Levand user_wake_sources); 62824828550SGeert Uytterhoeven 629ca052f79SGeert Uytterhoeven ps3_sys_manager_fin(dev); 63024828550SGeert Uytterhoeven } 63124828550SGeert Uytterhoeven 63224828550SGeert Uytterhoeven /** 63324828550SGeert Uytterhoeven * ps3_sys_manager_final_restart - The final platform machine_restart routine. 63424828550SGeert Uytterhoeven * 63524828550SGeert Uytterhoeven * This routine never returns. The routine disables asynchronous vuart reads 63624828550SGeert Uytterhoeven * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 63724828550SGeert Uytterhoeven * the shutdown command sent from the system manager. Soon after the 63824828550SGeert Uytterhoeven * acknowledgement is sent the lpar is destroyed by the HV. This routine 63924828550SGeert Uytterhoeven * should only be called from ps3_restart() through ps3_sys_manager_ops.restart. 64024828550SGeert Uytterhoeven */ 64124828550SGeert Uytterhoeven 64224828550SGeert Uytterhoeven static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) 64324828550SGeert Uytterhoeven { 64424828550SGeert Uytterhoeven BUG_ON(!dev); 64524828550SGeert Uytterhoeven 64624828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 64724828550SGeert Uytterhoeven 64824828550SGeert Uytterhoeven /* Check if we got here via a power button event. */ 64924828550SGeert Uytterhoeven 65024828550SGeert Uytterhoeven if (ps3_sm_force_power_off) { 65124828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: forcing poweroff\n", 65224828550SGeert Uytterhoeven __func__, __LINE__); 65324828550SGeert Uytterhoeven ps3_sys_manager_final_power_off(dev); 65424828550SGeert Uytterhoeven } 65524828550SGeert Uytterhoeven 65624828550SGeert Uytterhoeven ps3_vuart_cancel_async(dev); 65724828550SGeert Uytterhoeven 65824828550SGeert Uytterhoeven ps3_sys_manager_send_attr(dev, 0); 65975ffe88dSGeoff Levand ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_REBOOT, 6601c43d265SGeoff Levand user_wake_sources); 66124828550SGeert Uytterhoeven 662ca052f79SGeert Uytterhoeven ps3_sys_manager_fin(dev); 66324828550SGeert Uytterhoeven } 66424828550SGeert Uytterhoeven 66524828550SGeert Uytterhoeven /** 6661c43d265SGeoff Levand * ps3_sys_manager_get_wol - Get wake-on-lan setting. 6671c43d265SGeoff Levand */ 6681c43d265SGeoff Levand 6691c43d265SGeoff Levand int ps3_sys_manager_get_wol(void) 6701c43d265SGeoff Levand { 6711c43d265SGeoff Levand pr_debug("%s:%d\n", __func__, __LINE__); 6721c43d265SGeoff Levand 6731c43d265SGeoff Levand return (user_wake_sources & PS3_SM_WAKE_W_O_L) != 0; 6741c43d265SGeoff Levand } 6751c43d265SGeoff Levand EXPORT_SYMBOL_GPL(ps3_sys_manager_get_wol); 6761c43d265SGeoff Levand 6771c43d265SGeoff Levand /** 6781c43d265SGeoff Levand * ps3_sys_manager_set_wol - Set wake-on-lan setting. 6791c43d265SGeoff Levand */ 6801c43d265SGeoff Levand 6811c43d265SGeoff Levand void ps3_sys_manager_set_wol(int state) 6821c43d265SGeoff Levand { 6831c43d265SGeoff Levand static DEFINE_MUTEX(mutex); 6841c43d265SGeoff Levand 6851c43d265SGeoff Levand mutex_lock(&mutex); 6861c43d265SGeoff Levand 6871c43d265SGeoff Levand pr_debug("%s:%d: %d\n", __func__, __LINE__, state); 6881c43d265SGeoff Levand 6891c43d265SGeoff Levand if (state) 6901c43d265SGeoff Levand user_wake_sources |= PS3_SM_WAKE_W_O_L; 6911c43d265SGeoff Levand else 6921c43d265SGeoff Levand user_wake_sources &= ~PS3_SM_WAKE_W_O_L; 6931c43d265SGeoff Levand mutex_unlock(&mutex); 6941c43d265SGeoff Levand } 6951c43d265SGeoff Levand EXPORT_SYMBOL_GPL(ps3_sys_manager_set_wol); 6961c43d265SGeoff Levand 6971c43d265SGeoff Levand /** 69824828550SGeert Uytterhoeven * ps3_sys_manager_work - Asynchronous read handler. 69924828550SGeert Uytterhoeven * 70024828550SGeert Uytterhoeven * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port. 70124828550SGeert Uytterhoeven */ 70224828550SGeert Uytterhoeven 70324828550SGeert Uytterhoeven static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) 70424828550SGeert Uytterhoeven { 70524828550SGeert Uytterhoeven ps3_sys_manager_handle_msg(dev); 70624828550SGeert Uytterhoeven ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 70724828550SGeert Uytterhoeven } 70824828550SGeert Uytterhoeven 709*0fe763c5SGreg Kroah-Hartman static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) 71024828550SGeert Uytterhoeven { 71124828550SGeert Uytterhoeven int result; 71224828550SGeert Uytterhoeven struct ps3_sys_manager_ops ops; 71324828550SGeert Uytterhoeven 71424828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 71524828550SGeert Uytterhoeven 71624828550SGeert Uytterhoeven ops.power_off = ps3_sys_manager_final_power_off; 71724828550SGeert Uytterhoeven ops.restart = ps3_sys_manager_final_restart; 71824828550SGeert Uytterhoeven ops.dev = dev; 71924828550SGeert Uytterhoeven 72024828550SGeert Uytterhoeven /* ps3_sys_manager_register_ops copies ops. */ 72124828550SGeert Uytterhoeven 72224828550SGeert Uytterhoeven ps3_sys_manager_register_ops(&ops); 72324828550SGeert Uytterhoeven 72424828550SGeert Uytterhoeven result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); 72524828550SGeert Uytterhoeven BUG_ON(result); 72624828550SGeert Uytterhoeven 72724828550SGeert Uytterhoeven result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 72824828550SGeert Uytterhoeven BUG_ON(result); 72924828550SGeert Uytterhoeven 73024828550SGeert Uytterhoeven return result; 73124828550SGeert Uytterhoeven } 73224828550SGeert Uytterhoeven 73324828550SGeert Uytterhoeven static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev) 73424828550SGeert Uytterhoeven { 73524828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 73624828550SGeert Uytterhoeven return 0; 73724828550SGeert Uytterhoeven } 73824828550SGeert Uytterhoeven 73924828550SGeert Uytterhoeven static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev) 74024828550SGeert Uytterhoeven { 74124828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 74224828550SGeert Uytterhoeven } 74324828550SGeert Uytterhoeven 74424828550SGeert Uytterhoeven static struct ps3_vuart_port_driver ps3_sys_manager = { 74524828550SGeert Uytterhoeven .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER, 74624828550SGeert Uytterhoeven .core.core.name = "ps3_sys_manager", 74724828550SGeert Uytterhoeven .probe = ps3_sys_manager_probe, 74824828550SGeert Uytterhoeven .remove = ps3_sys_manager_remove, 74924828550SGeert Uytterhoeven .shutdown = ps3_sys_manager_shutdown, 75024828550SGeert Uytterhoeven .work = ps3_sys_manager_work, 75124828550SGeert Uytterhoeven }; 75224828550SGeert Uytterhoeven 75324828550SGeert Uytterhoeven static int __init ps3_sys_manager_init(void) 75424828550SGeert Uytterhoeven { 75524828550SGeert Uytterhoeven if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 75624828550SGeert Uytterhoeven return -ENODEV; 75724828550SGeert Uytterhoeven 75824828550SGeert Uytterhoeven return ps3_vuart_port_driver_register(&ps3_sys_manager); 75924828550SGeert Uytterhoeven } 76024828550SGeert Uytterhoeven 76124828550SGeert Uytterhoeven module_init(ps3_sys_manager_init); 76224828550SGeert Uytterhoeven /* Module remove not supported. */ 76324828550SGeert Uytterhoeven 76450dad902SGeoff Levand MODULE_AUTHOR("Sony Corporation"); 76550dad902SGeoff Levand MODULE_LICENSE("GPL v2"); 76650dad902SGeoff Levand MODULE_DESCRIPTION("PS3 System Manager"); 76724828550SGeert Uytterhoeven MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER); 768