Skip to content

Commit 7061835

Browse files
committed
Merge tag 'firewire-updates-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394
Pull firewire updates from Takashi Sakamoto: "This update replaces the remaining tasklet usage in the FireWire subsystem with workqueue for asynchronous packet transmission. With this change, tasklets are now fully eliminated from the subsystem. Asynchronous packet transmission is used for serial bus topology management as well as for the operation of the SBP-2 protocol driver (firewire-sbp2). To ensure reliability during low-memory conditions, the associated workqueue is created with the WQ_MEM_RECLAIM flag, allowing it to participate in memory reclaim paths. Other attributes are aligned with those used for isochronous packet handling, which was migrated to workqueues in v6.12. The workqueues are sleepable and support preemptible work items, making them more suitable for real-time workloads that benefit from timely task preemption at the system level. There remains an issue where 'schedule()' may be called within an RCU read-side critical section, due to a direct replacement of 'tasklet_disable_in_atomic()' with 'disable_work_sync()'. A proposed fix for this has been posted[1], and is currently under review and testing. It is expected to be sent upstream later" Link: https://lore.kernel.org/lkml/[email protected]/ [1] * tag 'firewire-updates-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394: firewire: ohci: reduce the size of common context structure by extracting members into AT structure firewire: core: minor code refactoring to localize table of gap count firewire: ohci: use workqueue to handle events of AT request/response contexts firewire: ohci: use workqueue to handle events of AR request/response contexts firewire: core: allocate workqueue for AR/AT request/response contexts firewire: core: use from_work() macro to expand parent structure of work_struct firewire: ohci: use from_work() macro to expand parent structure of work_struct firewire: ohci: correct code comments about bus_reset tasklet
2 parents a6923c0 + 95a042a commit 7061835

File tree

7 files changed

+146
-116
lines changed

7 files changed

+146
-116
lines changed

drivers/firewire/core-card.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ EXPORT_SYMBOL(fw_schedule_bus_reset);
237237

