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__)
_dump_sm_header(const struct ps3_sys_manager_header * h,const char * func,int 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
ps3_sys_manager_write(struct ps3_system_bus_device * dev,const struct ps3_sys_manager_header * header,const void * payload)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
ps3_sys_manager_send_attr(struct ps3_system_bus_device * dev,enum ps3_sys_manager_attr attr)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
ps3_sys_manager_send_next_op(struct ps3_system_bus_device * dev,enum ps3_sys_manager_next_op op,enum ps3_sys_manager_wake_source wake_source)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
ps3_sys_manager_send_request_shutdown(struct ps3_system_bus_device * dev)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
ps3_sys_manager_send_response(struct ps3_system_bus_device * dev,u64 status)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
ps3_sys_manager_handle_event(struct ps3_system_bus_device * dev)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
ps3_sys_manager_handle_cmd(struct ps3_system_bus_device * dev)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
ps3_sys_manager_handle_msg(struct ps3_system_bus_device * dev)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
ps3_sys_manager_fin(struct ps3_system_bus_device * dev)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
ps3_sys_manager_final_power_off(struct ps3_system_bus_device * dev)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
ps3_sys_manager_final_restart(struct ps3_system_bus_device * dev)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
ps3_sys_manager_get_wol(void)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
ps3_sys_manager_set_wol(int state)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
ps3_sys_manager_work(struct ps3_system_bus_device * dev)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
ps3_sys_manager_probe(struct ps3_system_bus_device * dev)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
ps3_sys_manager_remove(struct ps3_system_bus_device * dev)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
ps3_sys_manager_shutdown(struct ps3_system_bus_device * dev)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
ps3_sys_manager_init(void)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