Skip to content

Commit 72bf144

Browse files
committed
firewire: core: allocate workqueue for AR/AT request/response contexts
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. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Sakamoto <[email protected]>
1 parent f657a68 commit 72bf144

File tree

2 files changed

+35
-14
lines changed

2 files changed

+35
-14
lines changed

drivers/firewire/core-card.c

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,6 @@ EXPORT_SYMBOL(fw_card_initialize);
574574
int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
575575
unsigned int supported_isoc_contexts)
576576
{
577-
struct workqueue_struct *isoc_wq;
578577
int ret;
579578

580579
// This workqueue should be:
@@ -589,29 +588,48 @@ int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
589588
// * == WQ_SYSFS Parameters are available via sysfs.
590589
// * max_active == n_it + n_ir A hardIRQ could notify events for multiple isochronous
591590
// contexts if they are scheduled to the same cycle.
592-
isoc_wq = alloc_workqueue("firewire-isoc-card%u",
593-
WQ_UNBOUND | WQ_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS,
594-
supported_isoc_contexts, card->index);
595-
if (!isoc_wq)
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)
596595
return -ENOMEM;
597596

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+
598614
card->max_receive = max_receive;
599615
card->link_speed = link_speed;
600616
card->guid = guid;
601617

602-
guard(mutex)(&card_mutex);
618+
scoped_guard(mutex, &card_mutex) {
619+
generate_config_rom(card, tmp_config_rom);
620+
ret = card->driver->enable(card, tmp_config_rom, config_rom_length);
621+
if (ret < 0)
622+
goto err_async;
603623

604-
generate_config_rom(card, tmp_config_rom);
605-
ret = card->driver->enable(card, tmp_config_rom, config_rom_length);
606-
if (ret < 0) {
607-
destroy_workqueue(isoc_wq);
608-
return ret;
624+
list_add_tail(&card->link, &card_list);
609625
}
610626

611-
card->isoc_wq = isoc_wq;
612-
list_add_tail(&card->link, &card_list);
613-
614627
return 0;
628+
err_async:
629+
destroy_workqueue(card->async_wq);
630+
err_isoc:
631+
destroy_workqueue(card->isoc_wq);
632+
return ret;
615633
}
616634
EXPORT_SYMBOL(fw_card_add);
617635

@@ -744,6 +762,7 @@ void fw_core_remove_card(struct fw_card *card)
744762
dummy_driver.stop_iso = card->driver->stop_iso;
745763
card->driver = &dummy_driver;
746764
drain_workqueue(card->isoc_wq);
765+
drain_workqueue(card->async_wq);
747766

748767
scoped_guard(spinlock_irqsave, &card->lock)
749768
fw_destroy_nodes(card);
@@ -753,6 +772,7 @@ void fw_core_remove_card(struct fw_card *card)
753772
wait_for_completion(&card->done);
754773

755774
destroy_workqueue(card->isoc_wq);
775+
destroy_workqueue(card->async_wq);
756776

757777
WARN_ON(!list_empty(&card->transaction_list));
758778
}

include/linux/firewire.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ struct fw_card {
136136
__be32 maint_utility_register;
137137

138138
struct workqueue_struct *isoc_wq;
139+
struct workqueue_struct *async_wq;
139140
};
140141

141142
static inline struct fw_card *fw_card_get(struct fw_card *card)

0 commit comments

Comments
 (0)