|
|
@ -1,4 +1,4 @@
|
|
|
|
From 2b32e9bcc1f80ce457608b84bb74f0e5f191ae0a Mon Sep 17 00:00:00 2001
|
|
|
|
From e3c13b807bf54be7d176493a0e104ae807245ffc Mon Sep 17 00:00:00 2001
|
|
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
|
|
Date: Fri, 6 Dec 2019 11:56:12 +0100
|
|
|
|
Date: Fri, 6 Dec 2019 11:56:12 +0100
|
|
|
|
Subject: [PATCH 2/5] surface-sam
|
|
|
|
Subject: [PATCH 2/5] surface-sam
|
|
|
@ -20,11 +20,11 @@ Subject: [PATCH 2/5] surface-sam
|
|
|
|
.../x86/surface_sam/surface_sam_sid_power.h | 16 +
|
|
|
|
.../x86/surface_sam/surface_sam_sid_power.h | 16 +
|
|
|
|
.../x86/surface_sam/surface_sam_sid_vhf.c | 429 ++
|
|
|
|
.../x86/surface_sam/surface_sam_sid_vhf.c | 429 ++
|
|
|
|
.../x86/surface_sam/surface_sam_sid_vhf.h | 14 +
|
|
|
|
.../x86/surface_sam/surface_sam_sid_vhf.h | 14 +
|
|
|
|
.../x86/surface_sam/surface_sam_ssh.c | 5190 +++++++++++++++++
|
|
|
|
.../x86/surface_sam/surface_sam_ssh.c | 5329 +++++++++++++++++
|
|
|
|
.../x86/surface_sam/surface_sam_ssh.h | 717 +++
|
|
|
|
.../x86/surface_sam/surface_sam_ssh.h | 717 +++
|
|
|
|
.../x86/surface_sam/surface_sam_ssh_trace.h | 532 ++
|
|
|
|
.../x86/surface_sam/surface_sam_ssh_trace.h | 587 ++
|
|
|
|
.../x86/surface_sam/surface_sam_vhf.c | 266 +
|
|
|
|
.../x86/surface_sam/surface_sam_vhf.c | 266 +
|
|
|
|
20 files changed, 12241 insertions(+)
|
|
|
|
20 files changed, 12435 insertions(+)
|
|
|
|
create mode 100644 drivers/platform/x86/surface_sam/Kconfig
|
|
|
|
create mode 100644 drivers/platform/x86/surface_sam/Kconfig
|
|
|
|
create mode 100644 drivers/platform/x86/surface_sam/Makefile
|
|
|
|
create mode 100644 drivers/platform/x86/surface_sam/Makefile
|
|
|
|
create mode 100644 drivers/platform/x86/surface_sam/surface_sam_debugfs.c
|
|
|
|
create mode 100644 drivers/platform/x86/surface_sam/surface_sam_debugfs.c
|
|
|
@ -5685,10 +5685,10 @@ index 0000000000000..d956de5cf877a
|
|
|
|
+#endif /* _SURFACE_SAM_SID_VHF_H */
|
|
|
|
+#endif /* _SURFACE_SAM_SID_VHF_H */
|
|
|
|
diff --git a/drivers/platform/x86/surface_sam/surface_sam_ssh.c b/drivers/platform/x86/surface_sam/surface_sam_ssh.c
|
|
|
|
diff --git a/drivers/platform/x86/surface_sam/surface_sam_ssh.c b/drivers/platform/x86/surface_sam/surface_sam_ssh.c
|
|
|
|
new file mode 100644
|
|
|
|
new file mode 100644
|
|
|
|
index 0000000000000..4144fe0b3d192
|
|
|
|
index 0000000000000..4551b75570f22
|
|
|
|
--- /dev/null
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/platform/x86/surface_sam/surface_sam_ssh.c
|
|
|
|
+++ b/drivers/platform/x86/surface_sam/surface_sam_ssh.c
|
|
|
|
@@ -0,0 +1,5190 @@
|
|
|
|
@@ -0,0 +1,5329 @@
|
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
+/*
|
|
|
|
+/*
|
|
|
|
+ * Surface Serial Hub (SSH) driver for communication with the Surface/System
|
|
|
|
+ * Surface Serial Hub (SSH) driver for communication with the Surface/System
|
|
|
@ -5759,11 +5759,6 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ return rqid > 0 ? rqid + 1u : rqid + SSH_NUM_EVENTS + 1u;
|
|
|
|
+ return rqid > 0 ? rqid + 1u : rqid + SSH_NUM_EVENTS + 1u;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline u16 ssh_event_to_rqid(u16 event)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ return event + 1u;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static inline u16 ssh_rqid_to_event(u16 rqid)
|
|
|
|
+static inline u16 ssh_rqid_to_event(u16 rqid)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ return rqid - 1u;
|
|
|
|
+ return rqid - 1u;
|
|
|
@ -5779,11 +5774,6 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ return tc;
|
|
|
|
+ return tc;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline int ssh_tc_to_event(u8 tc)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ return ssh_rqid_to_event(ssh_tc_to_rqid(tc));
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static inline u8 ssh_channel_to_index(u8 channel)
|
|
|
|
+static inline u8 ssh_channel_to_index(u8 channel)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ return channel - 1u;
|
|
|
|
+ return channel - 1u;
|
|
|
@ -5859,31 +5849,6 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ msgb->ptr = ptr;
|
|
|
|
+ msgb->ptr = ptr;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline int msgb_alloc(struct msgbuf *msgb, size_t cap, gfp_t flags)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ u8 *buf;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ buf = kzalloc(cap, flags);
|
|
|
|
|
|
|
|
+ if (!buf)
|
|
|
|
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ msgb_init(msgb, buf, cap);
|
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static inline void msgb_free(struct msgbuf *msgb)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ kfree(msgb->begin);
|
|
|
|
|
|
|
|
+ msgb->begin = NULL;
|
|
|
|
|
|
|
|
+ msgb->end = NULL;
|
|
|
|
|
|
|
|
+ msgb->ptr = NULL;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static inline void msgb_reset(struct msgbuf *msgb)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ msgb->ptr = msgb->begin;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static inline size_t msgb_bytes_used(const struct msgbuf *msgb)
|
|
|
|
+static inline size_t msgb_bytes_used(const struct msgbuf *msgb)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ return msgb->ptr - msgb->begin;
|
|
|
|
+ return msgb->ptr - msgb->begin;
|
|
|
@ -6157,11 +6122,6 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ buf->cap = 0;
|
|
|
|
+ buf->cap = 0;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline void sshp_buf_reset(struct sshp_buf *buf)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ buf->len = 0;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static inline void sshp_buf_drop(struct sshp_buf *buf, size_t n)
|
|
|
|
+static inline void sshp_buf_drop(struct sshp_buf *buf, size_t n)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ memmove(buf->ptr, buf->ptr + n, buf->len - n);
|
|
|
|
+ memmove(buf->ptr, buf->ptr + n, buf->len - n);
|
|
|
@ -6576,10 +6536,8 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline int ssh_ptl_write_buf(struct ssh_ptl *ptl,
|
|
|
|
+static int ssh_ptl_write_buf(struct ssh_ptl *ptl, struct ssh_packet *packet,
|
|
|
|
+ struct ssh_packet *packet,
|
|
|
|
+ const unsigned char *buf, size_t count)
|
|
|
|
+ const unsigned char *buf,
|
|
|
|
|
|
|
|
+ size_t count)
|
|
|
|
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ int status;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -6596,7 +6554,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ return serdev_device_write_buf(ptl->serdev, buf, count);
|
|
|
|
+ return serdev_device_write_buf(ptl->serdev, buf, count);
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline void ssh_ptl_tx_inject_invalid_data(struct ssh_packet *packet)
|
|
|
|
+static void ssh_ptl_tx_inject_invalid_data(struct ssh_packet *packet)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ // ignore packets that don't carry any data (i.e. flush)
|
|
|
|
+ // ignore packets that don't carry any data (i.e. flush)
|
|
|
|
+ if (!packet->data.ptr || !packet->data.len)
|
|
|
|
+ if (!packet->data.ptr || !packet->data.len)
|
|
|
@ -6622,7 +6580,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ memset(packet->data.ptr, 0xb3, packet->data.len);
|
|
|
|
+ memset(packet->data.ptr, 0xb3, packet->data.len);
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
|
|
|
|
+static void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
|
|
|
|
+ struct ssam_span *data)
|
|
|
|
+ struct ssam_span *data)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ struct ssam_span frame;
|
|
|
|
+ struct ssam_span frame;
|
|
|
@ -6639,7 +6597,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ data->ptr[1] = 0xb3; // set second byte of SYN to "random" value
|
|
|
|
+ data->ptr[1] = 0xb3; // set second byte of SYN to "random" value
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline void ssh_ptl_rx_inject_invalid_data(struct ssh_ptl *ptl,
|
|
|
|
+static void ssh_ptl_rx_inject_invalid_data(struct ssh_ptl *ptl,
|
|
|
|
+ struct ssam_span *frame)
|
|
|
|
+ struct ssam_span *frame)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ size_t payload_len, message_len;
|
|
|
|
+ size_t payload_len, message_len;
|
|
|
@ -6756,41 +6714,51 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int ptl_alloc_ctrl_packet(struct ssh_ptl *ptl,
|
|
|
|
+static struct kmem_cache *ssh_ctrl_packet_cache;
|
|
|
|
+ struct ssh_packet **packet,
|
|
|
|
+
|
|
|
|
|
|
|
|
+static int __init ssh_ctrl_packet_cache_init(void)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ const unsigned int size = sizeof(struct ssh_packet) + SSH_MSG_LEN_CTRL;
|
|
|
|
|
|
|
|
+ const unsigned int align = __alignof__(struct ssh_packet);
|
|
|
|
|
|
|
|
+ struct kmem_cache *cache;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ cache = kmem_cache_create("ssam_ctrl_packet", size, align, 0, NULL);
|
|
|
|
|
|
|
|
+ if (!cache)
|
|
|
|
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ ssh_ctrl_packet_cache = cache;
|
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static void __exit ssh_ctrl_packet_cache_destroy(void)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ kmem_cache_destroy(ssh_ctrl_packet_cache);
|
|
|
|
|
|
|
|
+ ssh_ctrl_packet_cache = NULL;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
|
|
|
|
+ struct ssam_span *buffer, gfp_t flags)
|
|
|
|
+ struct ssam_span *buffer, gfp_t flags)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ // TODO: cache packets
|
|
|
|
+ *packet = kmem_cache_alloc(ssh_ctrl_packet_cache, flags);
|
|
|
|
+ // - Potential problem with kmem_cache: Minimum alloc size of that is
|
|
|
|
|
|
|
|
+ // PAGE_SIZE (???), which is somewhat overkill here.
|
|
|
|
|
|
|
|
+ // - Note: Mempool always tries to allocate with alloc callback first.
|
|
|
|
|
|
|
|
+ // Buffered objects are only chosen on allocation failure.
|
|
|
|
|
|
|
|
+ //
|
|
|
|
|
|
|
|
+ // => either kmem_cache or custom, try kmem_cache first and check via
|
|
|
|
|
|
|
|
+ // /proc/slabinfo
|
|
|
|
|
|
|
|
+ //
|
|
|
|
|
|
|
|
+ // Note: kmem_cache_create needs unique name
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ *packet = kzalloc(sizeof(struct ssh_packet) + SSH_MSG_LEN_CTRL, flags);
|
|
|
|
|
|
|
|
+ if (!*packet)
|
|
|
|
+ if (!*packet)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ buffer->ptr = (u8 *)(*packet + 1);
|
|
|
|
+ buffer->ptr = (u8 *)(*packet + 1);
|
|
|
|
+ buffer->len = SSH_MSG_LEN_CTRL;
|
|
|
|
+ buffer->len = SSH_MSG_LEN_CTRL;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+ trace_ssam_ctrl_packet_alloc(*packet, buffer->len);
|
|
|
|
+ return 0;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void ptl_free_ctrl_packet(struct ssh_packet *p)
|
|
|
|
+static void ssh_ctrl_packet_free(struct ssh_packet *p)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ // TODO: cache packets
|
|
|
|
+ trace_ssam_ctrl_packet_free(p);
|
|
|
|
+
|
|
|
|
+ kmem_cache_free(ssh_ctrl_packet_cache, p);
|
|
|
|
+ kfree(p);
|
|
|
|
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static const struct ssh_packet_ops ssh_ptl_ctrl_packet_ops = {
|
|
|
|
+static const struct ssh_packet_ops ssh_ptl_ctrl_packet_ops = {
|
|
|
|
+ .complete = NULL,
|
|
|
|
+ .complete = NULL,
|
|
|
|
+ .release = ptl_free_ctrl_packet,
|
|
|
|
+ .release = ssh_ctrl_packet_free,
|
|
|
|
+};
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -7640,7 +7608,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ struct msgbuf msgb;
|
|
|
|
+ struct msgbuf msgb;
|
|
|
|
+ int status;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ status = ptl_alloc_ctrl_packet(ptl, &packet, &buf, GFP_KERNEL);
|
|
|
|
+ status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
|
|
|
|
+ if (status) {
|
|
|
|
+ if (status) {
|
|
|
|
+ ptl_err(ptl, "ptl: failed to allocate ACK packet\n");
|
|
|
|
+ ptl_err(ptl, "ptl: failed to allocate ACK packet\n");
|
|
|
|
+ return;
|
|
|
|
+ return;
|
|
|
@ -7667,7 +7635,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ struct msgbuf msgb;
|
|
|
|
+ struct msgbuf msgb;
|
|
|
|
+ int status;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ status = ptl_alloc_ctrl_packet(ptl, &packet, &buf, GFP_KERNEL);
|
|
|
|
+ status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
|
|
|
|
+ if (status) {
|
|
|
|
+ if (status) {
|
|
|
|
+ ptl_err(ptl, "ptl: failed to allocate NAK packet\n");
|
|
|
|
+ ptl_err(ptl, "ptl: failed to allocate NAK packet\n");
|
|
|
|
+ return;
|
|
|
|
+ return;
|
|
|
@ -7974,7 +7942,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline struct device *ssh_ptl_get_device(struct ssh_ptl *ptl)
|
|
|
|
+static inline struct device *ssh_ptl_get_device(struct ssh_ptl *ptl)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ return &ptl->serdev->dev;
|
|
|
|
+ return ptl->serdev ? &ptl->serdev->dev : NULL;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int ssh_ptl_init(struct ssh_ptl *ptl, struct serdev_device *serdev,
|
|
|
|
+static int ssh_ptl_init(struct ssh_ptl *ptl, struct serdev_device *serdev,
|
|
|
@ -9346,6 +9314,11 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ return -ENOENT;
|
|
|
|
+ return -ENOENT;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+static bool ssam_nf_refcount_empty(struct ssam_nf *nf)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ return RB_EMPTY_ROOT(&nf->refcount);
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
+static void ssam_nf_call(struct ssam_nf *nf, struct device *dev, u16 rqid,
|
|
|
|
+static void ssam_nf_call(struct ssam_nf *nf, struct device *dev, u16 rqid,
|
|
|
|
+ struct ssam_event *event)
|
|
|
|
+ struct ssam_event *event)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
@ -9414,10 +9387,17 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+struct ssam_cplt;
|
|
|
|
+struct ssam_cplt;
|
|
|
|
|
|
|
|
+struct ssam_event_item;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+struct ssam_event_item_ops {
|
|
|
|
|
|
|
|
+ void (*free)(struct ssam_event_item *);
|
|
|
|
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+struct ssam_event_item {
|
|
|
|
+struct ssam_event_item {
|
|
|
|
+ struct list_head node;
|
|
|
|
+ struct list_head node;
|
|
|
|
+ u16 rqid;
|
|
|
|
+ u16 rqid;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ struct ssam_event_item_ops ops;
|
|
|
|
+ struct ssam_event event; // must be last
|
|
|
|
+ struct ssam_event event; // must be last
|
|
|
|
+};
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -9444,6 +9424,79 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+};
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
|
|
|
+ * Maximum payload length for cached `ssam_event_item`s.
|
|
|
|
|
|
|
|
+ *
|
|
|
|
|
|
|
|
+ * This length has been chosen to be accomodate standard touchpad and keyboard
|
|
|
|
|
|
|
|
+ * input events. Events with larger payloads will be allocated separately.
|
|
|
|
|
|
|
|
+ */
|
|
|
|
|
|
|
|
+#define SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN 32
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static struct kmem_cache *ssam_event_item_cache;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static int ssam_event_item_cache_init(void)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ const unsigned int size = sizeof(struct ssam_event_item)
|
|
|
|
|
|
|
|
+ + SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN;
|
|
|
|
|
|
|
|
+ const unsigned int align = __alignof__(struct ssam_event_item);
|
|
|
|
|
|
|
|
+ struct kmem_cache *cache;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ cache = kmem_cache_create("ssam_event_item", size, align, 0, NULL);
|
|
|
|
|
|
|
|
+ if (!cache)
|
|
|
|
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ ssam_event_item_cache = cache;
|
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static void ssam_event_item_cache_destroy(void)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ kmem_cache_destroy(ssam_event_item_cache);
|
|
|
|
|
|
|
|
+ ssam_event_item_cache = NULL;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static void __ssam_event_item_free_cached(struct ssam_event_item *item)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ kmem_cache_free(ssam_event_item_cache, item);
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static void __ssam_event_item_free_generic(struct ssam_event_item *item)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ kfree(item);
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static inline void ssam_event_item_free(struct ssam_event_item *item)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ trace_ssam_event_item_free(item);
|
|
|
|
|
|
|
|
+ item->ops.free(item);
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static struct ssam_event_item *ssam_event_item_alloc(size_t len, gfp_t flags)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ struct ssam_event_item *item;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (len <= SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN) {
|
|
|
|
|
|
|
|
+ item = kmem_cache_alloc(ssam_event_item_cache, GFP_KERNEL);
|
|
|
|
|
|
|
|
+ if (!item)
|
|
|
|
|
|
|
|
+ return NULL;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ item->ops.free = __ssam_event_item_free_cached;
|
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
|
|
+ const size_t n = sizeof(struct ssam_event_item) + len;
|
|
|
|
|
|
|
|
+ item = kzalloc(n, GFP_KERNEL);
|
|
|
|
|
|
|
|
+ if (!item)
|
|
|
|
|
|
|
|
+ return NULL;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ item->ops.free = __ssam_event_item_free_generic;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ item->event.length = len;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ trace_ssam_event_item_alloc(item, len);
|
|
|
|
|
|
|
|
+ return item;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+
|
|
|
|
+static void ssam_event_queue_push(struct ssam_event_queue *q,
|
|
|
|
+static void ssam_event_queue_push(struct ssam_event_queue *q,
|
|
|
|
+ struct ssam_event_item *item)
|
|
|
|
+ struct ssam_event_item *item)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
@ -9539,7 +9592,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ return;
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ ssam_nf_call(nf, dev, item->rqid, &item->event);
|
|
|
|
+ ssam_nf_call(nf, dev, item->rqid, &item->event);
|
|
|
|
+ kfree(item);
|
|
|
|
+ ssam_event_item_free(item);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (!ssam_event_queue_is_empty(queue))
|
|
|
|
+ if (!ssam_event_queue_is_empty(queue))
|
|
|
@ -9582,6 +9635,12 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void ssam_cplt_destroy(struct ssam_cplt *cplt)
|
|
|
|
+static void ssam_cplt_destroy(struct ssam_cplt *cplt)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
|
|
|
+ * Note: destroy_workqueue ensures that all currently queued work will
|
|
|
|
|
|
|
|
+ * be fully completed and the workqueue drained. This means that this
|
|
|
|
|
|
|
|
+ * call will inherently also free any queued ssam_event_items, thus we
|
|
|
|
|
|
|
|
+ * don't have to take care of that here explicitly.
|
|
|
|
|
|
|
|
+ */
|
|
|
|
+ destroy_workqueue(cplt->wq);
|
|
|
|
+ destroy_workqueue(cplt->wq);
|
|
|
|
+ ssam_nf_destroy(&cplt->event.notif);
|
|
|
|
+ ssam_nf_destroy(&cplt->event.notif);
|
|
|
|
+}
|
|
|
|
+}
|
|
|
@ -9632,7 +9691,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+struct device *ssam_controller_device(struct ssam_controller *c)
|
|
|
|
+struct device *ssam_controller_device(struct ssam_controller *c)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ return (c && c->rtl.ptl.serdev) ? &c->rtl.ptl.serdev->dev : NULL;
|
|
|
|
+ return ssh_rtl_get_device(&c->rtl);
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(ssam_controller_device);
|
|
|
|
+EXPORT_SYMBOL_GPL(ssam_controller_device);
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -9644,7 +9703,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ struct ssam_controller *ctrl = to_ssam_controller(rtl, rtl);
|
|
|
|
+ struct ssam_controller *ctrl = to_ssam_controller(rtl, rtl);
|
|
|
|
+ struct ssam_event_item *item;
|
|
|
|
+ struct ssam_event_item *item;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ item = kzalloc(sizeof(struct ssam_event_item) + data->len, GFP_KERNEL);
|
|
|
|
+ item = ssam_event_item_alloc(data->len, GFP_KERNEL);
|
|
|
|
+ if (!item)
|
|
|
|
+ if (!item)
|
|
|
|
+ return;
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -9653,7 +9712,6 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ item->event.command_id = cmd->cid;
|
|
|
|
+ item->event.command_id = cmd->cid;
|
|
|
|
+ item->event.instance_id = cmd->iid;
|
|
|
|
+ item->event.instance_id = cmd->iid;
|
|
|
|
+ item->event.channel = cmd->chn_in;
|
|
|
|
+ item->event.channel = cmd->chn_in;
|
|
|
|
+ item->event.length = data->len;
|
|
|
|
|
|
|
|
+ memcpy(&item->event.data[0], data->ptr, data->len);
|
|
|
|
+ memcpy(&item->event.data[0], data->ptr, data->len);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ ssam_cplt_submit_event(&ctrl->cplt, item);
|
|
|
|
+ ssam_cplt_submit_event(&ctrl->cplt, item);
|
|
|
@ -9664,6 +9722,10 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+};
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+static bool ssam_notifier_empty(struct ssam_controller *ctrl);
|
|
|
|
|
|
|
|
+static void ssam_notifier_unregister_all(struct ssam_controller *ctrl);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+
|
|
|
|
+#define SSAM_SSH_DSM_REVISION 0
|
|
|
|
+#define SSAM_SSH_DSM_REVISION 0
|
|
|
|
+#define SSAM_SSH_DSM_NOTIF_D0 8
|
|
|
|
+#define SSAM_SSH_DSM_NOTIF_D0 8
|
|
|
|
+static const guid_t SSAM_SSH_DSM_UUID = GUID_INIT(0xd5e383e1, 0xd892, 0x4a76,
|
|
|
|
+static const guid_t SSAM_SSH_DSM_UUID = GUID_INIT(0xd5e383e1, 0xd892, 0x4a76,
|
|
|
@ -9739,7 +9801,6 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ // initialize request and packet transmission layers
|
|
|
|
+ // initialize request and packet transmission layers
|
|
|
|
+ status = ssh_rtl_init(&ctrl->rtl, serdev, &ssam_rtl_ops);
|
|
|
|
+ status = ssh_rtl_init(&ctrl->rtl, serdev, &ssam_rtl_ops);
|
|
|
|
+ if (status) {
|
|
|
|
+ if (status) {
|
|
|
|
+ ssam_cplt_flush(&ctrl->cplt);
|
|
|
|
|
|
|
|
+ ssam_cplt_destroy(&ctrl->cplt);
|
|
|
|
+ ssam_cplt_destroy(&ctrl->cplt);
|
|
|
|
+ return status;
|
|
|
|
+ return status;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
@ -9785,9 +9846,22 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ status);
|
|
|
|
+ status);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // flush out all currently completing requests and events
|
|
|
|
+ // try to flush out all currently completing requests and events
|
|
|
|
+ ssam_cplt_flush(&ctrl->cplt);
|
|
|
|
+ ssam_cplt_flush(&ctrl->cplt);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
|
|
|
+ * We expect all notifiers to have been removed by the respective client
|
|
|
|
|
|
|
|
+ * driver that set them up at this point. If this warning occurs, some
|
|
|
|
|
|
|
|
+ * client driver has not done that...
|
|
|
|
|
|
|
|
+ */
|
|
|
|
|
|
|
|
+ WARN_ON(!ssam_notifier_empty(ctrl));
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
|
|
|
+ * Nevertheless, we should still take care of drivers that don't behave
|
|
|
|
|
|
|
|
+ * well. Thus disable all enabled events, unregister all notifiers.
|
|
|
|
|
|
|
|
+ */
|
|
|
|
|
|
|
|
+ ssam_notifier_unregister_all(ctrl);
|
|
|
|
|
|
|
|
+
|
|
|
|
+ // cancel rem. requests, ensure no new ones can be queued, stop threads
|
|
|
|
+ // cancel rem. requests, ensure no new ones can be queued, stop threads
|
|
|
|
+ ssh_rtl_tx_flush(&ctrl->rtl);
|
|
|
|
+ ssh_rtl_tx_flush(&ctrl->rtl);
|
|
|
|
+ ssh_rtl_shutdown(&ctrl->rtl);
|
|
|
|
+ ssh_rtl_shutdown(&ctrl->rtl);
|
|
|
@ -9801,13 +9875,12 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ return;
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ /*
|
|
|
|
+ * Ensure _all_ events are completed. New ones could still have been
|
|
|
|
+ * Note: New events could still have been received after the previous
|
|
|
|
+ * received after the previous flush in ssam_controller_shutdown, before
|
|
|
|
+ * flush in ssam_controller_shutdown, before the request transport layer
|
|
|
|
+ * the request transport layer has been shut down. At this point we can
|
|
|
|
+ * has been shut down. At this point, after the shutdown, we can be sure
|
|
|
|
+ * be sure that no new requests will be queued for completion after this
|
|
|
|
+ * that no new events will be queued. The call to ssam_cplt_destroy will
|
|
|
|
+ * call.
|
|
|
|
+ * ensure that those remaining are being completed and freed.
|
|
|
|
+ */
|
|
|
|
+ */
|
|
|
|
+ ssam_cplt_flush(&ctrl->cplt);
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // actually free resources
|
|
|
|
+ // actually free resources
|
|
|
|
+ ssam_cplt_destroy(&ctrl->cplt);
|
|
|
|
+ ssam_cplt_destroy(&ctrl->cplt);
|
|
|
@ -9816,7 +9889,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ smp_store_release(&ctrl->state, SSAM_CONTROLLER_UNINITIALIZED);
|
|
|
|
+ smp_store_release(&ctrl->state, SSAM_CONTROLLER_UNINITIALIZED);
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline int ssam_controller_suspend(struct ssam_controller *ctrl)
|
|
|
|
+static int ssam_controller_suspend(struct ssam_controller *ctrl)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED)
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ return -EINVAL;
|
|
|
@ -9826,7 +9899,7 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ return 0;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static inline int ssam_controller_resume(struct ssam_controller *ctrl)
|
|
|
|
+static int ssam_controller_resume(struct ssam_controller *ctrl)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_SUSPENDED)
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_SUSPENDED)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ return -EINVAL;
|
|
|
@ -10306,14 +10379,16 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ if (!ssh_rqid_is_event(rqid))
|
|
|
|
+ if (!ssh_rqid_is_event(rqid))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED)
|
|
|
|
|
|
|
|
+ return -ENXIO;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ nf = &ctrl->cplt.event.notif;
|
|
|
|
+ nf = &ctrl->cplt.event.notif;
|
|
|
|
+ nf_head = &nf->head[ssh_rqid_to_event(rqid)];
|
|
|
|
+ nf_head = &nf->head[ssh_rqid_to_event(rqid)];
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ mutex_lock(&nf->lock);
|
|
|
|
+ mutex_lock(&nf->lock);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED) {
|
|
|
|
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
|
|
|
|
|
+ return -ENXIO;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
+ rc = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id);
|
|
|
|
+ rc = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id);
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
@ -10360,14 +10435,16 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+ if (!ssh_rqid_is_event(rqid))
|
|
|
|
+ if (!ssh_rqid_is_event(rqid))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED)
|
|
|
|
|
|
|
|
+ return -ENXIO;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ nf = &ctrl->cplt.event.notif;
|
|
|
|
+ nf = &ctrl->cplt.event.notif;
|
|
|
|
+ nf_head = &nf->head[ssh_rqid_to_event(rqid)];
|
|
|
|
+ nf_head = &nf->head[ssh_rqid_to_event(rqid)];
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ mutex_lock(&nf->lock);
|
|
|
|
+ mutex_lock(&nf->lock);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED) {
|
|
|
|
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
|
|
|
|
|
+ return -ENXIO;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
+ rc = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id);
|
|
|
|
+ rc = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id);
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
@ -10391,6 +10468,33 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(ssam_notifier_unregister);
|
|
|
|
+EXPORT_SYMBOL_GPL(ssam_notifier_unregister);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+static bool ssam_notifier_empty(struct ssam_controller *ctrl)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ struct ssam_nf *nf = &ctrl->cplt.event.notif;
|
|
|
|
|
|
|
|
+ bool result;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ mutex_lock(&nf->lock);
|
|
|
|
|
|
|
|
+ result = ssam_nf_refcount_empty(nf);
|
|
|
|
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ return result;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static void ssam_notifier_unregister_all(struct ssam_controller *ctrl)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ struct ssam_nf *nf = &ctrl->cplt.event.notif;
|
|
|
|
|
|
|
|
+ struct ssam_nf_refcount_entry *pos, *n;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ mutex_lock(&nf->lock);
|
|
|
|
|
|
|
|
+ rbtree_postorder_for_each_entry_safe(pos, n, &nf->refcount, node) {
|
|
|
|
|
|
|
|
+ // ignore errors, will get logged in call
|
|
|
|
|
|
|
|
+ ssam_ssh_event_disable(ctrl, pos->key.reg, pos->key.id, 0);
|
|
|
|
|
|
|
|
+ kfree(pos);
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ nf->refcount = RB_ROOT;
|
|
|
|
|
|
|
|
+ mutex_unlock(&nf->lock);
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/* -- Wakeup IRQ. ----------------------------------------------------------- */
|
|
|
|
+/* -- Wakeup IRQ. ----------------------------------------------------------- */
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -10433,12 +10537,24 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int ssam_irq_setup(struct ssam_controller *ctrl)
|
|
|
|
+static int ssam_irq_setup(struct ssam_controller *ctrl)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ const int irqf = IRQF_SHARED | IRQF_ONESHOT;
|
|
|
|
|
|
|
|
+ struct device *dev = ssam_controller_device(ctrl);
|
|
|
|
+ struct device *dev = ssam_controller_device(ctrl);
|
|
|
|
+ struct gpio_desc *gpiod;
|
|
|
|
+ struct gpio_desc *gpiod;
|
|
|
|
+ int irq;
|
|
|
|
+ int irq;
|
|
|
|
+ int status;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
|
|
|
+ * The actual GPIO interrupt is declared in ACPI as TRIGGER_HIGH.
|
|
|
|
|
|
|
|
+ * However, the GPIO line only gets reset by sending the GPIO callback
|
|
|
|
|
|
|
|
+ * command to SAM (or alternatively the display-on notification). As
|
|
|
|
|
|
|
|
+ * proper handling for this interrupt is not implemented yet, leaving
|
|
|
|
|
|
|
|
+ * the IRQ at TRIGGER_HIGH would cause an IRQ storm (as the callback
|
|
|
|
|
|
|
|
+ * never gets sent and thus the line line never gets reset). To avoid
|
|
|
|
|
|
|
|
+ * this, mark the IRQ as TRIGGER_RISING for now, only creating a single
|
|
|
|
|
|
|
|
+ * interrupt, and let the SAM resume callback during the controller
|
|
|
|
|
|
|
|
+ * resume process clear it.
|
|
|
|
|
|
|
|
+ */
|
|
|
|
|
|
|
|
+ const int irqf = IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_RISING;
|
|
|
|
|
|
|
|
+
|
|
|
|
+ gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS);
|
|
|
|
+ gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS);
|
|
|
|
+ if (IS_ERR(gpiod))
|
|
|
|
+ if (IS_ERR(gpiod))
|
|
|
|
+ return PTR_ERR(gpiod);
|
|
|
|
+ return PTR_ERR(gpiod);
|
|
|
@ -10855,12 +10971,35 @@ index 0000000000000..4144fe0b3d192
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int __init surface_sam_ssh_init(void)
|
|
|
|
+static int __init surface_sam_ssh_init(void)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ return serdev_device_driver_register(&surface_sam_ssh);
|
|
|
|
+ int status;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ status = ssh_ctrl_packet_cache_init();
|
|
|
|
|
|
|
|
+ if (status)
|
|
|
|
|
|
|
|
+ goto err_cpkg;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ status = ssam_event_item_cache_init();
|
|
|
|
|
|
|
|
+ if (status)
|
|
|
|
|
|
|
|
+ goto err_evitem;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ status = serdev_device_driver_register(&surface_sam_ssh);
|
|
|
|
|
|
|
|
+ if (status)
|
|
|
|
|
|
|
|
+ goto err_register;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+err_register:
|
|
|
|
|
|
|
|
+ ssam_event_item_cache_destroy();
|
|
|
|
|
|
|
|
+err_evitem:
|
|
|
|
|
|
|
|
+ ssh_ctrl_packet_cache_destroy();
|
|
|
|
|
|
|
|
+err_cpkg:
|
|
|
|
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void __exit surface_sam_ssh_exit(void)
|
|
|
|
+static void __exit surface_sam_ssh_exit(void)
|
|
|
|
+{
|
|
|
|
+{
|
|
|
|
+ serdev_device_driver_unregister(&surface_sam_ssh);
|
|
|
|
+ serdev_device_driver_unregister(&surface_sam_ssh);
|
|
|
|
|
|
|
|
+ ssam_event_item_cache_destroy();
|
|
|
|
|
|
|
|
+ ssh_ctrl_packet_cache_destroy();
|
|
|
|
+}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+/*
|
|
|
@ -11604,10 +11743,10 @@ index 0000000000000..ba57adb2a3c9d
|
|
|
|
+#endif /* _SURFACE_SAM_SSH_H */
|
|
|
|
+#endif /* _SURFACE_SAM_SSH_H */
|
|
|
|
diff --git a/drivers/platform/x86/surface_sam/surface_sam_ssh_trace.h b/drivers/platform/x86/surface_sam/surface_sam_ssh_trace.h
|
|
|
|
diff --git a/drivers/platform/x86/surface_sam/surface_sam_ssh_trace.h b/drivers/platform/x86/surface_sam/surface_sam_ssh_trace.h
|
|
|
|
new file mode 100644
|
|
|
|
new file mode 100644
|
|
|
|
index 0000000000000..4755183fa423b
|
|
|
|
index 0000000000000..8ea9a2fc99d7e
|
|
|
|
--- /dev/null
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/platform/x86/surface_sam/surface_sam_ssh_trace.h
|
|
|
|
+++ b/drivers/platform/x86/surface_sam/surface_sam_ssh_trace.h
|
|
|
|
@@ -0,0 +1,532 @@
|
|
|
|
@@ -0,0 +1,587 @@
|
|
|
|
+#undef TRACE_SYSTEM
|
|
|
|
+#undef TRACE_SYSTEM
|
|
|
|
+#define TRACE_SYSTEM surface_sam_ssh
|
|
|
|
+#define TRACE_SYSTEM surface_sam_ssh
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -12078,6 +12217,55 @@ index 0000000000000..4755183fa423b
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+DECLARE_EVENT_CLASS(ssam_alloc_class,
|
|
|
|
|
|
|
|
+ TP_PROTO(void *ptr, size_t len),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_ARGS(ptr, len),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_STRUCT__entry(
|
|
|
|
|
|
|
|
+ __array(char, uid, SSAM_PTR_UID_LEN)
|
|
|
|
|
|
|
|
+ __field(size_t, len)
|
|
|
|
|
|
|
|
+ ),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_fast_assign(
|
|
|
|
|
|
|
|
+ ssam_trace_ptr_uid(ptr, __entry->uid);
|
|
|
|
|
|
|
|
+ __entry->len = len;
|
|
|
|
|
|
|
|
+ ),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_printk("uid=%s, len=%zu", __entry->uid, __entry->len)
|
|
|
|
|
|
|
|
+);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+#define DEFINE_SSAM_ALLOC_EVENT(name) \
|
|
|
|
|
|
|
|
+ DEFINE_EVENT(ssam_alloc_class, ssam_##name, \
|
|
|
|
|
|
|
|
+ TP_PROTO(void *ptr, size_t len), \
|
|
|
|
|
|
|
|
+ TP_ARGS(ptr, len) \
|
|
|
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+DECLARE_EVENT_CLASS(ssam_free_class,
|
|
|
|
|
|
|
|
+ TP_PROTO(void *ptr),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_ARGS(ptr),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_STRUCT__entry(
|
|
|
|
|
|
|
|
+ __array(char, uid, SSAM_PTR_UID_LEN)
|
|
|
|
|
|
|
|
+ __field(size_t, len)
|
|
|
|
|
|
|
|
+ ),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_fast_assign(
|
|
|
|
|
|
|
|
+ ssam_trace_ptr_uid(ptr, __entry->uid);
|
|
|
|
|
|
|
|
+ ),
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ TP_printk("uid=%s", __entry->uid)
|
|
|
|
|
|
|
|
+);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+#define DEFINE_SSAM_FREE_EVENT(name) \
|
|
|
|
|
|
|
|
+ DEFINE_EVENT(ssam_free_class, ssam_##name, \
|
|
|
|
|
|
|
|
+ TP_PROTO(void *ptr), \
|
|
|
|
|
|
|
|
+ TP_ARGS(ptr) \
|
|
|
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+
|
|
|
|
+DECLARE_EVENT_CLASS(ssam_generic_uint_class,
|
|
|
|
+DECLARE_EVENT_CLASS(ssam_generic_uint_class,
|
|
|
|
+ TP_PROTO(const char* property, unsigned int value),
|
|
|
|
+ TP_PROTO(const char* property, unsigned int value),
|
|
|
|
+
|
|
|
|
+
|
|
|
@ -12130,6 +12318,12 @@ index 0000000000000..4755183fa423b
|
|
|
|
+DEFINE_SSAM_FRAME_EVENT(ei_rx_corrupt_data);
|
|
|
|
+DEFINE_SSAM_FRAME_EVENT(ei_rx_corrupt_data);
|
|
|
|
+DEFINE_SSAM_REQUEST_EVENT(ei_rx_drop_response);
|
|
|
|
+DEFINE_SSAM_REQUEST_EVENT(ei_rx_drop_response);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
+DEFINE_SSAM_ALLOC_EVENT(ctrl_packet_alloc);
|
|
|
|
|
|
|
|
+DEFINE_SSAM_FREE_EVENT(ctrl_packet_free);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+DEFINE_SSAM_ALLOC_EVENT(event_item_alloc);
|
|
|
|
|
|
|
|
+DEFINE_SSAM_FREE_EVENT(event_item_free);
|
|
|
|
|
|
|
|
+
|
|
|
|
+#endif /* _SURFACE_SAM_SSH_TRACE_H */
|
|
|
|
+#endif /* _SURFACE_SAM_SSH_TRACE_H */
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/* This part must be outside protection */
|
|
|
|
+/* This part must be outside protection */
|
|
|
|