238238
static void br_work(struct work_struct *work)
239239
{
240-
struct fw_card *card = container_of(work, struct fw_card, br_work.work);
240+
struct fw_card *card = from_work(card, work, br_work.work);
241241

242242
/* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
243243
if (card->reset_jiffies != 0 &&
@@ -273,10 +273,6 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
273273
fw_device_set_broadcast_channel);
274274
}
275275

276-
static const char gap_count_table[] = {
277-
63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
278-
};
279-
280276
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
281277
{
282278
fw_card_get(card);
@@ -286,7 +282,10 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
286282

287283
static void bm_work(struct work_struct *work)
288284
{
289-
struct fw_card *card = container_of(work, struct fw_card, bm_work.work);
285+
static const char gap_count_table[] = {
286+
63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
287+
};
288+
struct fw_card *card = from_work(card, work, bm_work.work);
290289
struct fw_device *root_device, *irm_device;
291290
struct fw_node *root_node;
292291
int root_id, new_root_id, irm_id, bm_id, local_id;
@@ -574,7 +573,6 @@ EXPORT_SYMBOL(fw_card_initialize);
574573
int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
575574
unsigned int supported_isoc_contexts)
576575
{
577-
struct workqueue_struct *isoc_wq;
578576
int ret;
579577

580578
// This workqueue should be:
@@ -589,29 +587,48 @@ int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid,
589587
// * == WQ_SYSFS Parameters are available via sysfs.
590588
// * max_active == n_it + n_ir A hardIRQ could notify events for multiple isochronous
591589
// 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)
590+
card->isoc_wq = alloc_workqueue("firewire-isoc-card%u",
591+
WQ_UNBOUND | WQ_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS,
592+
supported_isoc_contexts, card->index);
593+
if (!card->isoc_wq)
596594
return -ENOMEM;
597595

596+
// This workqueue should be:
597+
// * != WQ_BH Sleepable.
598+
// * == WQ_UNBOUND Any core can process data for asynchronous context.
599+
// * == WQ_MEM_RECLAIM Used for any backend of block device.
600+
// * == WQ_FREEZABLE The target device would not be available when being freezed.
601+
// * == WQ_HIGHPRI High priority to process semi-realtime timestamped data.
602+
// * == WQ_SYSFS Parameters are available via sysfs.
603+
// * max_active == 4 A hardIRQ could notify events for a pair of requests and
604+
// response AR/AT contexts.
605+
card->async_wq = alloc_workqueue("firewire-async-card%u",
606+
WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_HIGHPRI | WQ_SYSFS,
607+
4, card->index);
608+
if (!card->async_wq) {
609+
ret = -ENOMEM;
610+
goto err_isoc;
611+
}
612+
598613
card->max_receive = max_receive;
599614
card->link_speed = link_speed;
600615
card->guid = guid;
601616

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

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;
623+
list_add_tail(&card->link, &card_list);
609624
}
610625

611-
card->isoc_wq = isoc_wq;
612-
list_add_tail(&card->link, &card_list);
613-
614626
return 0;
627+
err_async:
628+
destroy_workqueue(card->async_wq);
629+
err_isoc:
630+
destroy_workqueue(card->isoc_wq);
631+
return ret;
615632
}
616633
EXPORT_SYMBOL(fw_card_add);
617634

@@ -744,6 +761,7 @@ void fw_core_remove_card(struct fw_card *card)
744761
dummy_driver.stop_iso = card->driver->stop_iso;
745762
card->driver = &dummy_driver;
746763
drain_workqueue(card->isoc_wq);
764+
drain_workqueue(card->async_wq);
747765

748766
scoped_guard(spinlock_irqsave, &card->lock)
749767
fw_destroy_nodes(card);
@@ -753,6 +771,7 @@ void fw_core_remove_card(struct fw_card *card)
753771
wait_for_completion(&card->done);
754772

755773
destroy_workqueue(card->isoc_wq);
774+
destroy_workqueue(card->async_wq);
756775

757776
WARN_ON(!list_empty(&card->transaction_list));
758777
}

drivers/firewire/core-cdev.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,8 +1313,7 @@ static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg)
13131313
static void iso_resource_work(struct work_struct *work)
13141314
{
13151315
struct iso_resource_event *e;
1316-
struct iso_resource *r =
1317-
container_of(work, struct iso_resource, work.work);
1316+
struct iso_resource *r = from_work(r, work, work.work);
13181317
struct client *client = r->client;
13191318
unsigned long index = r->resource.handle;
13201319
int generation, channel, bandwidth, todo;

drivers/firewire/core-device.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -853,8 +853,7 @@ static void fw_schedule_device_work(struct fw_device *device,
853853

854854
static void fw_device_shutdown(struct work_struct *work)
855855
{
856-
struct fw_device *device =
857-
container_of(work, struct fw_device, work.work);
856+
struct fw_device *device = from_work(device, work, work.work);
858857

859858
if (time_before64(get_jiffies_64(),
860859
device->card->reset_jiffies + SHUTDOWN_DELAY)
@@ -921,8 +920,7 @@ static int update_unit(struct device *dev, void *data)
921920

922921
static void fw_device_update(struct work_struct *work)
923922
{
924-
struct fw_device *device =
925-
container_of(work, struct fw_device, work.work);
923+
struct fw_device *device = from_work(device, work, work.work);
926924

927925
fw_device_cdev_update(device);
928926
device_for_each_child(&device->device, NULL, update_unit);
@@ -1002,8 +1000,7 @@ static int compare_configuration_rom(struct device *dev, const void *data)
10021000

10031001
static void fw_device_init(struct work_struct *work)
10041002
{
1005-
struct fw_device *device =
1006-
container_of(work, struct fw_device, work.work);
1003+
struct fw_device *device = from_work(device, work, work.work);
10071004
struct fw_card *card = device->card;
10081005
struct device *found;
10091006
u32 minor;
@@ -1184,8 +1181,7 @@ static int reread_config_rom(struct fw_device *device, int generation,
11841181

11851182
static void fw_device_refresh(struct work_struct *work)
11861183
{
1187-
struct fw_device *device =
1188-
container_of(work, struct fw_device, work.work);
1184+
struct fw_device *device = from_work(device, work, work.work);
11891185
struct fw_card *card = device->card;
11901186
int ret, node_id = device->node_id;
11911187
bool changed;
@@ -1251,8 +1247,7 @@ static void fw_device_refresh(struct work_struct *work)
12511247

12521248
static void fw_device_workfn(struct work_struct *work)
12531249
{
1254-
struct fw_device *device = container_of(to_delayed_work(work),
1255-
struct fw_device, work);
1250+
struct fw_device *device = from_work(device, to_delayed_work(work), work);
12561251
device->workfn(work);
12571252
}
12581253

drivers/firewire/core-transaction.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -557,9 +557,10 @@ const struct fw_address_region fw_unit_space_region =
557557
*
558558
* region->start, ->end, and handler->length have to be quadlet-aligned.
559559
*
560-
* When a request is received that falls within the specified address range,
561-
* the specified callback is invoked. The parameters passed to the callback
562-
* give the details of the particular request.
560+
* When a request is received that falls within the specified address range, the specified callback
561+
* is invoked. The parameters passed to the callback give the details of the particular request.
562+
* The callback is invoked in the workqueue context in most cases. However, if the request is
563+
* initiated by the local node, the callback is invoked in the initiator's context.
563564
*
564565
* To be called in process context.
565566
* Return value: 0 on success, non-zero otherwise.

drivers/firewire/net.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
10071007

10081008
spin_lock_irqsave(&dev->lock, flags);
10091009

1010-
/* If the AT tasklet already ran, we may be last user. */
1010+
/* If the AT work item already ran, we may be last user. */
10111011
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
10121012
if (!free)
10131013
ptask->enqueued = true;
@@ -1026,7 +1026,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
10261026

10271027
spin_lock_irqsave(&dev->lock, flags);
10281028

1029-
/* If the AT tasklet already ran, we may be last user. */
1029+
/* If the AT work item already ran, we may be last user. */
10301030
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
10311031
if (!free)
10321032
ptask->enqueued = true;

0 commit comments

Comments
 (0)