diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-03 10:47:03 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-03 10:47:03 -0400 |
commit | 0f8f56c959c9c4a65a5ad13f1b49d97db30b5c2f (patch) | |
tree | 87fde35926c524d466fa0c4897d05e68e3c26718 /sound/pci/lola | |
parent | 333ff3971f374d9a057fd6d1492a2ef78989974d (diff) |
ALSA: lola - Fix PCM stalls
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/lola')
-rw-r--r-- | sound/pci/lola/lola.c | 17 | ||||
-rw-r--r-- | sound/pci/lola/lola.h | 1 | ||||
-rw-r--r-- | sound/pci/lola/lola_pcm.c | 103 |
3 files changed, 74 insertions, 47 deletions
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 16c6cad2e7cd..4d8221505b9e 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c | |||
@@ -73,6 +73,7 @@ static int corb_send_verb(struct lola *chip, unsigned int nid, | |||
73 | chip->last_data = data; | 73 | chip->last_data = data; |
74 | chip->last_extdata = extdata; | 74 | chip->last_extdata = extdata; |
75 | data |= (nid << 20) | (verb << 8); | 75 | data |= (nid << 20) | (verb << 8); |
76 | |||
76 | spin_lock_irqsave(&chip->reg_lock, flags); | 77 | spin_lock_irqsave(&chip->reg_lock, flags); |
77 | if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) { | 78 | if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) { |
78 | unsigned int wp = chip->corb.wp + 1; | 79 | unsigned int wp = chip->corb.wp + 1; |
@@ -338,8 +339,6 @@ static int setup_corb_rirb(struct lola *chip) | |||
338 | chip->corb.buf = (u32 *)chip->rb.area; | 339 | chip->corb.buf = (u32 *)chip->rb.area; |
339 | chip->rirb.addr = chip->rb.addr + 2048; | 340 | chip->rirb.addr = chip->rb.addr + 2048; |
340 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); | 341 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); |
341 | lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr); | ||
342 | lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr)); | ||
343 | 342 | ||
344 | /* disable ringbuffer DMAs */ | 343 | /* disable ringbuffer DMAs */ |
345 | lola_writeb(chip, BAR0, RIRBCTL, 0); | 344 | lola_writeb(chip, BAR0, RIRBCTL, 0); |
@@ -496,6 +495,10 @@ static int lola_parse_tree(struct lola *chip) | |||
496 | if (!chip->cold_reset) { | 495 | if (!chip->cold_reset) { |
497 | lola_reset_setups(chip); | 496 | lola_reset_setups(chip); |
498 | chip->cold_reset = 1; | 497 | chip->cold_reset = 1; |
498 | } else { | ||
499 | /* set the granularity if it is not the default */ | ||
500 | if (chip->granularity != LOLA_GRANULARITY_MIN) | ||
501 | lola_set_granularity(chip, chip->granularity, true); | ||
499 | } | 502 | } |
500 | 503 | ||
501 | return 0; | 504 | return 0; |
@@ -561,8 +564,14 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, | |||
561 | chip->pci = pci; | 564 | chip->pci = pci; |
562 | chip->irq = -1; | 565 | chip->irq = -1; |
563 | 566 | ||
564 | chip->sample_rate_min = 48000; | 567 | /* below a sample_rate of 16kHz the analogue audio quality |
565 | chip->granularity = LOLA_GRANULARITY_MIN; | 568 | * is NOT excellent |
569 | */ | ||
570 | chip->sample_rate_min = 16000; | ||
571 | /* for instance use always max granularity which is compatible | ||
572 | * with all sample rates | ||
573 | */ | ||
574 | chip->granularity = LOLA_GRANULARITY_MAX; | ||
566 | 575 | ||
567 | err = pci_request_regions(pci, DRVNAME); | 576 | err = pci_request_regions(pci, DRVNAME); |
568 | if (err < 0) { | 577 | if (err < 0) { |
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h index 1041b0f0e20f..839779dc32f9 100644 --- a/sound/pci/lola/lola.h +++ b/sound/pci/lola/lola.h | |||
@@ -305,6 +305,7 @@ struct lola_stream { | |||
305 | 305 | ||
306 | /* flags */ | 306 | /* flags */ |
307 | unsigned int opened:1; | 307 | unsigned int opened:1; |
308 | unsigned int prepared:1; | ||
308 | unsigned int running:1; | 309 | unsigned int running:1; |
309 | }; | 310 | }; |
310 | 311 | ||
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index a656439915c8..ef738e6c9919 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c | |||
@@ -29,7 +29,6 @@ | |||
29 | /* #define USE_SG_BUFFER */ | 29 | /* #define USE_SG_BUFFER */ |
30 | 30 | ||
31 | #define LOLA_MAX_BDL_ENTRIES 8 | 31 | #define LOLA_MAX_BDL_ENTRIES 8 |
32 | #define LOLA_MAX_FRAG 8 | ||
33 | #define LOLA_MAX_BUF_SIZE (1024*1024*1024) | 32 | #define LOLA_MAX_BUF_SIZE (1024*1024*1024) |
34 | #define LOLA_BDL_ENTRY_SIZE (16 * 16) | 33 | #define LOLA_BDL_ENTRY_SIZE (16 * 16) |
35 | 34 | ||
@@ -111,12 +110,6 @@ static void lola_stream_stop(struct lola *chip, struct lola_stream *str, | |||
111 | lola_stream_clear_pending_irq(chip, str); | 110 | lola_stream_clear_pending_irq(chip, str); |
112 | } | 111 | } |
113 | 112 | ||
114 | static void lola_stream_clear(struct lola *chip, struct lola_stream *str) | ||
115 | { | ||
116 | lola_dsd_write(chip, str->dsd, CTL, 0); | ||
117 | lola_stream_clear_pending_irq(chip, str); | ||
118 | } | ||
119 | |||
120 | static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) | 113 | static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) |
121 | { | 114 | { |
122 | unsigned long end_time = jiffies + msecs_to_jiffies(200); | 115 | unsigned long end_time = jiffies + msecs_to_jiffies(200); |
@@ -130,22 +123,15 @@ static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) | |||
130 | printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd); | 123 | printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd); |
131 | } | 124 | } |
132 | 125 | ||
133 | static void lola_stream_reset(struct lola *chip, struct lola_stream *str) | 126 | static int lola_stream_wait_for_fifo(struct lola *chip, |
127 | struct lola_stream *str, | ||
128 | bool ready) | ||
134 | { | 129 | { |
135 | lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST); | 130 | unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0; |
136 | wait_for_srst_clear(chip, str); | 131 | unsigned long end_time = jiffies + msecs_to_jiffies(200); |
137 | lola_dsd_write(chip, str->dsd, LVI, 0); | ||
138 | lola_dsd_write(chip, str->dsd, BDPU, 0); | ||
139 | lola_dsd_write(chip, str->dsd, BDPL, 0); | ||
140 | } | ||
141 | |||
142 | static int lola_stream_wait_for_fifo_ready(struct lola *chip, | ||
143 | struct lola_stream *str) | ||
144 | { | ||
145 | unsigned long end_time = jiffies + msecs_to_jiffies(1000); | ||
146 | while (time_before(jiffies, end_time)) { | 132 | while (time_before(jiffies, end_time)) { |
147 | unsigned int val = lola_dsd_read(chip, str->dsd, STS); | 133 | unsigned int reg = lola_dsd_read(chip, str->dsd, STS); |
148 | if (val & LOLA_DSD_STS_FIFORDY) | 134 | if ((reg & LOLA_DSD_STS_FIFORDY) == val) |
149 | return 0; | 135 | return 0; |
150 | msleep(1); | 136 | msleep(1); |
151 | } | 137 | } |
@@ -153,6 +139,23 @@ static int lola_stream_wait_for_fifo_ready(struct lola *chip, | |||
153 | return -EIO; | 139 | return -EIO; |
154 | } | 140 | } |
155 | 141 | ||
142 | static void lola_stream_reset(struct lola *chip, struct lola_stream *str) | ||
143 | { | ||
144 | if (str->prepared) { | ||
145 | str->prepared = 0; | ||
146 | |||
147 | lola_dsd_write(chip, str->dsd, CTL, | ||
148 | LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE); | ||
149 | lola_stream_wait_for_fifo(chip, str, false); | ||
150 | lola_stream_clear_pending_irq(chip, str); | ||
151 | lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST); | ||
152 | lola_dsd_write(chip, str->dsd, LVI, 0); | ||
153 | lola_dsd_write(chip, str->dsd, BDPU, 0); | ||
154 | lola_dsd_write(chip, str->dsd, BDPL, 0); | ||
155 | wait_for_srst_clear(chip, str); | ||
156 | } | ||
157 | } | ||
158 | |||
156 | static struct snd_pcm_hardware lola_pcm_hw = { | 159 | static struct snd_pcm_hardware lola_pcm_hw = { |
157 | .info = (SNDRV_PCM_INFO_MMAP | | 160 | .info = (SNDRV_PCM_INFO_MMAP | |
158 | SNDRV_PCM_INFO_INTERLEAVED | | 161 | SNDRV_PCM_INFO_INTERLEAVED | |
@@ -163,16 +166,16 @@ static struct snd_pcm_hardware lola_pcm_hw = { | |||
163 | SNDRV_PCM_FMTBIT_S24_LE | | 166 | SNDRV_PCM_FMTBIT_S24_LE | |
164 | SNDRV_PCM_FMTBIT_S32_LE | | 167 | SNDRV_PCM_FMTBIT_S32_LE | |
165 | SNDRV_PCM_FMTBIT_FLOAT_LE), | 168 | SNDRV_PCM_FMTBIT_FLOAT_LE), |
166 | .rates = SNDRV_PCM_RATE_48000, | 169 | .rates = SNDRV_PCM_RATE_8000_192000, |
167 | .rate_min = 48000, | 170 | .rate_min = 8000, |
168 | .rate_max = 48000, | 171 | .rate_max = 192000, |
169 | .channels_min = 1, | 172 | .channels_min = 1, |
170 | .channels_max = 2, | 173 | .channels_max = 2, |
171 | .buffer_bytes_max = LOLA_MAX_BUF_SIZE, | 174 | .buffer_bytes_max = LOLA_MAX_BUF_SIZE, |
172 | .period_bytes_min = 128, | 175 | .period_bytes_min = 128, |
173 | .period_bytes_max = LOLA_MAX_BUF_SIZE / 2, | 176 | .period_bytes_max = LOLA_MAX_BUF_SIZE / 2, |
174 | .periods_min = 2, | 177 | .periods_min = 2, |
175 | .periods_max = LOLA_MAX_FRAG, | 178 | .periods_max = LOLA_MAX_BDL_ENTRIES, |
176 | .fifo_size = 0, | 179 | .fifo_size = 0, |
177 | }; | 180 | }; |
178 | 181 | ||
@@ -194,10 +197,13 @@ static int lola_pcm_open(struct snd_pcm_substream *substream) | |||
194 | runtime->hw = lola_pcm_hw; | 197 | runtime->hw = lola_pcm_hw; |
195 | runtime->hw.channels_max = pcm->num_streams - str->index; | 198 | runtime->hw.channels_max = pcm->num_streams - str->index; |
196 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | 199 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); |
197 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | 200 | /* period size = multiple of chip->granularity (8, 16 or 32 frames) |
198 | 128); | 201 | * use LOLA_GRANULARITY_MAX = 32 for instance |
199 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | 202 | */ |
200 | 128); | 203 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
204 | LOLA_GRANULARITY_MAX); | ||
205 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
206 | LOLA_GRANULARITY_MAX); | ||
201 | mutex_unlock(&chip->open_mutex); | 207 | mutex_unlock(&chip->open_mutex); |
202 | return 0; | 208 | return 0; |
203 | } | 209 | } |
@@ -383,16 +389,24 @@ static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm, | |||
383 | struct lola_stream *str) | 389 | struct lola_stream *str) |
384 | { | 390 | { |
385 | dma_addr_t bdl; | 391 | dma_addr_t bdl; |
392 | |||
393 | if (str->prepared) | ||
394 | return -EINVAL; | ||
395 | |||
386 | /* set up BDL */ | 396 | /* set up BDL */ |
387 | bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index; | 397 | bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index; |
388 | lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl); | 398 | lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl); |
389 | lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl)); | 399 | lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl)); |
390 | /* program the stream LVI (last valid index) of the BDL */ | 400 | /* program the stream LVI (last valid index) of the BDL */ |
391 | lola_dsd_write(chip, str->dsd, LVI, str->frags - 1); | 401 | lola_dsd_write(chip, str->dsd, LVI, str->frags - 1); |
392 | lola_stream_stop(chip, str, lola_get_tstamp(chip, false)); | 402 | lola_stream_clear_pending_irq(chip, str); |
393 | lola_stream_wait_for_fifo_ready(chip, str); | ||
394 | 403 | ||
395 | return 0; | 404 | lola_dsd_write(chip, str->dsd, CTL, |
405 | LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN); | ||
406 | |||
407 | str->prepared = 1; | ||
408 | |||
409 | return lola_stream_wait_for_fifo(chip, str, true); | ||
396 | } | 410 | } |
397 | 411 | ||
398 | static int lola_pcm_prepare(struct snd_pcm_substream *substream) | 412 | static int lola_pcm_prepare(struct snd_pcm_substream *substream) |
@@ -421,22 +435,25 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream) | |||
421 | period_bytes = snd_pcm_lib_period_bytes(substream); | 435 | period_bytes = snd_pcm_lib_period_bytes(substream); |
422 | format_verb = lola_get_format_verb(substream); | 436 | format_verb = lola_get_format_verb(substream); |
423 | 437 | ||
424 | if (bufsize != str->bufsize || | 438 | str->bufsize = bufsize; |
425 | period_bytes != str->period_bytes || | 439 | str->period_bytes = period_bytes; |
426 | format_verb != str->format_verb) { | 440 | str->format_verb = format_verb; |
427 | str->bufsize = bufsize; | 441 | |
428 | str->period_bytes = period_bytes; | 442 | err = lola_setup_periods(chip, pcm, substream, str); |
429 | str->format_verb = format_verb; | 443 | if (err < 0) |
430 | err = lola_setup_periods(chip, pcm, substream, str); | 444 | return err; |
431 | if (err < 0) | ||
432 | return err; | ||
433 | } | ||
434 | 445 | ||
435 | err = lola_set_stream_config(chip, str, runtime->channels); | 446 | err = lola_set_stream_config(chip, str, runtime->channels); |
436 | if (err < 0) | 447 | if (err < 0) |
437 | return err; | 448 | return err; |
438 | 449 | ||
439 | return lola_setup_controller(chip, pcm, str); | 450 | err = lola_setup_controller(chip, pcm, str); |
451 | if (err < 0) { | ||
452 | lola_stream_reset(chip, str); | ||
453 | return err; | ||
454 | } | ||
455 | |||
456 | return 0; | ||
440 | } | 457 | } |
441 | 458 | ||
442 | static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 459 | static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |