mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 06:43:09 +00:00
ALSA: firewire-lib: support NO_PERIOD_WAKEUP in ALSA PCM runtime
Drivers of ALSA firewire stack can process packets for IT/IR context in process context when the process operates ALSA PCM character device by calling ioctl(2) with some requests. The ioctl requests are: * SNDRV_PCM_IOCTL_HWSYNC * SNDRV_PCM_IOCTL_SYNC_PTR * SNDRV_PCM_IOCTL_REWIND * SNDRV_PCM_IOCTL_FORWARD * SNDRV_PCM_IOCTL_WRITEI_FRAMES * SNDRV_PCM_IOCTL_READI_FRAMES * SNDRV_PCM_IOCTL_WRITEN_FRAMES * SNDRV_PCM_IOCTL_READN_FRAMES This means that general application can process PCM frames apart from hardware IRQ invocation, even if they are programmed by either IRQ-based scheduling model or Timer-based scheduling model. This commit add support for Timer-based scheduling model by allowing PCM runtime to suppress both process wakeup per period and scheduling hardware IRQ. SNDRV_PCM_INFO_BATCH is obsoleted since ALSA IEC 61883-1/6 packet streaming engine can report the number of transferred PCM frames within PCM period boundary. The granularity equals to SYT_INTERVAL in blocking transmission. In non-blocking transmission, it doesn't equal to SYT_INTERVAL but doesn't exceed. This patch is tested with PulseAudio, and --sched-model option of axfer with fix against the issue reported at: * https://lore.kernel.org/alsa-devel/687f9871-7484-1370-04d1-9c968e86f72b@linux.intel.com/#r Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Link: https://lore.kernel.org/r/20210527123253.174315-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
2f21a17763
commit
d360870a5b
@ -192,14 +192,13 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
|
||||
unsigned int maximum_usec_per_period;
|
||||
int err;
|
||||
|
||||
hw->info = SNDRV_PCM_INFO_BATCH |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
hw->info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_JOINT_DUPLEX |
|
||||
SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID;
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
|
||||
|
||||
/* SNDRV_PCM_INFO_BATCH */
|
||||
hw->periods_min = 2;
|
||||
hw->periods_max = UINT_MAX;
|
||||
|
||||
@ -610,7 +609,12 @@ static void update_pcm_pointers(struct amdtp_stream *s,
|
||||
s->pcm_period_pointer += frames;
|
||||
if (s->pcm_period_pointer >= pcm->runtime->period_size) {
|
||||
s->pcm_period_pointer -= pcm->runtime->period_size;
|
||||
queue_work(system_highpri_wq, &s->period_work);
|
||||
|
||||
// The program in user process should periodically check the status of intermediate
|
||||
// buffer associated to PCM substream to process PCM frames in the buffer, instead
|
||||
// of receiving notification of period elapsed by poll wait.
|
||||
if (!pcm->runtime->no_period_wakeup)
|
||||
queue_work(system_highpri_wq, &s->period_work);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1056,6 +1060,7 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
|
||||
unsigned int event_count = s->ctx_data.rx.event_count;
|
||||
unsigned int pkt_header_length;
|
||||
unsigned int packets;
|
||||
bool need_hw_irq;
|
||||
int i;
|
||||
|
||||
if (s->packet_index < 0)
|
||||
@ -1075,6 +1080,16 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
|
||||
else
|
||||
pkt_header_length = 0;
|
||||
|
||||
if (s == d->irq_target) {
|
||||
// At NO_PERIOD_WAKEUP mode, the packets for all IT/IR contexts are processed by
|
||||
// the tasks of user process operating ALSA PCM character device by calling ioctl(2)
|
||||
// with some requests, instead of scheduled hardware IRQ of an IT context.
|
||||
struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
|
||||
need_hw_irq = !pcm || !pcm->runtime->no_period_wakeup;
|
||||
} else {
|
||||
need_hw_irq = false;
|
||||
}
|
||||
|
||||
for (i = 0; i < packets; ++i) {
|
||||
const struct pkt_desc *desc = s->pkt_descs + i;
|
||||
struct {
|
||||
@ -1091,7 +1106,7 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
|
||||
event_count += desc->data_blocks;
|
||||
if (event_count >= events_per_period) {
|
||||
event_count -= events_per_period;
|
||||
sched_irq = true;
|
||||
sched_irq = need_hw_irq;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user