aboutsummaryrefslogtreecommitdiff
path: root/drivers/platform/surface/aggregator/ssh_request_layer.h
diff options
context:
space:
mode:
authorMaximilian Luz <luzmaximilian@gmail.com>2020-12-21 19:39:51 +0100
committerHans de Goede <hdegoede@redhat.com>2021-01-06 23:45:33 +0100
commitc167b9c7e3d6131b4a4865c112a3dbc86d2e997d (patch)
tree1ebabe095416a26860ccc0cf4dce3df4104cf474 /drivers/platform/surface/aggregator/ssh_request_layer.h
parent5b569302520ac8cef03e7a841e45cb37234f8b5f (diff)
platform/surface: Add Surface Aggregator subsystem
Add Surface System Aggregator Module core and Surface Serial Hub driver, required for the embedded controller found on Microsoft Surface devices. The Surface System Aggregator Module (SSAM, SAM or Surface Aggregator) is an embedded controller (EC) found on 4th and later generation Microsoft Surface devices, with the exception of the Surface Go series. This EC provides various functionality, depending on the device in question. This can include battery status and thermal reporting (5th and later generations), but also HID keyboard (6th+) and touchpad input (7th+) on Surface Laptop and Surface Book 3 series devices. This patch provides the basic necessities for communication with the SAM EC on 5th and later generation devices. On these devices, the EC provides an interface that acts as serial device, called the Surface Serial Hub (SSH). 4th generation devices, on which the EC interface is provided via an HID-over-I2C device, are not supported by this patch. Specifically, this patch adds a driver for the SSH device (device HID MSHW0084 in ACPI), as well as a controller structure and associated API. This represents the functional core of the Surface Aggregator kernel subsystem, introduced with this patch, and will be expanded upon in subsequent commits. The SSH driver acts as the main attachment point for this subsystem and sets-up and manages the controller structure. The controller in turn provides a basic communication interface, allowing to send requests from host to EC and receiving the corresponding responses, as well as managing and receiving events, sent from EC to host. It is structured into multiple layers, with the top layer presenting the API used by other kernel drivers and the lower layers modeled after the serial protocol used for communication. Said other drivers are then responsible for providing the (Surface model specific) functionality accessible through the EC (e.g. battery status reporting, thermal information, ...) via said controller structure and API, and will be added in future commits. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> Link: https://lore.kernel.org/r/20201221183959.1186143-2-luzmaximilian@gmail.com Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'drivers/platform/surface/aggregator/ssh_request_layer.h')
-rw-r--r--drivers/platform/surface/aggregator/ssh_request_layer.h143
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.h b/drivers/platform/surface/aggregator/ssh_request_layer.h
new file mode 100644
index 000000000000..cb35815858d1
--- /dev/null
+++ b/drivers/platform/surface/aggregator/ssh_request_layer.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * SSH request transport layer.
+ *
+ * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ */
+
+#ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H
+#define _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H
+
+#include <linux/atomic.h>
+#include <linux/ktime.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include <linux/surface_aggregator/serial_hub.h>
+#include <linux/surface_aggregator/controller.h>
+
+#include "ssh_packet_layer.h"
+
+/**
+ * enum ssh_rtl_state_flags - State-flags for &struct ssh_rtl.
+ *
+ * @SSH_RTL_SF_SHUTDOWN_BIT:
+ * Indicates that the request transport layer has been shut down or is
+ * being shut down and should not accept any new requests.
+ */
+enum ssh_rtl_state_flags {
+ SSH_RTL_SF_SHUTDOWN_BIT,
+};
+
+/**
+ * struct ssh_rtl_ops - Callback operations for request transport layer.
+ * @handle_event: Function called when a SSH event has been received. The
+ * specified function takes the request layer, received command
+ * struct, and corresponding payload as arguments. If the event
+ * has no payload, the payload span is empty (not %NULL).
+ */
+struct ssh_rtl_ops {
+ void (*handle_event)(struct ssh_rtl *rtl, const struct ssh_command *cmd,
+ const struct ssam_span *data);
+};
+
+/**
+ * struct ssh_rtl - SSH request transport layer.
+ * @ptl: Underlying packet transport layer.
+ * @state: State(-flags) of the transport layer.
+ * @queue: Request submission queue.
+ * @queue.lock: Lock for modifying the request submission queue.
+ * @queue.head: List-head of the request submission queue.
+ * @pending: Set/list of pending requests.
+ * @pending.lock: Lock for modifying the request set.
+ * @pending.head: List-head of the pending set/list.
+ * @pending.count: Number of currently pending requests.
+ * @tx: Transmitter subsystem.
+ * @tx.work: Transmitter work item.
+ * @rtx_timeout: Retransmission timeout subsystem.
+ * @rtx_timeout.lock: Lock for modifying the retransmission timeout reaper.
+ * @rtx_timeout.timeout: Timeout interval for retransmission.
+ * @rtx_timeout.expires: Time specifying when the reaper work is next scheduled.
+ * @rtx_timeout.reaper: Work performing timeout checks and subsequent actions.
+ * @ops: Request layer operations.
+ */
+struct ssh_rtl {
+ struct ssh_ptl ptl;
+ unsigned long state;
+
+ struct {
+ spinlock_t lock;
+ struct list_head head;
+ } queue;
+
+ struct {
+ spinlock_t lock;
+ struct list_head head;
+ atomic_t count;
+ } pending;
+
+ struct {
+ struct work_struct work;
+ } tx;
+
+ struct {
+ spinlock_t lock;
+ ktime_t timeout;
+ ktime_t expires;
+ struct delayed_work reaper;
+ } rtx_timeout;
+
+ struct ssh_rtl_ops ops;
+};
+
+#define rtl_dbg(r, fmt, ...) ptl_dbg(&(r)->ptl, fmt, ##__VA_ARGS__)
+#define rtl_info(p, fmt, ...) ptl_info(&(p)->ptl, fmt, ##__VA_ARGS__)
+#define rtl_warn(r, fmt, ...) ptl_warn(&(r)->ptl, fmt, ##__VA_ARGS__)
+#define rtl_err(r, fmt, ...) ptl_err(&(r)->ptl, fmt, ##__VA_ARGS__)
+#define rtl_dbg_cond(r, fmt, ...) __ssam_prcond(rtl_dbg, r, fmt, ##__VA_ARGS__)
+
+#define to_ssh_rtl(ptr, member) \
+ container_of(ptr, struct ssh_rtl, member)
+
+/**
+ * ssh_rtl_get_device() - Get device associated with request transport layer.
+ * @rtl: The request transport layer.
+ *
+ * Return: Returns the device on which the given request transport layer
+ * builds upon.
+ */
+static inline struct device *ssh_rtl_get_device(struct ssh_rtl *rtl)
+{
+ return ssh_ptl_get_device(&rtl->ptl);
+}
+
+/**
+ * ssh_request_rtl() - Get request transport layer associated with request.
+ * @rqst: The request to get the request transport layer reference for.
+ *
+ * Return: Returns the &struct ssh_rtl associated with the given SSH request.
+ */
+static inline struct ssh_rtl *ssh_request_rtl(struct ssh_request *rqst)
+{
+ struct ssh_ptl *ptl;
+
+ ptl = READ_ONCE(rqst->packet.ptl);
+ return likely(ptl) ? to_ssh_rtl(ptl, ptl) : NULL;
+}
+
+int ssh_rtl_submit(struct ssh_rtl *rtl, struct ssh_request *rqst);
+bool ssh_rtl_cancel(struct ssh_request *rqst, bool pending);
+
+int ssh_rtl_init(struct ssh_rtl *rtl, struct serdev_device *serdev,
+ const struct ssh_rtl_ops *ops);
+
+int ssh_rtl_start(struct ssh_rtl *rtl);
+int ssh_rtl_flush(struct ssh_rtl *rtl, unsigned long timeout);
+void ssh_rtl_shutdown(struct ssh_rtl *rtl);
+void ssh_rtl_destroy(struct ssh_rtl *rtl);
+
+int ssh_request_init(struct ssh_request *rqst, enum ssam_request_flags flags,
+ const struct ssh_request_ops *ops);
+
+#endif /* _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H */