Browse Source

Update v4.19 patches

Changes:
  SAM:
    - Fix bug that can cause IRQ storm when SSAM wake IRQ gets triggered.
    - Continued internal restructuring.
    - Other small bug fixes.

Links:
- kernel: https://github.com/linux-surface/kernel/commit/307c8337b95cb570e5c532dd4848e11964591d33
- SAM: https://github.com/linux-surface/surface-aggregator-module/commit/b9fe8f28b70b8a399c43177629a6a73641a87808
Maximilian Luz 4 năm trước cách đây
mục cha
commit
6787e5ada5

+ 1 - 1
patches/4.19/0001-surface3-power.patch

@@ -1,4 +1,4 @@
-From 425be7bc461cbd94823f74bca33e13cc1209ba0e Mon Sep 17 00:00:00 2001
+From 7758260ca65d048fc048997fde2b2835aeb56bf2 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 28 Sep 2019 18:00:43 +0200
 Subject: [PATCH 1/9] surface3-power

+ 1 - 1
patches/4.19/0002-surface3-touchscreen-dma-fix.patch

@@ -1,4 +1,4 @@
-From 6949462d2c416154c3f66d3ff5289abaad9d3536 Mon Sep 17 00:00:00 2001
+From 4ddb434540558cdfbf4c6a7302e5cf96a1cf016c Mon Sep 17 00:00:00 2001
 From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 Date: Sun, 5 Jul 2020 14:56:20 +0300
 Subject: [PATCH 2/9] surface3-touchscreen-dma-fix

+ 1 - 1
patches/4.19/0003-surface3-oemb.patch

@@ -1,4 +1,4 @@
-From fd6b140ce7e7844492502b24d82de376722dc499 Mon Sep 17 00:00:00 2001
+From 319a7962c8241d6d42765f31f932e3e71502e642 Mon Sep 17 00:00:00 2001
 From: Chih-Wei Huang <cwhuang@linux.org.tw>
 Date: Tue, 18 Sep 2018 11:01:37 +0800
 Subject: [PATCH 3/9] surface3-oemb

+ 1 - 1
patches/4.19/0004-surface-buttons.patch

@@ -1,4 +1,4 @@
-From 721b43d141ff16352b0448130991ac0c0e198bab Mon Sep 17 00:00:00 2001
+From 56a637b630a48dc4483c1d6e9dfbf09b324abb1b Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 27 Jul 2019 17:51:37 +0200
 Subject: [PATCH 4/9] surface-buttons

+ 295 - 101
patches/4.19/0005-surface-sam.patch

@@ -1,4 +1,4 @@
-From 56277ddafa4e4e40b6129f36e177082693199961 Mon Sep 17 00:00:00 2001
+From aca32242599b689b942043205c925c566f706fc3 Mon Sep 17 00:00:00 2001
 From: qzed <qzed@users.noreply.github.com>
 Date: Mon, 26 Aug 2019 01:15:40 +0200
 Subject: [PATCH 5/9] surface-sam
@@ -22,12 +22,12 @@ Subject: [PATCH 5/9] surface-sam
  .../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.h     |   14 +
- .../x86/surface_sam/surface_sam_ssh.c         | 5191 +++++++++++++++++
+ .../x86/surface_sam/surface_sam_ssh.c         | 5330 +++++++++++++++++
  .../x86/surface_sam/surface_sam_ssh.h         |  711 +++
- .../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 +
  drivers/tty/serdev/core.c                     |  110 +-
- 23 files changed, 12345 insertions(+), 29 deletions(-)
+ 23 files changed, 12539 insertions(+), 29 deletions(-)
  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/surface_sam_debugfs.c
@@ -5754,10 +5754,10 @@ index 0000000000000..d956de5cf877a
 +#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
 new file mode 100644
-index 0000000000000..98492403c239b
+index 0000000000000..3f39f383e3651
 --- /dev/null
 +++ b/drivers/platform/x86/surface_sam/surface_sam_ssh.c
