1*24828550SGeert Uytterhoeven /* 2*24828550SGeert Uytterhoeven * PS3 System Manager. 3*24828550SGeert Uytterhoeven * 4*24828550SGeert Uytterhoeven * Copyright (C) 2007 Sony Computer Entertainment Inc. 5*24828550SGeert Uytterhoeven * Copyright 2007 Sony Corp. 6*24828550SGeert Uytterhoeven * 7*24828550SGeert Uytterhoeven * This program is free software; you can redistribute it and/or modify 8*24828550SGeert Uytterhoeven * it under the terms of the GNU General Public License as published by 9*24828550SGeert Uytterhoeven * the Free Software Foundation; version 2 of the License. 10*24828550SGeert Uytterhoeven * 11*24828550SGeert Uytterhoeven * This program is distributed in the hope that it will be useful, 12*24828550SGeert Uytterhoeven * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*24828550SGeert Uytterhoeven * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*24828550SGeert Uytterhoeven * GNU General Public License for more details. 15*24828550SGeert Uytterhoeven * 16*24828550SGeert Uytterhoeven * You should have received a copy of the GNU General Public License 17*24828550SGeert Uytterhoeven * along with this program; if not, write to the Free Software 18*24828550SGeert Uytterhoeven * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19*24828550SGeert Uytterhoeven */ 20*24828550SGeert Uytterhoeven 21*24828550SGeert Uytterhoeven #include <linux/kernel.h> 22*24828550SGeert Uytterhoeven #include <linux/module.h> 23*24828550SGeert Uytterhoeven #include <linux/workqueue.h> 24*24828550SGeert Uytterhoeven #include <linux/reboot.h> 25*24828550SGeert Uytterhoeven 26*24828550SGeert Uytterhoeven #include <asm/firmware.h> 27*24828550SGeert Uytterhoeven #include <asm/ps3.h> 28*24828550SGeert Uytterhoeven 29*24828550SGeert Uytterhoeven #include "vuart.h" 30*24828550SGeert Uytterhoeven 31*24828550SGeert Uytterhoeven MODULE_AUTHOR("Sony Corporation"); 32*24828550SGeert Uytterhoeven MODULE_LICENSE("GPL v2"); 33*24828550SGeert Uytterhoeven MODULE_DESCRIPTION("PS3 System Manager"); 34*24828550SGeert Uytterhoeven 35*24828550SGeert Uytterhoeven /** 36*24828550SGeert Uytterhoeven * ps3_sys_manager - PS3 system manager driver. 37*24828550SGeert Uytterhoeven * 38*24828550SGeert Uytterhoeven * The system manager provides an asynchronous system event notification 39*24828550SGeert Uytterhoeven * mechanism for reporting events like thermal alert and button presses to 40*24828550SGeert Uytterhoeven * guests. It also provides support to control system shutdown and startup. 41*24828550SGeert Uytterhoeven * 42*24828550SGeert Uytterhoeven * The actual system manager is implemented as an application running in the 43*24828550SGeert Uytterhoeven * system policy module in lpar_1. Guests communicate with the system manager 44*24828550SGeert Uytterhoeven * through port 2 of the vuart using a simple packet message protocol. 45*24828550SGeert Uytterhoeven * Messages are comprised of a fixed field header followed by a message 46*24828550SGeert Uytterhoeven * specific payload. 47*24828550SGeert Uytterhoeven */ 48*24828550SGeert Uytterhoeven 49*24828550SGeert Uytterhoeven /** 50*24828550SGeert Uytterhoeven * struct ps3_sys_manager_header - System manager message header. 51*24828550SGeert Uytterhoeven * @version: Header version, currently 1. 52*24828550SGeert Uytterhoeven * @size: Header size in bytes, curently 16. 53*24828550SGeert Uytterhoeven * @payload_size: Message payload size in bytes. 54*24828550SGeert Uytterhoeven * @service_id: Message type, one of enum ps3_sys_manager_service_id. 55*24828550SGeert Uytterhoeven * @request_tag: Unique number to identify reply. 56*24828550SGeert Uytterhoeven */ 57*24828550SGeert Uytterhoeven 58*24828550SGeert Uytterhoeven struct ps3_sys_manager_header { 59*24828550SGeert Uytterhoeven /* version 1 */ 60*24828550SGeert Uytterhoeven u8 version; 61*24828550SGeert Uytterhoeven u8 size; 62*24828550SGeert Uytterhoeven u16 reserved_1; 63*24828550SGeert Uytterhoeven u32 payload_size; 64*24828550SGeert Uytterhoeven u16 service_id; 65*24828550SGeert Uytterhoeven u16 reserved_2; 66*24828550SGeert Uytterhoeven u32 request_tag; 67*24828550SGeert Uytterhoeven }; 68*24828550SGeert Uytterhoeven 69*24828550SGeert Uytterhoeven #define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__) 70*24828550SGeert Uytterhoeven static void __maybe_unused _dump_sm_header( 71*24828550SGeert Uytterhoeven const struct ps3_sys_manager_header *h, const char *func, int line) 72*24828550SGeert Uytterhoeven { 73*24828550SGeert Uytterhoeven pr_debug("%s:%d: version: %xh\n", func, line, h->version); 74*24828550SGeert Uytterhoeven pr_debug("%s:%d: size: %xh\n", func, line, h->size); 75*24828550SGeert Uytterhoeven pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size); 76*24828550SGeert Uytterhoeven pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id); 77*24828550SGeert Uytterhoeven pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag); 78*24828550SGeert Uytterhoeven } 79*24828550SGeert Uytterhoeven 80*24828550SGeert Uytterhoeven /** 81*24828550SGeert Uytterhoeven * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. 82*24828550SGeert Uytterhoeven * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. 83*24828550SGeert Uytterhoeven * 84*24828550SGeert Uytterhoeven * Currently all messages received from the system manager are either 85*24828550SGeert Uytterhoeven * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header 86*24828550SGeert Uytterhoeven * + 16 bytes payload = 32 bytes). This knowlege is used to simplify 87*24828550SGeert Uytterhoeven * the logic. 88*24828550SGeert Uytterhoeven */ 89*24828550SGeert Uytterhoeven 90*24828550SGeert Uytterhoeven enum { 91*24828550SGeert Uytterhoeven PS3_SM_RX_MSG_LEN_MIN = 24, 92*24828550SGeert Uytterhoeven PS3_SM_RX_MSG_LEN_MAX = 32, 93*24828550SGeert Uytterhoeven }; 94*24828550SGeert Uytterhoeven 95*24828550SGeert Uytterhoeven /** 96*24828550SGeert Uytterhoeven * enum ps3_sys_manager_service_id - Message header service_id. 97*24828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. 98*24828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. 99*24828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. 100*24828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. 101*24828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. 102*24828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. 103*24828550SGeert Uytterhoeven * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. 104*24828550SGeert Uytterhoeven * 105*24828550SGeert Uytterhoeven * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a 106*24828550SGeert Uytterhoeven * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when 107*24828550SGeert Uytterhoeven * a REQUEST message is sent at the wrong time. 108*24828550SGeert Uytterhoeven */ 109*24828550SGeert Uytterhoeven 110*24828550SGeert Uytterhoeven enum ps3_sys_manager_service_id { 111*24828550SGeert Uytterhoeven /* version 1 */ 112*24828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_REQUEST = 1, 113*24828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_RESPONSE = 2, 114*24828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_COMMAND = 3, 115*24828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, 116*24828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, 117*24828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_REQUEST_ERROR = 6, 118*24828550SGeert Uytterhoeven PS3_SM_SERVICE_ID_SET_ATTR = 8, 119*24828550SGeert Uytterhoeven }; 120*24828550SGeert Uytterhoeven 121*24828550SGeert Uytterhoeven /** 122*24828550SGeert Uytterhoeven * enum ps3_sys_manager_attr - Notification attribute (bit position mask). 123*24828550SGeert Uytterhoeven * @PS3_SM_ATTR_POWER: Power button. 124*24828550SGeert Uytterhoeven * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. 125*24828550SGeert Uytterhoeven * @PS3_SM_ATTR_THERMAL: Sytem thermal alert. 126*24828550SGeert Uytterhoeven * @PS3_SM_ATTR_CONTROLLER: Remote controller event. 127*24828550SGeert Uytterhoeven * @PS3_SM_ATTR_ALL: Logical OR of all. 128*24828550SGeert Uytterhoeven * 129*24828550SGeert Uytterhoeven * The guest tells the system manager which events it is interested in receiving 130*24828550SGeert Uytterhoeven * notice of by sending the system manager a logical OR of notification 131*24828550SGeert Uytterhoeven * attributes via the ps3_sys_manager_send_attr() routine. 132*24828550SGeert Uytterhoeven */ 133*24828550SGeert Uytterhoeven 134*24828550SGeert Uytterhoeven enum ps3_sys_manager_attr { 135*24828550SGeert Uytterhoeven /* version 1 */ 136*24828550SGeert Uytterhoeven PS3_SM_ATTR_POWER = 1, 137*24828550SGeert Uytterhoeven PS3_SM_ATTR_RESET = 2, 138*24828550SGeert Uytterhoeven PS3_SM_ATTR_THERMAL = 4, 139*24828550SGeert Uytterhoeven PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */ 140*24828550SGeert Uytterhoeven PS3_SM_ATTR_ALL = 0x0f, 141*24828550SGeert Uytterhoeven }; 142*24828550SGeert Uytterhoeven 143*24828550SGeert Uytterhoeven /** 144*24828550SGeert Uytterhoeven * enum ps3_sys_manager_event - External event type, reported by system manager. 145*24828550SGeert Uytterhoeven * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used. 146*24828550SGeert Uytterhoeven * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. 147*24828550SGeert Uytterhoeven * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used. 148*24828550SGeert Uytterhoeven * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. 149*24828550SGeert Uytterhoeven * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. 150*24828550SGeert Uytterhoeven * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. 151*24828550SGeert Uytterhoeven */ 152*24828550SGeert Uytterhoeven 153*24828550SGeert Uytterhoeven enum ps3_sys_manager_event { 154*24828550SGeert Uytterhoeven /* version 1 */ 155*24828550SGeert Uytterhoeven PS3_SM_EVENT_POWER_PRESSED = 3, 156*24828550SGeert Uytterhoeven PS3_SM_EVENT_POWER_RELEASED = 4, 157*24828550SGeert Uytterhoeven PS3_SM_EVENT_RESET_PRESSED = 5, 158*24828550SGeert Uytterhoeven PS3_SM_EVENT_RESET_RELEASED = 6, 159*24828550SGeert Uytterhoeven PS3_SM_EVENT_THERMAL_ALERT = 7, 160*24828550SGeert Uytterhoeven PS3_SM_EVENT_THERMAL_CLEARED = 8, 161*24828550SGeert Uytterhoeven /* no info on controller events */ 162*24828550SGeert Uytterhoeven }; 163*24828550SGeert Uytterhoeven 164*24828550SGeert Uytterhoeven /** 165*24828550SGeert Uytterhoeven * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. 166*24828550SGeert Uytterhoeven */ 167*24828550SGeert Uytterhoeven 168*24828550SGeert Uytterhoeven enum ps3_sys_manager_next_op { 169*24828550SGeert Uytterhoeven /* version 3 */ 170*24828550SGeert Uytterhoeven PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, 171*24828550SGeert Uytterhoeven PS3_SM_NEXT_OP_SYS_REBOOT = 2, 172*24828550SGeert Uytterhoeven PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, 173*24828550SGeert Uytterhoeven }; 174*24828550SGeert Uytterhoeven 175*24828550SGeert Uytterhoeven /** 176*24828550SGeert Uytterhoeven * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). 177*24828550SGeert Uytterhoeven * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR 178*24828550SGeert Uytterhoeven * controller, and bluetooth controller. 179*24828550SGeert Uytterhoeven * @PS3_SM_WAKE_RTC: 180*24828550SGeert Uytterhoeven * @PS3_SM_WAKE_RTC_ERROR: 181*24828550SGeert Uytterhoeven * @PS3_SM_WAKE_P_O_R: Power on reset. 182*24828550SGeert Uytterhoeven * 183*24828550SGeert Uytterhoeven * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. 184*24828550SGeert Uytterhoeven * System will always wake from the PS3_SM_WAKE_DEFAULT sources. 185*24828550SGeert Uytterhoeven */ 186*24828550SGeert Uytterhoeven 187*24828550SGeert Uytterhoeven enum ps3_sys_manager_wake_source { 188*24828550SGeert Uytterhoeven /* version 3 */ 189*24828550SGeert Uytterhoeven PS3_SM_WAKE_DEFAULT = 0, 190*24828550SGeert Uytterhoeven PS3_SM_WAKE_RTC = 0x00000040, 191*24828550SGeert Uytterhoeven PS3_SM_WAKE_RTC_ERROR = 0x00000080, 192*24828550SGeert Uytterhoeven PS3_SM_WAKE_P_O_R = 0x10000000, 193*24828550SGeert Uytterhoeven }; 194*24828550SGeert Uytterhoeven 195*24828550SGeert Uytterhoeven /** 196*24828550SGeert Uytterhoeven * enum ps3_sys_manager_cmd - Command from system manager to guest. 197*24828550SGeert Uytterhoeven * 198*24828550SGeert Uytterhoeven * The guest completes the actions needed, then acks or naks the command via 199*24828550SGeert Uytterhoeven * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, 200*24828550SGeert Uytterhoeven * the guest must be fully prepared for a system poweroff prior to acking the 201*24828550SGeert Uytterhoeven * command. 202*24828550SGeert Uytterhoeven */ 203*24828550SGeert Uytterhoeven 204*24828550SGeert Uytterhoeven enum ps3_sys_manager_cmd { 205*24828550SGeert Uytterhoeven /* version 1 */ 206*24828550SGeert Uytterhoeven PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ 207*24828550SGeert Uytterhoeven }; 208*24828550SGeert Uytterhoeven 209*24828550SGeert Uytterhoeven /** 210*24828550SGeert Uytterhoeven * ps3_sm_force_power_off - Poweroff helper. 211*24828550SGeert Uytterhoeven * 212*24828550SGeert Uytterhoeven * A global variable used to force a poweroff when the power button has 213*24828550SGeert Uytterhoeven * been pressed irrespective of how init handles the ctrl_alt_del signal. 214*24828550SGeert Uytterhoeven * 215*24828550SGeert Uytterhoeven */ 216*24828550SGeert Uytterhoeven 217*24828550SGeert Uytterhoeven static unsigned int ps3_sm_force_power_off; 218*24828550SGeert Uytterhoeven 219*24828550SGeert Uytterhoeven /** 220*24828550SGeert Uytterhoeven * ps3_sys_manager_write - Helper to write a two part message to the vuart. 221*24828550SGeert Uytterhoeven * 222*24828550SGeert Uytterhoeven */ 223*24828550SGeert Uytterhoeven 224*24828550SGeert Uytterhoeven static int ps3_sys_manager_write(struct ps3_system_bus_device *dev, 225*24828550SGeert Uytterhoeven const struct ps3_sys_manager_header *header, const void *payload) 226*24828550SGeert Uytterhoeven { 227*24828550SGeert Uytterhoeven int result; 228*24828550SGeert Uytterhoeven 229*24828550SGeert Uytterhoeven BUG_ON(header->version != 1); 230*24828550SGeert Uytterhoeven BUG_ON(header->size != 16); 231*24828550SGeert Uytterhoeven BUG_ON(header->payload_size != 8 && header->payload_size != 16); 232*24828550SGeert Uytterhoeven BUG_ON(header->service_id > 8); 233*24828550SGeert Uytterhoeven 234*24828550SGeert Uytterhoeven result = ps3_vuart_write(dev, header, 235*24828550SGeert Uytterhoeven sizeof(struct ps3_sys_manager_header)); 236*24828550SGeert Uytterhoeven 237*24828550SGeert Uytterhoeven if (!result) 238*24828550SGeert Uytterhoeven result = ps3_vuart_write(dev, payload, header->payload_size); 239*24828550SGeert Uytterhoeven 240*24828550SGeert Uytterhoeven return result; 241*24828550SGeert Uytterhoeven } 242*24828550SGeert Uytterhoeven 243*24828550SGeert Uytterhoeven /** 244*24828550SGeert Uytterhoeven * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. 245*24828550SGeert Uytterhoeven * 246*24828550SGeert Uytterhoeven */ 247*24828550SGeert Uytterhoeven 248*24828550SGeert Uytterhoeven static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev, 249*24828550SGeert Uytterhoeven enum ps3_sys_manager_attr attr) 250*24828550SGeert Uytterhoeven { 251*24828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 252*24828550SGeert Uytterhoeven struct { 253*24828550SGeert Uytterhoeven u8 version; 254*24828550SGeert Uytterhoeven u8 reserved_1[3]; 255*24828550SGeert Uytterhoeven u32 attribute; 256*24828550SGeert Uytterhoeven } payload; 257*24828550SGeert Uytterhoeven 258*24828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 8); 259*24828550SGeert Uytterhoeven 260*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); 261*24828550SGeert Uytterhoeven 262*24828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 263*24828550SGeert Uytterhoeven header.version = 1; 264*24828550SGeert Uytterhoeven header.size = 16; 265*24828550SGeert Uytterhoeven header.payload_size = 16; 266*24828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_SET_ATTR; 267*24828550SGeert Uytterhoeven 268*24828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 269*24828550SGeert Uytterhoeven payload.version = 1; 270*24828550SGeert Uytterhoeven payload.attribute = attr; 271*24828550SGeert Uytterhoeven 272*24828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 273*24828550SGeert Uytterhoeven } 274*24828550SGeert Uytterhoeven 275*24828550SGeert Uytterhoeven /** 276*24828550SGeert Uytterhoeven * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. 277*24828550SGeert Uytterhoeven * 278*24828550SGeert Uytterhoeven * Tell the system manager what to do after this lpar is destroyed. 279*24828550SGeert Uytterhoeven */ 280*24828550SGeert Uytterhoeven 281*24828550SGeert Uytterhoeven static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev, 282*24828550SGeert Uytterhoeven enum ps3_sys_manager_next_op op, 283*24828550SGeert Uytterhoeven enum ps3_sys_manager_wake_source wake_source) 284*24828550SGeert Uytterhoeven { 285*24828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 286*24828550SGeert Uytterhoeven struct { 287*24828550SGeert Uytterhoeven u8 version; 288*24828550SGeert Uytterhoeven u8 type; 289*24828550SGeert Uytterhoeven u8 gos_id; 290*24828550SGeert Uytterhoeven u8 reserved_1; 291*24828550SGeert Uytterhoeven u32 wake_source; 292*24828550SGeert Uytterhoeven u8 reserved_2[8]; 293*24828550SGeert Uytterhoeven } payload; 294*24828550SGeert Uytterhoeven 295*24828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 296*24828550SGeert Uytterhoeven 297*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); 298*24828550SGeert Uytterhoeven 299*24828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 300*24828550SGeert Uytterhoeven header.version = 1; 301*24828550SGeert Uytterhoeven header.size = 16; 302*24828550SGeert Uytterhoeven header.payload_size = 16; 303*24828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP; 304*24828550SGeert Uytterhoeven 305*24828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 306*24828550SGeert Uytterhoeven payload.version = 3; 307*24828550SGeert Uytterhoeven payload.type = op; 308*24828550SGeert Uytterhoeven payload.gos_id = 3; /* other os */ 309*24828550SGeert Uytterhoeven payload.wake_source = wake_source; 310*24828550SGeert Uytterhoeven 311*24828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 312*24828550SGeert Uytterhoeven } 313*24828550SGeert Uytterhoeven 314*24828550SGeert Uytterhoeven /** 315*24828550SGeert Uytterhoeven * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. 316*24828550SGeert Uytterhoeven * 317*24828550SGeert Uytterhoeven * The guest sends this message to request an operation or action of the system 318*24828550SGeert Uytterhoeven * manager. The reply is a command message from the system manager. In the 319*24828550SGeert Uytterhoeven * command handler the guest performs the requested operation. The result of 320*24828550SGeert Uytterhoeven * the command is then communicated back to the system manager with a response 321*24828550SGeert Uytterhoeven * message. 322*24828550SGeert Uytterhoeven * 323*24828550SGeert Uytterhoeven * Currently, the only supported request is the 'shutdown self' request. 324*24828550SGeert Uytterhoeven */ 325*24828550SGeert Uytterhoeven 326*24828550SGeert Uytterhoeven static int ps3_sys_manager_send_request_shutdown( 327*24828550SGeert Uytterhoeven struct ps3_system_bus_device *dev) 328*24828550SGeert Uytterhoeven { 329*24828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 330*24828550SGeert Uytterhoeven struct { 331*24828550SGeert Uytterhoeven u8 version; 332*24828550SGeert Uytterhoeven u8 type; 333*24828550SGeert Uytterhoeven u8 gos_id; 334*24828550SGeert Uytterhoeven u8 reserved_1[13]; 335*24828550SGeert Uytterhoeven } payload; 336*24828550SGeert Uytterhoeven 337*24828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 338*24828550SGeert Uytterhoeven 339*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 340*24828550SGeert Uytterhoeven 341*24828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 342*24828550SGeert Uytterhoeven header.version = 1; 343*24828550SGeert Uytterhoeven header.size = 16; 344*24828550SGeert Uytterhoeven header.payload_size = 16; 345*24828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_REQUEST; 346*24828550SGeert Uytterhoeven 347*24828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 348*24828550SGeert Uytterhoeven payload.version = 1; 349*24828550SGeert Uytterhoeven payload.type = 1; /* shutdown */ 350*24828550SGeert Uytterhoeven payload.gos_id = 0; /* self */ 351*24828550SGeert Uytterhoeven 352*24828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 353*24828550SGeert Uytterhoeven } 354*24828550SGeert Uytterhoeven 355*24828550SGeert Uytterhoeven /** 356*24828550SGeert Uytterhoeven * ps3_sys_manager_send_response - Send a 'response' to the system manager. 357*24828550SGeert Uytterhoeven * @status: zero = success, others fail. 358*24828550SGeert Uytterhoeven * 359*24828550SGeert Uytterhoeven * The guest sends this message to the system manager to acnowledge success or 360*24828550SGeert Uytterhoeven * failure of a command sent by the system manager. 361*24828550SGeert Uytterhoeven */ 362*24828550SGeert Uytterhoeven 363*24828550SGeert Uytterhoeven static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev, 364*24828550SGeert Uytterhoeven u64 status) 365*24828550SGeert Uytterhoeven { 366*24828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 367*24828550SGeert Uytterhoeven struct { 368*24828550SGeert Uytterhoeven u8 version; 369*24828550SGeert Uytterhoeven u8 reserved_1[3]; 370*24828550SGeert Uytterhoeven u8 status; 371*24828550SGeert Uytterhoeven u8 reserved_2[11]; 372*24828550SGeert Uytterhoeven } payload; 373*24828550SGeert Uytterhoeven 374*24828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(payload) != 16); 375*24828550SGeert Uytterhoeven 376*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 377*24828550SGeert Uytterhoeven (status ? "nak" : "ack")); 378*24828550SGeert Uytterhoeven 379*24828550SGeert Uytterhoeven memset(&header, 0, sizeof(header)); 380*24828550SGeert Uytterhoeven header.version = 1; 381*24828550SGeert Uytterhoeven header.size = 16; 382*24828550SGeert Uytterhoeven header.payload_size = 16; 383*24828550SGeert Uytterhoeven header.service_id = PS3_SM_SERVICE_ID_RESPONSE; 384*24828550SGeert Uytterhoeven 385*24828550SGeert Uytterhoeven memset(&payload, 0, sizeof(payload)); 386*24828550SGeert Uytterhoeven payload.version = 1; 387*24828550SGeert Uytterhoeven payload.status = status; 388*24828550SGeert Uytterhoeven 389*24828550SGeert Uytterhoeven return ps3_sys_manager_write(dev, &header, &payload); 390*24828550SGeert Uytterhoeven } 391*24828550SGeert Uytterhoeven 392*24828550SGeert Uytterhoeven /** 393*24828550SGeert Uytterhoeven * ps3_sys_manager_handle_event - Second stage event msg handler. 394*24828550SGeert Uytterhoeven * 395*24828550SGeert Uytterhoeven */ 396*24828550SGeert Uytterhoeven 397*24828550SGeert Uytterhoeven static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) 398*24828550SGeert Uytterhoeven { 399*24828550SGeert Uytterhoeven int result; 400*24828550SGeert Uytterhoeven struct { 401*24828550SGeert Uytterhoeven u8 version; 402*24828550SGeert Uytterhoeven u8 type; 403*24828550SGeert Uytterhoeven u8 reserved_1[2]; 404*24828550SGeert Uytterhoeven u32 value; 405*24828550SGeert Uytterhoeven u8 reserved_2[8]; 406*24828550SGeert Uytterhoeven } event; 407*24828550SGeert Uytterhoeven 408*24828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(event) != 16); 409*24828550SGeert Uytterhoeven 410*24828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &event, sizeof(event)); 411*24828550SGeert Uytterhoeven BUG_ON(result && "need to retry here"); 412*24828550SGeert Uytterhoeven 413*24828550SGeert Uytterhoeven if (event.version != 1) { 414*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", 415*24828550SGeert Uytterhoeven __func__, __LINE__, event.version); 416*24828550SGeert Uytterhoeven return -EIO; 417*24828550SGeert Uytterhoeven } 418*24828550SGeert Uytterhoeven 419*24828550SGeert Uytterhoeven switch (event.type) { 420*24828550SGeert Uytterhoeven case PS3_SM_EVENT_POWER_PRESSED: 421*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", 422*24828550SGeert Uytterhoeven __func__, __LINE__); 423*24828550SGeert Uytterhoeven ps3_sm_force_power_off = 1; 424*24828550SGeert Uytterhoeven /* 425*24828550SGeert Uytterhoeven * A memory barrier is use here to sync memory since 426*24828550SGeert Uytterhoeven * ps3_sys_manager_final_restart() could be called on 427*24828550SGeert Uytterhoeven * another cpu. 428*24828550SGeert Uytterhoeven */ 429*24828550SGeert Uytterhoeven wmb(); 430*24828550SGeert Uytterhoeven kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 431*24828550SGeert Uytterhoeven break; 432*24828550SGeert Uytterhoeven case PS3_SM_EVENT_POWER_RELEASED: 433*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", 434*24828550SGeert Uytterhoeven __func__, __LINE__, event.value); 435*24828550SGeert Uytterhoeven break; 436*24828550SGeert Uytterhoeven case PS3_SM_EVENT_RESET_PRESSED: 437*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: RESET_PRESSED\n", 438*24828550SGeert Uytterhoeven __func__, __LINE__); 439*24828550SGeert Uytterhoeven ps3_sm_force_power_off = 0; 440*24828550SGeert Uytterhoeven /* 441*24828550SGeert Uytterhoeven * A memory barrier is use here to sync memory since 442*24828550SGeert Uytterhoeven * ps3_sys_manager_final_restart() could be called on 443*24828550SGeert Uytterhoeven * another cpu. 444*24828550SGeert Uytterhoeven */ 445*24828550SGeert Uytterhoeven wmb(); 446*24828550SGeert Uytterhoeven kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 447*24828550SGeert Uytterhoeven break; 448*24828550SGeert Uytterhoeven case PS3_SM_EVENT_RESET_RELEASED: 449*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n", 450*24828550SGeert Uytterhoeven __func__, __LINE__, event.value); 451*24828550SGeert Uytterhoeven break; 452*24828550SGeert Uytterhoeven case PS3_SM_EVENT_THERMAL_ALERT: 453*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", 454*24828550SGeert Uytterhoeven __func__, __LINE__, event.value); 455*24828550SGeert Uytterhoeven printk(KERN_INFO "PS3 Thermal Alert Zone %u\n", event.value); 456*24828550SGeert Uytterhoeven break; 457*24828550SGeert Uytterhoeven case PS3_SM_EVENT_THERMAL_CLEARED: 458*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", 459*24828550SGeert Uytterhoeven __func__, __LINE__, event.value); 460*24828550SGeert Uytterhoeven break; 461*24828550SGeert Uytterhoeven default: 462*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", 463*24828550SGeert Uytterhoeven __func__, __LINE__, event.type); 464*24828550SGeert Uytterhoeven return -EIO; 465*24828550SGeert Uytterhoeven } 466*24828550SGeert Uytterhoeven 467*24828550SGeert Uytterhoeven return 0; 468*24828550SGeert Uytterhoeven } 469*24828550SGeert Uytterhoeven /** 470*24828550SGeert Uytterhoeven * ps3_sys_manager_handle_cmd - Second stage command msg handler. 471*24828550SGeert Uytterhoeven * 472*24828550SGeert Uytterhoeven * The system manager sends this in reply to a 'request' message from the guest. 473*24828550SGeert Uytterhoeven */ 474*24828550SGeert Uytterhoeven 475*24828550SGeert Uytterhoeven static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev) 476*24828550SGeert Uytterhoeven { 477*24828550SGeert Uytterhoeven int result; 478*24828550SGeert Uytterhoeven struct { 479*24828550SGeert Uytterhoeven u8 version; 480*24828550SGeert Uytterhoeven u8 type; 481*24828550SGeert Uytterhoeven u8 reserved_1[14]; 482*24828550SGeert Uytterhoeven } cmd; 483*24828550SGeert Uytterhoeven 484*24828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(cmd) != 16); 485*24828550SGeert Uytterhoeven 486*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 487*24828550SGeert Uytterhoeven 488*24828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); 489*24828550SGeert Uytterhoeven BUG_ON(result && "need to retry here"); 490*24828550SGeert Uytterhoeven 491*24828550SGeert Uytterhoeven if(result) 492*24828550SGeert Uytterhoeven return result; 493*24828550SGeert Uytterhoeven 494*24828550SGeert Uytterhoeven if (cmd.version != 1) { 495*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", 496*24828550SGeert Uytterhoeven __func__, __LINE__, cmd.version); 497*24828550SGeert Uytterhoeven return -EIO; 498*24828550SGeert Uytterhoeven } 499*24828550SGeert Uytterhoeven 500*24828550SGeert Uytterhoeven if (cmd.type != PS3_SM_CMD_SHUTDOWN) { 501*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", 502*24828550SGeert Uytterhoeven __func__, __LINE__, cmd.type); 503*24828550SGeert Uytterhoeven return -EIO; 504*24828550SGeert Uytterhoeven } 505*24828550SGeert Uytterhoeven 506*24828550SGeert Uytterhoeven ps3_sys_manager_send_response(dev, 0); 507*24828550SGeert Uytterhoeven return 0; 508*24828550SGeert Uytterhoeven } 509*24828550SGeert Uytterhoeven 510*24828550SGeert Uytterhoeven /** 511*24828550SGeert Uytterhoeven * ps3_sys_manager_handle_msg - First stage msg handler. 512*24828550SGeert Uytterhoeven * 513*24828550SGeert Uytterhoeven * Can be called directly to manually poll vuart and pump message handler. 514*24828550SGeert Uytterhoeven */ 515*24828550SGeert Uytterhoeven 516*24828550SGeert Uytterhoeven static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev) 517*24828550SGeert Uytterhoeven { 518*24828550SGeert Uytterhoeven int result; 519*24828550SGeert Uytterhoeven struct ps3_sys_manager_header header; 520*24828550SGeert Uytterhoeven 521*24828550SGeert Uytterhoeven result = ps3_vuart_read(dev, &header, 522*24828550SGeert Uytterhoeven sizeof(struct ps3_sys_manager_header)); 523*24828550SGeert Uytterhoeven 524*24828550SGeert Uytterhoeven if(result) 525*24828550SGeert Uytterhoeven return result; 526*24828550SGeert Uytterhoeven 527*24828550SGeert Uytterhoeven if (header.version != 1) { 528*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", 529*24828550SGeert Uytterhoeven __func__, __LINE__, header.version); 530*24828550SGeert Uytterhoeven dump_sm_header(&header); 531*24828550SGeert Uytterhoeven goto fail_header; 532*24828550SGeert Uytterhoeven } 533*24828550SGeert Uytterhoeven 534*24828550SGeert Uytterhoeven BUILD_BUG_ON(sizeof(header) != 16); 535*24828550SGeert Uytterhoeven 536*24828550SGeert Uytterhoeven if (header.size != 16 || (header.payload_size != 8 537*24828550SGeert Uytterhoeven && header.payload_size != 16)) { 538*24828550SGeert Uytterhoeven dump_sm_header(&header); 539*24828550SGeert Uytterhoeven BUG(); 540*24828550SGeert Uytterhoeven } 541*24828550SGeert Uytterhoeven 542*24828550SGeert Uytterhoeven switch (header.service_id) { 543*24828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_EXTERN_EVENT: 544*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); 545*24828550SGeert Uytterhoeven return ps3_sys_manager_handle_event(dev); 546*24828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_COMMAND: 547*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); 548*24828550SGeert Uytterhoeven return ps3_sys_manager_handle_cmd(dev); 549*24828550SGeert Uytterhoeven case PS3_SM_SERVICE_ID_REQUEST_ERROR: 550*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__, 551*24828550SGeert Uytterhoeven __LINE__); 552*24828550SGeert Uytterhoeven dump_sm_header(&header); 553*24828550SGeert Uytterhoeven break; 554*24828550SGeert Uytterhoeven default: 555*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", 556*24828550SGeert Uytterhoeven __func__, __LINE__, header.service_id); 557*24828550SGeert Uytterhoeven break; 558*24828550SGeert Uytterhoeven } 559*24828550SGeert Uytterhoeven goto fail_id; 560*24828550SGeert Uytterhoeven 561*24828550SGeert Uytterhoeven fail_header: 562*24828550SGeert Uytterhoeven ps3_vuart_clear_rx_bytes(dev, 0); 563*24828550SGeert Uytterhoeven return -EIO; 564*24828550SGeert Uytterhoeven fail_id: 565*24828550SGeert Uytterhoeven ps3_vuart_clear_rx_bytes(dev, header.payload_size); 566*24828550SGeert Uytterhoeven return -EIO; 567*24828550SGeert Uytterhoeven } 568*24828550SGeert Uytterhoeven 569*24828550SGeert Uytterhoeven /** 570*24828550SGeert Uytterhoeven * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. 571*24828550SGeert Uytterhoeven * 572*24828550SGeert Uytterhoeven * This routine never returns. The routine disables asynchronous vuart reads 573*24828550SGeert Uytterhoeven * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 574*24828550SGeert Uytterhoeven * the shutdown command sent from the system manager. Soon after the 575*24828550SGeert Uytterhoeven * acknowledgement is sent the lpar is destroyed by the HV. This routine 576*24828550SGeert Uytterhoeven * should only be called from ps3_power_off() through 577*24828550SGeert Uytterhoeven * ps3_sys_manager_ops.power_off. 578*24828550SGeert Uytterhoeven */ 579*24828550SGeert Uytterhoeven 580*24828550SGeert Uytterhoeven static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev) 581*24828550SGeert Uytterhoeven { 582*24828550SGeert Uytterhoeven BUG_ON(!dev); 583*24828550SGeert Uytterhoeven 584*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 585*24828550SGeert Uytterhoeven 586*24828550SGeert Uytterhoeven ps3_vuart_cancel_async(dev); 587*24828550SGeert Uytterhoeven 588*24828550SGeert Uytterhoeven ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, 589*24828550SGeert Uytterhoeven PS3_SM_WAKE_DEFAULT); 590*24828550SGeert Uytterhoeven ps3_sys_manager_send_request_shutdown(dev); 591*24828550SGeert Uytterhoeven 592*24828550SGeert Uytterhoeven printk(KERN_EMERG "System Halted, OK to turn off power\n"); 593*24828550SGeert Uytterhoeven 594*24828550SGeert Uytterhoeven while(1) 595*24828550SGeert Uytterhoeven ps3_sys_manager_handle_msg(dev); 596*24828550SGeert Uytterhoeven } 597*24828550SGeert Uytterhoeven 598*24828550SGeert Uytterhoeven /** 599*24828550SGeert Uytterhoeven * ps3_sys_manager_final_restart - The final platform machine_restart routine. 600*24828550SGeert Uytterhoeven * 601*24828550SGeert Uytterhoeven * This routine never returns. The routine disables asynchronous vuart reads 602*24828550SGeert Uytterhoeven * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 603*24828550SGeert Uytterhoeven * the shutdown command sent from the system manager. Soon after the 604*24828550SGeert Uytterhoeven * acknowledgement is sent the lpar is destroyed by the HV. This routine 605*24828550SGeert Uytterhoeven * should only be called from ps3_restart() through ps3_sys_manager_ops.restart. 606*24828550SGeert Uytterhoeven */ 607*24828550SGeert Uytterhoeven 608*24828550SGeert Uytterhoeven static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) 609*24828550SGeert Uytterhoeven { 610*24828550SGeert Uytterhoeven BUG_ON(!dev); 611*24828550SGeert Uytterhoeven 612*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 613*24828550SGeert Uytterhoeven 614*24828550SGeert Uytterhoeven /* Check if we got here via a power button event. */ 615*24828550SGeert Uytterhoeven 616*24828550SGeert Uytterhoeven if (ps3_sm_force_power_off) { 617*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d: forcing poweroff\n", 618*24828550SGeert Uytterhoeven __func__, __LINE__); 619*24828550SGeert Uytterhoeven ps3_sys_manager_final_power_off(dev); 620*24828550SGeert Uytterhoeven } 621*24828550SGeert Uytterhoeven 622*24828550SGeert Uytterhoeven ps3_vuart_cancel_async(dev); 623*24828550SGeert Uytterhoeven 624*24828550SGeert Uytterhoeven ps3_sys_manager_send_attr(dev, 0); 625*24828550SGeert Uytterhoeven ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT, 626*24828550SGeert Uytterhoeven PS3_SM_WAKE_DEFAULT); 627*24828550SGeert Uytterhoeven ps3_sys_manager_send_request_shutdown(dev); 628*24828550SGeert Uytterhoeven 629*24828550SGeert Uytterhoeven printk(KERN_EMERG "System Halted, OK to turn off power\n"); 630*24828550SGeert Uytterhoeven 631*24828550SGeert Uytterhoeven while(1) 632*24828550SGeert Uytterhoeven ps3_sys_manager_handle_msg(dev); 633*24828550SGeert Uytterhoeven } 634*24828550SGeert Uytterhoeven 635*24828550SGeert Uytterhoeven /** 636*24828550SGeert Uytterhoeven * ps3_sys_manager_work - Asynchronous read handler. 637*24828550SGeert Uytterhoeven * 638*24828550SGeert Uytterhoeven * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port. 639*24828550SGeert Uytterhoeven */ 640*24828550SGeert Uytterhoeven 641*24828550SGeert Uytterhoeven static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) 642*24828550SGeert Uytterhoeven { 643*24828550SGeert Uytterhoeven ps3_sys_manager_handle_msg(dev); 644*24828550SGeert Uytterhoeven ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 645*24828550SGeert Uytterhoeven } 646*24828550SGeert Uytterhoeven 647*24828550SGeert Uytterhoeven static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) 648*24828550SGeert Uytterhoeven { 649*24828550SGeert Uytterhoeven int result; 650*24828550SGeert Uytterhoeven struct ps3_sys_manager_ops ops; 651*24828550SGeert Uytterhoeven 652*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 653*24828550SGeert Uytterhoeven 654*24828550SGeert Uytterhoeven ops.power_off = ps3_sys_manager_final_power_off; 655*24828550SGeert Uytterhoeven ops.restart = ps3_sys_manager_final_restart; 656*24828550SGeert Uytterhoeven ops.dev = dev; 657*24828550SGeert Uytterhoeven 658*24828550SGeert Uytterhoeven /* ps3_sys_manager_register_ops copies ops. */ 659*24828550SGeert Uytterhoeven 660*24828550SGeert Uytterhoeven ps3_sys_manager_register_ops(&ops); 661*24828550SGeert Uytterhoeven 662*24828550SGeert Uytterhoeven result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); 663*24828550SGeert Uytterhoeven BUG_ON(result); 664*24828550SGeert Uytterhoeven 665*24828550SGeert Uytterhoeven result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 666*24828550SGeert Uytterhoeven BUG_ON(result); 667*24828550SGeert Uytterhoeven 668*24828550SGeert Uytterhoeven return result; 669*24828550SGeert Uytterhoeven } 670*24828550SGeert Uytterhoeven 671*24828550SGeert Uytterhoeven static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev) 672*24828550SGeert Uytterhoeven { 673*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 674*24828550SGeert Uytterhoeven return 0; 675*24828550SGeert Uytterhoeven } 676*24828550SGeert Uytterhoeven 677*24828550SGeert Uytterhoeven static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev) 678*24828550SGeert Uytterhoeven { 679*24828550SGeert Uytterhoeven dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 680*24828550SGeert Uytterhoeven } 681*24828550SGeert Uytterhoeven 682*24828550SGeert Uytterhoeven static struct ps3_vuart_port_driver ps3_sys_manager = { 683*24828550SGeert Uytterhoeven .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER, 684*24828550SGeert Uytterhoeven .core.core.name = "ps3_sys_manager", 685*24828550SGeert Uytterhoeven .probe = ps3_sys_manager_probe, 686*24828550SGeert Uytterhoeven .remove = ps3_sys_manager_remove, 687*24828550SGeert Uytterhoeven .shutdown = ps3_sys_manager_shutdown, 688*24828550SGeert Uytterhoeven .work = ps3_sys_manager_work, 689*24828550SGeert Uytterhoeven }; 690*24828550SGeert Uytterhoeven 691*24828550SGeert Uytterhoeven static int __init ps3_sys_manager_init(void) 692*24828550SGeert Uytterhoeven { 693*24828550SGeert Uytterhoeven if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 694*24828550SGeert Uytterhoeven return -ENODEV; 695*24828550SGeert Uytterhoeven 696*24828550SGeert Uytterhoeven return ps3_vuart_port_driver_register(&ps3_sys_manager); 697*24828550SGeert Uytterhoeven } 698*24828550SGeert Uytterhoeven 699*24828550SGeert Uytterhoeven module_init(ps3_sys_manager_init); 700*24828550SGeert Uytterhoeven /* Module remove not supported. */ 701*24828550SGeert Uytterhoeven 702*24828550SGeert Uytterhoeven MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER); 703