Skip to content

Commit 61efd0e

Browse files
committed
firewire: ohci: use threaded IRQ handler to handle SelfIDComplete event
The first step maintaining the bus topology is to handle SelfIDComplete event. This event occurs after initiating bus reset when 1394 OHCI link layer is enabled, or when the bus topology changes (e.g. when a device is added). Because enumeration of the selfID sequence can take some time, it should be processed in a bottom half. Currently, this is done in a module-local workqueue with the WQ_MEM_RECLAIM flag, to allow invocation during memory reclaim paths. A threaded IRQ handler is a preferable alternative, as it eliminates the need to manage workqueue attributes manually. Although SelfIDComplete events are not so frequent in normal usage, handling them correctly is critical for proper bus topology management. This commit switches SelfIDComplete handling to a threaded IRQ handler. Link: https://lore.kernel.org/r/20250823030954.268412-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
1 parent 6969682 commit 61efd0e

1 file changed

Lines changed: 22 additions & 18 deletions

File tree

drivers/firewire/ohci.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
760760
*
761761
* Alas some chips sometimes emit bus reset packets with a
762762
* wrong generation. We set the correct generation for these
763-
* at a slightly incorrect time (in bus_reset_work).
763+
* at a slightly incorrect time (in handle_selfid_complete_event).
764764
*/
765765
if (evt == OHCI1394_evt_bus_reset) {
766766
if (!(ohci->quirks & QUIRK_RESET_PACKET))
@@ -1830,9 +1830,9 @@ static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count)
18301830
return self_id_count;
18311831
}
18321832

1833-
static void bus_reset_work(struct work_struct *work)
1833+
static irqreturn_t handle_selfid_complete_event(int irq, void *data)
18341834
{
1835-
struct fw_ohci *ohci = from_work(ohci, work, bus_reset_work);
1835+
struct fw_ohci *ohci = data;
18361836
int self_id_count, generation, new_generation, i, j;
18371837
u32 reg, quadlet;
18381838
void *free_rom = NULL;
@@ -1843,11 +1843,11 @@ static void bus_reset_work(struct work_struct *work)
18431843
if (!(reg & OHCI1394_NodeID_idValid)) {
18441844
ohci_notice(ohci,
18451845
"node ID not valid, new bus reset in progress\n");
1846-
return;
1846+
goto end;
18471847
}
18481848
if ((reg & OHCI1394_NodeID_nodeNumber) == 63) {
18491849
ohci_notice(ohci, "malconfigured bus\n");
1850-
return;
1850+
goto end;
18511851
}
18521852
ohci->node_id = reg & (OHCI1394_NodeID_busNumber |
18531853
OHCI1394_NodeID_nodeNumber);
@@ -1861,7 +1861,7 @@ static void bus_reset_work(struct work_struct *work)
18611861
reg = reg_read(ohci, OHCI1394_SelfIDCount);
18621862
if (ohci1394_self_id_count_is_error(reg)) {
18631863
ohci_notice(ohci, "self ID receive error\n");
1864-
return;
1864+
goto end;
18651865
}
18661866

18671867
trace_self_id_complete(ohci->card.index, reg, ohci->self_id, has_be_header_quirk(ohci));
@@ -1876,7 +1876,7 @@ static void bus_reset_work(struct work_struct *work)
18761876

18771877
if (self_id_count > 252) {
18781878
ohci_notice(ohci, "bad selfIDSize (%08x)\n", reg);
1879-
return;
1879+
goto end;
18801880
}
18811881

18821882
quadlet = cond_le32_to_cpu(ohci->self_id[0], has_be_header_quirk(ohci));
@@ -1903,7 +1903,7 @@ static void bus_reset_work(struct work_struct *work)
19031903

19041904
ohci_notice(ohci, "bad self ID %d/%d (%08x != ~%08x)\n",
19051905
j, self_id_count, id, id2);
1906-
return;
1906+
goto end;
19071907
}
19081908
ohci->self_id_buffer[j] = id;
19091909
}
@@ -1913,13 +1913,13 @@ static void bus_reset_work(struct work_struct *work)
19131913
if (self_id_count < 0) {
19141914
ohci_notice(ohci,
19151915
"could not construct local self ID\n");
1916-
return;
1916+
goto end;
19171917
}
19181918
}
19191919

19201920
if (self_id_count == 0) {
19211921
ohci_notice(ohci, "no self IDs\n");
1922-
return;
1922+
goto end;
19231923
}
19241924
rmb();
19251925

@@ -1941,7 +1941,7 @@ static void bus_reset_work(struct work_struct *work)
19411941
new_generation = ohci1394_self_id_count_get_generation(reg);
19421942
if (new_generation != generation) {
19431943
ohci_notice(ohci, "new bus reset, discarding self ids\n");
1944-
return;
1944+
goto end;
19451945
}
19461946

19471947
// FIXME: Document how the locking works.
@@ -2002,6 +2002,8 @@ static void bus_reset_work(struct work_struct *work)
20022002
self_id_count, ohci->self_id_buffer,
20032003
ohci->csr_state_setclear_abdicate);
20042004
ohci->csr_state_setclear_abdicate = false;
2005+
end:
2006+
return IRQ_HANDLED;
20052007
}
20062008

20072009
static irqreturn_t irq_handler(int irq, void *data)
@@ -2023,13 +2025,10 @@ static irqreturn_t irq_handler(int irq, void *data)
20232025
event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr));
20242026
trace_irqs(ohci->card.index, event);
20252027

2026-
// The flag is masked again at bus_reset_work() scheduled by selfID event.
2028+
// The flag is masked again at handle_selfid_complete_event() scheduled by selfID event.
20272029
if (event & OHCI1394_busReset)
20282030
reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
20292031

2030-
if (event & OHCI1394_selfIDComplete)
2031-
queue_work(selfid_workqueue, &ohci->bus_reset_work);
2032-
20332032
if (event & OHCI1394_RQPkt)
20342033
queue_work(ohci->card.async_wq, &ohci->ar_request_ctx.work);
20352034

@@ -2100,7 +2099,10 @@ static irqreturn_t irq_handler(int irq, void *data)
21002099
} else
21012100
flush_writes(ohci);
21022101

2103-
return IRQ_HANDLED;
2102+
if (event & OHCI1394_selfIDComplete)
2103+
return IRQ_WAKE_THREAD;
2104+
else
2105+
return IRQ_HANDLED;
21042106
}
21052107

21062108
static int software_reset(struct fw_ohci *ohci)
@@ -2413,7 +2415,7 @@ static int ohci_set_config_rom(struct fw_card *card,
24132415
* then set up the real values for the two registers.
24142416
*
24152417
* We use ohci->lock to avoid racing with the code that sets
2416-
* ohci->next_config_rom to NULL (see bus_reset_work).
2418+
* ohci->next_config_rom to NULL (see handle_selfid_complete_event).
24172419
*/
24182420

24192421
next_config_rom = dmam_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE,
@@ -3620,7 +3622,9 @@ static int pci_probe(struct pci_dev *dev,
36203622
goto fail_msi;
36213623
}
36223624

3623-
err = request_threaded_irq(irq, irq_handler, NULL,
3625+
// IRQF_ONESHOT is not applied so that any events are handled in the hardIRQ handler during
3626+
// invoking the threaded IRQ handler for SelfIDComplete event.
3627+
err = request_threaded_irq(irq, irq_handler, handle_selfid_complete_event,
36243628
pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, ohci_driver_name,
36253629
ohci);
36263630
if (err < 0) {

0 commit comments

Comments
 (0)