-@@ -0,0 +1,5191 @@
+@@ -0,0 +1,5330 @@
 +// SPDX-License-Identifier: GPL-2.0-or-later
 +/*
 + * Surface Serial Hub (SSH) driver for communication with the Surface/System
@@ -5828,11 +5828,6 @@ index 0000000000000..98492403c239b
 +	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)
 +{
 +	return rqid - 1u;
@@ -5848,11 +5843,6 @@ index 0000000000000..98492403c239b
 +	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)
 +{
 +	return channel - 1u;
@@ -5928,31 +5918,6 @@ index 0000000000000..98492403c239b
 +	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)
 +{
 +	return msgb->ptr - msgb->begin;
@@ -6226,11 +6191,6 @@ index 0000000000000..98492403c239b
 +	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)
 +{
 +	memmove(buf->ptr, buf->ptr + n, buf->len - n);
@@ -6645,10 +6605,8 @@ index 0000000000000..98492403c239b
 +	}
 +}
 +
-+static inline int ssh_ptl_write_buf(struct ssh_ptl *ptl,
-+				    struct ssh_packet *packet,
-+				    const unsigned char *buf,
-+				    size_t count)
++static int ssh_ptl_write_buf(struct ssh_ptl *ptl, struct ssh_packet *packet,
++			     const unsigned char *buf, size_t count)
 +{
 +	int status;
 +
@@ -6665,7 +6623,7 @@ index 0000000000000..98492403c239b
 +	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)
 +	if (!packet->data.ptr || !packet->data.len)
@@ -6691,8 +6649,8 @@ index 0000000000000..98492403c239b
 +	memset(packet->data.ptr, 0xb3, packet->data.len);
 +}
 +
-+static inline void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
-+						 struct ssam_span *data)
++static void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
++					  struct ssam_span *data)
 +{
 +	struct ssam_span frame;
 +
@@ -6708,8 +6666,8 @@ index 0000000000000..98492403c239b
 +	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,
-+						  struct ssam_span *frame)
++static void ssh_ptl_rx_inject_invalid_data(struct ssh_ptl *ptl,
++					   struct ssam_span *frame)
 +{
 +	size_t payload_len, message_len;
 +	struct ssh_frame *sshf;
@@ -6825,41 +6783,51 @@ index 0000000000000..98492403c239b
 +}
 +
 +
-+static int ptl_alloc_ctrl_packet(struct ssh_ptl *ptl,
-+				 struct ssh_packet **packet,
-+				 struct ssam_span *buffer, gfp_t flags)
++static struct kmem_cache *ssh_ctrl_packet_cache;
++
++static int __init ssh_ctrl_packet_cache_init(void)
 +{
-+	// TODO: cache packets
-+	// - 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
++	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;
++}
 +
-+	*packet = kzalloc(sizeof(struct ssh_packet) + SSH_MSG_LEN_CTRL, flags);
++static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
++				 struct ssam_span *buffer, gfp_t flags)
++{
++	*packet = kmem_cache_alloc(ssh_ctrl_packet_cache, flags);
 +	if (!*packet)
 +		return -ENOMEM;
 +
 +	buffer->ptr = (u8 *)(*packet + 1);
 +	buffer->len = SSH_MSG_LEN_CTRL;
 +
++	trace_ssam_ctrl_packet_alloc(*packet, buffer->len);
 +	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
-+
-+	kfree(p);
++	trace_ssam_ctrl_packet_free(p);
++	kmem_cache_free(ssh_ctrl_packet_cache, p);
 +}
 +
 +static const struct ssh_packet_ops ssh_ptl_ctrl_packet_ops = {
 +	.complete = NULL,
-+	.release = ptl_free_ctrl_packet,
++	.release = ssh_ctrl_packet_free,
 +};
 +
 +
@@ -7709,7 +7677,7 @@ index 0000000000000..98492403c239b
 +	struct msgbuf msgb;
 +	int status;
 +
-+	status = ptl_alloc_ctrl_packet(ptl, &packet, &buf, GFP_KERNEL);
++	status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
 +	if (status) {
 +		ptl_err(ptl, "ptl: failed to allocate ACK packet\n");
 +		return;
@@ -7736,7 +7704,7 @@ index 0000000000000..98492403c239b
 +	struct msgbuf msgb;
 +	int status;
 +
-+	status = ptl_alloc_ctrl_packet(ptl, &packet, &buf, GFP_KERNEL);
++	status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
 +	if (status) {
 +		ptl_err(ptl, "ptl: failed to allocate NAK packet\n");
 +		return;
@@ -8043,7 +8011,7 @@ index 0000000000000..98492403c239b
 +
 +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,
@@ -9416,6 +9384,11 @@ index 0000000000000..98492403c239b
 +	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,
 +			 struct ssam_event *event)
 +{
@@ -9484,10 +9457,17 @@ index 0000000000000..98492403c239b
 +
 +
 +struct ssam_cplt;
++struct ssam_event_item;
++
++struct ssam_event_item_ops {
++	void (*free)(struct ssam_event_item *);
++};
 +
 +struct ssam_event_item {
 +	struct list_head node;
 +	u16 rqid;
++
++	struct ssam_event_item_ops ops;
 +	struct ssam_event event;	// must be last
 +};
 +
@@ -9514,6 +9494,79 @@ index 0000000000000..98492403c239b
 +};
 +
 +
++/**
++ * 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,
 +				  struct ssam_event_item *item)
 +{
@@ -9609,7 +9662,7 @@ index 0000000000000..98492403c239b
 +			return;
 +
 +		ssam_nf_call(nf, dev, item->rqid, &item->event);
-+		kfree(item);
++		ssam_event_item_free(item);
 +	}
 +
 +	if (!ssam_event_queue_is_empty(queue))
@@ -9652,6 +9705,12 @@ index 0000000000000..98492403c239b
 +
 +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);
 +	ssam_nf_destroy(&cplt->event.notif);
 +}
@@ -9702,7 +9761,7 @@ index 0000000000000..98492403c239b
 +
 +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);
 +
@@ -9714,7 +9773,7 @@ index 0000000000000..98492403c239b
 +	struct ssam_controller *ctrl = to_ssam_controller(rtl, rtl);
 +	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)
 +		return;
 +
@@ -9723,7 +9782,6 @@ index 0000000000000..98492403c239b
 +	item->event.command_id = cmd->cid;
 +	item->event.instance_id = cmd->iid;
 +	item->event.channel = cmd->chn_in;
-+	item->event.length  = data->len;
 +	memcpy(&item->event.data[0], data->ptr, data->len);
 +
 +	ssam_cplt_submit_event(&ctrl->cplt, item);
@@ -9734,6 +9792,10 @@ index 0000000000000..98492403c239b
 +};
 +
 +
++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_NOTIF_D0	8
 +static const guid_t SSAM_SSH_DSM_UUID = GUID_INIT(0xd5e383e1, 0xd892, 0x4a76,
@@ -9809,7 +9871,6 @@ index 0000000000000..98492403c239b
 +	// initialize request and packet transmission layers
 +	status = ssh_rtl_init(&ctrl->rtl, serdev, &ssam_rtl_ops);
 +	if (status) {
-+		ssam_cplt_flush(&ctrl->cplt);
 +		ssam_cplt_destroy(&ctrl->cplt);
 +		return status;
 +	}
@@ -9855,9 +9916,22 @@ index 0000000000000..98492403c239b
 +			 status);
 +	}
 +
-+	// flush out all currently completing requests and events
++	// try to flush out all currently completing requests and events
 +	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
 +	ssh_rtl_tx_flush(&ctrl->rtl);
 +	ssh_rtl_shutdown(&ctrl->rtl);
@@ -9871,13 +9945,12 @@ index 0000000000000..98492403c239b
 +		return;
 +
 +	/*
-+	 * Ensure _all_ events are completed. New ones could still have been
-+	 * received after the previous flush in ssam_controller_shutdown, before
-+	 * the request transport layer has been shut down. At this point we can
-+	 * be sure that no new requests will be queued for completion after this
-+	 * call.
++	 * Note: New events could still have been received after the previous
++	 * flush in ssam_controller_shutdown, before the request transport layer
++	 * has been shut down. At this point, after the shutdown, we can be sure
++	 * that no new events will be queued. The call to ssam_cplt_destroy will
++	 * ensure that those remaining are being completed and freed.
 +	 */
