Commit b6a969155b04416185f368bd4e2f1d49b17c1ee1

Authored by Takashi Iwai
Committed by Jaroslav Kysela
1 parent 4d572776d4

[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