mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
[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>
This commit is contained in:
parent
4d572776d4
commit
b6a969155b
@ -671,7 +671,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
module did formerly. It will allocate the buffers in advance
|
||||
when any HDSP cards are found. To make the buffer
|
||||
allocation sure, load snd-page-alloc module in the early
|
||||
stage of boot sequence.
|
||||
stage of boot sequence. See "Early Buffer Allocation"
|
||||
section.
|
||||
|
||||
Module snd-ice1712
|
||||
------------------
|
||||
@ -1067,7 +1068,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
module did formerly. It will allocate the buffers in advance
|
||||
when any RME9652 cards are found. To make the buffer
|
||||
allocation sure, load snd-page-alloc module in the early
|
||||
stage of boot sequence.
|
||||
stage of boot sequence. See "Early Buffer Allocation"
|
||||
section.
|
||||
|
||||
Module snd-sa11xx-uda1341 (on arm only)
|
||||
---------------------------------------
|
||||
@ -1545,6 +1547,36 @@ Proc interfaces (/proc/asound)
|
||||
echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss
|
||||
|
||||
|
||||
Early Buffer Allocation
|
||||
=======================
|
||||
|
||||
Some drivers (e.g. hdsp) require the large contiguous buffers, and
|
||||
sometimes it's too late to find such spaces when the driver module is
|
||||
actually loaded due to memory fragmentation. You can pre-allocate the
|
||||
PCM buffers by loading snd-page-alloc module and write commands to its
|
||||
proc file in prior, for example, in the early boot stage like
|
||||
/etc/init.d/*.local scripts.
|
||||
|
||||
Reading the proc file /proc/drivers/snd-page-alloc shows the current
|
||||
usage of page allocation. In writing, you can send the following
|
||||
commands to the snd-page-alloc driver:
|
||||
|
||||
- add VENDOR DEVICE MASK SIZE BUFFERS
|
||||
|
||||
VENDOR and DEVICE are PCI vendor and device IDs. They take
|
||||
integer numbers (0x prefix is needed for the hex).
|
||||
MASK is the PCI DMA mask. Pass 0 if not restricted.
|
||||
SIZE is the size of each buffer to allocate. You can pass
|
||||
k and m suffix for KB and MB. The max number is 16MB.
|
||||
BUFFERS is the number of buffers to allocate. It must be greater
|
||||
than 0. The max number is 4.
|
||||
|
||||
- erase
|
||||
|
||||
This will erase the all pre-allocated buffers which are not in
|
||||
use.
|
||||
|
||||
|
||||
Links
|
||||
=====
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/semaphore.h>
|
||||
@ -46,13 +47,6 @@ MODULE_LICENSE("GPL");
|
||||
#define SNDRV_CARDS 8
|
||||
#endif
|
||||
|
||||
/* FIXME: so far only some PCI devices have the preallocation table */
|
||||
#ifdef CONFIG_PCI
|
||||
static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
|
||||
#endif
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
@ -451,9 +445,13 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
|
||||
list_for_each(p, &mem_list_head) {
|
||||
mem = list_entry(p, struct snd_mem_list, list);
|
||||
if (mem->id == id &&
|
||||
! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) {
|
||||
(mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
|
||||
! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
|
||||
struct device *dev = dmab->dev.dev;
|
||||
list_del(p);
|
||||
*dmab = mem->buffer;
|
||||
if (dmab->dev.dev == NULL)
|
||||
dmab->dev.dev = dev;
|
||||
kfree(mem);
|
||||
up(&list_mutex);
|
||||
return dmab->bytes;
|
||||
@ -508,91 +506,13 @@ static void free_all_reserved_pages(void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* allocation of buffers for pre-defined devices
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
/* FIXME: for pci only - other bus? */
|
||||
struct prealloc_dev {
|
||||
unsigned short vendor;
|
||||
unsigned short device;
|
||||
unsigned long dma_mask;
|
||||
unsigned int size;
|
||||
unsigned int buffers;
|
||||
};
|
||||
|
||||
#define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000)
|
||||
|
||||
static struct prealloc_dev prealloc_devices[] __initdata = {
|
||||
{
|
||||
/* hammerfall */
|
||||
.vendor = 0x10ee,
|
||||
.device = 0x3fc4,
|
||||
.dma_mask = 0xffffffff,
|
||||
.size = HAMMERFALL_BUFFER_SIZE,
|
||||
.buffers = 2
|
||||
},
|
||||
{
|
||||
/* HDSP */
|
||||
.vendor = 0x10ee,
|
||||
.device = 0x3fc5,
|
||||
.dma_mask = 0xffffffff,
|
||||
.size = HAMMERFALL_BUFFER_SIZE,
|
||||
.buffers = 2
|
||||
},
|
||||
{ }, /* terminator */
|
||||
};
|
||||
|
||||
static void __init preallocate_cards(void)
|
||||
{
|
||||
struct pci_dev *pci = NULL;
|
||||
int card;
|
||||
|
||||
card = 0;
|
||||
|
||||
while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) {
|
||||
struct prealloc_dev *dev;
|
||||
unsigned int i;
|
||||
if (card >= SNDRV_CARDS)
|
||||
break;
|
||||
for (dev = prealloc_devices; dev->vendor; dev++) {
|
||||
if (dev->vendor == pci->vendor && dev->device == pci->device)
|
||||
break;
|
||||
}
|
||||
if (! dev->vendor)
|
||||
continue;
|
||||
if (! enable[card++]) {
|
||||
printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pci_set_dma_mask(pci, dev->dma_mask) < 0 ||
|
||||
pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) {
|
||||
printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device);
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < dev->buffers; i++) {
|
||||
struct snd_dma_buffer dmab;
|
||||
memset(&dmab, 0, sizeof(dmab));
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
dev->size, &dmab) < 0)
|
||||
printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size);
|
||||
else
|
||||
snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define preallocate_cards() /* NOP */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/*
|
||||
* proc file interface
|
||||
*/
|
||||
#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
|
||||
struct proc_dir_entry *snd_mem_proc;
|
||||
|
||||
static int snd_mem_proc_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
@ -621,6 +541,97 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
|
||||
up(&list_mutex);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* FIXME: for pci only - other bus? */
|
||||
#ifdef CONFIG_PCI
|
||||
#define gettoken(bufp) strsep(bufp, " \t\n")
|
||||
|
||||
static int snd_mem_proc_write(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
char buf[128];
|
||||
char *token, *p;
|
||||
|
||||
if (count > ARRAY_SIZE(buf) - 1)
|
||||
count = ARRAY_SIZE(buf) - 1;
|
||||
if (copy_from_user(buf, buffer, count))
|
||||
return -EFAULT;
|
||||
buf[ARRAY_SIZE(buf) - 1] = '\0';
|
||||
|
||||
p = buf;
|
||||
token = gettoken(&p);
|
||||
if (! token || *token == '#')
|
||||
return (int)count;
|
||||
if (strcmp(token, "add") == 0) {
|
||||
char *endp;
|
||||
int vendor, device, size, buffers;
|
||||
long mask;
|
||||
int i, alloced;
|
||||
struct pci_dev *pci;
|
||||
|
||||
if ((token = gettoken(&p)) == NULL ||
|
||||
(vendor = simple_strtol(token, NULL, 0)) <= 0 ||
|
||||
(token = gettoken(&p)) == NULL ||
|
||||
(device = simple_strtol(token, NULL, 0)) <= 0 ||
|
||||
(token = gettoken(&p)) == NULL ||
|
||||
(mask = simple_strtol(token, NULL, 0)) < 0 ||
|
||||
(token = gettoken(&p)) == NULL ||
|
||||
(size = memparse(token, &endp)) < 64*1024 ||
|
||||
size > 16*1024*1024 /* too big */ ||
|
||||
(token = gettoken(&p)) == NULL ||
|
||||
(buffers = simple_strtol(token, NULL, 0)) <= 0 ||
|
||||
buffers > 4) {
|
||||
printk(KERN_ERR "snd-page-alloc: invalid proc write format\n");
|
||||
return (int)count;
|
||||
}
|
||||
vendor &= 0xffff;
|
||||
device &= 0xffff;
|
||||
|
||||
alloced = 0;
|
||||
pci = NULL;
|
||||
while ((pci = pci_find_device(vendor, device, pci)) != NULL) {
|
||||
if (mask > 0 && mask < 0xffffffff) {
|
||||
if (pci_set_dma_mask(pci, mask) < 0 ||
|
||||
pci_set_consistent_dma_mask(pci, mask) < 0) {
|
||||
printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
|
||||
return (int)count;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < buffers; i++) {
|
||||
struct snd_dma_buffer dmab;
|
||||
memset(&dmab, 0, sizeof(dmab));
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
size, &dmab) < 0) {
|
||||
printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
|
||||
return (int)count;
|
||||
}
|
||||
snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
|
||||
}
|
||||
alloced++;
|
||||
}
|
||||
if (! alloced) {
|
||||
for (i = 0; i < buffers; i++) {
|
||||
struct snd_dma_buffer dmab;
|
||||
memset(&dmab, 0, sizeof(dmab));
|
||||
/* FIXME: We can allocate only in ZONE_DMA
|
||||
* without a device pointer!
|
||||
*/
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
|
||||
size, &dmab) < 0) {
|
||||
printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
|
||||
break;
|
||||
}
|
||||
snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
|
||||
}
|
||||
}
|
||||
} else if (strcmp(token, "erase") == 0)
|
||||
/* FIXME: need for releasing each buffer chunk? */
|
||||
free_all_reserved_pages();
|
||||
else
|
||||
printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n");
|
||||
return (int)count;
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
/*
|
||||
@ -630,15 +641,21 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
|
||||
static int __init snd_mem_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL);
|
||||
snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL);
|
||||
if (snd_mem_proc) {
|
||||
snd_mem_proc->read_proc = snd_mem_proc_read;
|
||||
#ifdef CONFIG_PCI
|
||||
snd_mem_proc->write_proc = snd_mem_proc_write;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
preallocate_cards();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit snd_mem_exit(void)
|
||||
{
|
||||
remove_proc_entry("driver/snd-page-alloc", NULL);
|
||||
if (snd_mem_proc)
|
||||
remove_proc_entry(SND_MEM_PROC_FILE, NULL);
|
||||
free_all_reserved_pages();
|
||||
if (snd_allocated_pages > 0)
|
||||
printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
|
||||
|
@ -559,18 +559,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
|
||||
{
|
||||
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
dmab->dev.dev = snd_dma_pci_data(pci);
|
||||
if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
size, dmab) < 0)
|
||||
return -ENOMEM;
|
||||
if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
|
||||
if (dmab->bytes >= size)
|
||||
return 0;
|
||||
}
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
size, dmab) < 0)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
|
||||
{
|
||||
if (dmab->area)
|
||||
if (dmab->area) {
|
||||
dmab->dev.dev = NULL; /* make it anonymous */
|
||||
snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -303,18 +303,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
|
||||
{
|
||||
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
dmab->dev.dev = snd_dma_pci_data(pci);
|
||||
if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
size, dmab) < 0)
|
||||
return -ENOMEM;
|
||||
if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
|
||||
if (dmab->bytes >= size)
|
||||
return 0;
|
||||
}
|
||||
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
|
||||
size, dmab) < 0)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
|
||||
{
|
||||
if (dmab->area)
|
||||
if (dmab->area) {
|
||||
dmab->dev.dev = NULL; /* make it anonymous */
|
||||
snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user