-+	ssam_cplt_flush(&ctrl->cplt);
 +
 +	// actually free resources
 +	ssam_cplt_destroy(&ctrl->cplt);
@@ -9886,7 +9959,7 @@ index 0000000000000..98492403c239b
 +	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)
 +		return -EINVAL;
@@ -9896,7 +9969,7 @@ index 0000000000000..98492403c239b
 +	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)
 +		return -EINVAL;
@@ -10376,14 +10449,16 @@ index 0000000000000..98492403c239b
 +	if (!ssh_rqid_is_event(rqid))
 +		return -EINVAL;
 +
-+	if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED)
-+		return -ENXIO;
-+
 +	nf = &ctrl->cplt.event.notif;
 +	nf_head = &nf->head[ssh_rqid_to_event(rqid)];
 +
 +	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);
 +	if (rc < 0) {
 +		mutex_unlock(&nf->lock);
@@ -10430,14 +10505,16 @@ index 0000000000000..98492403c239b
 +	if (!ssh_rqid_is_event(rqid))
 +		return -EINVAL;
 +
-+	if (smp_load_acquire(&ctrl->state) != SSAM_CONTROLLER_STARTED)
-+		return -ENXIO;
-+
 +	nf = &ctrl->cplt.event.notif;
 +	nf_head = &nf->head[ssh_rqid_to_event(rqid)];
 +
 +	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);
 +	if (rc < 0) {
 +		mutex_unlock(&nf->lock);
@@ -10461,6 +10538,33 @@ index 0000000000000..98492403c239b
 +}
 +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. ----------------------------------------------------------- */
 +
