brintos

brintos / linux-shallow public Read only

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