Lines Matching +full:surface +full:- +full:sam

1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for the Surface ACPI Notify (SAN) interface/shim.
5 * Translates communication from ACPI to Surface System Aggregator Module
6 * (SSAM/SAM) requests and back, specifically SAM-over-SSH. Translates SSAM
11 * Copyright (C) 2019-2022 Maximilian Luz <[email protected]>
42 /* -- dGPU notifier interface. ---------------------------------------------- */
64 status = -EBUSY; in san_set_rqsg_interface_device()
71 * san_client_link() - Link client as consumer to SAN device.
83 * Return: Returns zero on success, %-ENXIO if the SAN interface has not been
84 * set up yet, and %-ENOMEM if device link creation failed.
95 return -ENXIO; in san_client_link()
101 return -ENOMEM; in san_client_link()
104 if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) { in san_client_link()
106 return -ENXIO; in san_client_link()
115 * san_dgpu_notifier_register() - Register a SAN dGPU notifier.
116 * @nb: The notifier-block to register.
129 * san_dgpu_notifier_unregister() - Unregister a SAN dGPU notifier.
130 * @nb: The notifier-block to unregister.
142 ret = blocking_notifier_call_chain(&san_rqsg_if.nh, evt->command, evt); in san_dgpu_notifier_call()
147 /* -- ACPI _DSM event relay. ------------------------------------------------ */
151 /* 93b666c5-70c6-469f-a215-3d487c91ab3c */
200 return -EFAULT; in san_acpi_notify_event()
202 if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { in san_acpi_notify_event()
204 status = -EPROTO; in san_acpi_notify_event()
237 if (event->instance_id == 0x02) in san_evt_bat_bix()
249 if (event->instance_id == 0x02) in san_evt_bat_bst()
262 * The Surface ACPI expects a buffer and not a package. It specifically in san_evt_bat_dptf()
267 payload.buffer.length = event->length; in san_evt_bat_dptf()
268 payload.buffer.pointer = (u8 *)&event->data[0]; in san_evt_bat_dptf()
296 switch (event->command_id) { in san_evt_bat()
326 event->command_id); in san_evt_bat()
337 san_evt_bat(&ev->event, ev->dev); in san_evt_bat_workfn()
346 unsigned long delay = san_evt_bat_delay(event->command_id); in san_evt_bat_nf()
349 return san_evt_bat(event, d->dev) ? SSAM_NOTIF_HANDLED : 0; in san_evt_bat_nf()
351 work = kzalloc(sizeof(*work) + event->length, GFP_KERNEL); in san_evt_bat_nf()
353 return ssam_notifier_from_errno(-ENOMEM); in san_evt_bat_nf()
355 INIT_DELAYED_WORK(&work->work, san_evt_bat_workfn); in san_evt_bat_nf()
356 work->dev = d->dev; in san_evt_bat_nf()
358 work->event = *event; in san_evt_bat_nf()
359 memcpy(work->event.data, event->data, event->length); in san_evt_bat_nf()
361 queue_delayed_work(san_wq, &work->work, delay); in san_evt_bat_nf()
370 * The Surface ACPI expects an integer and not a package. This will in san_evt_tmp_trip()
375 param.integer.value = event->instance_id; in san_evt_tmp_trip()
384 switch (event->command_id) { in san_evt_tmp()
395 event->command_id); in san_evt_tmp()
406 return san_evt_tmp(event, d->dev) ? SSAM_NOTIF_HANDLED : 0; in san_evt_tmp_nf()
410 /* -- ACPI GSB OperationRegion handler -------------------------------------- */
421 u8 snc; /* Expect-response-flag. */
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))
468 struct gsb_data_etwl *etwl = &b->data.etwl; in san_etwl()
470 if (b->len < sizeof(struct gsb_data_etwl)) { in san_etwl()
471 dev_err(d->dev, "invalid ETWL package (len = %d)\n", b->len); in san_etwl()
475 dev_err(d->dev, "ETWL(%#04x, %#04x): %.*s\n", etwl->etw3, etwl->etw4, in san_etwl()
476 (unsigned int)(b->len - sizeof(struct gsb_data_etwl)), in san_etwl()
477 (char *)etwl->msg); in san_etwl()
480 b->status = 0x00; in san_etwl()
481 b->len = 0x00; in san_etwl()
490 struct gsb_data_rqsx *rqsx = &b->data.rqsx; in san_validate_rqsx()
492 if (b->len < sizeof(struct gsb_data_rqsx)) { in san_validate_rqsx()
493 dev_err(dev, "invalid %s package (len = %d)\n", type, b->len); in san_validate_rqsx()
497 if (get_unaligned(&rqsx->cdl) != b->len - sizeof(struct gsb_data_rqsx)) { in san_validate_rqsx()
499 type, b->len, get_unaligned(&rqsx->cdl)); in san_validate_rqsx()
503 if (get_unaligned(&rqsx->cdl) > SAN_GSB_MAX_RQSX_PAYLOAD) { in san_validate_rqsx()
505 type, get_unaligned(&rqsx->cdl)); in san_validate_rqsx()
514 gsb->status = 0x00; in gsb_rqsx_response_error()
515 gsb->len = 0x02; in gsb_rqsx_response_error()
516 gsb->data.out.status = (u8)(-status); in gsb_rqsx_response_error()
517 gsb->data.out.len = 0x00; in gsb_rqsx_response_error()
522 gsb->status = 0x00; in gsb_rqsx_response_success()
523 gsb->len = len + 2; in gsb_rqsx_response_success()
524 gsb->data.out.status = 0x00; in gsb_rqsx_response_success()
525 gsb->data.out.len = len; in gsb_rqsx_response_success()
528 memcpy(&gsb->data.out.pld[0], ptr, len); in gsb_rqsx_response_success()
535 if (rqst->target_category == SSAM_SSH_TC_BAS && rqst->command_id == 0x0D) { in san_rqst_fixup_suspended()
540 * suspended. In this case it will return '-EPERM'. This query in san_rqst_fixup_suspended()
553 dev_dbg(d->dev, "rqst: fixup: base-state quirk\n"); in san_rqst_fixup_suspended()
559 gsb_rqsx_response_error(gsb, -ENXIO); in san_rqst_fixup_suspended()
571 gsb_rqst = san_validate_rqsx(d->dev, "RQST", buffer); in san_rqst()
575 rqst.target_category = gsb_rqst->tc; in san_rqst()
576 rqst.target_id = gsb_rqst->tid; in san_rqst()
577 rqst.command_id = gsb_rqst->cid; in san_rqst()
578 rqst.instance_id = gsb_rqst->iid; in san_rqst()
579 rqst.flags = gsb_rqst->snc ? SSAM_REQUEST_HAS_RESPONSE : 0; in san_rqst()
580 rqst.length = get_unaligned(&gsb_rqst->cdl); in san_rqst()
581 rqst.payload = &gsb_rqst->pld[0]; in san_rqst()
588 if (d->dev->power.is_suspended) { in san_rqst()
589 dev_warn(d->dev, "rqst: device is suspended, not executing\n"); in san_rqst()
594 d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD); in san_rqst()
599 dev_err(d->dev, "rqst: failed with error %d\n", status); in san_rqst()
612 gsb_rqsg = san_validate_rqsx(d->dev, "RQSG", buffer); in san_rqsg()
616 evt.category = gsb_rqsg->tc; in san_rqsg()
617 evt.target = gsb_rqsg->tid; in san_rqsg()
618 evt.command = gsb_rqsg->cid; in san_rqsg()
619 evt.instance = gsb_rqsg->iid; in san_rqsg()
620 evt.length = get_unaligned(&gsb_rqsg->cdl); in san_rqsg()
621 evt.payload = &gsb_rqsg->pld[0]; in san_rqsg()
627 dev_err(d->dev, "rqsg: failed with error %d\n", status); in san_rqsg()
643 dev_warn(d->dev, "unsupported command: %#04llx\n", command); in san_opreg_handler()
648 dev_err(d->dev, "invalid access type: %#04x\n", accessor_type); in san_opreg_handler()
652 /* Buffer must have at least contain the command-value. */ in san_opreg_handler()
653 if (buffer->len == 0) { in san_opreg_handler()
654 dev_err(d->dev, "request-package too small\n"); in san_opreg_handler()
658 switch (buffer->data.in.cv) { in san_opreg_handler()
669 dev_warn(d->dev, "unsupported SAN0 request (cv: %#04x)\n", in san_opreg_handler()
670 buffer->data.in.cv); in san_opreg_handler()
676 /* -- Driver setup. --------------------------------------------------------- */
683 d->nf_bat.base.priority = 1; in san_events_register()
684 d->nf_bat.base.fn = san_evt_bat_nf; in san_events_register()
685 d->nf_bat.event.reg = SSAM_EVENT_REGISTRY_SAM; in san_events_register()
686 d->nf_bat.event.id.target_category = SSAM_SSH_TC_BAT; in san_events_register()
687 d->nf_bat.event.id.instance = 0; in san_events_register()
688 d->nf_bat.event.mask = SSAM_EVENT_MASK_TARGET; in san_events_register()
689 d->nf_bat.event.flags = SSAM_EVENT_SEQUENCED; in san_events_register()
691 d->nf_tmp.base.priority = 1; in san_events_register()
692 d->nf_tmp.base.fn = san_evt_tmp_nf; in san_events_register()
693 d->nf_tmp.event.reg = SSAM_EVENT_REGISTRY_SAM; in san_events_register()
694 d->nf_tmp.event.id.target_category = SSAM_SSH_TC_TMP; in san_events_register()
695 d->nf_tmp.event.id.instance = 0; in san_events_register()
696 d->nf_tmp.event.mask = SSAM_EVENT_MASK_TARGET; in san_events_register()
697 d->nf_tmp.event.flags = SSAM_EVENT_SEQUENCED; in san_events_register()
699 status = ssam_notifier_register(d->ctrl, &d->nf_bat); in san_events_register()
703 status = ssam_notifier_register(d->ctrl, &d->nf_tmp); in san_events_register()
705 ssam_notifier_unregister(d->ctrl, &d->nf_bat); in san_events_register()
714 ssam_notifier_unregister(d->ctrl, &d->nf_bat); in san_events_unregister()
715 ssam_notifier_unregister(d->ctrl, &d->nf_tmp); in san_events_unregister()
747 if (!acpi_device_dep(handle, ACPI_HANDLE(&pdev->dev))) in san_consumer_setup()
755 san_consumer_dbg(&pdev->dev, handle, "creating device link\n"); in san_consumer_setup()
758 link = device_link_add(&adev->dev, &pdev->dev, flags); in san_consumer_setup()
760 san_consumer_warn(&pdev->dev, handle, "failed to create device link\n"); in san_consumer_setup()
775 return status ? -EFAULT : 0; in san_consumer_links_setup()
780 struct acpi_device *san = ACPI_COMPANION(&pdev->dev); in san_probe()
786 ctrl = ssam_client_bind(&pdev->dev); in san_probe()
788 return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); in san_probe()
794 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); in san_probe()
796 return -ENOMEM; in san_probe()
798 data->dev = &pdev->dev; in san_probe()
799 data->ctrl = ctrl; in san_probe()
803 astatus = acpi_install_address_space_handler(san->handle, in san_probe()
806 &data->info); in san_probe()
808 return -ENXIO; in san_probe()
814 status = san_set_rqsg_interface_device(&pdev->dev); in san_probe()
831 acpi_handle san = ACPI_HANDLE(&pdev->dev); in san_remove()
867 return -ENOMEM; in san_init()
883 MODULE_DESCRIPTION("Surface ACPI Notify driver for Surface System Aggregator Module");