brintos

brintos / linux-shallow public Read only

0
0
Text · 22.3 KiB · 14a9d8a Raw
885 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Driver for the Surface ACPI Notify (SAN) interface/shim.4 *5 * Translates communication from ACPI to Surface System Aggregator Module6 * (SSAM/SAM) requests and back, specifically SAM-over-SSH. Translates SSAM7 * events back to ACPI notifications. Allows handling of discrete GPU8 * notifications sent from ACPI via the SAN interface by providing them to any9 * registered external driver.10 *11 * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>12 */13 14#include <linux/unaligned.h>15#include <linux/acpi.h>16#include <linux/delay.h>17#include <linux/jiffies.h>18#include <linux/kernel.h>19#include <linux/module.h>20#include <linux/notifier.h>21#include <linux/platform_device.h>22#include <linux/rwsem.h>23 24#include <linux/surface_aggregator/controller.h>25#include <linux/surface_acpi_notify.h>26 27struct san_data {28	struct device *dev;29	struct ssam_controller *ctrl;30 31	struct acpi_connection_info info;32 33	struct ssam_event_notifier nf_bat;34	struct ssam_event_notifier nf_tmp;35};36 37#define to_san_data(ptr, member) \38	container_of(ptr, struct san_data, member)39 40static struct workqueue_struct *san_wq;41 42/* -- dGPU notifier interface. ---------------------------------------------- */43 44struct san_rqsg_if {45	struct rw_semaphore lock;46	struct device *dev;47	struct blocking_notifier_head nh;48};49 50static struct san_rqsg_if san_rqsg_if = {51	.lock = __RWSEM_INITIALIZER(san_rqsg_if.lock),52	.dev = NULL,53	.nh = BLOCKING_NOTIFIER_INIT(san_rqsg_if.nh),54};55 56static int san_set_rqsg_interface_device(struct device *dev)57{58	int status = 0;59 60	down_write(&san_rqsg_if.lock);61	if (!san_rqsg_if.dev && dev)62		san_rqsg_if.dev = dev;63	else64		status = -EBUSY;65	up_write(&san_rqsg_if.lock);66 67	return status;68}69 70/**71 * san_client_link() - Link client as consumer to SAN device.72 * @client: The client to link.73 *74 * Sets up a device link between the provided client device as consumer and75 * the SAN device as provider. This function can be used to ensure that the76 * SAN interface has been set up and will be set up for as long as the driver77 * of the client device is bound. This guarantees that, during that time, all78 * dGPU events will be received by any registered notifier.79 *80 * The link will be automatically removed once the client device's driver is81 * unbound.82 *83 * Return: Returns zero on success, %-ENXIO if the SAN interface has not been84 * set up yet, and %-ENOMEM if device link creation failed.85 */86int san_client_link(struct device *client)87{88	const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;89	struct device_link *link;90 91	down_read(&san_rqsg_if.lock);92 93	if (!san_rqsg_if.dev) {94		up_read(&san_rqsg_if.lock);95		return -ENXIO;96	}97 98	link = device_link_add(client, san_rqsg_if.dev, flags);99	if (!link) {100		up_read(&san_rqsg_if.lock);101		return -ENOMEM;102	}103 104	if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) {105		up_read(&san_rqsg_if.lock);106		return -ENXIO;107	}108 109	up_read(&san_rqsg_if.lock);110	return 0;111}112EXPORT_SYMBOL_GPL(san_client_link);113 114/**115 * san_dgpu_notifier_register() - Register a SAN dGPU notifier.116 * @nb: The notifier-block to register.117 *118 * Registers a SAN dGPU notifier, receiving any new SAN dGPU events sent from119 * ACPI. The registered notifier will be called with &struct san_dgpu_event120 * as notifier data and the command ID of that event as notifier action.121 */122int san_dgpu_notifier_register(struct notifier_block *nb)123{124	return blocking_notifier_chain_register(&san_rqsg_if.nh, nb);125}126EXPORT_SYMBOL_GPL(san_dgpu_notifier_register);127 128/**129 * san_dgpu_notifier_unregister() - Unregister a SAN dGPU notifier.130 * @nb: The notifier-block to unregister.131 */132int san_dgpu_notifier_unregister(struct notifier_block *nb)133{134	return blocking_notifier_chain_unregister(&san_rqsg_if.nh, nb);135}136EXPORT_SYMBOL_GPL(san_dgpu_notifier_unregister);137 138static int san_dgpu_notifier_call(struct san_dgpu_event *evt)139{140	int ret;141 142	ret = blocking_notifier_call_chain(&san_rqsg_if.nh, evt->command, evt);143	return notifier_to_errno(ret);144}145 146 147/* -- ACPI _DSM event relay. ------------------------------------------------ */148 149#define SAN_DSM_REVISION	0150 151/* 93b666c5-70c6-469f-a215-3d487c91ab3c */152static const guid_t SAN_DSM_UUID =153	GUID_INIT(0x93b666c5, 0x70c6, 0x469f, 0xa2, 0x15, 0x3d,154		  0x48, 0x7c, 0x91, 0xab, 0x3c);155 156enum san_dsm_event_fn {157	SAN_DSM_EVENT_FN_BAT1_STAT = 0x03,158	SAN_DSM_EVENT_FN_BAT1_INFO = 0x04,159	SAN_DSM_EVENT_FN_ADP1_STAT = 0x05,160	SAN_DSM_EVENT_FN_ADP1_INFO = 0x06,161	SAN_DSM_EVENT_FN_BAT2_STAT = 0x07,162	SAN_DSM_EVENT_FN_BAT2_INFO = 0x08,163	SAN_DSM_EVENT_FN_THERMAL   = 0x09,164	SAN_DSM_EVENT_FN_DPTF      = 0x0a,165};166 167enum sam_event_cid_bat {168	SAM_EVENT_CID_BAT_BIX  = 0x15,169	SAM_EVENT_CID_BAT_BST  = 0x16,170	SAM_EVENT_CID_BAT_ADP  = 0x17,171	SAM_EVENT_CID_BAT_PROT = 0x18,172	SAM_EVENT_CID_BAT_DPTF = 0x4f,173};174 175enum sam_event_cid_tmp {176	SAM_EVENT_CID_TMP_TRIP = 0x0b,177};178 179struct san_event_work {180	struct delayed_work work;181	struct device *dev;182	struct ssam_event event;	/* must be last */183};184 185static int san_acpi_notify_event(struct device *dev, u64 func,186				 union acpi_object *param)187{188	acpi_handle san = ACPI_HANDLE(dev);189	union acpi_object *obj;190	int status = 0;191 192	if (!acpi_check_dsm(san, &SAN_DSM_UUID, SAN_DSM_REVISION, BIT_ULL(func)))193		return 0;194 195	dev_dbg(dev, "notify event %#04llx\n", func);196 197	obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION,198				      func, param, ACPI_TYPE_BUFFER);199	if (!obj)200		return -EFAULT;201 202	if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) {203		dev_err(dev, "got unexpected result from _DSM\n");204		status = -EPROTO;205	}206 207	ACPI_FREE(obj);208	return status;209}210 211static int san_evt_bat_adp(struct device *dev, const struct ssam_event *event)212{213	int status;214 215	status = san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_ADP1_STAT, NULL);216	if (status)217		return status;218 219	/*220	 * Ensure that the battery states get updated correctly. When the221	 * battery is fully charged and an adapter is plugged in, it sometimes222	 * is not updated correctly, instead showing it as charging.223	 * Explicitly trigger battery updates to fix this.224	 */225 226	status = san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_BAT1_STAT, NULL);227	if (status)228		return status;229 230	return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_BAT2_STAT, NULL);231}232 233static int san_evt_bat_bix(struct device *dev, const struct ssam_event *event)234{235	enum san_dsm_event_fn fn;236 237	if (event->instance_id == 0x02)238		fn = SAN_DSM_EVENT_FN_BAT2_INFO;239	else240		fn = SAN_DSM_EVENT_FN_BAT1_INFO;241 242	return san_acpi_notify_event(dev, fn, NULL);243}244 245static int san_evt_bat_bst(struct device *dev, const struct ssam_event *event)246{247	enum san_dsm_event_fn fn;248 249	if (event->instance_id == 0x02)250		fn = SAN_DSM_EVENT_FN_BAT2_STAT;251	else252		fn = SAN_DSM_EVENT_FN_BAT1_STAT;253 254	return san_acpi_notify_event(dev, fn, NULL);255}256 257static int san_evt_bat_dptf(struct device *dev, const struct ssam_event *event)258{259	union acpi_object payload;260 261	/*262	 * The Surface ACPI expects a buffer and not a package. It specifically263	 * checks for ObjectType (Arg3) == 0x03. This will cause a warning in264	 * acpica/nsarguments.c, but that warning can be safely ignored.265	 */266	payload.type = ACPI_TYPE_BUFFER;267	payload.buffer.length = event->length;268	payload.buffer.pointer = (u8 *)&event->data[0];269 270	return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_DPTF, &payload);271}272 273static unsigned long san_evt_bat_delay(u8 cid)274{275	switch (cid) {276	case SAM_EVENT_CID_BAT_ADP:277		/*278		 * Wait for battery state to update before signaling adapter279		 * change.280		 */281		return msecs_to_jiffies(5000);282 283	case SAM_EVENT_CID_BAT_BST:284		/* Ensure we do not miss anything important due to caching. */285		return msecs_to_jiffies(2000);286 287	default:288		return 0;289	}290}291 292static bool san_evt_bat(const struct ssam_event *event, struct device *dev)293{294	int status;295 296	switch (event->command_id) {297	case SAM_EVENT_CID_BAT_BIX:298		status = san_evt_bat_bix(dev, event);299		break;300 301	case SAM_EVENT_CID_BAT_BST:302		status = san_evt_bat_bst(dev, event);303		break;304 305	case SAM_EVENT_CID_BAT_ADP:306		status = san_evt_bat_adp(dev, event);307		break;308 309	case SAM_EVENT_CID_BAT_PROT:310		/*311		 * TODO: Implement support for battery protection status change312		 *       event.313		 */314		return true;315 316	case SAM_EVENT_CID_BAT_DPTF:317		status = san_evt_bat_dptf(dev, event);318		break;319 320	default:321		return false;322	}323 324	if (status) {325		dev_err(dev, "error handling power event (cid = %#04x)\n",326			event->command_id);327	}328 329	return true;330}331 332static void san_evt_bat_workfn(struct work_struct *work)333{334	struct san_event_work *ev;335 336	ev = container_of(work, struct san_event_work, work.work);337	san_evt_bat(&ev->event, ev->dev);338	kfree(ev);339}340 341static u32 san_evt_bat_nf(struct ssam_event_notifier *nf,342			  const struct ssam_event *event)343{344	struct san_data *d = to_san_data(nf, nf_bat);345	struct san_event_work *work;346	unsigned long delay = san_evt_bat_delay(event->command_id);347 348	if (delay == 0)349		return san_evt_bat(event, d->dev) ? SSAM_NOTIF_HANDLED : 0;350 351	work = kzalloc(sizeof(*work) + event->length, GFP_KERNEL);352	if (!work)353		return ssam_notifier_from_errno(-ENOMEM);354 355	INIT_DELAYED_WORK(&work->work, san_evt_bat_workfn);356	work->dev = d->dev;357 358	work->event = *event;359	memcpy(work->event.data, event->data, event->length);360 361	queue_delayed_work(san_wq, &work->work, delay);362	return SSAM_NOTIF_HANDLED;363}364 365static int san_evt_tmp_trip(struct device *dev, const struct ssam_event *event)366{367	union acpi_object param;368 369	/*370	 * The Surface ACPI expects an integer and not a package. This will371	 * cause a warning in acpica/nsarguments.c, but that warning can be372	 * safely ignored.373	 */374	param.type = ACPI_TYPE_INTEGER;375	param.integer.value = event->instance_id;376 377	return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_THERMAL, &param);378}379 380static bool san_evt_tmp(const struct ssam_event *event, struct device *dev)381{382	int status;383 384	switch (event->command_id) {385	case SAM_EVENT_CID_TMP_TRIP:386		status = san_evt_tmp_trip(dev, event);387		break;388 389	default:390		return false;391	}392 393	if (status) {394		dev_err(dev, "error handling thermal event (cid = %#04x)\n",395			event->command_id);396	}397 398	return true;399}400 401static u32 san_evt_tmp_nf(struct ssam_event_notifier *nf,402			  const struct ssam_event *event)403{404	struct san_data *d = to_san_data(nf, nf_tmp);405 406	return san_evt_tmp(event, d->dev) ? SSAM_NOTIF_HANDLED : 0;407}408 409 410/* -- ACPI GSB OperationRegion handler -------------------------------------- */411 412struct gsb_data_in {413	u8 cv;414} __packed;415 416struct gsb_data_rqsx {417	u8 cv;				/* Command value (san_gsb_request_cv). */418	u8 tc;				/* Target category. */419	u8 tid;				/* Target ID. */420	u8 iid;				/* Instance ID. */421	u8 snc;				/* Expect-response-flag. */422	u8 cid;				/* Command ID. */423	u16 cdl;			/* Payload length. */424	u8 pld[];			/* Payload. */425} __packed;426 427struct gsb_data_etwl {428	u8 cv;				/* Command value (should be 0x02). */429	u8 etw3;			/* Unknown. */430	u8 etw4;			/* Unknown. */431	u8 msg[];			/* Error message (ASCIIZ). */432} __packed;433 434struct gsb_data_out {435	u8 status;			/* _SSH communication status. */436	u8 len;				/* _SSH payload length. */437	u8 pld[];			/* _SSH payload. */438} __packed;439 440union gsb_buffer_data {441	struct gsb_data_in   in;	/* Common input. */442	struct gsb_data_rqsx rqsx;	/* RQSX input. */443	struct gsb_data_etwl etwl;	/* ETWL input. */444	struct gsb_data_out  out;	/* Output. */445};446 447struct gsb_buffer {448	u8 status;			/* GSB AttribRawProcess status. */449	u8 len;				/* GSB AttribRawProcess length. */450	union gsb_buffer_data data;451} __packed;452 453#define SAN_GSB_MAX_RQSX_PAYLOAD  (U8_MAX - 2 - sizeof(struct gsb_data_rqsx))454#define SAN_GSB_MAX_RESPONSE	  (U8_MAX - 2 - sizeof(struct gsb_data_out))455 456#define SAN_GSB_COMMAND		0457 458enum san_gsb_request_cv {459	SAN_GSB_REQUEST_CV_RQST = 0x01,460	SAN_GSB_REQUEST_CV_ETWL = 0x02,461	SAN_GSB_REQUEST_CV_RQSG = 0x03,462};463 464#define SAN_REQUEST_NUM_TRIES	5465 466static acpi_status san_etwl(struct san_data *d, struct gsb_buffer *b)467{468	struct gsb_data_etwl *etwl = &b->data.etwl;469 470	if (b->len < sizeof(struct gsb_data_etwl)) {471		dev_err(d->dev, "invalid ETWL package (len = %d)\n", b->len);472		return AE_OK;473	}474 475	dev_err(d->dev, "ETWL(%#04x, %#04x): %.*s\n", etwl->etw3, etwl->etw4,476		(unsigned int)(b->len - sizeof(struct gsb_data_etwl)),477		(char *)etwl->msg);478 479	/* Indicate success. */480	b->status = 0x00;481	b->len = 0x00;482 483	return AE_OK;484}485 486static487struct gsb_data_rqsx *san_validate_rqsx(struct device *dev, const char *type,488					struct gsb_buffer *b)489{490	struct gsb_data_rqsx *rqsx = &b->data.rqsx;491 492	if (b->len < sizeof(struct gsb_data_rqsx)) {493		dev_err(dev, "invalid %s package (len = %d)\n", type, b->len);494		return NULL;495	}496 497	if (get_unaligned(&rqsx->cdl) != b->len - sizeof(struct gsb_data_rqsx)) {498		dev_err(dev, "bogus %s package (len = %d, cdl = %d)\n",499			type, b->len, get_unaligned(&rqsx->cdl));500		return NULL;501	}502 503	if (get_unaligned(&rqsx->cdl) > SAN_GSB_MAX_RQSX_PAYLOAD) {504		dev_err(dev, "payload for %s package too large (cdl = %d)\n",505			type, get_unaligned(&rqsx->cdl));506		return NULL;507	}508 509	return rqsx;510}511 512static void gsb_rqsx_response_error(struct gsb_buffer *gsb, int status)513{514	gsb->status = 0x00;515	gsb->len = 0x02;516	gsb->data.out.status = (u8)(-status);517	gsb->data.out.len = 0x00;518}519 520static void gsb_rqsx_response_success(struct gsb_buffer *gsb, u8 *ptr, size_t len)521{522	gsb->status = 0x00;523	gsb->len = len + 2;524	gsb->data.out.status = 0x00;525	gsb->data.out.len = len;526 527	if (len)528		memcpy(&gsb->data.out.pld[0], ptr, len);529}530 531static acpi_status san_rqst_fixup_suspended(struct san_data *d,532					    struct ssam_request *rqst,533					    struct gsb_buffer *gsb)534{535	if (rqst->target_category == SSAM_SSH_TC_BAS && rqst->command_id == 0x0D) {536		u8 base_state = 1;537 538		/* Base state quirk:539		 * The base state may be queried from ACPI when the EC is still540		 * suspended. In this case it will return '-EPERM'. This query541		 * will only be triggered from the ACPI lid GPE interrupt, thus542		 * we are either in laptop or studio mode (base status 0x01 or543		 * 0x02). Furthermore, we will only get here if the device (and544		 * EC) have been suspended.545		 *546		 * We now assume that the device is in laptop mode (0x01). This547		 * has the drawback that it will wake the device when unfolding548		 * it in studio mode, but it also allows us to avoid actively549		 * waiting for the EC to wake up, which may incur a notable550		 * delay.551		 */552 553		dev_dbg(d->dev, "rqst: fixup: base-state quirk\n");554 555		gsb_rqsx_response_success(gsb, &base_state, sizeof(base_state));556		return AE_OK;557	}558 559	gsb_rqsx_response_error(gsb, -ENXIO);560	return AE_OK;561}562 563static acpi_status san_rqst(struct san_data *d, struct gsb_buffer *buffer)564{565	u8 rspbuf[SAN_GSB_MAX_RESPONSE];566	struct gsb_data_rqsx *gsb_rqst;567	struct ssam_request rqst;568	struct ssam_response rsp;569	int status = 0;570 571	gsb_rqst = san_validate_rqsx(d->dev, "RQST", buffer);572	if (!gsb_rqst)573		return AE_OK;574 575	rqst.target_category = gsb_rqst->tc;576	rqst.target_id = gsb_rqst->tid;577	rqst.command_id = gsb_rqst->cid;578	rqst.instance_id = gsb_rqst->iid;579	rqst.flags = gsb_rqst->snc ? SSAM_REQUEST_HAS_RESPONSE : 0;580	rqst.length = get_unaligned(&gsb_rqst->cdl);581	rqst.payload = &gsb_rqst->pld[0];582 583	rsp.capacity = ARRAY_SIZE(rspbuf);584	rsp.length = 0;585	rsp.pointer = &rspbuf[0];586 587	/* Handle suspended device. */588	if (d->dev->power.is_suspended) {589		dev_warn(d->dev, "rqst: device is suspended, not executing\n");590		return san_rqst_fixup_suspended(d, &rqst, buffer);591	}592 593	status = __ssam_retry(ssam_request_do_sync_onstack, SAN_REQUEST_NUM_TRIES,594			      d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD);595 596	if (!status) {597		gsb_rqsx_response_success(buffer, rsp.pointer, rsp.length);598	} else {599		dev_err(d->dev, "rqst: failed with error %d\n", status);600		gsb_rqsx_response_error(buffer, status);601	}602 603	return AE_OK;604}605 606static acpi_status san_rqsg(struct san_data *d, struct gsb_buffer *buffer)607{608	struct gsb_data_rqsx *gsb_rqsg;609	struct san_dgpu_event evt;610	int status;611 612	gsb_rqsg = san_validate_rqsx(d->dev, "RQSG", buffer);613	if (!gsb_rqsg)614		return AE_OK;615 616	evt.category = gsb_rqsg->tc;617	evt.target = gsb_rqsg->tid;618	evt.command = gsb_rqsg->cid;619	evt.instance = gsb_rqsg->iid;620	evt.length = get_unaligned(&gsb_rqsg->cdl);621	evt.payload = &gsb_rqsg->pld[0];622 623	status = san_dgpu_notifier_call(&evt);624	if (!status) {625		gsb_rqsx_response_success(buffer, NULL, 0);626	} else {627		dev_err(d->dev, "rqsg: failed with error %d\n", status);628		gsb_rqsx_response_error(buffer, status);629	}630 631	return AE_OK;632}633 634static acpi_status san_opreg_handler(u32 function, acpi_physical_address command,635				     u32 bits, u64 *value64, void *opreg_context,636				     void *region_context)637{638	struct san_data *d = to_san_data(opreg_context, info);639	struct gsb_buffer *buffer = (struct gsb_buffer *)value64;640	int accessor_type = (function & 0xFFFF0000) >> 16;641 642	if (command != SAN_GSB_COMMAND) {643		dev_warn(d->dev, "unsupported command: %#04llx\n", command);644		return AE_OK;645	}646 647	if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {648		dev_err(d->dev, "invalid access type: %#04x\n", accessor_type);649		return AE_OK;650	}651 652	/* Buffer must have at least contain the command-value. */653	if (buffer->len == 0) {654		dev_err(d->dev, "request-package too small\n");655		return AE_OK;656	}657 658	switch (buffer->data.in.cv) {659	case SAN_GSB_REQUEST_CV_RQST:660		return san_rqst(d, buffer);661 662	case SAN_GSB_REQUEST_CV_ETWL:663		return san_etwl(d, buffer);664 665	case SAN_GSB_REQUEST_CV_RQSG:666		return san_rqsg(d, buffer);667 668	default:669		dev_warn(d->dev, "unsupported SAN0 request (cv: %#04x)\n",670			 buffer->data.in.cv);671		return AE_OK;672	}673}674 675 676/* -- Driver setup. --------------------------------------------------------- */677 678static int san_events_register(struct platform_device *pdev)679{680	struct san_data *d = platform_get_drvdata(pdev);681	int status;682 683	d->nf_bat.base.priority = 1;684	d->nf_bat.base.fn = san_evt_bat_nf;685	d->nf_bat.event.reg = SSAM_EVENT_REGISTRY_SAM;686	d->nf_bat.event.id.target_category = SSAM_SSH_TC_BAT;687	d->nf_bat.event.id.instance = 0;688	d->nf_bat.event.mask = SSAM_EVENT_MASK_TARGET;689	d->nf_bat.event.flags = SSAM_EVENT_SEQUENCED;690 691	d->nf_tmp.base.priority = 1;692	d->nf_tmp.base.fn = san_evt_tmp_nf;693	d->nf_tmp.event.reg = SSAM_EVENT_REGISTRY_SAM;694	d->nf_tmp.event.id.target_category = SSAM_SSH_TC_TMP;695	d->nf_tmp.event.id.instance = 0;696	d->nf_tmp.event.mask = SSAM_EVENT_MASK_TARGET;697	d->nf_tmp.event.flags = SSAM_EVENT_SEQUENCED;698 699	status = ssam_notifier_register(d->ctrl, &d->nf_bat);700	if (status)701		return status;702 703	status = ssam_notifier_register(d->ctrl, &d->nf_tmp);704	if (status)705		ssam_notifier_unregister(d->ctrl, &d->nf_bat);706 707	return status;708}709 710static void san_events_unregister(struct platform_device *pdev)711{712	struct san_data *d = platform_get_drvdata(pdev);713 714	ssam_notifier_unregister(d->ctrl, &d->nf_bat);715	ssam_notifier_unregister(d->ctrl, &d->nf_tmp);716}717 718#define san_consumer_printk(level, dev, handle, fmt, ...)			\719do {										\720	char *path = "<error getting consumer path>";				\721	struct acpi_buffer buffer = {						\722		.length = ACPI_ALLOCATE_BUFFER,					\723		.pointer = NULL,						\724	};									\725										\726	if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer)))	\727		path = buffer.pointer;						\728										\729	dev_##level(dev, "[%s]: " fmt, path, ##__VA_ARGS__);			\730	kfree(buffer.pointer);							\731} while (0)732 733#define san_consumer_dbg(dev, handle, fmt, ...) \734	san_consumer_printk(dbg, dev, handle, fmt, ##__VA_ARGS__)735 736#define san_consumer_warn(dev, handle, fmt, ...) \737	san_consumer_printk(warn, dev, handle, fmt, ##__VA_ARGS__)738 739static acpi_status san_consumer_setup(acpi_handle handle, u32 lvl,740				      void *context, void **rv)741{742	const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER;743	struct platform_device *pdev = context;744	struct acpi_device *adev;745	struct device_link *link;746 747	if (!acpi_device_dep(handle, ACPI_HANDLE(&pdev->dev)))748		return AE_OK;749 750	/* Ignore ACPI devices that are not present. */751	adev = acpi_fetch_acpi_dev(handle);752	if (!adev)753		return AE_OK;754 755	san_consumer_dbg(&pdev->dev, handle, "creating device link\n");756 757	/* Try to set up device links, ignore but log errors. */758	link = device_link_add(&adev->dev, &pdev->dev, flags);759	if (!link) {760		san_consumer_warn(&pdev->dev, handle, "failed to create device link\n");761		return AE_OK;762	}763 764	return AE_OK;765}766 767static int san_consumer_links_setup(struct platform_device *pdev)768{769	acpi_status status;770 771	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,772				     ACPI_UINT32_MAX, san_consumer_setup, NULL,773				     pdev, NULL);774 775	return status ? -EFAULT : 0;776}777 778static int san_probe(struct platform_device *pdev)779{780	struct acpi_device *san = ACPI_COMPANION(&pdev->dev);781	struct ssam_controller *ctrl;782	struct san_data *data;783	acpi_status astatus;784	int status;785 786	ctrl = ssam_client_bind(&pdev->dev);787	if (IS_ERR(ctrl))788		return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);789 790	status = san_consumer_links_setup(pdev);791	if (status)792		return status;793 794	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);795	if (!data)796		return -ENOMEM;797 798	data->dev = &pdev->dev;799	data->ctrl = ctrl;800 801	platform_set_drvdata(pdev, data);802 803	astatus = acpi_install_address_space_handler(san->handle,804						     ACPI_ADR_SPACE_GSBUS,805						     &san_opreg_handler, NULL,806						     &data->info);807	if (ACPI_FAILURE(astatus))808		return -ENXIO;809 810	status = san_events_register(pdev);811	if (status)812		goto err_enable_events;813 814	status = san_set_rqsg_interface_device(&pdev->dev);815	if (status)816		goto err_install_dev;817 818	acpi_dev_clear_dependencies(san);819	return 0;820 821err_install_dev:822	san_events_unregister(pdev);823err_enable_events:824	acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS,825					  &san_opreg_handler);826	return status;827}828 829static void san_remove(struct platform_device *pdev)830{831	acpi_handle san = ACPI_HANDLE(&pdev->dev);832 833	san_set_rqsg_interface_device(NULL);834	acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS,835					  &san_opreg_handler);836	san_events_unregister(pdev);837 838	/*839	 * We have unregistered our event sources. Now we need to ensure that840	 * all delayed works they may have spawned are run to completion.841	 */842	flush_workqueue(san_wq);843}844 845static const struct acpi_device_id san_match[] = {846	{ "MSHW0091" },847	{ },848};849MODULE_DEVICE_TABLE(acpi, san_match);850 851static struct platform_driver surface_acpi_notify = {852	.probe = san_probe,853	.remove_new = san_remove,854	.driver = {855		.name = "surface_acpi_notify",856		.acpi_match_table = san_match,857		.probe_type = PROBE_PREFER_ASYNCHRONOUS,858	},859};860 861static int __init san_init(void)862{863	int ret;864 865	san_wq = alloc_workqueue("san_wq", 0, 0);866	if (!san_wq)867		return -ENOMEM;868	ret = platform_driver_register(&surface_acpi_notify);869	if (ret)870		destroy_workqueue(san_wq);871	return ret;872}873module_init(san_init);874 875static void __exit san_exit(void)876{877	platform_driver_unregister(&surface_acpi_notify);878	destroy_workqueue(san_wq);879}880module_exit(san_exit);881 882MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");883MODULE_DESCRIPTION("Surface ACPI Notify driver for Surface System Aggregator Module");884MODULE_LICENSE("GPL");885