@@ -10503,12 +10607,24 @@ index 0000000000000..98492403c239b
 +
 +static int ssam_irq_setup(struct ssam_controller *ctrl)
 +{
-+	const int irqf = IRQF_SHARED | IRQF_ONESHOT;
 +	struct device *dev = ssam_controller_device(ctrl);
 +	struct gpio_desc *gpiod;
 +	int irq;
 +	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);
 +	if (IS_ERR(gpiod))
 +		return PTR_ERR(gpiod);
@@ -10925,12 +11041,35 @@ index 0000000000000..98492403c239b
 +
 +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)
 +{
 +	serdev_device_driver_unregister(&surface_sam_ssh);
++	ssam_event_item_cache_destroy();
++	ssh_ctrl_packet_cache_destroy();
 +}
 +
 +/*
@@ -11668,10 +11807,10 @@ index 0000000000000..473927699efd0
 +#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
 new file mode 100644
-index 0000000000000..4755183fa423b
+index 0000000000000..8ea9a2fc99d7e
 --- /dev/null
 +++ b/drivers/platform/x86/surface_sam/surface_sam_ssh_trace.h
-@@ -0,0 +1,532 @@
+@@ -0,0 +1,587 @@
 +#undef TRACE_SYSTEM
 +#define TRACE_SYSTEM surface_sam_ssh
 +
@@ -12142,6 +12281,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,
 +	TP_PROTO(const char* property, unsigned int value),
 +
@@ -12194,6 +12382,12 @@ index 0000000000000..4755183fa423b
 +DEFINE_SSAM_FRAME_EVENT(ei_rx_corrupt_data);
 +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 */
 +
 +/* This part must be outside protection */

+ 1 - 1
patches/4.19/0006-surface-sam-over-hid.patch

@@ -1,4 +1,4 @@
-From 1a23a40eb02e8f4bc9588512c60d69a9e7820332 Mon Sep 17 00:00:00 2001
+From dff041886f4e1e942fcabb40a2fc1a6e9556374f Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 25 Jul 2020 17:19:53 +0200
 Subject: [PATCH 6/9] surface-sam-over-hid

+ 1 - 1
patches/4.19/0007-suspend.patch

