diff options
Diffstat (limited to 'drivers/platform/surface')
17 files changed, 814 insertions, 147 deletions
diff --git a/drivers/platform/surface/aggregator/Kconfig b/drivers/platform/surface/aggregator/Kconfig index 3aaeea9f0433..fd6dc452f3e8 100644 --- a/drivers/platform/surface/aggregator/Kconfig +++ b/drivers/platform/surface/aggregator/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0+ -# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> +# Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> menuconfig SURFACE_AGGREGATOR tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers" diff --git a/drivers/platform/surface/aggregator/Makefile b/drivers/platform/surface/aggregator/Makefile index c112e2c7112b..c8498c41e758 100644 --- a/drivers/platform/surface/aggregator/Makefile +++ b/drivers/platform/surface/aggregator/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0+ -# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> +# Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> # For include/trace/define_trace.h to include trace.h CFLAGS_core.o = -I$(src) diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c index a9b660af0917..0169677c243e 100644 --- a/drivers/platform/surface/aggregator/bus.c +++ b/drivers/platform/surface/aggregator/bus.c @@ -2,7 +2,7 @@ /* * Surface System Aggregator Module bus and device integration. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #include <linux/device.h> diff --git a/drivers/platform/surface/aggregator/bus.h b/drivers/platform/surface/aggregator/bus.h index 7712baaed6a5..ed032c2cbdb2 100644 --- a/drivers/platform/surface/aggregator/bus.h +++ b/drivers/platform/surface/aggregator/bus.h @@ -2,7 +2,7 @@ /* * Surface System Aggregator Module bus and device integration. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #ifndef _SURFACE_AGGREGATOR_BUS_H diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index a06964aa96e7..b8c377b3f932 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -2,7 +2,7 @@ /* * Main SSAM/SSH controller structure and functionality. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #include <linux/acpi.h> @@ -408,6 +408,31 @@ ssam_nf_refcount_dec(struct ssam_nf *nf, struct ssam_event_registry reg, } /** + * ssam_nf_refcount_dec_free() - Decrement reference-/activation-count of the + * given event and free its entry if the reference count reaches zero. + * @nf: The notifier system reference. + * @reg: The registry used to enable/disable the event. + * @id: The event ID. + * + * Decrements the reference-/activation-count of the specified event, freeing + * its entry if it reaches zero. + * + * Note: ``nf->lock`` must be held when calling this function. + */ +static void ssam_nf_refcount_dec_free(struct ssam_nf *nf, + struct ssam_event_registry reg, + struct ssam_event_id id) +{ + struct ssam_nf_refcount_entry *entry; + + lockdep_assert_held(&nf->lock); + + entry = ssam_nf_refcount_dec(nf, reg, id); + if (entry && entry->refcount == 0) + kfree(entry); +} + +/** * ssam_nf_refcount_empty() - Test if the notification system has any * enabled/active events. * @nf: The notification system. @@ -2123,13 +2148,122 @@ int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl) /* -- Top-level event registry interface. ----------------------------------- */ /** + * ssam_nf_refcount_enable() - Enable event for reference count entry if it has + * not already been enabled. + * @ctrl: The controller to enable the event on. + * @entry: The reference count entry for the event to be enabled. + * @flags: The flags used for enabling the event on the EC. + * + * Enable the event associated with the given reference count entry if the + * reference count equals one, i.e. the event has not previously been enabled. + * If the event has already been enabled (i.e. reference count not equal to + * one), check that the flags used for enabling match and warn about this if + * they do not. + * + * This does not modify the reference count itself, which is done with + * ssam_nf_refcount_inc() / ssam_nf_refcount_dec(). + * + * Note: ``nf->lock`` must be held when calling this function. + * + * Return: Returns zero on success. If the event is enabled by this call, + * returns the status of the event-enable EC command. + */ +static int ssam_nf_refcount_enable(struct ssam_controller *ctrl, + struct ssam_nf_refcount_entry *entry, u8 flags) +{ + const struct ssam_event_registry reg = entry->key.reg; + const struct ssam_event_id id = entry->key.id; + struct ssam_nf *nf = &ctrl->cplt.event.notif; + int status; + + lockdep_assert_held(&nf->lock); + + ssam_dbg(ctrl, "enabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", + reg.target_category, id.target_category, id.instance, entry->refcount); + + if (entry->refcount == 1) { + status = ssam_ssh_event_enable(ctrl, reg, id, flags); + if (status) + return status; + + entry->flags = flags; + + } else if (entry->flags != flags) { + ssam_warn(ctrl, + "inconsistent flags when enabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n", + flags, entry->flags, reg.target_category, id.target_category, + id.instance); + } + + return 0; +} + +/** + * ssam_nf_refcount_disable_free() - Disable event for reference count entry if it is + * no longer in use and free the corresponding entry. + * @ctrl: The controller to disable the event on. + * @entry: The reference count entry for the event to be disabled. + * @flags: The flags used for enabling the event on the EC. + * + * If the reference count equals zero, i.e. the event is no longer requested by + * any client, the event will be disabled and the corresponding reference count + * entry freed. The reference count entry must not be used any more after a + * call to this function. + * + * Also checks if the flags used for disabling the event match the flags used + * for enabling the event and warns if they do not (regardless of reference + * count). + * + * This does not modify the reference count itself, which is done with + * ssam_nf_refcount_inc() / ssam_nf_refcount_dec(). + * + * Note: ``nf->lock`` must be held when calling this function. + * + * Return: Returns zero on success. If the event is disabled by this call, + * returns the status of the event-enable EC command. + */ +static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, + struct ssam_nf_refcount_entry *entry, u8 flags) +{ + const struct ssam_event_registry reg = entry->key.reg; + const struct ssam_event_id id = entry->key.id; + struct ssam_nf *nf = &ctrl->cplt.event.notif; + int status = 0; + + lockdep_assert_held(&nf->lock); + + ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", + reg.target_category, id.target_category, id.instance, entry->refcount); + + if (entry->flags != flags) { + ssam_warn(ctrl, + "inconsistent flags when disabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n", + flags, entry->flags, reg.target_category, id.target_category, + id.instance); + } + + if (entry->refcount == 0) { + status = ssam_ssh_event_disable(ctrl, reg, id, flags); + kfree(entry); + } + + return status; +} + +/** * ssam_notifier_register() - Register an event notifier. * @ctrl: The controller to register the notifier on. * @n: The event notifier to register. * - * Register an event notifier and increment the usage counter of the - * associated SAM event. If the event was previously not enabled, it will be - * enabled during this call. + * Register an event notifier. Increment the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the event is not + * marked as an observer and is currently not enabled, it will be enabled + * during this call. If the notifier is marked as an observer, no attempt will + * be made at enabling any event and no reference count will be modified. + * + * Notifiers marked as observers do not need to be associated with one specific + * event, i.e. as long as no event matching is performed, only the event target + * category needs to be set. * * Return: Returns zero on success, %-ENOSPC if there have already been * %INT_MAX notifiers for the event ID/type associated with the notifier block @@ -2138,11 +2272,10 @@ int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl) * for the specific associated event, returns the status of the event-enable * EC-command. */ -int ssam_notifier_register(struct ssam_controller *ctrl, - struct ssam_event_notifier *n) +int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notifier *n) { u16 rqid = ssh_tc_to_rqid(n->event.id.target_category); - struct ssam_nf_refcount_entry *entry; + struct ssam_nf_refcount_entry *entry = NULL; struct ssam_nf_head *nf_head; struct ssam_nf *nf; int status; @@ -2155,44 +2288,32 @@ int ssam_notifier_register(struct ssam_controller *ctrl, mutex_lock(&nf->lock); - entry = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id); - if (IS_ERR(entry)) { - mutex_unlock(&nf->lock); - return PTR_ERR(entry); + if (!(n->flags & SSAM_EVENT_NOTIFIER_OBSERVER)) { + entry = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id); + if (IS_ERR(entry)) { + mutex_unlock(&nf->lock); + return PTR_ERR(entry); + } } - ssam_dbg(ctrl, "enabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", - n->event.reg.target_category, n->event.id.target_category, - n->event.id.instance, entry->refcount); - status = ssam_nfblk_insert(nf_head, &n->base); if (status) { - entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id); - if (entry->refcount == 0) - kfree(entry); + if (entry) + ssam_nf_refcount_dec_free(nf, n->event.reg, n->event.id); mutex_unlock(&nf->lock); return status; } - if (entry->refcount == 1) { - status = ssam_ssh_event_enable(ctrl, n->event.reg, n->event.id, - n->event.flags); + if (entry) { + status = ssam_nf_refcount_enable(ctrl, entry, n->event.flags); if (status) { ssam_nfblk_remove(&n->base); - kfree(ssam_nf_refcount_dec(nf, n->event.reg, n->event.id)); + ssam_nf_refcount_dec_free(nf, n->event.reg, n->event.id); mutex_unlock(&nf->lock); synchronize_srcu(&nf_head->srcu); return status; } - - entry->flags = n->event.flags; - - } else if (entry->flags != n->event.flags) { - ssam_warn(ctrl, - "inconsistent flags when enabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n", - n->event.flags, entry->flags, n->event.reg.target_category, - n->event.id.target_category, n->event.id.instance); } mutex_unlock(&nf->lock); @@ -2205,17 +2326,16 @@ EXPORT_SYMBOL_GPL(ssam_notifier_register); * @ctrl: The controller the notifier has been registered on. * @n: The event notifier to unregister. * - * Unregister an event notifier and decrement the usage counter of the - * associated SAM event. If the usage counter reaches zero, the event will be - * disabled. + * Unregister an event notifier. Decrement the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the usage counter + * reaches zero, the event will be disabled. * * Return: Returns zero on success, %-ENOENT if the given notifier block has * not been registered on the controller. If the given notifier block was the * last one associated with its specific event, returns the status of the * event-disable EC-command. */ -int ssam_notifier_unregister(struct ssam_controller *ctrl, - struct ssam_event_notifier *n) +int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n) { u16 rqid = ssh_tc_to_rqid(n->event.id.target_category); struct ssam_nf_refcount_entry *entry; @@ -2236,33 +2356,24 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl, return -ENOENT; } - entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id); - if (WARN_ON(!entry)) { - /* - * If this does not return an entry, there's a logic error - * somewhere: The notifier block is registered, but the event - * refcount entry is not there. Remove the notifier block - * anyways. - */ - status = -ENOENT; - goto remove; - } - - ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", - n->event.reg.target_category, n->event.id.target_category, - n->event.id.instance, entry->refcount); - - if (entry->flags != n->event.flags) { - ssam_warn(ctrl, - "inconsistent flags when disabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n", - n->event.flags, entry->flags, n->event.reg.target_category, - n->event.id.target_category, n->event.id.instance); - } + /* + * If this is an observer notifier, do not attempt to disable the + * event, just remove it. + */ + if (!(n->flags & SSAM_EVENT_NOTIFIER_OBSERVER)) { + entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id); + if (WARN_ON(!entry)) { + /* + * If this does not return an entry, there's a logic + * error somewhere: The notifier block is registered, + * but the event refcount entry is not there. Remove + * the notifier block anyways. + */ + status = -ENOENT; + goto remove; + } - if (entry->refcount == 0) { - status = ssam_ssh_event_disable(ctrl, n->event.reg, n->event.id, - n->event.flags); - kfree(entry); + status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags); } remove: @@ -2275,6 +2386,105 @@ remove: EXPORT_SYMBOL_GPL(ssam_notifier_unregister); /** + * ssam_controller_event_enable() - Enable the specified event. + * @ctrl: The controller to enable the event for. + * @reg: The event registry to use for enabling the event. + * @id: The event ID specifying the event to be enabled. + * @flags: The SAM event flags used for enabling the event. + * + * Increment the event reference count of the specified event. If the event has + * not been enabled previously, it will be enabled by this call. + * + * Note: In general, ssam_notifier_register() with a non-observer notifier + * should be preferred for enabling/disabling events, as this will guarantee + * proper ordering and event forwarding in case of errors during event + * enabling/disabling. + * + * Return: Returns zero on success, %-ENOSPC if the reference count for the + * specified event has reached its maximum, %-ENOMEM if the corresponding event + * entry could not be allocated. If this is the first time that this event has + * been enabled (i.e. the reference count was incremented from zero to one by + * this call), returns the status of the event-enable EC-command. + */ +int ssam_controller_event_enable(struct ssam_controller *ctrl, + struct ssam_event_registry reg, + struct ssam_event_id id, u8 flags) +{ + u16 rqid = ssh_tc_to_rqid(id.target_category); + struct ssam_nf *nf = &ctrl->cplt.event.notif; + struct ssam_nf_refcount_entry *entry; + int status; + + if (!ssh_rqid_is_event(rqid)) + return -EINVAL; + + mutex_lock(&nf->lock); + + entry = ssam_nf_refcount_inc(nf, reg, id); + if (IS_ERR(entry)) { + mutex_unlock(&nf->lock); + return PTR_ERR(entry); + } + + status = ssam_nf_refcount_enable(ctrl, entry, flags); + if (status) { + ssam_nf_refcount_dec_free(nf, reg, id); + mutex_unlock(&nf->lock); + return status; + } + + mutex_unlock(&nf->lock); + return 0; +} +EXPORT_SYMBOL_GPL(ssam_controller_event_enable); + +/** + * ssam_controller_event_disable() - Disable the specified event. + * @ctrl: The controller to disable the event for. + * @reg: The event registry to use for disabling the event. + * @id: The event ID specifying the event to be disabled. + * @flags: The flags used when enabling the event. + * + * Decrement the reference count of the specified event. If the reference count + * reaches zero, the event will be disabled. + * + * Note: In general, ssam_notifier_register()/ssam_notifier_unregister() with a + * non-observer notifier should be preferred for enabling/disabling events, as + * this will guarantee proper ordering and event forwarding in case of errors + * during event enabling/disabling. + * + * Return: Returns zero on success, %-ENOENT if the given event has not been + * enabled on the controller. If the reference count of the event reaches zero + * during this call, returns the status of the event-disable EC-command. + */ +int ssam_controller_event_disable(struct ssam_controller *ctrl, + struct ssam_event_registry reg, + struct ssam_event_id id, u8 flags) +{ + u16 rqid = ssh_tc_to_rqid(id.target_category); + struct ssam_nf *nf = &ctrl->cplt.event.notif; + struct ssam_nf_refcount_entry *entry; + int status; + + if (!ssh_rqid_is_event(rqid)) + return -EINVAL; + + mutex_lock(&nf->lock); + + entry = ssam_nf_refcount_dec(nf, reg, id); + if (!entry) { + mutex_unlock(&nf->lock); + return -ENOENT; + } + + status = ssam_nf_refcount_disable_free(ctrl, entry, flags); + + mutex_unlock(&nf->lock); + return status; +} +EXPORT_SYMBOL_GPL(ssam_controller_event_disable); + +/** * ssam_notifier_disable_registered() - Disable events for all registered * notifiers. * @ctrl: The controller for which to disable the notifiers/events. diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h index 8297d34e7489..a0963c3562ff 100644 --- a/drivers/platform/surface/aggregator/controller.h +++ b/drivers/platform/surface/aggregator/controller.h @@ -2,7 +2,7 @@ /* * Main SSAM/SSH controller structure and functionality. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #ifndef _SURFACE_AGGREGATOR_CONTROLLER_H diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index 517f774a6e60..279d9df19c01 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -7,7 +7,7 @@ * Handles communication via requests as well as enabling, disabling, and * relaying of events. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #include <linux/acpi.h> diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h index 1221f642dda1..e562958ffdf0 100644 --- a/drivers/platform/surface/aggregator/ssh_msgb.h +++ b/drivers/platform/surface/aggregator/ssh_msgb.h @@ -2,7 +2,7 @@ /* * SSH message builder functions. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c index 15d96eac6811..8a4451c1ffe5 100644 --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c @@ -2,7 +2,7 @@ /* * SSH packet transport layer. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #include <asm/unaligned.h> @@ -1567,9 +1567,7 @@ static void ssh_ptl_timeout_reap(struct work_struct *work) clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state); atomic_dec(&ptl->pending.count); - list_del(&p->pending_node); - - list_add_tail(&p->pending_node, &claimed); + list_move_tail(&p->pending_node, &claimed); } spin_unlock(&ptl->pending.lock); @@ -1957,8 +1955,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl) smp_mb__before_atomic(); clear_bit(SSH_PACKET_SF_QUEUED_BIT, &p->state); - list_del(&p->queue_node); - list_add_tail(&p->queue_node, &complete_q); + list_move_tail(&p->queue_node, &complete_q); } spin_unlock(&ptl->queue.lock); @@ -1970,8 +1967,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl) smp_mb__before_atomic(); clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state); - list_del(&p->pending_node); - list_add_tail(&p->pending_node, &complete_q); + list_move_tail(&p->pending_node, &complete_q); } atomic_set(&ptl->pending.count, 0); spin_unlock(&ptl->pending.lock); diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h index e8757d03f279..2eb329f0b91a 100644 --- a/drivers/platform/surface/aggregator/ssh_packet_layer.h +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h @@ -2,7 +2,7 @@ /* * SSH packet transport layer. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H diff --git a/drivers/platform/surface/aggregator/ssh_parser.c b/drivers/platform/surface/aggregator/ssh_parser.c index e2dead8de94a..b77912f8f13b 100644 --- a/drivers/platform/surface/aggregator/ssh_parser.c +++ b/drivers/platform/surface/aggregator/ssh_parser.c @@ -2,7 +2,7 @@ /* * SSH message parser. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #include <asm/unaligned.h> diff --git a/drivers/platform/surface/aggregator/ssh_parser.h b/drivers/platform/surface/aggregator/ssh_parser.h index 63c38d350988..3bd6e180fd16 100644 --- a/drivers/platform/surface/aggregator/ssh_parser.h +++ b/drivers/platform/surface/aggregator/ssh_parser.h @@ -2,7 +2,7 @@ /* * SSH message parser. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #ifndef _SURFACE_AGGREGATOR_SSH_PARSER_H diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c index 52a83a8fcf82..790f7f0eee98 100644 --- a/drivers/platform/surface/aggregator/ssh_request_layer.c +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c @@ -2,7 +2,7 @@ /* * SSH request transport layer. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #include <asm/unaligned.h> @@ -863,9 +863,7 @@ static void ssh_rtl_timeout_reap(struct work_struct *work) clear_bit(SSH_REQUEST_SF_PENDING_BIT, &r->state); atomic_dec(&rtl->pending.count); - list_del(&r->node); - - list_add_tail(&r->node, &claimed); + list_move_tail(&r->node, &claimed); } spin_unlock(&rtl->pending.lock); @@ -1204,8 +1202,7 @@ void ssh_rtl_shutdown(struct ssh_rtl *rtl) smp_mb__before_atomic(); clear_bit(SSH_REQUEST_SF_QUEUED_BIT, &r->state); - list_del(&r->node); - list_add_tail(&r->node, &claimed); + list_move_tail(&r->node, &claimed); } spin_unlock(&rtl->queue.lock); @@ -1238,8 +1235,7 @@ void ssh_rtl_shutdown(struct ssh_rtl *rtl) smp_mb__before_atomic(); clear_bit(SSH_REQUEST_SF_PENDING_BIT, &r->state); - list_del(&r->node); - list_add_tail(&r->node, &claimed); + list_move_tail(&r->node, &claimed); } spin_unlock(&rtl->pending.lock); } diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.h b/drivers/platform/surface/aggregator/ssh_request_layer.h index cb35815858d1..9c3cbae2d4bd 100644 --- a/drivers/platform/surface/aggregator/ssh_request_layer.h +++ b/drivers/platform/surface/aggregator/ssh_request_layer.h @@ -2,7 +2,7 @@ /* * SSH request transport layer. * - * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h index eb332bb53ae4..de64cf169060 100644 --- a/drivers/platform/surface/aggregator/trace.h +++ b/drivers/platform/surface/aggregator/trace.h @@ -2,7 +2,7 @@ /* * Trace points for SSAM/SSH. * - * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #undef TRACE_SYSTEM diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c index 79e28fab7e40..30fb50fde450 100644 --- a/drivers/platform/surface/surface_aggregator_cdev.c +++ b/drivers/platform/surface/surface_aggregator_cdev.c @@ -3,29 +3,69 @@ * Provides user-space access to the SSAM EC via the /dev/surface/aggregator * misc device. Intended for debugging and development. * - * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com> + * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com> */ #include <linux/fs.h> +#include <linux/ioctl.h> #include <linux/kernel.h> +#include <linux/kfifo.h> #include <linux/kref.h> #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/poll.h> #include <linux/rwsem.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/vmalloc.h> #include <linux/surface_aggregator/cdev.h> #include <linux/surface_aggregator/controller.h> +#include <linux/surface_aggregator/serial_hub.h> #define SSAM_CDEV_DEVICE_NAME "surface_aggregator_cdev" + +/* -- Main structures. ------------------------------------------------------ */ + +enum ssam_cdev_device_state { + SSAM_CDEV_DEVICE_SHUTDOWN_BIT = BIT(0), +}; + struct ssam_cdev { struct kref kref; struct rw_semaphore lock; + + struct device *dev; struct ssam_controller *ctrl; struct miscdevice mdev; + unsigned long flags; + + struct rw_semaphore client_lock; /* Guards client list. */ + struct list_head client_list; +}; + +struct ssam_cdev_client; + +struct ssam_cdev_notifier { + struct ssam_cdev_client *client; + struct ssam_event_notifier nf; +}; + +struct ssam_cdev_client { + struct ssam_cdev *cdev; + struct list_head node; + + struct mutex notifier_lock; /* Guards notifier access for registration */ + struct ssam_cdev_notifier *notifier[SSH_NUM_EVENTS]; + + struct mutex read_lock; /* Guards FIFO buffer read access */ + struct mutex write_lock; /* Guards FIFO buffer write access */ + DECLARE_KFIFO(buffer, u8, 4096); + + wait_queue_head_t waitq; + struct fasync_struct *fasync; }; static void __ssam_cdev_release(struct kref *kref) @@ -47,24 +87,173 @@ static void ssam_cdev_put(struct ssam_cdev *cdev) kref_put(&cdev->kref, __ssam_cdev_release); } -static int ssam_cdev_device_open(struct inode *inode, struct file *filp) + +/* -- Notifier handling. ---------------------------------------------------- */ + +static u32 ssam_cdev_notifier(struct ssam_event_notifier *nf, const struct ssam_event *in) { - struct miscdevice *mdev = filp->private_data; - struct ssam_cdev *cdev = container_of(mdev, struct ssam_cdev, mdev); + struct ssam_cdev_notifier *cdev_nf = container_of(nf, struct ssam_cdev_notifier, nf); + struct ssam_cdev_client *client = cdev_nf->client; + struct ssam_cdev_event event; + size_t n = struct_size(&event, data, in->length); + + /* Translate event. */ + event.target_category = in->target_category; + event.target_id = in->target_id; + event.command_id = in->command_id; + event.instance_id = in->instance_id; + event.length = in->length; + + mutex_lock(&client->write_lock); + + /* Make sure we have enough space. */ + if (kfifo_avail(&client->buffer) < n) { + dev_warn(client->cdev->dev, + "buffer full, dropping event (tc: %#04x, tid: %#04x, cid: %#04x, iid: %#04x)\n", + in->target_category, in->target_id, in->command_id, in->instance_id); + mutex_unlock(&client->write_lock); + return 0; + } + + /* Copy event header and payload. */ + kfifo_in(&client->buffer, (const u8 *)&event, struct_size(&event, data, 0)); + kfifo_in(&client->buffer, &in->data[0], in->length); + + mutex_unlock(&client->write_lock); + + /* Notify waiting readers. */ + kill_fasync(&client->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&client->waitq); - filp->private_data = ssam_cdev_get(cdev); - return stream_open(inode, filp); + /* + * Don't mark events as handled, this is the job of a proper driver and + * not the debugging interface. + */ + return 0; } -static int ssam_cdev_device_release(struct inode *inode, struct file *filp) +static int ssam_cdev_notifier_register(struct ssam_cdev_client *client, u8 tc, int priority) { - ssam_cdev_put(filp->private_data); - return 0; + const u16 rqid = ssh_tc_to_rqid(tc); + const u16 event = ssh_rqid_to_event(rqid); + struct ssam_cdev_notifier *nf; + int status; + + lockdep_assert_held_read(&client->cdev->lock); + + /* Validate notifier target category. */ + if (!ssh_rqid_is_event(rqid)) + return -EINVAL; + + mutex_lock(&client->notifier_lock); + + /* Check if the notifier has already been registered. */ + if (client->notifier[event]) { + mutex_unlock(&client->notifier_lock); + return -EEXIST; + } + + /* Allocate new notifier. */ + nf = kzalloc(sizeof(*nf), GFP_KERNEL); + if (!nf) { + mutex_unlock(&client->notifier_lock); + return -ENOMEM; + } + + /* + * Create a dummy notifier with the minimal required fields for + * observer registration. Note that we can skip fully specifying event + * and registry here as we do not need any matching and use silent + * registration, which does not enable the corresponding event. + */ + nf->client = client; + nf->nf.base.fn = ssam_cdev_notifier; + nf->nf.base.priority = priority; + nf->nf.event.id.target_category = tc; + nf->nf.event.mask = 0; /* Do not do any matching. */ + nf->nf.flags = SSAM_EVENT_NOTIFIER_OBSERVER; + + /* Register notifier. */ + status = ssam_notifier_register(client->cdev->ctrl, &nf->nf); + if (status) + kfree(nf); + else + client->notifier[event] = nf; + + mutex_unlock(&client->notifier_lock); + return status; +} + +static int ssam_cdev_notifier_unregister(struct ssam_cdev_client *client, u8 tc) +{ + const u16 rqid = ssh_tc_to_rqid(tc); + const u16 event = ssh_rqid_to_event(rqid); + int status; + + lockdep_assert_held_read(&client->cdev->lock); + + /* Validate notifier target category. */ + if (!ssh_rqid_is_event(rqid)) + return -EINVAL; + + mutex_lock(&client->notifier_lock); + + /* Check if the notifier is currently registered. */ + if (!client->notifier[event]) { + mutex_unlock(&client->notifier_lock); + return -ENOENT; + } + + /* Unregister and free notifier. */ + status = ssam_notifier_unregister(client->cdev->ctrl, &client->notifier[event]->nf); + kfree(client->notifier[event]); + client->notifier[event] = NULL; + + mutex_unlock(&client->notifier_lock); + return status; +} + +static void ssam_cdev_notifier_unregister_all(struct ssam_cdev_client *client) +{ + int i; + + down_read(&client->cdev->lock); + + /* + * This function may be used during shutdown, thus we need to test for + * cdev->ctrl instead of the SSAM_CDEV_DEVICE_SHUTDOWN_BIT bit. + */ + if (client->cdev->ctrl) { + for (i = 0; i < SSH_NUM_EVENTS; i++) + ssam_cdev_notifier_unregister(client, i + 1); + + } else { + int count = 0; + + /* + * Device has been shut down. Any notifier remaining is a bug, + * so warn about that as this would otherwise hardly be + * noticeable. Nevertheless, free them as well. + */ + mutex_lock(&client->notifier_lock); + for (i = 0; i < SSH_NUM_EVENTS; i++) { + count += !!(client->notifier[i]); + kfree(client->notifier[i]); + client->notifier[i] = NULL; + } + mutex_unlock(&client->notifier_lock); + + WARN_ON(count > 0); + } + + up_read(&client->cdev->lock); } -static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg) + +/* -- IOCTL functions. ------------------------------------------------------ */ + +static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_request __user *r) { - struct ssam_cdev_request __user *r; struct ssam_cdev_request rqst; struct ssam_request spec = {}; struct ssam_response rsp = {}; @@ -72,7 +261,8 @@ static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg) void __user *rspdata; int status = 0, ret = 0, tmp; - r = (struct ssam_cdev_request __user *)arg; + lockdep_assert_held_read(&client->cdev->lock); + ret = copy_struct_from_user(&rqst, sizeof(rqst), r, sizeof(*r)); if (ret) goto out; @@ -152,7 +342,7 @@ static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg) } /* Perform request. */ - status = ssam_request_sync(cdev->ctrl, &spec, &rsp); + status = ssam_request_sync(client->cdev->ctrl, &spec, &rsp); if (status) goto out; @@ -177,48 +367,315 @@ out: return ret; } -static long __ssam_cdev_device_ioctl(struct ssam_cdev *cdev, unsigned int cmd, +static long ssam_cdev_notif_register(struct ssam_cdev_client *client, + const struct ssam_cdev_notifier_desc __user *d) +{ + struct ssam_cdev_notifier_desc desc; + long ret; + + lockdep_assert_held_read(&client->cdev->lock); + + ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d)); + if (ret) + return ret; + + return ssam_cdev_notifier_register(client, desc.target_category, desc.priority); +} + +static long ssam_cdev_notif_unregister(struct ssam_cdev_client *client, + const struct ssam_cdev_notifier_desc __user *d) +{ + struct ssam_cdev_notifier_desc desc; + long ret; + + lockdep_assert_held_read(&client->cdev->lock); + + ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d)); + if (ret) + return ret; + + return ssam_cdev_notifier_unregister(client, desc.target_category); +} + +static long ssam_cdev_event_enable(struct ssam_cdev_client *client, + const struct ssam_cdev_event_desc __user *d) +{ + struct ssam_cdev_event_desc desc; + struct ssam_event_registry reg; + struct ssam_event_id id; + long ret; + + lockdep_assert_held_read(&client->cdev->lock); + + /* Read descriptor from user-space. */ + ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d)); + if (ret) + return ret; + + /* Translate descriptor. */ + reg.target_category = desc.reg.target_category; + reg.target_id = desc.reg.target_id; + reg.cid_enable = desc.reg.cid_enable; + reg.cid_disable = desc.reg.cid_disable; + + id.target_category = desc.id.target_category; + id.instance = desc.id.instance; + + /* Disable event. */ + return ssam_controller_event_enable(client->cdev->ctrl, reg, id, desc.flags); +} + +static long ssam_cdev_event_disable(struct ssam_cdev_client *client, + const struct ssam_cdev_event_desc __user *d) +{ + struct ssam_cdev_event_desc desc; + struct ssam_event_registry reg; + struct ssam_event_id id; + long ret; + + lockdep_assert_held_read(&client->cdev->lock); + + /* Read descriptor from user-space. */ + ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d)); + if (ret) + return ret; + + /* Translate descriptor. */ + reg.target_category = desc.reg.target_category; + reg.target_id = desc.reg.target_id; + reg.cid_enable = desc.reg.cid_enable; + reg.cid_disable = desc.reg.cid_disable; + + id.target_category = desc.id.target_category; + id.instance = desc.id.instance; + + /* Disable event. */ + return ssam_controller_event_disable(client->cdev->ctrl, reg, id, desc.flags); +} + + +/* -- File operations. ------------------------------------------------------ */ + +static int ssam_cdev_device_open(struct inode *inode, struct file *filp) +{ + struct miscdevice *mdev = filp->private_data; + struct ssam_cdev_client *client; + struct ssam_cdev *cdev = container_of(mdev, struct ssam_cdev, mdev); + + /* Initialize client */ + client = vzalloc(sizeof(*client)); + if (!client) + return -ENOMEM; + + client->cdev = ssam_cdev_get(cdev); + + INIT_LIST_HEAD(&client->node); + + mutex_init(&client->notifier_lock); + + mutex_init(&client->read_lock); + mutex_init(&client->write_lock); + INIT_KFIFO(client->buffer); + init_waitqueue_head(&client->waitq); + + filp->private_data = client; + + /* Attach client. */ + down_write(&cdev->client_lock); + + if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags)) { + up_write(&cdev->client_lock); + mutex_destroy(&client->write_lock); + mutex_destroy(&client->read_lock); + mutex_destroy(&client->notifier_lock); + ssam_cdev_put(client->cdev); + vfree(client); + return -ENODEV; + } + list_add_tail(&client->node, &cdev->client_list); + + up_write(&cdev->client_lock); + + stream_open(inode, filp); + return 0; +} + +static int ssam_cdev_device_release(struct inode *inode, struct file *filp) +{ + struct ssam_cdev_client *client = filp->private_data; + + /* Force-unregister all remaining notifiers of this client. */ + ssam_cdev_notifier_unregister_all(client); + + /* Detach client. */ + down_write(&client->cdev->client_lock); + list_del(&client->node); + up_write(&client->cdev->client_lock); + + /* Free client. */ + mutex_destroy(&client->write_lock); + mutex_destroy(&client->read_lock); + + mutex_destroy(&client->notifier_lock); + + ssam_cdev_put(client->cdev); + vfree(client); + + return 0; +} + +static long __ssam_cdev_device_ioctl(struct ssam_cdev_client *client, unsigned int cmd, unsigned long arg) { + lockdep_assert_held_read(&client->cdev->lock); + switch (cmd) { case SSAM_CDEV_REQUEST: - return ssam_cdev_request(cdev, arg); + return ssam_cdev_request(client, (struct ssam_cdev_request __user *)arg); + + case SSAM_CDEV_NOTIF_REGISTER: + return ssam_cdev_notif_register(client, + (struct ssam_cdev_notifier_desc __user *)arg); + + case SSAM_CDEV_NOTIF_UNREGISTER: + return ssam_cdev_notif_unregister(client, + (struct ssam_cdev_notifier_desc __user *)arg); + + case SSAM_CDEV_EVENT_ENABLE: + return ssam_cdev_event_enable(client, (struct ssam_cdev_event_desc __user *)arg); + + case SSAM_CDEV_EVENT_DISABLE: + return ssam_cdev_event_disable(client, (struct ssam_cdev_event_desc __user *)arg); default: return -ENOTTY; } } -static long ssam_cdev_device_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static long ssam_cdev_device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct ssam_cdev *cdev = file->private_data; + struct ssam_cdev_client *client = file->private_data; long status; /* Ensure that controller is valid for as long as we need it. */ + if (down_read_killable(&client->cdev->lock)) + return -ERESTARTSYS; + + if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &client->cdev->flags)) { + up_read(&client->cdev->lock); + return -ENODEV; + } + + status = __ssam_cdev_device_ioctl(client, cmd, arg); + + up_read(&client->cdev->lock); + return status; +} + +static ssize_t ssam_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *offs) +{ + struct ssam_cdev_client *client = file->private_data; + struct ssam_cdev *cdev = client->cdev; + unsigned int copied; + int status = 0; + if (down_read_killable(&cdev->lock)) return -ERESTARTSYS; - if (!cdev->ctrl) { + /* Make sure we're not shut down. */ + if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags)) { up_read(&cdev->lock); return -ENODEV; } - status = __ssam_cdev_device_ioctl(cdev, cmd, arg); + do { + /* Check availability, wait if necessary. */ + if (kfifo_is_empty(&client->buffer)) { + up_read(&cdev->lock); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + status = wait_event_interruptible(client->waitq, + !kfifo_is_empty(&client->buffer) || + test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, + &cdev->flags)); + if (status < 0) + return status; + + if (down_read_killable(&cdev->lock)) + return -ERESTARTSYS; + + /* Need to check that we're not shut down again. */ + if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags)) { + up_read(&cdev->lock); + return -ENODEV; + } + } + + /* Try to read from FIFO. */ + if (mutex_lock_interruptible(&client->read_lock)) { + up_read(&cdev->lock); + return -ERESTARTSYS; + } + + status = kfifo_to_user(&client->buffer, buf, count, &copied); + mutex_unlock(&client->read_lock); + + if (status < 0) { + up_read(&cdev->lock); + return status; + } + + /* We might not have gotten anything, check this here. */ + if (copied == 0 && (file->f_flags & O_NONBLOCK)) { + up_read(&cdev->lock); + return -EAGAIN; + } + } while (copied == 0); up_read(&cdev->lock); - return status; + return copied; +} + +static __poll_t ssam_cdev_poll(struct file *file, struct poll_table_struct *pt) +{ + struct ssam_cdev_client *client = file->private_data; + __poll_t events = 0; + + if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &client->cdev->flags)) + return EPOLLHUP | EPOLLERR; + + poll_wait(file, &client->waitq, pt); + + if (!kfifo_is_empty(&client->buffer)) + events |= EPOLLIN | EPOLLRDNORM; + + return events; +} + +static int ssam_cdev_fasync(int fd, struct file *file, int on) +{ + struct ssam_cdev_client *client = file->private_data; + + return fasync_helper(fd, file, on, &client->fasync); } static const struct file_operations ssam_controller_fops = { .owner = THIS_MODULE, .open = ssam_cdev_device_open, .release = ssam_cdev_device_release, + .read = ssam_cdev_read, + .poll = ssam_cdev_poll, + .fasync = ssam_cdev_fasync, .unlocked_ioctl = ssam_cdev_device_ioctl, .compat_ioctl = ssam_cdev_device_ioctl, - .llseek = noop_llseek, + .llseek = no_llseek, }; + +/* -- Device and driver setup ----------------------------------------------- */ + static int ssam_dbg_device_probe(struct platform_device *pdev) { struct ssam_controller *ctrl; @@ -236,6 +693,7 @@ static int ssam_dbg_device_probe(struct platform_device *pdev) kref_init(&cdev->kref); init_rwsem(&cdev->lock); cdev->ctrl = ctrl; + cdev->dev = &pdev->dev; cdev->mdev.parent = &pdev->dev; cdev->mdev.minor = MISC_DYNAMIC_MINOR; @@ -243,6 +701,9 @@ static int ssam_dbg_device_probe(struct platform_device *pdev) cdev->mdev.nodename = "surface/aggregator"; cdev->mdev.fops = &ssam_controller_fops; + init_rwsem(&cdev->client_lock); + INIT_LIST_HEAD(&cdev->client_list); + status = misc_register(&cdev->mdev); if (status) { kfree(cdev); @@ -256,8 +717,32 @@ static int ssam_dbg_device_probe(struct platform_device *pdev) static int ssam_dbg_device_remove(struct platform_device *pdev) { struct ssam_cdev *cdev = platform_get_drvdata(pdev); + struct ssam_cdev_client *client; - misc_deregister(&cdev->mdev); + /* + * Mark device as shut-down. Prevent new clients from being added and + * new operations from being executed. + */ + set_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags); + + down_write(&cdev->client_lock); + + /* Remove all notifiers registered by us. */ + list_for_each_entry(client, &cdev->client_list, node) { + ssam_cdev_notifier_unregister_all(client); + } + + /* Wake up async clients. */ + list_for_each_entry(client, &cdev->client_list, node) { + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + } + + /* Wake up blocking clients. */ + list_for_each_entry(client, &cdev->client_list, node) { + wake_up_interruptible(&client->waitq); + } + + up_write(&cdev->client_lock); /* * The controller is only guaranteed to be valid for as long as the @@ -266,8 +751,11 @@ static int ssam_dbg_device_remove(struct platform_device *pdev) */ down_write(&cdev->lock); cdev->ctrl = NULL; + cdev->dev = NULL; up_write(&cdev->lock); + misc_deregister(&cdev->mdev); + ssam_cdev_put(cdev); return 0; } diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index ef83461fa536..4428c4330229 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -119,8 +119,13 @@ static const struct software_node ssam_node_hid_base_iid6 = { .parent = &ssam_node_hub_base, }; -/* Devices for Surface Book 2. */ -static const struct software_node *ssam_node_group_sb2[] = { +/* + * Devices for 5th- and 6th-generations models: + * - Surface Book 2, + * - Surface Laptop 1 and 2, + * - Surface Pro 5 and 6. + */ +static const struct software_node *ssam_node_group_gen5[] = { &ssam_node_root, &ssam_node_tmp_pprof, NULL, @@ -142,20 +147,6 @@ static const struct software_node *ssam_node_group_sb3[] = { NULL, }; -/* Devices for Surface Laptop 1. */ -static const struct software_node *ssam_node_group_sl1[] = { - &ssam_node_root, - &ssam_node_tmp_pprof, - NULL, -}; - -/* Devices for Surface Laptop 2. */ -static const struct software_node *ssam_node_group_sl2[] = { - &ssam_node_root, - &ssam_node_tmp_pprof, - NULL, -}; - /* Devices for Surface Laptop 3 and 4. */ static const struct software_node *ssam_node_group_sl3[] = { &ssam_node_root, @@ -177,20 +168,6 @@ static const struct software_node *ssam_node_group_slg1[] = { NULL, }; -/* Devices for Surface Pro 5. */ -static const struct software_node *ssam_node_group_sp5[] = { - &ssam_node_root, - &ssam_node_tmp_pprof, - NULL, -}; - -/* Devices for Surface Pro 6. */ -static const struct software_node *ssam_node_group_sp6[] = { - &ssam_node_root, - &ssam_node_tmp_pprof, - NULL, -}; - /* Devices for Surface Pro 7 and Surface Pro 7+. */ static const struct software_node *ssam_node_group_sp7[] = { &ssam_node_root, @@ -495,10 +472,10 @@ static struct ssam_device_driver ssam_base_hub_driver = { static const struct acpi_device_id ssam_platform_hub_match[] = { /* Surface Pro 4, 5, and 6 (OMBR < 0x10) */ - { "MSHW0081", (unsigned long)ssam_node_group_sp5 }, + { "MSHW0081", (unsigned long)ssam_node_group_gen5 }, /* Surface Pro 6 (OMBR >= 0x10) */ - { "MSHW0111", (unsigned long)ssam_node_group_sp6 }, + { "MSHW0111", (unsigned long)ssam_node_group_gen5 }, /* Surface Pro 7 */ { "MSHW0116", (unsigned long)ssam_node_group_sp7 }, @@ -507,16 +484,16 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { { "MSHW0119", (unsigned long)ssam_node_group_sp7 }, /* Surface Book 2 */ - { "MSHW0107", (unsigned long)ssam_node_group_sb2 }, + { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, /* Surface Book 3 */ { "MSHW0117", (unsigned long)ssam_node_group_sb3 }, /* Surface Laptop 1 */ - { "MSHW0086", (unsigned long)ssam_node_group_sl1 }, + { "MSHW0086", (unsigned long)ssam_node_group_gen5 }, /* Surface Laptop 2 */ - { "MSHW0112", (unsigned long)ssam_node_group_sl2 }, + { "MSHW0112", (unsigned long)ssam_node_group_gen5 }, /* Surface Laptop 3 (13", Intel) */ { "MSHW0114", (unsigned long)ssam_node_group_sl3 }, |