@@ -1182,6 +1182,47 @@ static void context_tasklet(unsigned long data)
11821182 }
11831183}
11841184
1185+ static void ohci_isoc_context_work (struct work_struct * work )
1186+ {
1187+ struct fw_iso_context * base = container_of (work , struct fw_iso_context , work );
1188+ struct iso_context * isoc_ctx = container_of (base , struct iso_context , base );
1189+ struct context * ctx = & isoc_ctx -> context ;
1190+ struct descriptor * d , * last ;
1191+ u32 address ;
1192+ int z ;
1193+ struct descriptor_buffer * desc ;
1194+
1195+ desc = list_entry (ctx -> buffer_list .next , struct descriptor_buffer , list );
1196+ last = ctx -> last ;
1197+ while (last -> branch_address != 0 ) {
1198+ struct descriptor_buffer * old_desc = desc ;
1199+
1200+ address = le32_to_cpu (last -> branch_address );
1201+ z = address & 0xf ;
1202+ address &= ~0xf ;
1203+ ctx -> current_bus = address ;
1204+
1205+ // If the branch address points to a buffer outside of the current buffer, advance
1206+ // to the next buffer.
1207+ if (address < desc -> buffer_bus || address >= desc -> buffer_bus + desc -> used )
1208+ desc = list_entry (desc -> list .next , struct descriptor_buffer , list );
1209+ d = desc -> buffer + (address - desc -> buffer_bus ) / sizeof (* d );
1210+ last = find_branch_descriptor (d , z );
1211+
1212+ if (!ctx -> callback (ctx , d , last ))
1213+ break ;
1214+
1215+ if (old_desc != desc ) {
1216+ // If we've advanced to the next buffer, move the previous buffer to the
1217+ // free list.
1218+ old_desc -> used = 0 ;
1219+ guard (spinlock_irqsave )(& ctx -> ohci -> lock );
1220+ list_move_tail (& old_desc -> list , & ctx -> buffer_list );
1221+ }
1222+ ctx -> last = last ;
1223+ }
1224+ }
1225+
11851226/*
11861227 * Allocate a new buffer and add it to the list of free buffers for this
11871228 * context. Must be called with ohci->lock held.
@@ -2242,8 +2283,7 @@ static irqreturn_t irq_handler(int irq, void *data)
22422283
22432284 while (iso_event ) {
22442285 i = ffs (iso_event ) - 1 ;
2245- tasklet_schedule (
2246- & ohci -> ir_context_list [i ].context .tasklet );
2286+ fw_iso_context_queue_work (& ohci -> ir_context_list [i ].base );
22472287 iso_event &= ~(1 << i );
22482288 }
22492289 }
@@ -2254,8 +2294,7 @@ static irqreturn_t irq_handler(int irq, void *data)
22542294
22552295 while (iso_event ) {
22562296 i = ffs (iso_event ) - 1 ;
2257- tasklet_schedule (
2258- & ohci -> it_context_list [i ].context .tasklet );
2297+ fw_iso_context_queue_work (& ohci -> it_context_list [i ].base );
22592298 iso_event &= ~(1 << i );
22602299 }
22612300 }
@@ -3130,6 +3169,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
31303169 ret = context_init (& ctx -> context , ohci , regs , callback );
31313170 if (ret < 0 )
31323171 goto out_with_header ;
3172+ fw_iso_context_init_work (& ctx -> base , ohci_isoc_context_work );
31333173
31343174 if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL ) {
31353175 set_multichannel_mask (ohci , 0 );
@@ -3227,7 +3267,6 @@ static int ohci_stop_iso(struct fw_iso_context *base)
32273267 }
32283268 flush_writes (ohci );
32293269 context_stop (& ctx -> context );
3230- tasklet_kill (& ctx -> context .tasklet );
32313270
32323271 return 0 ;
32333272}
@@ -3584,10 +3623,8 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base)
35843623 struct iso_context * ctx = container_of (base , struct iso_context , base );
35853624 int ret = 0 ;
35863625
3587- tasklet_disable_in_atomic (& ctx -> context .tasklet );
3588-
35893626 if (!test_and_set_bit_lock (0 , & ctx -> flushing_completions )) {
3590- context_tasklet (( unsigned long ) & ctx -> context );
3627+ ohci_isoc_context_work ( & base -> work );
35913628
35923629 switch (base -> type ) {
35933630 case FW_ISO_CONTEXT_TRANSMIT :
@@ -3607,8 +3644,6 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base)
36073644 smp_mb__after_atomic ();
36083645 }
36093646
3610- tasklet_enable (& ctx -> context .tasklet );
3611-
36123647 return ret ;
36133648}
36143649
0 commit comments