diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-05-30 12:27:03 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-06-22 06:27:47 -0400 |
commit | b6a969155b04416185f368bd4e2f1d49b17c1ee1 (patch) | |
tree | c6db67bdc4b4d107902cf6ced9d66fb0ab15600c | |
parent | 4d572776d4dfa2d5385a2ec3acec3cc059149e13 (diff) |
[ALSA] Add write support to snd-page-alloc proc file
Documentation,Memalloc module,RME HDSP driver,RME9652 driver
Add the write support to snd-page-alloc proc file for buffer pre-allocation.
Removed the pre-allocation codes via module options.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | Documentation/sound/alsa/ALSA-Configuration.txt | 36 | ||||
-rw-r--r-- | sound/core/memalloc.c | 201 | ||||
-rw-r--r-- | sound/pci/rme9652/hdsp.c | 14 | ||||
-rw-r--r-- | sound/pci/rme9652/rme9652.c | 14 |
4 files changed, 161 insertions, 104 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 226013035d72..812ed2b80b8d 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 | ||
1550 | Early Buffer Allocation | ||
1551 | ======================= | ||
1552 | |||
1553 | Some drivers (e.g. hdsp) require the large contiguous buffers, and | ||
1554 | sometimes it's too late to find such spaces when the driver module is | ||
1555 | actually loaded due to memory fragmentation. You can pre-allocate the | ||
1556 | PCM buffers by loading snd-page-alloc module and write commands to its | ||
1557 | proc file in prior, for example, in the early boot stage like | ||
1558 | /etc/init.d/*.local scripts. | ||
1559 | |||
1560 | Reading the proc file /proc/drivers/snd-page-alloc shows the current | ||
1561 | usage of page allocation. In writing, you can send the following | ||
1562 | commands 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 | |||
1548 | Links | 1580 | Links |
1549 | ===== | 1581 | ===== |
1550 | 1582 | ||
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 344a83fd7c2e..dbc23e35fa06 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 | ||
51 | static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; | ||
52 | module_param_array(enable, bool, NULL, 0444); | ||
53 | MODULE_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? */ | ||
518 | struct 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 | |||
528 | static 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 | |||
548 | static 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" | ||
514 | struct proc_dir_entry *snd_mem_proc; | ||
515 | |||
596 | static int snd_mem_proc_read(char *page, char **start, off_t off, | 516 | static 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 | |||
549 | static 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, | |||
630 | static int __init snd_mem_init(void) | 641 | static 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 | ||
639 | static void __exit snd_mem_exit(void) | 655 | static 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 b35ed5f0c042..a673cc438b91 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 | ||
570 | static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) | 572 | static 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 5861f234af21..f3037402d58f 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 | ||
314 | static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) | 316 | static 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 | ||