diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-03 10:41:02 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-03 10:41:02 -0400 |
commit | 333ff3971f374d9a057fd6d1492a2ef78989974d (patch) | |
tree | 194f15d828c478ff3dfe22e597cf202383fd2ddd /sound/pci/lola | |
parent | a426c787233c87587b6cac797ac840162bdb09c2 (diff) |
ALSA: lola - Use a single BDL
Use a single BDL for both buffers instead of allocating for each.
Also a few tune-up to avoid the stream stalls in the PCM code and
the prelimianry work for SG-buffer support are added, too.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/lola')
-rw-r--r-- | sound/pci/lola/lola.h | 2 | ||||
-rw-r--r-- | sound/pci/lola/lola_pcm.c | 78 |
2 files changed, 49 insertions, 31 deletions
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h index 23831a1a95ad..1041b0f0e20f 100644 --- a/sound/pci/lola/lola.h +++ b/sound/pci/lola/lola.h | |||
@@ -299,7 +299,6 @@ struct lola_stream { | |||
299 | unsigned int bufsize; | 299 | unsigned int bufsize; |
300 | unsigned int period_bytes; | 300 | unsigned int period_bytes; |
301 | unsigned int frags; | 301 | unsigned int frags; |
302 | struct snd_dma_buffer bdl; /* BDL buffer */ | ||
303 | 302 | ||
304 | /* format + channel setup */ | 303 | /* format + channel setup */ |
305 | unsigned int format_verb; | 304 | unsigned int format_verb; |
@@ -314,6 +313,7 @@ struct lola_stream { | |||
314 | 313 | ||
315 | struct lola_pcm { | 314 | struct lola_pcm { |
316 | unsigned int num_streams; | 315 | unsigned int num_streams; |
316 | struct snd_dma_buffer bdl; /* BDL buffer */ | ||
317 | struct lola_stream streams[MAX_STREAM_COUNT]; | 317 | struct lola_stream streams[MAX_STREAM_COUNT]; |
318 | }; | 318 | }; |
319 | 319 | ||
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index bf17f921d45f..a656439915c8 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c | |||
@@ -26,10 +26,28 @@ | |||
26 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
27 | #include "lola.h" | 27 | #include "lola.h" |
28 | 28 | ||
29 | #define BDL_SIZE 4096 | 29 | /* #define USE_SG_BUFFER */ |
30 | #define LOLA_MAX_BDL_ENTRIES (BDL_SIZE / 16) | 30 | |
31 | #define LOLA_MAX_FRAG 32 | 31 | #define LOLA_MAX_BDL_ENTRIES 8 |
32 | #define LOLA_MAX_FRAG 8 | ||
32 | #define LOLA_MAX_BUF_SIZE (1024*1024*1024) | 33 | #define LOLA_MAX_BUF_SIZE (1024*1024*1024) |
34 | #define LOLA_BDL_ENTRY_SIZE (16 * 16) | ||
35 | |||
36 | #ifdef USE_SG_BUFFER | ||
37 | #define get_addr(substream, ofs) \ | ||
38 | snd_pcm_sgbuf_get_addr(substream, ofs) | ||
39 | #define get_size(substream, ofs, size) \ | ||
40 | snd_pcm_sgbuf_get_chunk_size(substream, ofs, size) | ||
41 | #define ops_page snd_pcm_sgbuf_ops_page | ||
42 | #define PREALLOC_TYPE SNDRV_DMA_TYPE_DEV_SG | ||
43 | #else | ||
44 | #define get_addr(substream, ofs) \ | ||
45 | ((substream)->runtime->dma_addr + ofs) | ||
46 | #define get_size(substream, ofs, size) \ | ||
47 | (size) | ||
48 | #define ops_page NULL | ||
49 | #define PREALLOC_TYPE SNDRV_DMA_TYPE_DEV | ||
50 | #endif | ||
33 | 51 | ||
34 | static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream) | 52 | static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream) |
35 | { | 53 | { |
@@ -101,7 +119,7 @@ static void lola_stream_clear(struct lola *chip, struct lola_stream *str) | |||
101 | 119 | ||
102 | static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) | 120 | static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) |
103 | { | 121 | { |
104 | unsigned long end_time = jiffies + msecs_to_jiffies(50); | 122 | unsigned long end_time = jiffies + msecs_to_jiffies(200); |
105 | while (time_before(jiffies, end_time)) { | 123 | while (time_before(jiffies, end_time)) { |
106 | unsigned int val; | 124 | unsigned int val; |
107 | val = lola_dsd_read(chip, str->dsd, CTL); | 125 | val = lola_dsd_read(chip, str->dsd, CTL); |
@@ -115,16 +133,16 @@ static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) | |||
115 | static void lola_stream_reset(struct lola *chip, struct lola_stream *str) | 133 | static void lola_stream_reset(struct lola *chip, struct lola_stream *str) |
116 | { | 134 | { |
117 | lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST); | 135 | lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST); |
136 | wait_for_srst_clear(chip, str); | ||
118 | lola_dsd_write(chip, str->dsd, LVI, 0); | 137 | lola_dsd_write(chip, str->dsd, LVI, 0); |
119 | lola_dsd_write(chip, str->dsd, BDPU, 0); | 138 | lola_dsd_write(chip, str->dsd, BDPU, 0); |
120 | lola_dsd_write(chip, str->dsd, BDPL, 0); | 139 | lola_dsd_write(chip, str->dsd, BDPL, 0); |
121 | wait_for_srst_clear(chip, str); | ||
122 | } | 140 | } |
123 | 141 | ||
124 | static int lola_stream_wait_for_fifo_ready(struct lola *chip, | 142 | static int lola_stream_wait_for_fifo_ready(struct lola *chip, |
125 | struct lola_stream *str) | 143 | struct lola_stream *str) |
126 | { | 144 | { |
127 | unsigned long end_time = jiffies + msecs_to_jiffies(50); | 145 | unsigned long end_time = jiffies + msecs_to_jiffies(1000); |
128 | while (time_before(jiffies, end_time)) { | 146 | while (time_before(jiffies, end_time)) { |
129 | unsigned int val = lola_dsd_read(chip, str->dsd, STS); | 147 | unsigned int val = lola_dsd_read(chip, str->dsd, STS); |
130 | if (val & LOLA_DSD_STS_FIFORDY) | 148 | if (val & LOLA_DSD_STS_FIFORDY) |
@@ -164,21 +182,12 @@ static int lola_pcm_open(struct snd_pcm_substream *substream) | |||
164 | struct lola_pcm *pcm = lola_get_pcm(substream); | 182 | struct lola_pcm *pcm = lola_get_pcm(substream); |
165 | struct lola_stream *str = lola_get_stream(substream); | 183 | struct lola_stream *str = lola_get_stream(substream); |
166 | struct snd_pcm_runtime *runtime = substream->runtime; | 184 | struct snd_pcm_runtime *runtime = substream->runtime; |
167 | int err; | ||
168 | 185 | ||
169 | mutex_lock(&chip->open_mutex); | 186 | mutex_lock(&chip->open_mutex); |
170 | if (str->opened) { | 187 | if (str->opened) { |
171 | mutex_unlock(&chip->open_mutex); | 188 | mutex_unlock(&chip->open_mutex); |
172 | return -EBUSY; | 189 | return -EBUSY; |
173 | } | 190 | } |
174 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, | ||
175 | snd_dma_pci_data(chip->pci), | ||
176 | PAGE_SIZE, &str->bdl); | ||
177 | if (err < 0) { | ||
178 | mutex_unlock(&chip->open_mutex); | ||
179 | printk(KERN_ERR SFX "Can't allocate BDL\n"); | ||
180 | return err; | ||
181 | } | ||
182 | str->substream = substream; | 191 | str->substream = substream; |
183 | str->master = NULL; | 192 | str->master = NULL; |
184 | str->opened = 1; | 193 | str->opened = 1; |
@@ -216,7 +225,6 @@ static int lola_pcm_close(struct snd_pcm_substream *substream) | |||
216 | str->substream = NULL; | 225 | str->substream = NULL; |
217 | str->opened = 0; | 226 | str->opened = 0; |
218 | } | 227 | } |
219 | snd_dma_free_pages(&str->bdl); | ||
220 | mutex_unlock(&chip->open_mutex); | 228 | mutex_unlock(&chip->open_mutex); |
221 | return 0; | 229 | return 0; |
222 | } | 230 | } |
@@ -262,12 +270,12 @@ static int setup_bdle(struct snd_pcm_substream *substream, | |||
262 | if (str->frags >= LOLA_MAX_BDL_ENTRIES) | 270 | if (str->frags >= LOLA_MAX_BDL_ENTRIES) |
263 | return -EINVAL; | 271 | return -EINVAL; |
264 | 272 | ||
265 | addr = snd_pcm_sgbuf_get_addr(substream, ofs); | 273 | addr = get_addr(substream, ofs); |
266 | /* program the address field of the BDL entry */ | 274 | /* program the address field of the BDL entry */ |
267 | bdl[0] = cpu_to_le32((u32)addr); | 275 | bdl[0] = cpu_to_le32((u32)addr); |
268 | bdl[1] = cpu_to_le32(upper_32_bits(addr)); | 276 | bdl[1] = cpu_to_le32(upper_32_bits(addr)); |
269 | /* program the size field of the BDL entry */ | 277 | /* program the size field of the BDL entry */ |
270 | chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size); | 278 | chunk = get_size(substream, ofs, size); |
271 | bdl[2] = cpu_to_le32(chunk); | 279 | bdl[2] = cpu_to_le32(chunk); |
272 | /* program the IOC to enable interrupt | 280 | /* program the IOC to enable interrupt |
273 | * only when the whole fragment is processed | 281 | * only when the whole fragment is processed |
@@ -285,7 +293,7 @@ static int setup_bdle(struct snd_pcm_substream *substream, | |||
285 | /* | 293 | /* |
286 | * set up BDL entries | 294 | * set up BDL entries |
287 | */ | 295 | */ |
288 | static int lola_setup_periods(struct lola *chip, | 296 | static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm, |
289 | struct snd_pcm_substream *substream, | 297 | struct snd_pcm_substream *substream, |
290 | struct lola_stream *str) | 298 | struct lola_stream *str) |
291 | { | 299 | { |
@@ -296,7 +304,7 @@ static int lola_setup_periods(struct lola *chip, | |||
296 | periods = str->bufsize / period_bytes; | 304 | periods = str->bufsize / period_bytes; |
297 | 305 | ||
298 | /* program the initial BDL entries */ | 306 | /* program the initial BDL entries */ |
299 | bdl = (u32 *)str->bdl.area; | 307 | bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index); |
300 | ofs = 0; | 308 | ofs = 0; |
301 | str->frags = 0; | 309 | str->frags = 0; |
302 | for (i = 0; i < periods; i++) { | 310 | for (i = 0; i < periods; i++) { |
@@ -371,13 +379,14 @@ static int lola_set_stream_config(struct lola *chip, | |||
371 | /* | 379 | /* |
372 | * set up the SD for streaming | 380 | * set up the SD for streaming |
373 | */ | 381 | */ |
374 | static int lola_setup_controller(struct lola *chip, struct lola_stream *str) | 382 | static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm, |
383 | struct lola_stream *str) | ||
375 | { | 384 | { |
376 | /* make sure the run bit is zero for SD */ | 385 | dma_addr_t bdl; |
377 | lola_stream_clear(chip, str); | ||
378 | /* set up BDL */ | 386 | /* set up BDL */ |
379 | lola_dsd_write(chip, str->dsd, BDPL, (u32)str->bdl.addr); | 387 | bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index; |
380 | lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(str->bdl.addr)); | 388 | lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl); |
389 | lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl)); | ||
381 | /* program the stream LVI (last valid index) of the BDL */ | 390 | /* program the stream LVI (last valid index) of the BDL */ |
382 | lola_dsd_write(chip, str->dsd, LVI, str->frags - 1); | 391 | lola_dsd_write(chip, str->dsd, LVI, str->frags - 1); |
383 | lola_stream_stop(chip, str, lola_get_tstamp(chip, false)); | 392 | lola_stream_stop(chip, str, lola_get_tstamp(chip, false)); |
@@ -418,7 +427,7 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream) | |||
418 | str->bufsize = bufsize; | 427 | str->bufsize = bufsize; |
419 | str->period_bytes = period_bytes; | 428 | str->period_bytes = period_bytes; |
420 | str->format_verb = format_verb; | 429 | str->format_verb = format_verb; |
421 | err = lola_setup_periods(chip, substream, str); | 430 | err = lola_setup_periods(chip, pcm, substream, str); |
422 | if (err < 0) | 431 | if (err < 0) |
423 | return err; | 432 | return err; |
424 | } | 433 | } |
@@ -427,7 +436,7 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream) | |||
427 | if (err < 0) | 436 | if (err < 0) |
428 | return err; | 437 | return err; |
429 | 438 | ||
430 | return lola_setup_controller(chip, str); | 439 | return lola_setup_controller(chip, pcm, str); |
431 | } | 440 | } |
432 | 441 | ||
433 | static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 442 | static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
@@ -504,7 +513,7 @@ static struct snd_pcm_ops lola_pcm_ops = { | |||
504 | .prepare = lola_pcm_prepare, | 513 | .prepare = lola_pcm_prepare, |
505 | .trigger = lola_pcm_trigger, | 514 | .trigger = lola_pcm_trigger, |
506 | .pointer = lola_pcm_pointer, | 515 | .pointer = lola_pcm_pointer, |
507 | .page = snd_pcm_sgbuf_ops_page, | 516 | .page = ops_page, |
508 | }; | 517 | }; |
509 | 518 | ||
510 | int __devinit lola_create_pcm(struct lola *chip) | 519 | int __devinit lola_create_pcm(struct lola *chip) |
@@ -512,6 +521,14 @@ int __devinit lola_create_pcm(struct lola *chip) | |||
512 | struct snd_pcm *pcm; | 521 | struct snd_pcm *pcm; |
513 | int i, err; | 522 | int i, err; |
514 | 523 | ||
524 | for (i = 0; i < 2; i++) { | ||
525 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, | ||
526 | snd_dma_pci_data(chip->pci), | ||
527 | PAGE_SIZE, &chip->pcm[i].bdl); | ||
528 | if (err < 0) | ||
529 | return err; | ||
530 | } | ||
531 | |||
515 | err = snd_pcm_new(chip->card, "Digigram Lola", 0, | 532 | err = snd_pcm_new(chip->card, "Digigram Lola", 0, |
516 | chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams, | 533 | chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams, |
517 | chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams, | 534 | chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams, |
@@ -525,7 +542,7 @@ int __devinit lola_create_pcm(struct lola *chip) | |||
525 | snd_pcm_set_ops(pcm, i, &lola_pcm_ops); | 542 | snd_pcm_set_ops(pcm, i, &lola_pcm_ops); |
526 | } | 543 | } |
527 | /* buffer pre-allocation */ | 544 | /* buffer pre-allocation */ |
528 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, | 545 | snd_pcm_lib_preallocate_pages_for_all(pcm, PREALLOC_TYPE, |
529 | snd_dma_pci_data(chip->pci), | 546 | snd_dma_pci_data(chip->pci), |
530 | 1024 * 64, 32 * 1024 * 1024); | 547 | 1024 * 64, 32 * 1024 * 1024); |
531 | return 0; | 548 | return 0; |
@@ -533,7 +550,8 @@ int __devinit lola_create_pcm(struct lola *chip) | |||
533 | 550 | ||
534 | void lola_free_pcm(struct lola *chip) | 551 | void lola_free_pcm(struct lola *chip) |
535 | { | 552 | { |
536 | /* nothing to do */ | 553 | snd_dma_free_pages(&chip->pcm[0].bdl); |
554 | snd_dma_free_pages(&chip->pcm[1].bdl); | ||
537 | } | 555 | } |
538 | 556 | ||
539 | /* | 557 | /* |