Skip to content

Commit c6fb88a

Browse files
committed
firewire: core: allocate workqueue to handle isochronous contexts in card
This commit adds a workqueue dedicated for isochronous context processing. The workqueue is allocated per instance of fw_card structure to satisfy the following characteristics descending from 1394 OHCI specification: In 1394 OHCI specification, memory pages are reserved to each isochronous context dedicated to DMA transmission. It allows to operate these per-context pages concurrently. Software can schedule hardware interrupt for several isochronous context to the same cycle, thus WQ_UNBOUND is specified. Additionally, it is sleepable to operate the content of pages, thus WQ_BH is not used. The isochronous context delivers the packets with time stamp, thus WQ_HIGHPRI is specified for semi real-time data such as IEC 61883-1/6 protocol implemented by ALSA firewire stack. The isochronous context is not used by the implementation of SCSI over IEEE1394 protocol (sbp2), thus WQ_MEM_RECLAIM is not specified. It is useful for users to adjust cpu affinity of the workqueue depending on their work loads, thus WQ_SYS is specified to expose the attributes to user space. Tested-by: Edmund Raile <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Sakamoto <[email protected]>
1 parent 7d35a00 commit c6fb88a

File tree

4 files changed

+35
-6
lines changed

4 files changed

+35
-6
lines changed

drivers/firewire/core-card.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,11 +571,30 @@ void fw_card_initialize(struct fw_card *card,
571571
}
572572
EXPORT_SYMBOL(fw_card_initialize);
573573

574-
int fw_card_add(struct fw_card *card,
575-
u32 max_receive, u32 link_speed, u64 guid)
574+
int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
575+
unsigned int supported_isoc_contexts)
576576
{
577+
struct workqueue_struct *isoc_wq;
577578
int ret;
578579

580+
// This workqueue should be:
581+
// * != WQ_BH Sleepable.
582+
// * == WQ_UNBOUND Any core can process data for isoc context. The
583+
// implementation of unit protocol could consumes the core
584+
// longer somehow.
585+
// * != WQ_MEM_RECLAIM Not used for any backend of block device.
586+
// * == WQ_FREEZABLE Isochronous communication is at regular interval in real
587+
// time, thus should be drained if possible at freeze phase.
588+
// * == WQ_HIGHPRI High priority to process semi-realtime timestamped data.
589+
// * == WQ_SYSFS Parameters are available via sysfs.
590+
// * max_active == n_it + n_ir A hardIRQ could notify events for multiple isochronous
591+
// 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)
596+
return -ENOMEM;
597+
579598
card->max_receive = max_receive;
580599
card->link_speed = link_speed;
581600
card->guid = guid;
@@ -584,9 +603,12 @@ int fw_card_add(struct fw_card *card,
584603

585604
generate_config_rom(card, tmp_config_rom);
586605
ret = card->driver->enable(card, tmp_config_rom, config_rom_length);
587-
if (ret < 0)
606+
if (ret < 0) {
607+
destroy_workqueue(isoc_wq);
588608
return ret;
609+
}
589610

611+
card->isoc_wq = isoc_wq;
590612
list_add_tail(&card->link, &card_list);
591613

592614
return 0;
@@ -708,6 +730,8 @@ void fw_core_remove_card(struct fw_card *card)
708730
{
709731
struct fw_card_driver dummy_driver = dummy_driver_template;
710732

733+
might_sleep();
734+
711735
card->driver->update_phy_reg(card, 4,
712736
PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
713737
fw_schedule_bus_reset(card, false, true);
@@ -719,6 +743,7 @@ void fw_core_remove_card(struct fw_card *card)
719743
dummy_driver.free_iso_context = card->driver->free_iso_context;
720744
dummy_driver.stop_iso = card->driver->stop_iso;
721745
card->driver = &dummy_driver;
746+
drain_workqueue(card->isoc_wq);
722747

723748
scoped_guard(spinlock_irqsave, &card->lock)
724749
fw_destroy_nodes(card);
@@ -727,6 +752,8 @@ void fw_core_remove_card(struct fw_card *card)
727752
fw_card_put(card);
728753
wait_for_completion(&card->done);
729754

755+
destroy_workqueue(card->isoc_wq);
756+
730757
WARN_ON(!list_empty(&card->transaction_list));
731758
}
732759
EXPORT_SYMBOL(fw_core_remove_card);

drivers/firewire/core.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ struct fw_card_driver {
115115

116116
void fw_card_initialize(struct fw_card *card,
117117
const struct fw_card_driver *driver, struct device *device);
118-
int fw_card_add(struct fw_card *card,
119-
u32 max_receive, u32 link_speed, u64 guid);
118+
int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
119+
unsigned int supported_isoc_contexts);
120120
void fw_core_remove_card(struct fw_card *card);
121121
int fw_compute_block_crc(__be32 *block);
122122
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);

drivers/firewire/ohci.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3827,7 +3827,7 @@ static int pci_probe(struct pci_dev *dev,
38273827
goto fail_msi;
38283828
}
38293829

3830-
err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
3830+
err = fw_card_add(&ohci->card, max_receive, link_speed, guid, ohci->n_it + ohci->n_ir);
38313831
if (err)
38323832
goto fail_irq;
38333833

include/linux/firewire.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ struct fw_card {
134134
__be32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
135135

136136
__be32 maint_utility_register;
137+
138+
struct workqueue_struct *isoc_wq;
137139
};
138140

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

0 commit comments

Comments
 (0)