@@ -1,4 +1,4 @@
-From 41405a469737887a7769e564ff45aa04546f55f0 Mon Sep 17 00:00:00 2001
+From b6a4004590ccd476e3880c03d8e9fb4b80a54eba Mon Sep 17 00:00:00 2001
 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
 Date: Sat, 28 Sep 2019 17:48:21 +0200
 Subject: [PATCH 7/9] suspend

+ 1 - 1
patches/4.19/0008-ipts.patch

@@ -1,4 +1,4 @@
-From 2c053417d2e08043a1931b8e11b174d882ce9b49 Mon Sep 17 00:00:00 2001
+From bfa54c16d6e9e112be44081b80d422100b839ead Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 28 Sep 2019 17:58:17 +0200
 Subject: [PATCH 8/9] ipts

+ 1 - 1
patches/4.19/0009-wifi.patch

@@ -1,4 +1,4 @@
-From d62b2cd4d47686639f5950a87013db90860c8d0b Mon Sep 17 00:00:00 2001
+From a2cac7e8bbc67148a6480cde4ccb9bd455e5892e Mon Sep 17 00:00:00 2001
 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
 Date: Thu, 20 Feb 2020 16:51:11 +0900
 Subject: [PATCH 9/9] wifi

+ 9 - 9
pkg/arch/kernel-lts/PKGBUILD

@@ -40,15 +40,15 @@ sha256sums=('33d7cecaa6258233881d2a5ecf25d40134639da5b1d497222eb1cbed9e32af98'
             '4e68572e7cc4c5368f0236e0792660ae8498373988625dca46e509399a7eaea6'
             'a13581d3c6dc595206e4fe7fcf6b542e7a1bdbe96101f0f010fc5be49f99baf2'
             'ecd70de98096cd4fbfaf1c52a9d3d56a0a5c909761e674afb8373fa1b046a944'
-            '97fa4e1e781e21d93c13a0f3f935cb8c20a617ca17c8f1be2667e7f7e323a2ee'
-            '07841f5045ba1119bda8379b8b64b4dfde252473bbb4c791a71af9df9257905b'
-            '43bab276a7a3a927f1a9446c38637f3b4a8e17b3d3a162e8b849f5f70202912f'
-            'ed98e5aeafadb5c921edd4e446cce7cf5a4fb71645fd6cf1cd0d66144e8daf48'
-            '8ff8701bb94b375bfe50870ba11da302c89da176dd5e9e6acc7a5644f2d0e0c9'
-            '0becd7832ae34fe09c7fc9101aa566a8c1a5ec710de9720ca3cda35c49f0d830'
-            '0685d86f61df78ce2b0533fb563adb00b2a40bba6e55f766fdffde4dfa621a01'
-            '7cd6c85a466a58a564d91fc1d5de1073d163a1b44825b61a17041f5fe3c63907'
-            '53a78facd545a19d196c070d8c16d26937336133b0284d5137c9e9a549b729ef')
+            '91ffa503907109951878e1ef58dd5ebe4deef7a75a3c4e06dbad747418869acb'
+            '02b670f7e2f1ab7ae00aebbc3569d7757a228fb662ae81203bacb1f704dd9c5a'
+            '38e4c43a780f62582340bfcd7a1e22558b5d98719e8463e35dec6571322fe51a'
+            '3dbcdc0cf83fbc1a97634ab736ddfc2518034758c2aed19ac406a3a1dee40377'
+            '6c521827ec9d6dcd89c895c1dc140457163347311adb4f441f62d6fb6ecaca26'
+            'bfbc9ce608433badd5b856f2941d4c71070bb8e01b97313091d4339766f0fa4c'
+            'a9d05b5564ada9305a87eabdc78b7d27d58d597481b49c98af93319bdc57f83e'
+            '56d31e9aa1425403c6c1cd7dc9a79d026c866bdd29effdb951bfaea91816386c'
+            '44c73f31333c98049f287a1949ce12d47d6d1810fca22b90aa3b5d21bfa648b6')
 
 export KBUILD_BUILD_HOST=archlinux
 export KBUILD_BUILD_USER=$pkgbase