linux1394-devel Mailing List for IEEE 1394 for Linux
Brought to you by:
aeb,
bencollins
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
(39) |
Apr
(154) |
May
(172) |
Jun
(237) |
Jul
(127) |
Aug
(135) |
Sep
(193) |
Oct
(175) |
Nov
(173) |
Dec
(148) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(161) |
Feb
(225) |
Mar
(193) |
Apr
(158) |
May
(179) |
Jun
(292) |
Jul
(146) |
Aug
(134) |
Sep
(185) |
Oct
(190) |
Nov
(149) |
Dec
(161) |
2002 |
Jan
(186) |
Feb
(236) |
Mar
(254) |
Apr
(207) |
May
(189) |
Jun
(182) |
Jul
(202) |
Aug
(155) |
Sep
(149) |
Oct
(449) |
Nov
(191) |
Dec
(108) |
2003 |
Jan
(174) |
Feb
(242) |
Mar
(243) |
Apr
(255) |
May
(202) |
Jun
(290) |
Jul
(237) |
Aug
(178) |
Sep
(101) |
Oct
(153) |
Nov
(144) |
Dec
(95) |
2004 |
Jan
(162) |
Feb
(278) |
Mar
(282) |
Apr
(152) |
May
(127) |
Jun
(138) |
Jul
(94) |
Aug
(63) |
Sep
(64) |
Oct
(150) |
Nov
(102) |
Dec
(197) |
2005 |
Jan
(102) |
Feb
(172) |
Mar
(89) |
Apr
(158) |
May
(139) |
Jun
(160) |
Jul
(288) |
Aug
(89) |
Sep
(201) |
Oct
(92) |
Nov
(190) |
Dec
(139) |
2006 |
Jan
(121) |
Feb
(204) |
Mar
(133) |
Apr
(134) |
May
(91) |
Jun
(226) |
Jul
(122) |
Aug
(101) |
Sep
(144) |
Oct
(141) |
Nov
|
Dec
|
2023 |
Jan
(19) |
Feb
(1) |
Mar
(5) |
Apr
(5) |
May
(33) |
Jun
(17) |
Jul
|
Aug
|
Sep
(3) |
Oct
(1) |
Nov
(5) |
Dec
(40) |
2024 |
Jan
(26) |
Feb
(14) |
Mar
(26) |
Apr
(46) |
May
(17) |
Jun
(47) |
Jul
(23) |
Aug
(72) |
Sep
(33) |
Oct
|
Nov
|
Dec
|
From: Takashi S. <o-t...@sa...> - 2024-09-10 08:51:27
|
On Mon, Sep 09, 2024 at 11:00:16PM +0900, Takashi Sakamoto wrote: > Hi, > > It seems to be the last week for v6.12 development. I realize it > unpreferable to propose intrusive changes, however I also realized that > there is a room to refactor core functions in respect to handler of work > item for isochronous context for the next merge window... > > This series of changes refactors the core function to call > fw_iso_context_flush_completions() from the work item. It optimizes some > event waiting and mediation of concurrent calls as well. > > Takashi Sakamoto (2): > firewire: core: move workqueue handler from 1394 OHCI driver to core > function > firewire: core: use mutex to coordinate concurrent calls to flush > completions > > drivers/firewire/core-iso.c | 31 ++++++++------- > drivers/firewire/core.h | 5 --- > drivers/firewire/ohci.c | 78 +++++++------------------------------ > include/linux/firewire.h | 1 + > 4 files changed, 31 insertions(+), 84 deletions(-) Applied to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-09-09 14:00:37
|
In current implementation, test_and_set_bit_lock() is used to mediate concurrent calls of ohci_flush_iso_completions(). However, the ad-hoc usage of atomic operations is not preferable. This commit uses mutex_trylock() as the similar operations. The core function is responsible for the mediation, instead of 1394 OHCI driver. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-iso.c | 11 +++++++++-- drivers/firewire/ohci.c | 37 ++++++++++++++----------------------- include/linux/firewire.h | 1 + 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 9f41c78878ad..a5c5ef3c725d 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -157,6 +157,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, ctx->callback.sc = callback; ctx->callback_data = callback_data; INIT_WORK(&ctx->work, flush_completions_work); + mutex_init(&ctx->flushing_completions_mutex); trace_isoc_outbound_allocate(ctx, channel, speed); trace_isoc_inbound_single_allocate(ctx, channel, header_size); @@ -173,6 +174,8 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx) trace_isoc_inbound_multiple_destroy(ctx); ctx->card->driver->free_iso_context(ctx); + + mutex_destroy(&ctx->flushing_completions_mutex); } EXPORT_SYMBOL(fw_iso_context_destroy); @@ -226,7 +229,7 @@ EXPORT_SYMBOL(fw_iso_context_queue_flush); * to process the context asynchronously, fw_iso_context_schedule_flush_completions() is available * instead. * - * Context: Process context. + * Context: Process context due to mutex_trylock(). */ int fw_iso_context_flush_completions(struct fw_iso_context *ctx) { @@ -234,7 +237,11 @@ int fw_iso_context_flush_completions(struct fw_iso_context *ctx) trace_isoc_inbound_single_flush_completions(ctx); trace_isoc_inbound_multiple_flush_completions(ctx); - return ctx->card->driver->flush_iso_completions(ctx); + scoped_cond_guard(mutex_try, /* nothing to do */, &ctx->flushing_completions_mutex) { + return ctx->card->driver->flush_iso_completions(ctx); + } + + return 0; } EXPORT_SYMBOL(fw_iso_context_flush_completions); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 02ff0363d3ad..b182998a77f4 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -166,7 +166,6 @@ struct iso_context { struct context context; void *header; size_t header_length; - unsigned long flushing_completions; u32 mc_buffer_bus; u16 mc_completed; u16 last_timestamp; @@ -3579,31 +3578,23 @@ static void ohci_flush_queue_iso(struct fw_iso_context *base) static int ohci_flush_iso_completions(struct fw_iso_context *base) { struct iso_context *ctx = container_of(base, struct iso_context, base); - int ret = 0; - if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) { - // Note that tasklet softIRQ is not used to process isochronous context anymore. - context_tasklet((unsigned long)&ctx->context); + // Note that tasklet softIRQ is not used to process isochronous context anymore. + context_tasklet((unsigned long)&ctx->context); - switch (base->type) { - case FW_ISO_CONTEXT_TRANSMIT: - case FW_ISO_CONTEXT_RECEIVE: - if (ctx->header_length != 0) - flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH); - break; - case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: - if (ctx->mc_completed != 0) - flush_ir_buffer_fill(ctx); - break; - default: - ret = -ENOSYS; - } - - clear_bit_unlock(0, &ctx->flushing_completions); - smp_mb__after_atomic(); + switch (base->type) { + case FW_ISO_CONTEXT_TRANSMIT: + case FW_ISO_CONTEXT_RECEIVE: + if (ctx->header_length != 0) + flush_iso_completions(ctx, FW_ISO_CONTEXT_COMPLETIONS_CAUSE_FLUSH); + return 0; + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + if (ctx->mc_completed != 0) + flush_ir_buffer_fill(ctx); + return 0; + default: + return -ENOSYS; } - - return ret; } static const struct fw_card_driver ohci_driver = { diff --git a/include/linux/firewire.h b/include/linux/firewire.h index f815d12deda0..19e8c5f9537c 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -512,6 +512,7 @@ union fw_iso_callback { struct fw_iso_context { struct fw_card *card; struct work_struct work; + struct mutex flushing_completions_mutex; int type; int channel; int speed; -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-09 14:00:31
|
In current implementation, the work item for isochronous context executes the same procedure of fw_iso_context_flush_completions() internally. There is a space to refactor the implementation. This commit calls fw_iso_context_flush_completions() in the work item. It obsoletes fw_iso_context_init_work(). It also obsoletes a pair of disable_work_sync() and enable_work() since the usage of test_and_set_bit_lock() mediates concurrent call already. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-iso.c | 26 +++++++++------------ drivers/firewire/core.h | 5 ----- drivers/firewire/ohci.c | 45 ++----------------------------------- 3 files changed, 12 insertions(+), 64 deletions(-) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index f2394f3ed194..9f41c78878ad 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -131,6 +131,13 @@ size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed) return 0; } +static void flush_completions_work(struct work_struct *work) +{ + struct fw_iso_context *ctx = container_of(work, struct fw_iso_context, work); + + fw_iso_context_flush_completions(ctx); +} + struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, int channel, int speed, size_t header_size, fw_iso_callback_t callback, void *callback_data) @@ -149,6 +156,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, ctx->header_size = header_size; ctx->callback.sc = callback; ctx->callback_data = callback_data; + INIT_WORK(&ctx->work, flush_completions_work); trace_isoc_outbound_allocate(ctx, channel, speed); trace_isoc_inbound_single_allocate(ctx, channel, header_size); @@ -218,29 +226,15 @@ EXPORT_SYMBOL(fw_iso_context_queue_flush); * to process the context asynchronously, fw_iso_context_schedule_flush_completions() is available * instead. * - * Context: Process context. May sleep due to disable_work_sync(). + * Context: Process context. */ int fw_iso_context_flush_completions(struct fw_iso_context *ctx) { - int err; - trace_isoc_outbound_flush_completions(ctx); trace_isoc_inbound_single_flush_completions(ctx); trace_isoc_inbound_multiple_flush_completions(ctx); - might_sleep(); - - // Avoid dead lock due to programming mistake. - if (WARN_ON_ONCE(current_work() == &ctx->work)) - return 0; - - disable_work_sync(&ctx->work); - - err = ctx->card->driver->flush_iso_completions(ctx); - - enable_work(&ctx->work); - - return err; + return ctx->card->driver->flush_iso_completions(ctx); } EXPORT_SYMBOL(fw_iso_context_flush_completions); diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 0ae2c84ecafe..96ae366889e0 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -159,11 +159,6 @@ int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count); int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card, enum dma_data_direction direction); -static inline void fw_iso_context_init_work(struct fw_iso_context *ctx, work_func_t func) -{ - INIT_WORK(&ctx->work, func); -} - /* -topology */ diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 3a911cfb5ff3..02ff0363d3ad 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1182,47 +1182,6 @@ static void context_tasklet(unsigned long data) } } -static void ohci_isoc_context_work(struct work_struct *work) -{ - struct fw_iso_context *base = container_of(work, struct fw_iso_context, work); - struct iso_context *isoc_ctx = container_of(base, struct iso_context, base); - struct context *ctx = &isoc_ctx->context; - struct descriptor *d, *last; - u32 address; - int z; - struct descriptor_buffer *desc; - - desc = list_entry(ctx->buffer_list.next, struct descriptor_buffer, list); - last = ctx->last; - while (last->branch_address != 0) { - struct descriptor_buffer *old_desc = desc; - - address = le32_to_cpu(last->branch_address); - z = address & 0xf; - address &= ~0xf; - ctx->current_bus = address; - - // If the branch address points to a buffer outside of the current buffer, advance - // to the next buffer. - if (address < desc->buffer_bus || address >= desc->buffer_bus + desc->used) - desc = list_entry(desc->list.next, struct descriptor_buffer, list); - d = desc->buffer + (address - desc->buffer_bus) / sizeof(*d); - last = find_branch_descriptor(d, z); - - if (!ctx->callback(ctx, d, last)) - break; - - if (old_desc != desc) { - // If we've advanced to the next buffer, move the previous buffer to the - // free list. - old_desc->used = 0; - guard(spinlock_irqsave)(&ctx->ohci->lock); - list_move_tail(&old_desc->list, &ctx->buffer_list); - } - ctx->last = last; - } -} - /* * Allocate a new buffer and add it to the list of free buffers for this * context. Must be called with ohci->lock held. @@ -3169,7 +3128,6 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, ret = context_init(&ctx->context, ohci, regs, callback); if (ret < 0) goto out_with_header; - fw_iso_context_init_work(&ctx->base, ohci_isoc_context_work); if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) { set_multichannel_mask(ohci, 0); @@ -3624,7 +3582,8 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base) int ret = 0; if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) { - ohci_isoc_context_work(&base->work); + // Note that tasklet softIRQ is not used to process isochronous context anymore. + context_tasklet((unsigned long)&ctx->context); switch (base->type) { case FW_ISO_CONTEXT_TRANSMIT: -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-09 14:00:29
|
Hi, It seems to be the last week for v6.12 development. I realize it unpreferable to propose intrusive changes, however I also realized that there is a room to refactor core functions in respect to handler of work item for isochronous context for the next merge window... This series of changes refactors the core function to call fw_iso_context_flush_completions() from the work item. It optimizes some event waiting and mediation of concurrent calls as well. Takashi Sakamoto (2): firewire: core: move workqueue handler from 1394 OHCI driver to core function firewire: core: use mutex to coordinate concurrent calls to flush completions drivers/firewire/core-iso.c | 31 ++++++++------- drivers/firewire/core.h | 5 --- drivers/firewire/ohci.c | 78 +++++++------------------------------ include/linux/firewire.h | 1 + 4 files changed, 31 insertions(+), 84 deletions(-) -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-09 00:22:44
|
On Sun, Sep 08, 2024 at 01:05:47PM +0900, Takashi Sakamoto wrote: > Hi, > > ALSA firewire stack uses packet-per-buffer mode for both isochronous > receive (IR) and transmit (IT) contexts of 1394 OHCI. To process time > stamp per packet (or per sample in some cases) steadily for media clock > recovery against unexpected transmission skips in the IR context, it uses > an IT context to operate all of isochronous contexts by calls of > fw_iso_context_flush_completions() in the bottom-half of hardIRQ for the > IT context. > > Although it looks well to handle all of isochronous contexts in a single > bottom-half context, it relatively takes longer time to finish. In the > future code integration (not yet), it is possible to apply parallelism > method to process these context. In the case, it is useful to allow unit > drivers to schedule work items to process these isochronous contexts. > > As a preparation, in this series of changes, > fw_iso_context_schedule_flush_completions() is exposed as a kernel API > available by unit drivers. It is a counter part of > fw_iso_context_flush_completions(). This series of changes also includes > documentation about these kernel APIs. > > Takashi Sakamoto (2): > firewire: core: expose kernel API to schedule work item to process > isochronous context > firewire: core: fulfill documentation of > fw_iso_context_flush_completions() > > Documentation/driver-api/firewire.rst | 2 ++ > drivers/firewire/core-iso.c | 11 +++++++++++ > drivers/firewire/core.h | 5 ----- > drivers/firewire/ohci.c | 4 ++-- > include/linux/firewire.h | 17 +++++++++++++++++ > 5 files changed, 32 insertions(+), 7 deletions(-) Applied to for-next branch. Regards Takashi Sakamoto |
From: Adam G. <ad...@po...> - 2024-09-08 04:26:18
|
On Mon, Sep 02, 2024 at 05:07:40PM +0100, Andrew Ferguson wrote: > Adam, would you be willing to send me the serial number of the PowerBook G4 > you used? That lets me see all of the specs and whether or not it is > similar to mine. Separately (and very much a n00b question!), what's the > best / easiest way to get kernel version 6.8-rc1? is there a specific > distro that ships with development / rc builds of the kernel, or is it > better to install something like Debian Stable and then compile / install a > development build? Ideally I'd replicate your setup to confirm it isn't an > issue on my end. Hi Andrew, Sorry for my late reply. My PowerBook G4's serial number is QT23727VLP4. This is my recipe for building kernels from kernel.org tarballs on Debian Bookworm: sudo apt-get install build-essential sudo apt-get build-dep linux tar xzf linux-6.11-rc1.tar.gz cd linux-source-6.11-rc1 cp /boot/config-6.1.0-15-amd64 .config scripts/config --enable DEBUG_INFO_NONE scripts/config --disable DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT scripts/config --disable CONFIG_DEBUG_INFO_BTF scripts/config --disable SECURITY_LOCKDOWN_LSM scripts/config --disable MODULE_SIG make olddefconfig make clean make bindeb-pkg Note that the upstream kernel source contains a build script for Debian packages. However, Debian has their own, different procedure for building development kernels: https://kernel-team.pages.debian.net/kernel-handbook/ch-common-tasks.html#s-common-official-vcs I've also tested with 6.11-rc1 now. Again, the Linux box was able to access the PowerBook's drive over Firewire. I was able to mount sdb10 as an hfsplus filesystem and see the contents. -- Adam |
From: Takashi S. <o-t...@sa...> - 2024-09-08 04:06:10
|
The fw_iso_context_flush_completions() is the counterpart of fw_iso_context_schedule_work() to process isochronous context in current process context. This commit fulfills its documentation. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-iso.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index a249974a0f87..f2394f3ed194 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -209,6 +209,17 @@ void fw_iso_context_queue_flush(struct fw_iso_context *ctx) } EXPORT_SYMBOL(fw_iso_context_queue_flush); +/** + * fw_iso_context_flush_completions() - process isochronous context in current process context. + * @ctx: the isochronous context + * + * Process the isochronous context in the current process context. The registered callback function + * is called if some packets have been already transferred since the last time. If it is required + * to process the context asynchronously, fw_iso_context_schedule_flush_completions() is available + * instead. + * + * Context: Process context. May sleep due to disable_work_sync(). + */ int fw_iso_context_flush_completions(struct fw_iso_context *ctx) { int err; -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-08 04:06:09
|
In packet-per-buffer mode for isochronous context of 1394 OHCI, software can schedule hardIRQ to the buffer in which the content of isochronous packet is processed. The actual behaviour is different between isochronous receive (IR) and transmit (IT) contexts in respect to isochronous cycle in which the hardIRQ occurs. In IR context, the hardIRQ occurs when the buffer is filled actually by the content of received packet. If there are any isochronous cycles in which the packet transmission is skipped, it is postponed to generate the hardIRQ in respect to the isochronous cycle. In IT context, software can schedule the content of packet every isochronous cycle including skipping, therefore the hardIRQ occurs in the isochronous cycle to which the software scheduled. ALSA firewire stack uses the packet-per-buffer mode for both IR/IT contexts. To process time stamp per packet (or per sample in some cases) steadily for media clock recovery against unexpected transmission skips, it uses an IT context to operate all of isochronous contexts by calls of fw_iso_context_flush_completions() in the bottom-half of hardIRQ for the IT context. Although it looks well to handle all of isochronous contexts in a single bottom-half context, it relatively takes longer time. In the future code integration (not yet), it is possible to apply parallelism method to process these context. In the case, it is useful to allow unit drivers to schedule work items to process these isochronous contexts. As a preparation, this commit exposes fw_iso_context_schedule_flush_completions() as a kernel API available by unit drivers. It is renamed from fw_iso_context_queue_work() since it is a counter part of fw_iso_context_flush_completions(). Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- Documentation/driver-api/firewire.rst | 2 ++ drivers/firewire/core.h | 5 ----- drivers/firewire/ohci.c | 4 ++-- include/linux/firewire.h | 17 +++++++++++++++++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Documentation/driver-api/firewire.rst b/Documentation/driver-api/firewire.rst index d3cfa73cbb2b..28a32410f7d2 100644 --- a/Documentation/driver-api/firewire.rst +++ b/Documentation/driver-api/firewire.rst @@ -43,6 +43,8 @@ Firewire core transaction interfaces Firewire Isochronous I/O interfaces =================================== +.. kernel-doc:: include/linux/firewire.h + :functions: fw_iso_context_schedule_flush_completions .. kernel-doc:: drivers/firewire/core-iso.c :export: diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 2874f316156a..0ae2c84ecafe 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -164,11 +164,6 @@ static inline void fw_iso_context_init_work(struct fw_iso_context *ctx, work_fun INIT_WORK(&ctx->work, func); } -static inline void fw_iso_context_queue_work(struct fw_iso_context *ctx) -{ - queue_work(ctx->card->isoc_wq, &ctx->work); -} - /* -topology */ diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index d0b1fccc450f..3a911cfb5ff3 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2283,7 +2283,7 @@ static irqreturn_t irq_handler(int irq, void *data) while (iso_event) { i = ffs(iso_event) - 1; - fw_iso_context_queue_work(&ohci->ir_context_list[i].base); + fw_iso_context_schedule_flush_completions(&ohci->ir_context_list[i].base); iso_event &= ~(1 << i); } } @@ -2294,7 +2294,7 @@ static irqreturn_t irq_handler(int irq, void *data) while (iso_event) { i = ffs(iso_event) - 1; - fw_iso_context_queue_work(&ohci->it_context_list[i].base); + fw_iso_context_schedule_flush_completions(&ohci->it_context_list[i].base); iso_event &= ~(1 << i); } } diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 72f497b61739..f815d12deda0 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -531,6 +531,23 @@ int fw_iso_context_queue(struct fw_iso_context *ctx, unsigned long payload); void fw_iso_context_queue_flush(struct fw_iso_context *ctx); int fw_iso_context_flush_completions(struct fw_iso_context *ctx); + +/** + * fw_iso_context_schedule_flush_completions() - schedule work item to process isochronous context. + * @ctx: the isochronous context + * + * Schedule a work item on workqueue to process the isochronous context. The registered callback + * function is called in the worker if some packets have been already transferred since the last + * time. If it is required to process the context in the current context, + * fw_iso_context_flush_completions() is available instead. + * + * Context: Any context. + */ +static inline void fw_iso_context_schedule_flush_completions(struct fw_iso_context *ctx) +{ + queue_work(ctx->card->isoc_wq, &ctx->work); +} + int fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags); int fw_iso_context_stop(struct fw_iso_context *ctx); -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-08 04:06:08
|
Hi, ALSA firewire stack uses packet-per-buffer mode for both isochronous receive (IR) and transmit (IT) contexts of 1394 OHCI. To process time stamp per packet (or per sample in some cases) steadily for media clock recovery against unexpected transmission skips in the IR context, it uses an IT context to operate all of isochronous contexts by calls of fw_iso_context_flush_completions() in the bottom-half of hardIRQ for the IT context. Although it looks well to handle all of isochronous contexts in a single bottom-half context, it relatively takes longer time to finish. In the future code integration (not yet), it is possible to apply parallelism method to process these context. In the case, it is useful to allow unit drivers to schedule work items to process these isochronous contexts. As a preparation, in this series of changes, fw_iso_context_schedule_flush_completions() is exposed as a kernel API available by unit drivers. It is a counter part of fw_iso_context_flush_completions(). This series of changes also includes documentation about these kernel APIs. Takashi Sakamoto (2): firewire: core: expose kernel API to schedule work item to process isochronous context firewire: core: fulfill documentation of fw_iso_context_flush_completions() Documentation/driver-api/firewire.rst | 2 ++ drivers/firewire/core-iso.c | 11 +++++++++++ drivers/firewire/core.h | 5 ----- drivers/firewire/ohci.c | 4 ++-- include/linux/firewire.h | 17 +++++++++++++++++ 5 files changed, 32 insertions(+), 7 deletions(-) -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-06 15:42:39
|
On Thu, Sep 05, 2024 at 10:10:29PM +0900, Takashi Sakamoto wrote: > It is enough to notify programming mistakes to programmers just once. > > Suggested-by: Takashi Iwai <ti...@su...> > Signed-off-by: Takashi Sakamoto <o-t...@sa...> > --- > drivers/firewire/core-iso.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c > index af76fa1823f1..a249974a0f87 100644 > --- a/drivers/firewire/core-iso.c > +++ b/drivers/firewire/core-iso.c > @@ -220,7 +220,7 @@ int fw_iso_context_flush_completions(struct fw_iso_context *ctx) > might_sleep(); > > // Avoid dead lock due to programming mistake. > - if (WARN_ON(current_work() == &ctx->work)) > + if (WARN_ON_ONCE(current_work() == &ctx->work)) > return 0; > > disable_work_sync(&ctx->work); > @@ -244,7 +244,7 @@ int fw_iso_context_stop(struct fw_iso_context *ctx) > might_sleep(); > > // Avoid dead lock due to programming mistake. > - if (WARN_ON(current_work() == &ctx->work)) > + if (WARN_ON_ONCE(current_work() == &ctx->work)) > return 0; > > err = ctx->card->driver->stop_iso(ctx); Applied to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-09-05 13:12:21
|
On Wed, Sep 04, 2024 at 09:58:19PM +0900, Takashi Sakamoto wrote: > Hi, > > (resend to linux1394-devel since the original post has so many > receivers. Please refer to it for any reply: > https://lore.kernel.org/lkml/202...@sa.../) > > This series of changes updates my previous RFT[1] to apply for v6.12 > kernel. For the detail, please refer to the previous one. > > To Iwai-san, this series includes the change for sound subsystem as > well. All of changes are specific to ALSA firewire stack, so I would > like to send it to Linus as the part of firewire subsystem updates if > you do not mind it. > > Changes from the RFT: > * WQ_FREEZABLE is newly supported in the workqueue > * Improve code comment in IEC 61883-1/6 packet streaming engine > * Avoid dead lock in the calls of workqueue sync API > > [1] https://lore.kernel.org/lkml/202...@sa.../ > > > Regards > > Takashi Sakamoto (5): > firewire: core: allocate workqueue to handle isochronous contexts in > card > firewire: core: add local API to queue work item to workqueue specific > to isochronous contexts > firewire: ohci: operate IT/IR events in sleepable work process instead > of tasklet softIRQ > firewire: core: non-atomic memory allocation for isochronous event to > user client > ALSA: firewire: use nonatomic PCM operation > > drivers/firewire/core-card.c | 33 ++++++++++++-- > drivers/firewire/core-cdev.c | 4 +- > drivers/firewire/core-iso.c | 30 ++++++++++++- > drivers/firewire/core.h | 14 +++++- > drivers/firewire/ohci.c | 57 +++++++++++++++++++----- > include/linux/firewire.h | 3 ++ > sound/firewire/amdtp-stream.c | 34 +++++++++++--- > sound/firewire/bebob/bebob_pcm.c | 1 + > sound/firewire/dice/dice-pcm.c | 1 + > sound/firewire/digi00x/digi00x-pcm.c | 1 + > sound/firewire/fireface/ff-pcm.c | 1 + > sound/firewire/fireworks/fireworks_pcm.c | 1 + > sound/firewire/isight.c | 1 + > sound/firewire/motu/motu-pcm.c | 1 + > sound/firewire/oxfw/oxfw-pcm.c | 1 + > sound/firewire/tascam/tascam-pcm.c | 1 + > 16 files changed, 157 insertions(+), 27 deletions(-) I applied all of them to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-09-05 13:10:46
|
It is enough to notify programming mistakes to programmers just once. Suggested-by: Takashi Iwai <ti...@su...> Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-iso.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index af76fa1823f1..a249974a0f87 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -220,7 +220,7 @@ int fw_iso_context_flush_completions(struct fw_iso_context *ctx) might_sleep(); // Avoid dead lock due to programming mistake. - if (WARN_ON(current_work() == &ctx->work)) + if (WARN_ON_ONCE(current_work() == &ctx->work)) return 0; disable_work_sync(&ctx->work); @@ -244,7 +244,7 @@ int fw_iso_context_stop(struct fw_iso_context *ctx) might_sleep(); // Avoid dead lock due to programming mistake. - if (WARN_ON(current_work() == &ctx->work)) + if (WARN_ON_ONCE(current_work() == &ctx->work)) return 0; err = ctx->card->driver->stop_iso(ctx); -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-05 08:18:33
|
Hi, Thanks for your test. On Wed, Sep 04, 2024 at 08:45:51PM +0000, Edmund Raile wrote: > Hello Sakamoto-San, I very much appreciate the idea and effort to take on the tasklet conversion in small steps instead of all-at-once! > > I also thank you for the CC, I'd like to be the testing canary for the coal mine of firewire ALSA with RME FireFace! > The ALSA mailing list is a bit overwhelming and I'll likely unsubscribe so a direct CC for anything I can test is a good idea. > > Trying to apply patch 1 of 5 to mainline, your kernel tree appears to be out of sync with mainline! > It was missing b171e20 from 2009 and a7ecbe9 from 2022! > I hope nothing else important is missing! Yes. The series of changes is prepared for the next merge window to v6.12 kernel. It is on the top of for-next branch in linux1394 tree. You can see some patches on v6.12-rc2 tag. https://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git/log/?h=for-next > Since in fw_card_initialize, ret is tested to be 0 we'd need an else instead, is this correct? > > I edited these functions of patch 1, now everything applies just fine: > > @@ -571,11 +571,28 @@ void fw_card_initialize(struct fw_card *card, > } > EXPORT_SYMBOL(fw_card_initialize); > > -int fw_card_add(struct fw_card *card, > - u32 max_receive, u32 link_speed, u64 guid) > +int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid, > + unsigned int supported_isoc_contexts) > { > + struct workqueue_struct *isoc_wq; > int ret; > > + // This workqueue should be: > + // * != WQ_BH Sleepable. > + // * == WQ_UNBOUND Any core can process data for isoc context. The > + // implementation of unit protocol could consumes the core > + // longer somehow. > + // * != WQ_MEM_RECLAIM Not used for any backend of block device. > + // * == WQ_HIGHPRI High priority to process semi-realtime timestamped data. > + // * == WQ_SYSFS Parameters are available via sysfs. > + // * max_active == n_it + n_ir A hardIRQ could notify events for multiple isochronous > + // contexts if they are scheduled to the same cycle. > + isoc_wq = alloc_workqueue("firewire-isoc-card%u", > + WQ_UNBOUND | WQ_HIGHPRI | WQ_SYSFS, > + supported_isoc_contexts, card->index); > + if (!isoc_wq) > + return -ENOMEM; > + > card->max_receive = max_receive; > card->link_speed = link_speed; > card->guid = guid; > @@ -584,9 +601,13 @@ int fw_card_add(struct fw_card *card, > > generate_config_rom(card, tmp_config_rom); > ret = card->driver->enable(card, tmp_config_rom, config_rom_length); > if (ret == 0) > list_add_tail(&card->link, &card_list); > + else > + destroy_workqueue(isoc_wq); > + > + card->isoc_wq = isoc_wq; > > mutex_unlock(&card_mutex); > > return ret; > @@ -709,7 +729,9 @@ void fw_core_remove_card(struct fw_card *card) > { > struct fw_card_driver dummy_driver = dummy_driver_template; > unsigned long flags; > > + might_sleep(); > + > card->driver->update_phy_reg(card, 4, > PHY_LINK_ACTIVE | PHY_CONTENDER, 0); > fw_schedule_bus_reset(card, false, true); > @@ -719,6 +741,7 @@ void fw_core_remove_card(struct fw_card *card) > dummy_driver.free_iso_context = card->driver->free_iso_context; > dummy_driver.stop_iso = card->driver->stop_iso; > card->driver = &dummy_driver; > + drain_workqueue(card->isoc_wq); > > spin_lock_irqsave(&card->lock, flags); > fw_destroy_nodes(card); > > Building a kernel with the patch produced 6.11.0-rc6-1-mainline-00019-g67784a74e258-dirty. > Testing it with TI XIO2213B and RME Fireface 800 so far > 1 hour reveals no issues at all. > ALSA streaming works fine: > mpv --audio-device=alsa/sysdefault:CARD=Fireface800 Spor-Ignition.flac > > Though I haven't the faintest clue how to measure CPU usage impact of the patch, it looks like it would be neglible. > > As of finishing this, I noticed you released [2] https://lore.kernel.org/lkml/202...@sa.../T/ > I'll get around to testing that one too, but tomorrow at the earliest. > > Kind regards, > Edmund Raile. > > Signed-off-by: Edmund Raile <edm...@pr...> > Tested-by: Edmund Raile <edm...@pr...> If using v6.11 kernel, it is convenient to use my remote repository to backport changes for v6.12. But let you be careful to the history of changes anyway. * https://github.com/takaswie/linux-firewire-dkms/ Thanks Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-09-04 12:58:45
|
In the former commits, the callback of isochronous context runs on usual work process. In the case, ALSA PCM device has a flag, nonatomic, to acquire mutex lock instead of spin lock for PCM substream group. This commit uses the flag. It has an advantage in the case that ALSA PCM application uses the large size of intermediate buffer, since it takes too long time even in tasklet softIRQ to process many of isochronous packets, then result in the delay of system event due to disabled IRQ so long. It is avertible to switch to nonatomic operation. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- sound/firewire/amdtp-stream.c | 34 +++++++++++++++++++----- sound/firewire/bebob/bebob_pcm.c | 1 + sound/firewire/dice/dice-pcm.c | 1 + sound/firewire/digi00x/digi00x-pcm.c | 1 + sound/firewire/fireface/ff-pcm.c | 1 + sound/firewire/fireworks/fireworks_pcm.c | 1 + sound/firewire/isight.c | 1 + sound/firewire/motu/motu-pcm.c | 1 + sound/firewire/oxfw/oxfw-pcm.c | 1 + sound/firewire/tascam/tascam-pcm.c | 1 + 10 files changed, 36 insertions(+), 7 deletions(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index c827d7d8d800..c72b2a754775 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -615,6 +615,22 @@ static void update_pcm_pointers(struct amdtp_stream *s, // The program in user process should periodically check the status of intermediate // buffer associated to PCM substream to process PCM frames in the buffer, instead // of receiving notification of period elapsed by poll wait. + // + // Use another work item for period elapsed event to prevent the following AB/BA + // deadlock: + // + // thread 1 thread 2 + // ================================= ================================= + // A.work item (process) pcm ioctl (process) + // v v + // process_rx_packets() B.PCM stream lock + // process_tx_packets() v + // v callbacks in snd_pcm_ops + // update_pcm_pointers() v + // snd_pcm_elapsed() fw_iso_context_flush_completions() + // snd_pcm_stream_lock_irqsave() disable_work_sync() + // v v + // wait until release of B wait until A exits if (!pcm->runtime->no_period_wakeup) queue_work(system_highpri_wq, &s->period_work); } @@ -1055,8 +1071,15 @@ static void generate_rx_packet_descs(struct amdtp_stream *s, struct pkt_desc *de static inline void cancel_stream(struct amdtp_stream *s) { + struct work_struct *work = current_work(); + s->packet_index = -1; - if (in_softirq()) + + // Detect work items for any isochronous context. The work item for pcm_period_work() + // should be avoided since the call of snd_pcm_period_elapsed() can reach via + // snd_pcm_ops.pointer() under acquiring PCM stream(group) lock and causes dead lock at + // snd_pcm_stop_xrun(). + if (work && work != &s->period_work) amdtp_stream_pcm_abort(s); WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); } @@ -1856,12 +1879,9 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, struct amdtp_stream *irq_target = d->irq_target; if (irq_target && amdtp_stream_running(irq_target)) { - // use wq to prevent AB/BA deadlock competition for - // substream lock: - // fw_iso_context_flush_completions() acquires - // lock by ohci_flush_iso_completions(), - // amdtp-stream process_rx_packets() attempts to - // acquire same lock by snd_pcm_elapsed() + // The work item to call snd_pcm_period_elapsed() can reach here by the call of + // snd_pcm_ops.pointer(), however less packets would be available then. Therefore + // the following call is just for user process contexts. if (current_work() != &s->period_work) fw_iso_context_flush_completions(irq_target->context); } diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index ce49eef0fcba..360ebf3c4ca2 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -367,6 +367,7 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) goto end; pcm->private_data = bebob; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", bebob->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index d64366217d57..2cf2adb48f2a 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -441,6 +441,7 @@ int snd_dice_create_pcm(struct snd_dice *dice) if (err < 0) return err; pcm->private_data = dice; + pcm->nonatomic = true; strcpy(pcm->name, dice->card->shortname); if (capture > 0) diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 3bd1575c9d9c..85e65cbc00c4 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -350,6 +350,7 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) return err; pcm->private_data = dg00x; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", dg00x->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index ec915671a79b..63457d24a288 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -390,6 +390,7 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff) return err; pcm->private_data = ff; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", ff->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index c3c21860b245..eaf7778211de 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -397,6 +397,7 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) goto end; pcm->private_data = efw; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 806f82c9ceee..b1e059f0d473 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -454,6 +454,7 @@ static int isight_create_pcm(struct isight *isight) if (err < 0) return err; pcm->private_data = isight; + pcm->nonatomic = true; strcpy(pcm->name, "iSight"); isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; isight->pcm->ops = &ops; diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index d410c2efbde5..f3b48495acae 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -360,6 +360,7 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) if (err < 0) return err; pcm->private_data = motu; + pcm->nonatomic = true; strcpy(pcm->name, motu->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 5f43a0b826d2..8ca9dde54ec6 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -440,6 +440,7 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) return err; pcm->private_data = oxfw; + pcm->nonatomic = true; strcpy(pcm->name, oxfw->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); if (cap > 0) diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index f6da571707ac..a73003ac11e6 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -279,6 +279,7 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) return err; pcm->private_data = tscm; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", tscm->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-04 12:58:41
|
In the previous commit, the workqueue is added per the instance of fw_card structure for isochronous contexts. The workqueue is designed to be used by the implementation of fw_card_driver structure underlying the fw_card. This commit adds some local APIs to be used by the implementation. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-iso.c | 30 ++++++++++++++++++++++++++++-- drivers/firewire/core.h | 10 ++++++++++ include/linux/firewire.h | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 101433b8bb51..af76fa1823f1 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -211,21 +211,47 @@ EXPORT_SYMBOL(fw_iso_context_queue_flush); int fw_iso_context_flush_completions(struct fw_iso_context *ctx) { + int err; + trace_isoc_outbound_flush_completions(ctx); trace_isoc_inbound_single_flush_completions(ctx); trace_isoc_inbound_multiple_flush_completions(ctx); - return ctx->card->driver->flush_iso_completions(ctx); + might_sleep(); + + // Avoid dead lock due to programming mistake. + if (WARN_ON(current_work() == &ctx->work)) + return 0; + + disable_work_sync(&ctx->work); + + err = ctx->card->driver->flush_iso_completions(ctx); + + enable_work(&ctx->work); + + return err; } EXPORT_SYMBOL(fw_iso_context_flush_completions); int fw_iso_context_stop(struct fw_iso_context *ctx) { + int err; + trace_isoc_outbound_stop(ctx); trace_isoc_inbound_single_stop(ctx); trace_isoc_inbound_multiple_stop(ctx); - return ctx->card->driver->stop_iso(ctx); + might_sleep(); + + // Avoid dead lock due to programming mistake. + if (WARN_ON(current_work() == &ctx->work)) + return 0; + + err = ctx->card->driver->stop_iso(ctx); + + cancel_work_sync(&ctx->work); + + return err; } EXPORT_SYMBOL(fw_iso_context_stop); diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 96ae366889e0..2874f316156a 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -159,6 +159,16 @@ int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count); int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card, enum dma_data_direction direction); +static inline void fw_iso_context_init_work(struct fw_iso_context *ctx, work_func_t func) +{ + INIT_WORK(&ctx->work, func); +} + +static inline void fw_iso_context_queue_work(struct fw_iso_context *ctx) +{ + queue_work(ctx->card->isoc_wq, &ctx->work); +} + /* -topology */ diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 10e135d60824..72f497b61739 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -511,6 +511,7 @@ union fw_iso_callback { struct fw_iso_context { struct fw_card *card; + struct work_struct work; int type; int channel; int speed; -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-04 12:58:39
|
Hi, (resend to linux1394-devel since the original post has so many receivers. Please refer to it for any reply: https://lore.kernel.org/lkml/202...@sa.../) This series of changes updates my previous RFT[1] to apply for v6.12 kernel. For the detail, please refer to the previous one. To Iwai-san, this series includes the change for sound subsystem as well. All of changes are specific to ALSA firewire stack, so I would like to send it to Linus as the part of firewire subsystem updates if you do not mind it. Changes from the RFT: * WQ_FREEZABLE is newly supported in the workqueue * Improve code comment in IEC 61883-1/6 packet streaming engine * Avoid dead lock in the calls of workqueue sync API [1] https://lore.kernel.org/lkml/202...@sa.../ Regards Takashi Sakamoto (5): firewire: core: allocate workqueue to handle isochronous contexts in card firewire: core: add local API to queue work item to workqueue specific to isochronous contexts firewire: ohci: operate IT/IR events in sleepable work process instead of tasklet softIRQ firewire: core: non-atomic memory allocation for isochronous event to user client ALSA: firewire: use nonatomic PCM operation drivers/firewire/core-card.c | 33 ++++++++++++-- drivers/firewire/core-cdev.c | 4 +- drivers/firewire/core-iso.c | 30 ++++++++++++- drivers/firewire/core.h | 14 +++++- drivers/firewire/ohci.c | 57 +++++++++++++++++++----- include/linux/firewire.h | 3 ++ sound/firewire/amdtp-stream.c | 34 +++++++++++--- sound/firewire/bebob/bebob_pcm.c | 1 + sound/firewire/dice/dice-pcm.c | 1 + sound/firewire/digi00x/digi00x-pcm.c | 1 + sound/firewire/fireface/ff-pcm.c | 1 + sound/firewire/fireworks/fireworks_pcm.c | 1 + sound/firewire/isight.c | 1 + sound/firewire/motu/motu-pcm.c | 1 + sound/firewire/oxfw/oxfw-pcm.c | 1 + sound/firewire/tascam/tascam-pcm.c | 1 + 16 files changed, 157 insertions(+), 27 deletions(-) -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-04 12:58:38
|
In the former commits, the callback of isochronous context runs on work process, thus no need to use atomic memory allocation. This commit replaces GFP_ATOMIC with GCP_KERNEL in the callback for user client. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-cdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 3ea220d96c31..518eaa073b2b 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -982,7 +982,7 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, struct client *client = data; struct iso_interrupt_event *e; - e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC); + e = kmalloc(sizeof(*e) + header_length, GFP_KERNEL); if (e == NULL) return; @@ -1001,7 +1001,7 @@ static void iso_mc_callback(struct fw_iso_context *context, struct client *client = data; struct iso_interrupt_mc_event *e; - e = kmalloc(sizeof(*e), GFP_ATOMIC); + e = kmalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) return; -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-04 12:58:37
|
This commit queues work item for IT/IR events at hardIRQ handler to operate the corresponding isochronous context. The work item is queued to any of worker-pools. The callback for either the implementation of unit protocol and user space clients is executed in sleepable work process context. The change could results in any errors of concurrent processing as well as sleep at atomic context. These errors are fixed by the following commits. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 55 +++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 50627b8fc38f..d0b1fccc450f 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1182,6 +1182,47 @@ static void context_tasklet(unsigned long data) } } +static void ohci_isoc_context_work(struct work_struct *work) +{ + struct fw_iso_context *base = container_of(work, struct fw_iso_context, work); + struct iso_context *isoc_ctx = container_of(base, struct iso_context, base); + struct context *ctx = &isoc_ctx->context; + struct descriptor *d, *last; + u32 address; + int z; + struct descriptor_buffer *desc; + + desc = list_entry(ctx->buffer_list.next, struct descriptor_buffer, list); + last = ctx->last; + while (last->branch_address != 0) { + struct descriptor_buffer *old_desc = desc; + + address = le32_to_cpu(last->branch_address); + z = address & 0xf; + address &= ~0xf; + ctx->current_bus = address; + + // If the branch address points to a buffer outside of the current buffer, advance + // to the next buffer. + if (address < desc->buffer_bus || address >= desc->buffer_bus + desc->used) + desc = list_entry(desc->list.next, struct descriptor_buffer, list); + d = desc->buffer + (address - desc->buffer_bus) / sizeof(*d); + last = find_branch_descriptor(d, z); + + if (!ctx->callback(ctx, d, last)) + break; + + if (old_desc != desc) { + // If we've advanced to the next buffer, move the previous buffer to the + // free list. + old_desc->used = 0; + guard(spinlock_irqsave)(&ctx->ohci->lock); + list_move_tail(&old_desc->list, &ctx->buffer_list); + } + ctx->last = last; + } +} + /* * Allocate a new buffer and add it to the list of free buffers for this * context. Must be called with ohci->lock held. @@ -2242,8 +2283,7 @@ static irqreturn_t irq_handler(int irq, void *data) while (iso_event) { i = ffs(iso_event) - 1; - tasklet_schedule( - &ohci->ir_context_list[i].context.tasklet); + fw_iso_context_queue_work(&ohci->ir_context_list[i].base); iso_event &= ~(1 << i); } } @@ -2254,8 +2294,7 @@ static irqreturn_t irq_handler(int irq, void *data) while (iso_event) { i = ffs(iso_event) - 1; - tasklet_schedule( - &ohci->it_context_list[i].context.tasklet); + fw_iso_context_queue_work(&ohci->it_context_list[i].base); iso_event &= ~(1 << i); } } @@ -3130,6 +3169,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, ret = context_init(&ctx->context, ohci, regs, callback); if (ret < 0) goto out_with_header; + fw_iso_context_init_work(&ctx->base, ohci_isoc_context_work); if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) { set_multichannel_mask(ohci, 0); @@ -3227,7 +3267,6 @@ static int ohci_stop_iso(struct fw_iso_context *base) } flush_writes(ohci); context_stop(&ctx->context); - tasklet_kill(&ctx->context.tasklet); return 0; } @@ -3584,10 +3623,8 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base) struct iso_context *ctx = container_of(base, struct iso_context, base); int ret = 0; - tasklet_disable_in_atomic(&ctx->context.tasklet); - if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) { - context_tasklet((unsigned long)&ctx->context); + ohci_isoc_context_work(&base->work); switch (base->type) { case FW_ISO_CONTEXT_TRANSMIT: @@ -3607,8 +3644,6 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base) smp_mb__after_atomic(); } - tasklet_enable(&ctx->context.tasklet); - return ret; } -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-04 10:15:18
|
On Tue, Sep 03, 2024 at 07:14:55PM +0900, Takashi Sakamoto wrote: > Many tracepoints events have been added to 6.10 and 6.11 kernels. They are > available as an alternative of debug parameter in firewire-ohci module. > > The logging messages enabled by the parameter require some cumbersomes in > a point of maintenance; e.g. the code to decode transaction frame. > > This commit adds deprecation text to conduct users to them.. > > Signed-off-by: Takashi Sakamoto <o-t...@sa...> > --- > drivers/firewire/ohci.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) Applied to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-09-04 10:14:48
|
On Tue, Sep 03, 2024 at 07:15:23PM +0900, Takashi Sakamoto wrote: > A commit 77006a0a8282 ("ratelimit: add comment warning people off > printk_ratelimit()") has already deprecated printk_ratelimit(). > > This commit uses alternative functions to obsolete its usage. > > Signed-off-by: Takashi Sakamoto <o-t...@sa...> > --- > drivers/firewire/ohci.c | 9 +++------ > 1 file changed, 3 insertions(+), 6 deletions(-) Applied to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2024-09-03 10:15:34
|
A commit 77006a0a8282 ("ratelimit: add comment warning people off printk_ratelimit()") has already deprecated printk_ratelimit(). This commit uses alternative functions to obsolete its usage. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index e662dc30c21f..3930fdd56155 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2268,13 +2268,11 @@ static irqreturn_t irq_handler(int irq, void *data) reg_read(ohci, OHCI1394_PostedWriteAddressLo); reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_postedWriteErr); - if (printk_ratelimit()) - ohci_err(ohci, "PCI posted write error\n"); + dev_err_ratelimited(ohci->card.device, "PCI posted write error\n"); } if (unlikely(event & OHCI1394_cycleTooLong)) { - if (printk_ratelimit()) - ohci_notice(ohci, "isochronous cycle too long\n"); + dev_notice_ratelimited(ohci->card.device, "isochronous cycle too long\n"); reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_cycleMaster); } @@ -2286,8 +2284,7 @@ static irqreturn_t irq_handler(int irq, void *data) * stop active cycleMatch iso contexts now and restart * them at least two cycles later. (FIXME?) */ - if (printk_ratelimit()) - ohci_notice(ohci, "isochronous cycle inconsistent\n"); + dev_notice_ratelimited(ohci->card.device, "isochronous cycle inconsistent\n"); } if (unlikely(event & OHCI1394_unrecoverableError)) -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-03 10:15:12
|
Many tracepoints events have been added to 6.10 and 6.11 kernels. They are available as an alternative of debug parameter in firewire-ohci module. The logging messages enabled by the parameter require some cumbersomes in a point of maintenance; e.g. the code to decode transaction frame. This commit adds deprecation text to conduct users to them.. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/ohci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index a3a37955b174..e662dc30c21f 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -396,7 +396,7 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" static int param_debug; module_param_named(debug, param_debug, int, 0644); -MODULE_PARM_DESC(debug, "Verbose logging (default = 0" +MODULE_PARM_DESC(debug, "Verbose logging, deprecated in v6.11 kernel or later. (default = 0" ", AT/AR events = " __stringify(OHCI_PARAM_DEBUG_AT_AR) ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS) ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS) @@ -2197,6 +2197,11 @@ static irqreturn_t irq_handler(int irq, void *data) if (!event || !~event) return IRQ_NONE; + if (unlikely(param_debug > 0)) { + dev_notice_ratelimited(ohci->card.device, + "The debug parameter is superceded by tracepoints events, and deprecated."); + } + /* * busReset and postedWriteErr events must not be cleared yet * (OHCI 1.1 clauses 7.2.3.2 and 13.2.8.1) -- 2.43.0 |
From: Andrew F. <and...@gm...> - 2024-09-02 16:08:05
|
Hello Takashi, Adam. Thanks both for the replies (and apologies for the tardiness of my response). Takashi, I completely understand that this is of less interest to you - it is an extremely niche case. Your work on the ALSA drivers is amazing. Just a few weeks ago I was helping a friend setup a Digidesign 002R on Linux (thanks to the ALSA drivers). They will be using it to record their Wurlitzer theatre organ for conversion to a "sample pack" to allow them to play it digitally on their computer. I also have used a Mackie Onyx 400F with my 8-track analogue tape recorder, although I managed to break it (the Mackie) by accidentally looping phantom power into it. There's a Focusrite Liquid Saffire 56 on ebay I may get as a replacement - I need 192kHz input. I don't have any experience of kernel development, but I know C through various work on 5G network stacks. So there is (some!) hope that I will be able to fumble my way to a solution. Thank you for your advice about the tracepoint events - I will investigate this. (I'm about to go on a trip abroad for work reasons, so no / few updates doesn't mean that I'm not interested in solving this!). Adam, would you be willing to send me the serial number of the PowerBook G4 you used? That lets me see all of the specs and whether or not it is similar to mine. Separately (and very much a n00b question!), what's the best / easiest way to get kernel version 6.8-rc1? is there a specific distro that ships with development / rc builds of the kernel, or is it better to install something like Debian Stable and then compile / install a development build? Ideally I'd replicate your setup to confirm it isn't an issue on my end. Thanks! Andrew On Sat, 31 Aug 2024 at 10:59, Adam Goldman <ad...@po...> wrote: > On Sun, Aug 25, 2024 at 09:31:40PM +0100, Andrew Ferguson wrote: > > I have encountered a bug in that some Macs are not detected in Linux, > when > > the Mac is being used in "Target Disk Mode". > [...] > > Mac models that do not work: > > iBook G4 > > Powerbook G4 > > Hi Andrew, > > I did a quick test with kernel 6.8-rc1 and a titanium Powerbook G4 > (powerbook3,4 A1001). I held down T and turned on the Powerbook. After > about 25 seconds, the FireWire logo appeared on the screen, and the > drive appeared on Linux as sdb. I was able to read from the drive with > dd. > > Can you provide steps to reproduce the problem? > > -- Adam > |
From: Takashi S. <o-t...@sa...> - 2024-09-01 11:16:35
|
In the former commits, the callback of isochronous context runs on work process, thus no need to use atomic memory allocation. This commit replaces GFP_ATOMIC with GCP_KERNEL in the callback for user client. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-cdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 3ea220d96c31..518eaa073b2b 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -982,7 +982,7 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, struct client *client = data; struct iso_interrupt_event *e; - e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC); + e = kmalloc(sizeof(*e) + header_length, GFP_KERNEL); if (e == NULL) return; @@ -1001,7 +1001,7 @@ static void iso_mc_callback(struct fw_iso_context *context, struct client *client = data; struct iso_interrupt_mc_event *e; - e = kmalloc(sizeof(*e), GFP_ATOMIC); + e = kmalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) return; -- 2.43.0 |
From: Takashi S. <o-t...@sa...> - 2024-09-01 11:16:34
|
In the former commits, the callback of isochronous context runs on work process. In the case, ALSA PCM device has a flag, nonatomic, to acquire mutex lock instead of spin lock for PCM substream group. This commit uses the flag. It has an advantage in the case that ALSA PCM application uses the large size of intermediate buffer, since it takes too long time even in tasklet softIRQ to process many of isochronous packets. It could result in the delay of system event due to disabled IRQ so long. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- sound/firewire/amdtp-stream.c | 9 ++++++++- sound/firewire/bebob/bebob_pcm.c | 1 + sound/firewire/dice/dice-pcm.c | 1 + sound/firewire/digi00x/digi00x-pcm.c | 1 + sound/firewire/fireface/ff-pcm.c | 1 + sound/firewire/fireworks/fireworks_pcm.c | 1 + sound/firewire/isight.c | 1 + sound/firewire/motu/motu-pcm.c | 1 + sound/firewire/oxfw/oxfw-pcm.c | 1 + sound/firewire/tascam/tascam-pcm.c | 1 + 10 files changed, 17 insertions(+), 1 deletion(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index c827d7d8d800..7e97ad133874 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1055,8 +1055,15 @@ static void generate_rx_packet_descs(struct amdtp_stream *s, struct pkt_desc *de static inline void cancel_stream(struct amdtp_stream *s) { + struct work_struct *work = current_work(); + s->packet_index = -1; - if (in_softirq()) + + // Detect work items for any isochronous context. The work item for pcm_period_work() + // should be avoided since the call of snd_pcm_period_elapsed() can reach via + // snd_pcm_ops.pointer() under acquiring PCM stream(group) lock and causes dead lock at + // snd_pcm_stop_xrun(). + if (work && work != &s->period_work) amdtp_stream_pcm_abort(s); WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); } diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index ce49eef0fcba..360ebf3c4ca2 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -367,6 +367,7 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) goto end; pcm->private_data = bebob; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", bebob->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index d64366217d57..2cf2adb48f2a 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -441,6 +441,7 @@ int snd_dice_create_pcm(struct snd_dice *dice) if (err < 0) return err; pcm->private_data = dice; + pcm->nonatomic = true; strcpy(pcm->name, dice->card->shortname); if (capture > 0) diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 3bd1575c9d9c..85e65cbc00c4 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -350,6 +350,7 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) return err; pcm->private_data = dg00x; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", dg00x->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index ec915671a79b..63457d24a288 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -390,6 +390,7 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff) return err; pcm->private_data = ff; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", ff->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index c3c21860b245..eaf7778211de 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -397,6 +397,7 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) goto end; pcm->private_data = efw; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 806f82c9ceee..b1e059f0d473 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -454,6 +454,7 @@ static int isight_create_pcm(struct isight *isight) if (err < 0) return err; pcm->private_data = isight; + pcm->nonatomic = true; strcpy(pcm->name, "iSight"); isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; isight->pcm->ops = &ops; diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index d410c2efbde5..f3b48495acae 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -360,6 +360,7 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu) if (err < 0) return err; pcm->private_data = motu; + pcm->nonatomic = true; strcpy(pcm->name, motu->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 5f43a0b826d2..8ca9dde54ec6 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -440,6 +440,7 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) return err; pcm->private_data = oxfw; + pcm->nonatomic = true; strcpy(pcm->name, oxfw->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); if (cap > 0) diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index f6da571707ac..a73003ac11e6 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -279,6 +279,7 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) return err; pcm->private_data = tscm; + pcm->nonatomic = true; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", tscm->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); -- 2.43.0 |