Commit b6a969155b04416185f368bd4e2f1d49b17c1ee1
Committed by
Jaroslav Kysela
1 parent
4d572776d4
Exists in
master
and in
39 other branches
[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>
Showing 4 changed files with 161 additions and 104 deletions Side-by-side Diff
Documentation/sound/alsa/ALSA-Configuration.txt
... | ... | @@ -671,7 +671,8 @@ |
671 | 671 | module did formerly. It will allocate the buffers in advance |
672 | 672 | when any HDSP cards are found. To make the buffer |
673 | 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 | 677 | Module snd-ice1712 |
677 | 678 | ------------------ |
... | ... | @@ -1067,7 +1068,8 @@ |
1067 | 1068 | module did formerly. It will allocate the buffers in advance |
1068 | 1069 | when any RME9652 cards are found. To make the buffer |
1069 | 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 | 1074 | Module snd-sa11xx-uda1341 (on arm only) |
1073 | 1075 | --------------------------------------- |
... | ... | @@ -1543,6 +1545,36 @@ |
1543 | 1545 | Example: echo "x11amp 128 16384" > /proc/asound/card0/pcm0p/oss |
1544 | 1546 | echo "squake 0 0 disable" > /proc/asound/card0/pcm0c/oss |
1545 | 1547 | echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss |
1548 | + | |
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. | |
1546 | 1578 | |
1547 | 1579 | |
1548 | 1580 | Links |
sound/core/memalloc.c
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | #include <linux/pci.h> |
29 | 29 | #include <linux/slab.h> |
30 | 30 | #include <linux/mm.h> |
31 | +#include <asm/uaccess.h> | |
31 | 32 | #include <linux/dma-mapping.h> |
32 | 33 | #include <linux/moduleparam.h> |
33 | 34 | #include <asm/semaphore.h> |
... | ... | @@ -46,13 +47,6 @@ |
46 | 47 | #define SNDRV_CARDS 8 |
47 | 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 | |
59 | 53 | |
... | ... | @@ -451,9 +445,13 @@ |
451 | 445 | list_for_each(p, &mem_list_head) { |
452 | 446 | mem = list_entry(p, struct snd_mem_list, list); |
453 | 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 | 451 | list_del(p); |
456 | 452 | *dmab = mem->buffer; |
453 | + if (dmab->dev.dev == NULL) | |
454 | + dmab->dev.dev = dev; | |
457 | 455 | kfree(mem); |
458 | 456 | up(&list_mutex); |
459 | 457 | return dmab->bytes; |
460 | 458 | |
... | ... | @@ -508,91 +506,13 @@ |
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 | 509 | #ifdef CONFIG_PROC_FS |
593 | 510 | /* |
594 | 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 | 516 | static int snd_mem_proc_read(char *page, char **start, off_t off, |
597 | 517 | int count, int *eof, void *data) |
598 | 518 | { |
... | ... | @@ -621,6 +541,97 @@ |
621 | 541 | up(&list_mutex); |
622 | 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 | 635 | #endif /* CONFIG_PROC_FS */ |
625 | 636 | |
626 | 637 | /* |
627 | 638 | |
628 | 639 | |
... | ... | @@ -630,15 +641,21 @@ |
630 | 641 | static int __init snd_mem_init(void) |
631 | 642 | { |
632 | 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; | |
634 | 649 | #endif |
635 | - preallocate_cards(); | |
650 | + } | |
651 | +#endif | |
636 | 652 | return 0; |
637 | 653 | } |
638 | 654 | |
639 | 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 | 659 | free_all_reserved_pages(); |
643 | 660 | if (snd_allocated_pages > 0) |
644 | 661 | printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); |
sound/pci/rme9652/hdsp.c
... | ... | @@ -559,18 +559,22 @@ |
559 | 559 | { |
560 | 560 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; |
561 | 561 | dmab->dev.dev = snd_dma_pci_data(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), | |
564 | - size, dmab) < 0) | |
565 | - return -ENOMEM; | |
562 | + if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { | |
563 | + if (dmab->bytes >= size) | |
564 | + return 0; | |
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 | 569 | return 0; |
568 | 570 | } |
569 | 571 | |
570 | 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 | 576 | snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); |
577 | + } | |
574 | 578 | } |
575 | 579 | |
576 | 580 |
sound/pci/rme9652/rme9652.c
... | ... | @@ -303,18 +303,22 @@ |
303 | 303 | { |
304 | 304 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; |
305 | 305 | dmab->dev.dev = snd_dma_pci_data(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), | |
308 | - size, dmab) < 0) | |
309 | - return -ENOMEM; | |
306 | + if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { | |
307 | + if (dmab->bytes >= size) | |
308 | + return 0; | |
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 | 313 | return 0; |
312 | 314 | } |
313 | 315 | |
314 | 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 | 320 | snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); |
321 | + } | |
318 | 322 | } |
319 | 323 | |
320 | 324 |