Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ALSA: firewire: Replace tasklet with work

The tasklet is an old API that should be deprecated, usually can be
converted to another decent API. In FireWire driver, a tasklet is
still used for offloading the AMDTP PCM stream handling. It can be
achieved gracefully with a work queued, too.

This patch replaces the tasklet usage in firewire-lib driver with a
simple work. The conversion is fairly straightforward but for the
in_interrupt() checks that are replaced with the check using the
current_work().

Note that in_interrupt() in amdtp_packet tracepoint is still kept as
is. This is the place that is probed by both softirq of 1394 OHCI and
a user task of a PCM application, and the work handling is already
filtered in amdtp_domain_stream_pcm_pointer().

Tested-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Acked-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20200909163659.21708-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+14 -13
+13 -12
sound/firewire/amdtp-stream.c
··· 64 64 #define IT_PKT_HEADER_SIZE_CIP 8 // For 2 CIP header. 65 65 #define IT_PKT_HEADER_SIZE_NO_CIP 0 // Nothing. 66 66 67 - static void pcm_period_tasklet(struct tasklet_struct *t); 67 + static void pcm_period_work(struct work_struct *work); 68 68 69 69 /** 70 70 * amdtp_stream_init - initialize an AMDTP stream structure ··· 94 94 s->flags = flags; 95 95 s->context = ERR_PTR(-1); 96 96 mutex_init(&s->mutex); 97 - tasklet_setup(&s->period_tasklet, pcm_period_tasklet); 97 + INIT_WORK(&s->period_work, pcm_period_work); 98 98 s->packet_index = 0; 99 99 100 100 init_waitqueue_head(&s->callback_wait); ··· 203 203 204 204 // Linux driver for 1394 OHCI controller voluntarily flushes isoc 205 205 // context when total size of accumulated context header reaches 206 - // PAGE_SIZE. This kicks tasklet for the isoc context and brings 206 + // PAGE_SIZE. This kicks work for the isoc context and brings 207 207 // callback in the middle of scheduled interrupts. 208 208 // Although AMDTP streams in the same domain use the same events per 209 209 // IRQ, use the largest size of context header between IT/IR contexts. ··· 333 333 */ 334 334 void amdtp_stream_pcm_prepare(struct amdtp_stream *s) 335 335 { 336 - tasklet_kill(&s->period_tasklet); 336 + cancel_work_sync(&s->period_work); 337 337 s->pcm_buffer_pointer = 0; 338 338 s->pcm_period_pointer = 0; 339 339 } ··· 437 437 s->pcm_period_pointer += frames; 438 438 if (s->pcm_period_pointer >= pcm->runtime->period_size) { 439 439 s->pcm_period_pointer -= pcm->runtime->period_size; 440 - tasklet_hi_schedule(&s->period_tasklet); 440 + queue_work(system_highpri_wq, &s->period_work); 441 441 } 442 442 } 443 443 444 - static void pcm_period_tasklet(struct tasklet_struct *t) 444 + static void pcm_period_work(struct work_struct *work) 445 445 { 446 - struct amdtp_stream *s = from_tasklet(s, t, period_tasklet); 446 + struct amdtp_stream *s = container_of(work, struct amdtp_stream, 447 + period_work); 447 448 struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); 448 449 449 450 if (pcm) ··· 795 794 static inline void cancel_stream(struct amdtp_stream *s) 796 795 { 797 796 s->packet_index = -1; 798 - if (in_interrupt()) 797 + if (current_work() == &s->period_work) 799 798 amdtp_stream_pcm_abort(s); 800 799 WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); 801 800 } ··· 1185 1184 1186 1185 if (irq_target && amdtp_stream_running(irq_target)) { 1187 1186 // This function is called in software IRQ context of 1188 - // period_tasklet or process context. 1187 + // period_work or process context. 1189 1188 // 1190 1189 // When the software IRQ context was scheduled by software IRQ 1191 1190 // context of IT contexts, queued packets were already handled. ··· 1196 1195 // immediately to keep better granularity of PCM pointer. 1197 1196 // 1198 1197 // Later, the process context will sometimes schedules software 1199 - // IRQ context of the period_tasklet. Then, no need to flush the 1198 + // IRQ context of the period_work. Then, no need to flush the 1200 1199 // queue by the same reason as described in the above 1201 - if (!in_interrupt()) { 1200 + if (current_work() != &s->period_work) { 1202 1201 // Queued packet should be processed without any kernel 1203 1202 // preemption to keep latency against bus cycle. 1204 1203 preempt_disable(); ··· 1264 1263 return; 1265 1264 } 1266 1265 1267 - tasklet_kill(&s->period_tasklet); 1266 + cancel_work_sync(&s->period_work); 1268 1267 fw_iso_context_stop(s->context); 1269 1268 fw_iso_context_destroy(s->context); 1270 1269 s->context = ERR_PTR(-1);
+1 -1
sound/firewire/amdtp-stream.h
··· 163 163 164 164 /* For a PCM substream processing. */ 165 165 struct snd_pcm_substream *pcm; 166 - struct tasklet_struct period_tasklet; 166 + struct work_struct period_work; 167 167 snd_pcm_uframes_t pcm_buffer_pointer; 168 168 unsigned int pcm_period_pointer; 169 169