aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt36
-rw-r--r--sound/core/memalloc.c201
-rw-r--r--sound/pci/rme9652/hdsp.c14
-rw-r--r--sound/pci/rme9652/rme9652.c14
4 files changed, 161 insertions, 104 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 226013035d7..812ed2b80b8 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -671,7 +671,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
671 module did formerly. It will allocate the buffers in advance 671 module did formerly. It will allocate the buffers in advance
672 when any HDSP cards are found. To make the buffer 672 when any HDSP cards are found. To make the buffer
673 allocation sure, load snd-page-alloc module in the early 673 allocation sure, load snd-page-alloc module in the early
674 stage of boot sequence. 674 stage of boot sequence. See "Early Buffer Allocation"
675 section.
675 676
676 Module snd-ice1712 677 Module snd-ice1712
677 ------------------ 678 ------------------
@@ -1067,7 +1068,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
1067 module did formerly. It will allocate the buffers in advance 1068 module did formerly. It will allocate the buffers in advance
1068 when any RME9652 cards are found. To make the buffer 1069 when any RME9652 cards are found. To make the buffer
1069 allocation sure, load snd-page-alloc module in the early 1070 allocation sure, load snd-page-alloc module in the early
1070 stage of boot sequence. 1071 stage of boot sequence. See "Early Buffer Allocation"
1072 section.
1071 1073
1072 Module snd-sa11xx-uda1341 (on arm only) 1074 Module snd-sa11xx-uda1341 (on arm only)
1073 --------------------------------------- 1075 ---------------------------------------
@@ -1545,6 +1547,36 @@ Proc interfaces (/proc/asound)
1545 echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss 1547 echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss
1546 1548
1547 1549
1550Early Buffer Allocation
1551=======================
1552
1553Some drivers (e.g. hdsp) require the large contiguous buffers, and
1554sometimes it's too late to find such spaces when the driver module is
1555actually loaded due to memory fragmentation. You can pre-allocate the
1556PCM buffers by loading snd-page-alloc module and write commands to its
1557proc file in prior, for example, in the early boot stage like
1558/etc/init.d/*.local scripts.
1559
1560Reading the proc file /proc/drivers/snd-page-alloc shows the current
1561usage of page allocation. In writing, you can send the following
1562commands to the snd-page-alloc driver:
1563
1564 - add VENDOR DEVICE MASK SIZE BUFFERS
1565
1566 VENDOR and DEVICE are PCI vendor and device IDs. They take
1567 integer numbers (0x prefix is needed for the hex).
1568 MASK is the PCI DMA mask. Pass 0 if not restricted.
1569 SIZE is the size of each buffer to allocate. You can pass
1570 k and m suffix for KB and MB. The max number is 16MB.
1571 BUFFERS is the number of buffers to allocate. It must be greater
1572 than 0. The max number is 4.
1573
1574 - erase
1575
1576 This will erase the all pre-allocated buffers which are not in
1577 use.
1578
1579
1548Links 1580Links
1549===== 1581=====
1550 1582
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 344a83fd7c2..dbc23e35fa0 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -28,6 +28,7 @@
28#include <linux/pci.h> 28#include <linux/pci.h>
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/mm.h> 30#include <linux/mm.h>
31#include <asm/uaccess.h>
31#include <linux/dma-mapping.h> 32#include <linux/dma-mapping.h>
32#include <linux/moduleparam.h> 33#include <linux/moduleparam.h>
33#include <asm/semaphore.h> 34#include <asm/semaphore.h>
@@ -46,13 +47,6 @@ MODULE_LICENSE("GPL");
46#define SNDRV_CARDS 8 47#define SNDRV_CARDS 8
47#endif 48#endif
48 49
49/* FIXME: so far only some PCI devices have the preallocation table */
50#ifdef CONFIG_PCI
51static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
52module_param_array(enable, bool, NULL, 0444);
53MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
54#endif
55
56/* 50/*
57 */ 51 */
58 52
@@ -451,9 +445,13 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
451 list_for_each(p, &mem_list_head) { 445 list_for_each(p, &mem_list_head) {
452 mem = list_entry(p, struct snd_mem_list, list); 446 mem = list_entry(p, struct snd_mem_list, list);
453 if (mem->id == id && 447 if (mem->id == id &&
454 ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) { 448 (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
449 ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
450 struct device *dev = dmab->dev.dev;
455 list_del(p); 451 list_del(p);
456 *dmab = mem->buffer; 452 *dmab = mem->buffer;
453 if (dmab->dev.dev == NULL)
454 dmab->dev.dev = dev;
457 kfree(mem); 455 kfree(mem);
458 up(&list_mutex); 456 up(&list_mutex);
459 return dmab->bytes; 457 return dmab->bytes;
@@ -508,91 +506,13 @@ static void free_all_reserved_pages(void)
508} 506}
509 507
510 508
511
512/*
513 * allocation of buffers for pre-defined devices
514 */
515
516#ifdef CONFIG_PCI
517/* FIXME: for pci only - other bus? */
518struct prealloc_dev {
519 unsigned short vendor;
520 unsigned short device;
521 unsigned long dma_mask;
522 unsigned int size;
523 unsigned int buffers;
524};
525
526#define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000)
527
528static struct prealloc_dev prealloc_devices[] __initdata = {
529 {
530 /* hammerfall */
531 .vendor = 0x10ee,
532 .device = 0x3fc4,
533 .dma_mask = 0xffffffff,
534 .size = HAMMERFALL_BUFFER_SIZE,
535 .buffers = 2
536 },
537 {
538 /* HDSP */
539 .vendor = 0x10ee,
540 .device = 0x3fc5,
541 .dma_mask = 0xffffffff,
542 .size = HAMMERFALL_BUFFER_SIZE,
543 .buffers = 2
544 },
545 { }, /* terminator */
546};
547
548static void __init preallocate_cards(void)
549{
550 struct pci_dev *pci = NULL;
551 int card;
552
553 card = 0;
554
555 while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) {
556 struct prealloc_dev *dev;
557 unsigned int i;
558 if (card >= SNDRV_CARDS)
559 break;
560 for (dev = prealloc_devices; dev->vendor; dev++) {
561 if (dev->vendor == pci->vendor && dev->device == pci->device)
562 break;
563 }
564 if (! dev->vendor)
565 continue;
566 if (! enable[card++]) {
567 printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device);
568 continue;
569 }
570
571 if (pci_set_dma_mask(pci, dev->dma_mask) < 0 ||
572 pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) {
573 printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device);
574 continue;
575 }
576 for (i = 0; i < dev->buffers; i++) {
577 struct snd_dma_buffer dmab;
578 memset(&dmab, 0, sizeof(dmab));
579 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
580 dev->size, &dmab) < 0)
581 printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size);
582 else
583 snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
584 }
585 }
586}
587#else
588#define preallocate_cards() /* NOP */
589#endif
590
591
592#ifdef CONFIG_PROC_FS 509#ifdef CONFIG_PROC_FS
593/* 510/*
594 * proc file interface 511 * proc file interface
595 */ 512 */
513#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
514struct proc_dir_entry *snd_mem_proc;
515
596static int snd_mem_proc_read(char *page, char **start, off_t off, 516static int snd_mem_proc_read(char *page, char **start, off_t off,
597 int count, int *eof, void *data) 517 int count, int *eof, void *data)
598{ 518{
@@ -621,6 +541,97 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
621 up(&list_mutex); 541 up(&list_mutex);
622 return len; 542 return len;
623} 543}
544
545/* FIXME: for pci only - other bus? */
546#ifdef CONFIG_PCI
547#define gettoken(bufp) strsep(bufp, " \t\n")
548
549static int snd_mem_proc_write(struct file *file, const char __user *buffer,
550 unsigned long count, void *data)
551{
552 char buf[128];
553 char *token, *p;
554
555 if (count > ARRAY_SIZE(buf) - 1)
556 count = ARRAY_SIZE(buf) - 1;
557 if (copy_from_user(buf, buffer, count))
558 return -EFAULT;
559 buf[ARRAY_SIZE(buf) - 1] = '\0';
560
561 p = buf;
562 token = gettoken(&p);
563 if (! token || *token == '#')
564 return (int)count;
565 if (strcmp(token, "add") == 0) {
566 char *endp;
567 int vendor, device, size, buffers;
568 long mask;
569 int i, alloced;
570 struct pci_dev *pci;
571
572 if ((token = gettoken(&p)) == NULL ||
573 (vendor = simple_strtol(token, NULL, 0)) <= 0 ||
574 (token = gettoken(&p)) == NULL ||
575 (device = simple_strtol(token, NULL, 0)) <= 0 ||
576 (token = gettoken(&p)) == NULL ||
577 (mask = simple_strtol(token, NULL, 0)) < 0 ||
578 (token = gettoken(&p)) == NULL ||
579 (size = memparse(token, &endp)) < 64*1024 ||
580 size > 16*1024*1024 /* too big */ ||
581 (token = gettoken(&p)) == NULL ||
582 (buffers = simple_strtol(token, NULL, 0)) <= 0 ||
583 buffers > 4) {
584 printk(KERN_ERR "snd-page-alloc: invalid proc write format\n");
585 return (int)count;
586 }
587 vendor &= 0xffff;
588 device &= 0xffff;
589
590 alloced = 0;
591 pci = NULL;
592 while ((pci = pci_find_device(vendor, device, pci)) != NULL) {
593 if (mask > 0 && mask < 0xffffffff) {
594 if (pci_set_dma_mask(pci, mask) < 0 ||
595 pci_set_consistent_dma_mask(pci, mask) < 0) {
596 printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
597 return (int)count;
598 }
599 }
600 for (i = 0; i < buffers; i++) {
601 struct snd_dma_buffer dmab;
602 memset(&dmab, 0, sizeof(dmab));
603 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
604 size, &dmab) < 0) {
605 printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
606 return (int)count;
607 }
608 snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
609 }
610 alloced++;
611 }
612 if (! alloced) {
613 for (i = 0; i < buffers; i++) {
614 struct snd_dma_buffer dmab;
615 memset(&dmab, 0, sizeof(dmab));
616 /* FIXME: We can allocate only in ZONE_DMA
617 * without a device pointer!
618 */
619 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
620 size, &dmab) < 0) {
621 printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
622 break;
623 }
624 snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
625 }
626 }
627 } else if (strcmp(token, "erase") == 0)
628 /* FIXME: need for releasing each buffer chunk? */
629 free_all_reserved_pages();
630 else
631 printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n");
632 return (int)count;
633}
634#endif /* CONFIG_PCI */
624#endif /* CONFIG_PROC_FS */ 635#endif /* CONFIG_PROC_FS */
625 636
626/* 637/*
@@ -630,15 +641,21 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
630static int __init snd_mem_init(void) 641static int __init snd_mem_init(void)
631{ 642{
632#ifdef CONFIG_PROC_FS 643#ifdef CONFIG_PROC_FS
633 create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL); 644 snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL);
645 if (snd_mem_proc) {
646 snd_mem_proc->read_proc = snd_mem_proc_read;
647#ifdef CONFIG_PCI
648 snd_mem_proc->write_proc = snd_mem_proc_write;
649#endif
650 }
634#endif 651#endif
635 preallocate_cards();
636 return 0; 652 return 0;
637} 653}
638 654
639static void __exit snd_mem_exit(void) 655static void __exit snd_mem_exit(void)
640{ 656{
641 remove_proc_entry("driver/snd-page-alloc", NULL); 657 if (snd_mem_proc)
658 remove_proc_entry(SND_MEM_PROC_FILE, NULL);
642 free_all_reserved_pages(); 659 free_all_reserved_pages();
643 if (snd_allocated_pages > 0) 660 if (snd_allocated_pages > 0)
644 printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); 661 printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index b35ed5f0c04..a673cc438b9 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -559,18 +559,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
559{ 559{
560 dmab->dev.type = SNDRV_DMA_TYPE_DEV; 560 dmab->dev.type = SNDRV_DMA_TYPE_DEV;
561 dmab->dev.dev = snd_dma_pci_data(pci); 561 dmab->dev.dev = snd_dma_pci_data(pci);
562 if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { 562 if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
563 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 563 if (dmab->bytes >= size)
564 size, dmab) < 0) 564 return 0;
565 return -ENOMEM;
566 } 565 }
566 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
567 size, dmab) < 0)
568 return -ENOMEM;
567 return 0; 569 return 0;
568} 570}
569 571
570static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) 572static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
571{ 573{
572 if (dmab->area) 574 if (dmab->area) {
575 dmab->dev.dev = NULL; /* make it anonymous */
573 snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); 576 snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
577 }
574} 578}
575 579
576 580
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index 5861f234af2..f3037402d58 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -303,18 +303,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
303{ 303{
304 dmab->dev.type = SNDRV_DMA_TYPE_DEV; 304 dmab->dev.type = SNDRV_DMA_TYPE_DEV;
305 dmab->dev.dev = snd_dma_pci_data(pci); 305 dmab->dev.dev = snd_dma_pci_data(pci);
306 if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { 306 if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
307 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 307 if (dmab->bytes >= size)
308 size, dmab) < 0) 308 return 0;
309 return -ENOMEM;
310 } 309 }
310 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
311 size, dmab) < 0)
312 return -ENOMEM;
311 return 0; 313 return 0;
312} 314}
313 315
314static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) 316static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
315{ 317{
316 if (dmab->area) 318 if (dmab->area) {
319 dmab->dev.dev = NULL; /* make it anonymous */
317 snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); 320 snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
321 }
318} 322}
319 323
320 324