Some tasklets (softIRQs) are still used as bottom-halves to handle
events for 1394 OHCI AR/AT contexts. However, using softIRQs for IRQ
bottom halves is generally discouraged today.
This commit adds a per-fw_card workqueue to accommodate the behaviour
specified by the 1394 OHCI specification.
According to the 1394 OHCI specification, system memory pages are
reserved for each asynchronous DMA context. This allows concurrent
operation across contexts. In the 1394 OHCI PCI driver implementation,
the hardware generates IRQs either upon receiving asynchronous packets
from other nodes (incoming) or after completing transmission to them
(outgoing). These independent events can occur in the same transmission
cycle, therefore the max_active parameter for the workqueue is set to the
total number of AR/AT contexts (=4). The WQ_UNBOUND flag is used to
allow the work to be scheduled on any available core, since there is
little CPU cache affinity benefit for the data.
Each DMA context uses a circular descriptor list in system memory,
allowing deferred data processing in software as long as buffer overrun
are avoided. Since the overall operation is sleepable except for small
atomic regions, WQ_BH is not used. As the descriptors contain
timestamps, WQ_HIGHPRI is specified to support semi-real-time
processing.
The asynchronous context is also used by the SCSI over IEEE 1394
protocol implementation (sbp2), which can be part of memory reclaim paths.
Therefore, WQ_MEM_RECLAIM is required.
To allow uses to adjust CPU affinity according to workload, WQ_SYSFS is
specified so that workqueue attributes are exposed to user space.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-card.c | 40 +++++++++++++++++++++++++++---------
include/linux/firewire.h | 1 +
2 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 2b6ad47b6d57..df0bb5b96ddc 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -574,7 +574,6 @@ EXPORT_SYMBOL(fw_card_initialize);
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:
@@ -589,12 +588,29 @@ int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
// * == 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_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS,
- supported_isoc_contexts, card->index);
- if (!isoc_wq)
+ card->isoc_wq = alloc_workqueue("firewire-isoc-card%u",
+ WQ_UNBOUND | WQ_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS,
+ supported_isoc_contexts, card->index);
+ if (!card->isoc_wq)
return -ENOMEM;
+ // This workqueue should be:
+ // * != WQ_BH Sleepable.
+ // * == WQ_UNBOUND Any core can process data for asynchronous context.
+ // * == WQ_MEM_RECLAIM Used for any backend of block device.
+ // * == WQ_FREEZABLE The target device would not be available when being freezed.
+ // * == WQ_HIGHPRI High priority to process semi-realtime timestamped data.
+ // * == WQ_SYSFS Parameters are available via sysfs.
+ // * max_active == 4 A hardIRQ could notify events for a pair of requests and
+ // response AR/AT contexts.
+ card->async_wq = alloc_workqueue("firewire-async-card%u",
+ WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS,
+ 4, card->index);
+ if (!card->async_wq) {
+ ret = -ENOMEM;
+ goto err_isoc;
+ }
+
card->max_receive = max_receive;
card->link_speed = link_speed;
card->guid = guid;
@@ -603,15 +619,17 @@ int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
generate_config_rom(card, tmp_config_rom);
ret = card->driver->enable(card, tmp_config_rom, config_rom_length);
- if (ret < 0) {
- destroy_workqueue(isoc_wq);
- return ret;
- }
+ if (ret < 0)
+ goto err_async;
- card->isoc_wq = isoc_wq;
list_add_tail(&card->link, &card_list);
return 0;
+err_async:
+ destroy_workqueue(card->async_wq);
+err_isoc:
+ destroy_workqueue(card->isoc_wq);
+ return ret;
}
EXPORT_SYMBOL(fw_card_add);
@@ -744,6 +762,7 @@ void fw_core_remove_card(struct fw_card *card)
dummy_driver.stop_iso = card->driver->stop_iso;
card->driver = &dummy_driver;
drain_workqueue(card->isoc_wq);
+ drain_workqueue(card->async_wq);
scoped_guard(spinlock_irqsave, &card->lock)
fw_destroy_nodes(card);
@@ -753,6 +772,7 @@ void fw_core_remove_card(struct fw_card *card)
wait_for_completion(&card->done);
destroy_workqueue(card->isoc_wq);
+ destroy_workqueue(card->async_wq);
WARN_ON(!list_empty(&card->transaction_list));
}
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index b632eec3ab52..c55b8e30e700 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -136,6 +136,7 @@ struct fw_card {
__be32 maint_utility_register;
struct workqueue_struct *isoc_wq;
+ struct workqueue_struct *async_wq;
};
static inline struct fw_card *fw_card_get(struct fw_card *card)
--
2.48.1
Hi Takashi, kernel test robot noticed the following build errors: [auto build test ERROR on ieee1394-linux1394/for-next] [also build test ERROR on linus/master v6.16-rc1 next-20250613] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Takashi-Sakamoto/firewire-core-allocate-workqueue-for-AR-AT-request-response-contexts/20250614-194424 base: https://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git for-next patch link: https://lore.kernel.org/r/20250614113449.388758-2-o-takashi%40sakamocchi.jp patch subject: [PATCH 1/3] firewire: core: allocate workqueue for AR/AT request/response contexts config: x86_64-buildonly-randconfig-004-20250615 (https://download.01.org/0day-ci/archive/20250615/202506151242.vncWEzlc-lkp@intel.com/config) compiler: clang version 20.1.2 (https://github.com/llvm/llvm-project 58df0ef89dd64126512e4ee27b4ac3fd8ddf6247) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250615/202506151242.vncWEzlc-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202506151242.vncWEzlc-lkp@intel.com/ All errors (new ones prefixed by >>): >> drivers/firewire/core-card.c:611:3: error: cannot jump from this goto statement to its label 611 | goto err_isoc; | ^ drivers/firewire/core-card.c:618:2: note: jump bypasses initialization of variable with __attribute__((cleanup)) 618 | guard(mutex)(&card_mutex); | ^ include/linux/cleanup.h:338:15: note: expanded from macro 'guard' 338 | CLASS(_name, __UNIQUE_ID(guard)) | ^ include/linux/compiler.h:166:29: note: expanded from macro '__UNIQUE_ID' 166 | #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) | ^ include/linux/compiler_types.h:84:22: note: expanded from macro '__PASTE' 84 | #define __PASTE(a,b) ___PASTE(a,b) | ^ include/linux/compiler_types.h:83:23: note: expanded from macro '___PASTE' 83 | #define ___PASTE(a,b) a##b | ^ <scratch space>:71:1: note: expanded from here 71 | __UNIQUE_ID_guard795 | ^ 1 error generated. vim +611 drivers/firewire/core-card.c 573 574 int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid, 575 unsigned int supported_isoc_contexts) 576 { 577 int ret; 578 579 // This workqueue should be: 580 // * != WQ_BH Sleepable. 581 // * == WQ_UNBOUND Any core can process data for isoc context. The 582 // implementation of unit protocol could consumes the core 583 // longer somehow. 584 // * != WQ_MEM_RECLAIM Not used for any backend of block device. 585 // * == WQ_FREEZABLE Isochronous communication is at regular interval in real 586 // time, thus should be drained if possible at freeze phase. 587 // * == WQ_HIGHPRI High priority to process semi-realtime timestamped data. 588 // * == WQ_SYSFS Parameters are available via sysfs. 589 // * max_active == n_it + n_ir A hardIRQ could notify events for multiple isochronous 590 // contexts if they are scheduled to the same cycle. 591 card->isoc_wq = alloc_workqueue("firewire-isoc-card%u", 592 WQ_UNBOUND | WQ_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS, 593 supported_isoc_contexts, card->index); 594 if (!card->isoc_wq) 595 return -ENOMEM; 596 597 // This workqueue should be: 598 // * != WQ_BH Sleepable. 599 // * == WQ_UNBOUND Any core can process data for asynchronous context. 600 // * == WQ_MEM_RECLAIM Used for any backend of block device. 601 // * == WQ_FREEZABLE The target device would not be available when being freezed. 602 // * == WQ_HIGHPRI High priority to process semi-realtime timestamped data. 603 // * == WQ_SYSFS Parameters are available via sysfs. 604 // * max_active == 4 A hardIRQ could notify events for a pair of requests and 605 // response AR/AT contexts. 606 card->async_wq = alloc_workqueue("firewire-async-card%u", 607 WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS, 608 4, card->index); 609 if (!card->async_wq) { 610 ret = -ENOMEM; > 611 goto err_isoc; 612 } 613 614 card->max_receive = max_receive; 615 card->link_speed = link_speed; 616 card->guid = guid; 617 618 guard(mutex)(&card_mutex); 619 620 generate_config_rom(card, tmp_config_rom); 621 ret = card->driver->enable(card, tmp_config_rom, config_rom_length); 622 if (ret < 0) 623 goto err_async; 624 625 list_add_tail(&card->link, &card_list); 626 627 return 0; 628 err_async: 629 destroy_workqueue(card->async_wq); 630 err_isoc: 631 destroy_workqueue(card->isoc_wq); 632 return ret; 633 } 634 EXPORT_SYMBOL(fw_card_add); 635 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.