summaryrefslogtreecommitdiffstats
path: root/sound/firewire/packets-buffer.c
diff options
context:
space:
mode:
authorFan Wu <fanwu01@zju.edu.cn>2026-08-20 13:53:06 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-01 16:50:04 +0200
commit263f7d61a4201cde16849b2d016251806e7418be (patch)
tree861df7c5b878b85741cf319ece81111b4c41c3b1 /sound/firewire/packets-buffer.c
downloadlinux-stable-263f7d61a4201cde16849b2d016251806e7418be.tar.gz
linux-stable-263f7d61a4201cde16849b2d016251806e7418be.zip
usb: typec: qcom-pmic-typec: disable cc_debounce_dwork on stopgrafted
cc_debounce_dwork is queued from the set_cc() and start_toggling() callbacks, which run from TCPM's kthread worker. port_stop() returns before tcpm_unregister_port() destroys that worker. Flushing the worker during unregister may therefore run a callback which queues the delayed work after port_stop() has returned. The delayed work can then run after devres has freed pmic_typec_port. Use disable_delayed_work_sync() in port_stop() to cancel a pending instance and prevent the TCPM callbacks from queueing another one. This issue was found by an in-house static analysis tool. Fixes: a4422ff22142 ("usb: typec: qcom: Add Qualcomm PMIC Type-C driver") Cc: stable <stable@kernel.org> # v6.10+ Assisted-by: Codex:gpt-5.6 Signed-off-by: Fan Wu <fanwu01@zju.edu.cn> Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://patch.msgid.link/20260820135307.153773-2-fanwu01@zju.edu.cn Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound/firewire/packets-buffer.c')
-rw-r--r--sound/firewire/packets-buffer.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c
new file mode 100644
index 000000000..2093a5fbd
--- /dev/null
+++ b/sound/firewire/packets-buffer.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * helpers for managing a buffer for many packets
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ */
+
+#include <linux/firewire.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include "packets-buffer.h"
+
+/**
+ * iso_packets_buffer_init - allocates the memory for packets
+ * @b: the buffer structure to initialize
+ * @unit: the device at the other end of the stream
+ * @count: the number of packets
+ * @packet_size: the (maximum) size of a packet, in bytes
+ * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE
+ */
+int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit,
+ unsigned int count, unsigned int packet_size,
+ enum dma_data_direction direction)
+{
+ unsigned int packets_per_page, pages;
+ unsigned int i, page_index, offset_in_page;
+ void *p;
+ int err;
+
+ b->packets = kmalloc_objs(*b->packets, count);
+ if (!b->packets) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ packet_size = L1_CACHE_ALIGN(packet_size);
+ packets_per_page = PAGE_SIZE / packet_size;
+ if (WARN_ON(!packets_per_page)) {
+ err = -EINVAL;
+ goto err_packets;
+ }
+ pages = DIV_ROUND_UP(count, packets_per_page);
+
+ err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card,
+ pages, direction);
+ if (err < 0)
+ goto err_packets;
+
+ for (i = 0; i < count; ++i) {
+ page_index = i / packets_per_page;
+ p = page_address(b->iso_buffer.pages[page_index]);
+ offset_in_page = (i % packets_per_page) * packet_size;
+ b->packets[i].buffer = p + offset_in_page;
+ b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page;
+ }
+
+ return 0;
+
+err_packets:
+ kfree(b->packets);
+error:
+ return err;
+}
+EXPORT_SYMBOL(iso_packets_buffer_init);
+
+/**
+ * iso_packets_buffer_destroy - frees packet buffer resources
+ * @b: the buffer structure to free
+ * @unit: the device at the other end of the stream
+ */
+void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
+ struct fw_unit *unit)
+{
+ fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
+ kfree(b->packets);
+}
+EXPORT_SYMBOL(iso_packets_buffer_destroy);