Update of /cvsroot/alsa/alsa-kernel/core In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18820/alsa-kernel/core
Modified Files: Makefile memalloc.c pcm_lib.c pcm_memory.c sgbuf.c Log Message: Big DMA cleanup originated by Russell King <[EMAIL PROTECTED]> * Russel - introduced 'struct device' support for 2.6 dma_alloc_coherent() * Jaroslav - removed all bus-specific allocation functions - extended snd_dma_alloc_pages/snd_dma_free_pages to handle all bus types - recoded all (or almost all) device drivers - sgbuf functions are bus independent now Index: Makefile =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/core/Makefile,v retrieving revision 1.48 retrieving revision 1.49 diff -u -r1.48 -r1.49 --- Makefile 23 Feb 2004 19:10:23 -0000 1.48 +++ Makefile 2 Mar 2004 15:32:35 -0000 1.49 @@ -15,10 +15,7 @@ snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o -snd-page-alloc-objs := memalloc.o -ifeq ($(CONFIG_PCI),y) -snd-page-alloc-objs += sgbuf.o -endif +snd-page-alloc-objs := memalloc.o sgbuf.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o Index: memalloc.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/core/memalloc.c,v retrieving revision 1.21 retrieving revision 1.22 diff -u -r1.21 -r1.22 --- memalloc.c 19 Jan 2004 18:37:35 -0000 1.21 +++ memalloc.c 2 Mar 2004 15:32:35 -0000 1.22 @@ -43,6 +43,13 @@ MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); +/* + */ + +void *snd_malloc_sgbuf_pages(const struct snd_dma_device *dev, + size_t size, struct snd_dma_buffer *dmab, + size_t *res_size); +int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab); /* */ @@ -73,14 +80,19 @@ #define snd_assert(expr, args...) /**/ #endif +/* + * Hacks + */ + #ifdef CONFIG_PCI + #if defined(__i386__) || defined(__ppc__) || defined(__x86_64__) #define HACK_PCI_ALLOC_CONSISTENT /* - * A hack to allocate large buffers via pci_alloc_consistent() + * A hack to allocate large buffers via dma_alloc_coherent() * - * since pci_alloc_consistent always tries GFP_DMA when the requested + * since dma_alloc_coherent always tries GFP_DMA when the requested * pci memory region is below 32bit, it happens quite often that even * 2 order of pages cannot be allocated. * @@ -88,314 +100,45 @@ * allocation will be done without GFP_DMA. if the area doesn't match * with the requested region, then realloate with the original dma_mask * again. + * + * Really, we want to move this type of thing into dma_alloc_coherent() + * so dma_mask doesn't have to be messed with. */ -static void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) +static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, int flags) { void *ret; - u64 dma_mask, cdma_mask; - unsigned long mask; + u64 dma_mask; - if (hwdev == NULL) - return pci_alloc_consistent(hwdev, size, dma_handle); - dma_mask = hwdev->dma_mask; - cdma_mask = hwdev->consistent_dma_mask; - mask = (unsigned long)dma_mask && (unsigned long)cdma_mask; - hwdev->dma_mask = 0xffffffff; /* do without masking */ - hwdev->consistent_dma_mask = 0xffffffff; /* do without masking */ - ret = pci_alloc_consistent(hwdev, size, dma_handle); - hwdev->dma_mask = dma_mask; /* restore */ - hwdev->consistent_dma_mask = cdma_mask; /* restore */ + if (dev == NULL) + return dma_alloc_coherent(dev, size, dma_handle, flags); + dma_mask = *dev->dma_mask; + *dev->dma_mask = 0xffffffff; /* do without masking */ + ret = dma_alloc_coherent(dev, size, dma_handle, flags); + *dev->dma_mask = dma_mask; /* restore */ if (ret) { /* obtained address is out of range? */ - if (((unsigned long)*dma_handle + size - 1) & ~mask) { + if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) { /* reallocate with the proper mask */ - pci_free_consistent(hwdev, size, ret, *dma_handle); - ret = pci_alloc_consistent(hwdev, size, dma_handle); + dma_free_coherent(dev, size, ret, *dma_handle); + ret = dma_alloc_coherent(dev, size, dma_handle, flags); } } else { /* wish to success now with the proper mask... */ - if (mask != 0xffffffffUL) - ret = pci_alloc_consistent(hwdev, size, dma_handle); + if (dma_mask != 0xffffffffUL) + ret = dma_alloc_coherent(dev, size, dma_handle, flags); } return ret; } -/* redefine pci_alloc_consistent for some architectures */ -#undef pci_alloc_consistent -#define pci_alloc_consistent snd_pci_hack_alloc_consistent +/* redefine dma_alloc_coherent for some architectures */ +#undef dma_alloc_coherent +#define dma_alloc_coherent snd_dma_hack_alloc_coherent #endif /* arch */ #endif /* CONFIG_PCI */ - -/* - * compare the two devices - * returns non-zero if matched. - */ -static int compare_device(const struct snd_dma_device *a, const struct snd_dma_device *b, int allow_unused) -{ - if (a->type != b->type) - return 0; - if (a->id != b->id) { - if (! allow_unused || (a->id != SNDRV_DMA_DEVICE_UNUSED && b->id != SNDRV_DMA_DEVICE_UNUSED)) - return 0; - } - switch (a->type) { - case SNDRV_DMA_TYPE_CONTINUOUS: -#ifdef CONFIG_ISA - case SNDRV_DMA_TYPE_ISA: -#endif - return a->dev.flags == b->dev.flags; -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - case SNDRV_DMA_TYPE_PCI_SG: - return a->dev.pci == b->dev.pci; -#endif -#ifdef CONFIG_SBUS - case SNDRV_DMA_TYPE_SBUS: - return a->dev.sbus == b->dev.sbus; -#endif - } - return 0; -} - -/** - * snd_dma_alloc_pages - allocate the buffer area according to the given type - * @dev: the buffer device info - * @size: the buffer size to allocate - * @dmab: buffer allocation record to store the allocated data - * - * Calls the memory-allocator function for the corresponding - * buffer type. - * - * Returns zero if the buffer with the given size is allocated successfuly, - * other a negative value at error. - */ -int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size, - struct snd_dma_buffer *dmab) -{ - snd_assert(dev != NULL, return -ENXIO); - snd_assert(size > 0, return -ENXIO); - snd_assert(dmab != NULL, return -ENXIO); - - dmab->bytes = 0; - switch (dev->type) { - case SNDRV_DMA_TYPE_CONTINUOUS: - dmab->area = snd_malloc_pages(size, dev->dev.flags); - dmab->addr = 0; - break; -#ifdef CONFIG_ISA - case SNDRV_DMA_TYPE_ISA: - dmab->area = snd_malloc_isa_pages(size, &dmab->addr); - break; -#endif -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - dmab->area = snd_malloc_pci_pages(dev->dev.pci, size, &dmab->addr); - break; - case SNDRV_DMA_TYPE_PCI_SG: - snd_malloc_sgbuf_pages(dev->dev.pci, size, dmab); - break; -#endif -#ifdef CONFIG_SBUS - case SNDRV_DMA_TYPE_SBUS: - dmab->area = snd_malloc_sbus_pages(dev->dev.sbus, size, &dmab->addr); - break; -#endif - default: - printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); - dmab->area = NULL; - dmab->addr = 0; - return -ENXIO; - } - if (! dmab->area) - return -ENOMEM; - dmab->bytes = size; - return 0; -} - - -/** - * snd_dma_free_pages - release the allocated buffer - * @dev: the buffer device info - * @dmbab: the buffer allocation record to release - * - * Releases the allocated buffer via snd_dma_alloc_pages(). - */ -void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab) -{ - switch (dev->type) { - case SNDRV_DMA_TYPE_CONTINUOUS: - snd_free_pages(dmab->area, dmab->bytes); - break; -#ifdef CONFIG_ISA - case SNDRV_DMA_TYPE_ISA: - snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr); - break; -#endif -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - snd_free_pci_pages(dev->dev.pci, dmab->bytes, dmab->area, dmab->addr); - break; - case SNDRV_DMA_TYPE_PCI_SG: - snd_free_sgbuf_pages(dmab); - break; -#endif -#ifdef CONFIG_SBUS - case SNDRV_DMA_TYPE_SBUS: - snd_free_sbus_pages(dev->dev.sbus, dmab->bytes, dmab->area, dmab->addr); - break; -#endif - default: - printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); - } -} - - -/* - * search for the device - */ -static struct snd_mem_list *mem_list_find(const struct snd_dma_device *dev, int search_empty) -{ - struct list_head *p; - struct snd_mem_list *mem; - - list_for_each(p, &mem_list_head) { - mem = list_entry(p, struct snd_mem_list, list); - if (mem->used && search_empty) - continue; - if (compare_device(&mem->dev, dev, search_empty)) - return mem; - } - return NULL; -} - -/** - * snd_dma_get_reserved - get the reserved buffer for the given device - * @dev: the buffer device info - * @dmab: the buffer allocation record to store - * - * Looks for the reserved-buffer list and re-uses if the same buffer - * is found in the list. When the buffer is found, it's marked as used. - * For unmarking the buffer, call snd_dma_free_reserved(). - * - * Returns the size of buffer if the buffer is found, or zero if not found. - */ -size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab) -{ - struct snd_mem_list *mem; - - snd_assert(dev && dmab, return 0); - - down(&list_mutex); - mem = mem_list_find(dev, 1); - if (mem) { - mem->used = 1; - mem->dev = *dev; - *dmab = mem->buffer; - up(&list_mutex); - return dmab->bytes; - } - up(&list_mutex); - return 0; -} - -/** - * snd_dma_free_reserved - unmark the reserved buffer - * @dev: the buffer device info - * - * Looks for the matching reserved buffer and erases the mark on it - * if found. - * - * Returns zero. - */ -int snd_dma_free_reserved(const struct snd_dma_device *dev) -{ - struct snd_mem_list *mem; - - snd_assert(dev, return -EINVAL); - down(&list_mutex); - mem = mem_list_find(dev, 0); - if (mem) - mem->used = 0; - up(&list_mutex); - return 0; -} - -/** - * snd_dma_set_reserved - reserve the buffer - * @dev: the buffer device info - * @dmab: the buffer to reserve - * - * Reserves the given buffer as a reserved buffer. - * When an old reserved buffer already exists, the old one is released - * and replaced with the new one. - * - * When NULL buffer pointer or zero buffer size is given, the existing - * buffer is released and the entry is removed. - * - * Returns zero if successful, or a negative code at error. - */ -int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab) -{ - struct snd_mem_list *mem; - - snd_assert(dev, return -EINVAL); - down(&list_mutex); - mem = mem_list_find(dev, 0); - if (mem) { - if (mem->used) - printk(KERN_WARNING "snd-page-alloc: releasing the used block (type=%d, id=0x%x\n", mem->dev.type, mem->dev.id); - snd_dma_free_pages(dev, &mem->buffer); - if (! dmab || ! dmab->bytes) { - /* remove the entry */ - list_del(&mem->list); - kfree(mem); - up(&list_mutex); - return 0; - } - } else { - if (! dmab || ! dmab->bytes) { - up(&list_mutex); - return 0; - } - mem = kmalloc(sizeof(*mem), GFP_KERNEL); - if (! mem) { - up(&list_mutex); - return -ENOMEM; - } - mem->dev = *dev; - list_add_tail(&mem->list, &mem_list_head); - } - /* store the entry */ - mem->used = 1; - mem->buffer = *dmab; - up(&list_mutex); - return 0; -} - -/* - * purge all reserved buffers - */ -static void free_all_reserved_pages(void) -{ - struct list_head *p; - struct snd_mem_list *mem; - - down(&list_mutex); - while (! list_empty(&mem_list_head)) { - p = mem_list_head.next; - mem = list_entry(p, struct snd_mem_list, list); - list_del(p); - snd_dma_free_pages(&mem->dev, &mem->buffer); - kfree(mem); - } - up(&list_mutex); -} - - /* * * Generic memory allocators @@ -457,7 +200,7 @@ * res_size argument. * * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ + */ void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size) { void *res; @@ -492,18 +235,60 @@ free_pages((unsigned long) ptr, pg); } -#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI) - -/** - * snd_malloc_isa_pages - allocate pages for ISA bus with the given size - * @size: the size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer +/* * - * Allocates the physically contiguous pages with the given size for - * ISA bus. + * Bus-specific memory allocators * - * Returns the pointer of the buffer, or NULL if no enoguh memory. */ + +static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) +{ + int pg; + void *res; + + snd_assert(size > 0, return NULL); + snd_assert(dma != NULL, return NULL); + pg = get_order(size); + res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, GFP_KERNEL); + if (res != NULL) + mark_pages(res, pg); + + return res; +} + +static inline +void *snd_malloc_dev_pages_fallback(struct device *dev, size_t size, + dma_addr_t *dma, size_t *res_size) +{ + void *res; + + snd_assert(res_size != NULL, return NULL); + do { + if ((res = snd_malloc_dev_pages(dev, size, dma)) != NULL) { + *res_size = size; + return res; + } + size >>= 1; + } while (size >= PAGE_SIZE); + return NULL; +} + +static inline +void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, + dma_addr_t dma) +{ + int pg; + + if (ptr == NULL) + return; + pg = get_order(size); + unmark_pages(ptr, pg); + dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); +} + +#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI) + +static inline void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr) { void *dma_area; @@ -512,19 +297,7 @@ return dma_area; } -/** - * snd_malloc_isa_pages_fallback - allocate pages with the given size with fallback for ISA bus - * @size: the requested size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * @res_size: the pointer to store the size of buffer actually allocated - * - * Allocates the physically contiguous pages with the given request - * size for PCI bus. When no space is left, this function reduces the size and - * tries to allocate again. The size actually allocated is stored in - * res_size argument. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ +static inline void *snd_malloc_isa_pages_fallback(size_t size, dma_addr_t *dma_addr, size_t *res_size) @@ -535,24 +308,42 @@ return dma_area; } -#endif /* CONFIG_ISA && !CONFIG_PCI */ +static inline +void snd_free_isa_pages(size_t size, void *ptr, dma_addr_t addr) +{ + return snd_free_pages(ptr, size); +} -#ifdef CONFIG_PCI +#endif -/** - * snd_malloc_pci_pages - allocate pages for PCI bus with the given size - * @pci: the pci device pointer - * @size: the size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * - * Allocates the physically contiguous pages with the given size for - * PCI bus. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_pci_pages(struct pci_dev *pci, - size_t size, - dma_addr_t *dma_addr) +#if defined(CONFIG_ISA) && defined(CONFIG_PCI) + +static inline +void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr) +{ + return snd_malloc_dev_pages(NULL, size, dma_addr); +} + +static inline +void *snd_malloc_isa_pages_fallback(size_t size, + dma_addr_t *dma_addr, + size_t *res_size) +{ + return snd_malloc_dev_pages_fallback(NULL, size, dma_addr, res_size); +} + +static inline +void snd_free_isa_pages(size_t size, void *ptr, dma_addr_t addr) +{ + return snd_free_dev_pages(NULL, size, ptr, addr); +} + +#endif + +#ifdef CONFIG_SBUS + +static void *snd_malloc_sbus_pages(struct sbus_dev *sdev, size_t size, + dma_addr_t *dma_addr) { int pg; void *res; @@ -560,37 +351,21 @@ snd_assert(size > 0, return NULL); snd_assert(dma_addr != NULL, return NULL); for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr); + res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr); if (res != NULL) { mark_pages(res, pg); } return res; } -/** - * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for PCI bus - * @pci: pci device pointer - * @size: the requested size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * @res_size: the pointer to store the size of buffer actually allocated - * - * Allocates the physically contiguous pages with the given request - * size for PCI bus. When no space is left, this function reduces the size and - * tries to allocate again. The size actually allocated is stored in - * res_size argument. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, - size_t size, - dma_addr_t *dma_addr, - size_t *res_size) +static void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, size_t size, + dma_addr_t *dma_addr, size_t *res_size) { void *res; snd_assert(res_size != NULL, return NULL); do { - if ((res = snd_malloc_pci_pages(pci, size, dma_addr)) != NULL) { + if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) { *res_size = size; return res; } @@ -599,190 +374,358 @@ return NULL; } +static void snd_free_sbus_pages(struct sbus_dev *sdev, size_t size, + void *ptr, dma_addr_t dma_addr) +{ + int pg; + + if (ptr == NULL) + return; + for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); + unmark_pages(ptr, pg); + sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr); +} + +#endif /* CONFIG_SBUS */ + +/* + * + * ALSA generic memory management + * + */ + + +/* + * compare the two devices + * returns non-zero if matched. + */ +static int compare_device(const struct snd_dma_device *a, const struct snd_dma_device *b, int allow_unused) +{ + if (a->type != b->type) + return 0; + if (a->id != b->id) { + if (! allow_unused || (a->id != SNDRV_DMA_DEVICE_UNUSED && b->id != SNDRV_DMA_DEVICE_UNUSED)) + return 0; + } + switch (a->type) { + case SNDRV_DMA_TYPE_CONTINUOUS: +#ifdef CONFIG_ISA + case SNDRV_DMA_TYPE_ISA: +#endif + return a->dev.flags == b->dev.flags; +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + return a->dev.sbus == b->dev.sbus; +#endif + case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_SG: + return a->dev.dev == b->dev.dev; + } + return 0; +} + +/** + * snd_dma_alloc_pages - allocate the buffer area according to the given type + * @dev: the buffer device info + * @size: the buffer size to allocate + * @dmab: buffer allocation record to store the allocated data + * + * Calls the memory-allocator function for the corresponding + * buffer type. + * + * Returns zero if the buffer with the given size is allocated successfuly, + * other a negative value at error. + */ +int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size, + struct snd_dma_buffer *dmab) +{ + snd_assert(dev != NULL, return -ENXIO); + snd_assert(size > 0, return -ENXIO); + snd_assert(dmab != NULL, return -ENXIO); + + dmab->bytes = 0; + switch (dev->type) { + case SNDRV_DMA_TYPE_CONTINUOUS: + dmab->area = snd_malloc_pages(size, dev->dev.flags); + dmab->addr = 0; + break; +#ifdef CONFIG_ISA + case SNDRV_DMA_TYPE_ISA: + dmab->area = snd_malloc_isa_pages(size, &dmab->addr); + break; +#endif +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + dmab->area = snd_malloc_sbus_pages(dev->dev.sbus, size, &dmab->addr); + break; +#endif +#ifdef CONFIG_PCI + case SNDRV_DMA_TYPE_PCI: + dmab->area = snd_malloc_dev_pages(&dev->dev.pci->dev, size, &dmab->addr); + break; +#endif + case SNDRV_DMA_TYPE_DEV: + dmab->area = snd_malloc_dev_pages(dev->dev.dev, size, &dmab->addr); + break; + case SNDRV_DMA_TYPE_PCI_SG: + case SNDRV_DMA_TYPE_DEV_SG: + snd_malloc_sgbuf_pages(dev, size, dmab, NULL); + break; + default: + printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); + dmab->area = NULL; + dmab->addr = 0; + return -ENXIO; + } + if (! dmab->area) + return -ENOMEM; + dmab->bytes = size; + return 0; +} + /** - * snd_free_pci_pages - release the pages - * @pci: pci device pointer - * @size: the allocated buffer size - * @ptr: the buffer pointer to release - * @dma_addr: the physical address of the buffer + * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback + * @dev: the buffer device info + * @size: the buffer size to allocate + * @dmab: buffer allocation record to store the allocated data * - * Releases the buffer allocated via snd_malloc_pci_pages(). + * Calls the memory-allocator function for the corresponding + * buffer type. When no space is left, this function reduces the size and + * tries to allocate again. The size actually allocated is stored in + * res_size argument. + * + * Returns zero if the buffer with the given size is allocated successfuly, + * other a negative value at error. */ -void snd_free_pci_pages(struct pci_dev *pci, - size_t size, - void *ptr, - dma_addr_t dma_addr) +int snd_dma_alloc_pages_fallback(const struct snd_dma_device *dev, size_t size, + struct snd_dma_buffer *dmab) { - int pg; + snd_assert(dev != NULL, return -ENXIO); + snd_assert(size > 0, return -ENXIO); + snd_assert(dmab != NULL, return -ENXIO); - if (ptr == NULL) - return; - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - unmark_pages(ptr, pg); - pci_free_consistent(pci, PAGE_SIZE * (1 << pg), ptr, dma_addr); + dmab->bytes = 0; + switch (dev->type) { + case SNDRV_DMA_TYPE_CONTINUOUS: + dmab->area = snd_malloc_pages_fallback(size, dev->dev.flags, &dmab->bytes); + dmab->addr = 0; + break; +#ifdef CONFIG_ISA + case SNDRV_DMA_TYPE_ISA: + dmab->area = snd_malloc_isa_pages_fallback(size, &dmab->addr, &dmab->bytes); + break; +#endif +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + dmab->area = snd_malloc_sbus_pages_fallback(dev->dev.sbus, size, &dmab->addr, &dmab->bytes); + break; +#endif +#ifdef CONFIG_PCI + case SNDRV_DMA_TYPE_PCI: + dmab->area = snd_malloc_dev_pages_fallback(&dev->dev.pci->dev, size, &dmab->addr, &dmab->bytes); + break; +#endif + case SNDRV_DMA_TYPE_DEV: + dmab->area = snd_malloc_dev_pages_fallback(dev->dev.dev, size, &dmab->addr, &dmab->bytes); + break; + case SNDRV_DMA_TYPE_PCI_SG: + case SNDRV_DMA_TYPE_DEV_SG: + snd_malloc_sgbuf_pages(dev, size, dmab, &dmab->bytes); + break; + default: + printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); + dmab->area = NULL; + dmab->addr = 0; + return -ENXIO; + } + if (! dmab->area) + return -ENOMEM; + return 0; } -#if defined(__i386__) -/* - * on ix86, we allocate a page with GFP_KERNEL to assure the - * allocation. the code is almost same with kernel/i386/pci-dma.c but - * it allocates only a single page and checks the validity of the - * page address with the given pci dma mask. - */ - /** - * snd_malloc_pci_page - allocate a page in the valid pci dma mask - * @pci: pci device pointer - * @addrp: the pointer to store the physical address of the buffer + * snd_dma_free_pages - release the allocated buffer + * @dev: the buffer device info + * @dmbab: the buffer allocation record to release * - * Allocates a single page for the given PCI device and returns - * the virtual address and stores the physical address on addrp. - * - * This function cannot be called from interrupt handlers or - * within spinlocks. + * Releases the allocated buffer via snd_dma_alloc_pages(). */ -void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp) +void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab) { - void *ptr; - dma_addr_t addr; - unsigned long mask; - - mask = pci ? (unsigned long)pci->consistent_dma_mask : 0x00ffffffUL; - ptr = (void *)__get_free_page(GFP_KERNEL); - if (ptr) { - addr = virt_to_phys(ptr); - if (((unsigned long)addr + PAGE_SIZE - 1) & ~mask) { - /* try to reallocate with the GFP_DMA */ - free_page((unsigned long)ptr); - /* use GFP_ATOMIC for the DMA zone to avoid stall */ - ptr = (void *)__get_free_page(GFP_ATOMIC | GFP_DMA); - if (ptr) /* ok, the address must be within lower 16MB... */ - addr = virt_to_phys(ptr); - else - addr = 0; - } - } else - addr = 0; - if (ptr) { - memset(ptr, 0, PAGE_SIZE); - mark_pages(ptr, 0); + switch (dev->type) { + case SNDRV_DMA_TYPE_CONTINUOUS: + snd_free_pages(dmab->area, dmab->bytes); + break; +#ifdef CONFIG_ISA + case SNDRV_DMA_TYPE_ISA: + snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr); + break; +#endif +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + snd_free_sbus_pages(dev->dev.sbus, dmab->bytes, dmab->area, dmab->addr); + break; +#endif +#ifdef CONFIG_PCI + case SNDRV_DMA_TYPE_PCI: + snd_free_dev_pages(&dev->dev.pci->dev, dmab->bytes, dmab->area, dmab->addr); + break; +#endif + case SNDRV_DMA_TYPE_DEV: + snd_free_dev_pages(dev->dev.dev, dmab->bytes, dmab->area, dmab->addr); + break; + case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_PCI_SG: + snd_free_sgbuf_pages(dmab); + break; + default: + printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); } - *addrp = addr; - return ptr; } -#else -/* on other architectures, call snd_malloc_pci_pages() helper function - * which uses pci_alloc_consistent(). + +/* + * search for the device */ -void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp) +static struct snd_mem_list *mem_list_find(const struct snd_dma_device *dev, int search_empty) { - return snd_malloc_pci_pages(pci, PAGE_SIZE, addrp); -} + struct list_head *p; + struct snd_mem_list *mem; -#endif + list_for_each(p, &mem_list_head) { + mem = list_entry(p, struct snd_mem_list, list); + if (mem->used && search_empty) + continue; + if (compare_device(&mem->dev, dev, search_empty)) + return mem; + } + return NULL; +} -#if 0 /* for kernel-doc */ /** - * snd_free_pci_page - release a page - * @pci: pci device pointer - * @ptr: the buffer pointer to release - * @dma_addr: the physical address of the buffer + * snd_dma_get_reserved - get the reserved buffer for the given device + * @dev: the buffer device info + * @dmab: the buffer allocation record to store + * + * Looks for the reserved-buffer list and re-uses if the same buffer + * is found in the list. When the buffer is found, it's marked as used. + * For unmarking the buffer, call snd_dma_free_reserved(). * - * Releases the buffer allocated via snd_malloc_pci_page(). + * Returns the size of buffer if the buffer is found, or zero if not found. */ -void snd_free_pci_page(struct pci_dev *pci, void *ptr, dma_addr_t dma_addr); -#endif /* for kernel-doc */ +size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab) +{ + struct snd_mem_list *mem; -#endif /* CONFIG_PCI */ + snd_assert(dev && dmab, return 0); -#ifdef CONFIG_SBUS + down(&list_mutex); + mem = mem_list_find(dev, 1); + if (mem) { + mem->used = 1; + mem->dev = *dev; + *dmab = mem->buffer; + up(&list_mutex); + return dmab->bytes; + } + up(&list_mutex); + return 0; +} /** - * snd_malloc_sbus_pages - allocate pages for SBUS with the given size - * @sdev: sbus device pointer - * @size: the size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer + * snd_dma_free_reserved - unmark the reserved buffer + * @dev: the buffer device info * - * Allocates the physically contiguous pages with the given size for - * SBUS. + * Looks for the matching reserved buffer and erases the mark on it + * if found. * - * Returns the pointer of the buffer, or NULL if no enoguh memory. + * Returns zero. */ -void *snd_malloc_sbus_pages(struct sbus_dev *sdev, - size_t size, - dma_addr_t *dma_addr) +int snd_dma_free_reserved(const struct snd_dma_device *dev) { - int pg; - void *res; + struct snd_mem_list *mem; - snd_assert(size > 0, return NULL); - snd_assert(dma_addr != NULL, return NULL); - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr); - if (res != NULL) { - mark_pages(res, pg); - } - return res; + snd_assert(dev, return -EINVAL); + down(&list_mutex); + mem = mem_list_find(dev, 0); + if (mem) + mem->used = 0; + up(&list_mutex); + return 0; } /** - * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for SBUS - * @sdev: sbus device pointer - * @size: the requested size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * @res_size: the pointer to store the size of buffer actually allocated + * snd_dma_set_reserved - reserve the buffer + * @dev: the buffer device info + * @dmab: the buffer to reserve * - * Allocates the physically contiguous pages with the given request - * size for SBUS. When no space is left, this function reduces the size and - * tries to allocate again. The size actually allocated is stored in - * res_size argument. + * Reserves the given buffer as a reserved buffer. + * When an old reserved buffer already exists, the old one is released + * and replaced with the new one. * - * Returns the pointer of the buffer, or NULL if no enoguh memory. + * When NULL buffer pointer or zero buffer size is given, the existing + * buffer is released and the entry is removed. + * + * Returns zero if successful, or a negative code at error. */ -void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, - size_t size, - dma_addr_t *dma_addr, - size_t *res_size) +int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab) { - void *res; + struct snd_mem_list *mem; - snd_assert(res_size != NULL, return NULL); - do { - if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) { - *res_size = size; - return res; + snd_assert(dev, return -EINVAL); + down(&list_mutex); + mem = mem_list_find(dev, 0); + if (mem) { + if (mem->used) + printk(KERN_WARNING "snd-page-alloc: releasing the used block (type=%d, id=0x%x\n", mem->dev.type, mem->dev.id); + snd_dma_free_pages(dev, &mem->buffer); + if (! dmab || ! dmab->bytes) { + /* remove the entry */ + list_del(&mem->list); + kfree(mem); + up(&list_mutex); + return 0; } - size >>= 1; - } while (size >= PAGE_SIZE); - return NULL; + } else { + if (! dmab || ! dmab->bytes) { + up(&list_mutex); + return 0; + } + mem = kmalloc(sizeof(*mem), GFP_KERNEL); + if (! mem) { + up(&list_mutex); + return -ENOMEM; + } + mem->dev = *dev; + list_add_tail(&mem->list, &mem_list_head); + } + /* store the entry */ + mem->used = 1; + mem->buffer = *dmab; + up(&list_mutex); + return 0; } -/** - * snd_free_sbus_pages - release the pages - * @sdev: sbus device pointer - * @size: the allocated buffer size - * @ptr: the buffer pointer to release - * @dma_addr: the physical address of the buffer - * - * Releases the buffer allocated via snd_malloc_pci_pages(). +/* + * purge all reserved buffers */ -void snd_free_sbus_pages(struct sbus_dev *sdev, - size_t size, - void *ptr, - dma_addr_t dma_addr) +static void free_all_reserved_pages(void) { - int pg; + struct list_head *p; + struct snd_mem_list *mem; - if (ptr == NULL) - return; - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - unmark_pages(ptr, pg); - sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr); + down(&list_mutex); + while (! list_empty(&mem_list_head)) { + p = mem_list_head.next; + mem = list_entry(p, struct snd_mem_list, list); + list_del(p); + snd_dma_free_pages(&mem->dev, &mem->buffer); + kfree(mem); + } + up(&list_mutex); } -#endif /* CONFIG_SBUS */ /* @@ -821,6 +764,17 @@ { }, /* terminator */ }; +/* + * compose a snd_dma_device struct for the PCI device + */ +static inline void snd_dma_device_pci(struct snd_dma_device *dev, struct pci_dev *pci, unsigned int id) +{ + memset(dev, 0, sizeof(*dev)); + dev->type = SNDRV_DMA_TYPE_DEV; + dev->dev.dev = &pci->dev; + dev->id = id; +} + static void __init preallocate_cards(void) { struct pci_dev *pci = NULL; @@ -904,17 +858,6 @@ case SNDRV_DMA_TYPE_CONTINUOUS: len += sprintf(page + len, "CONT [%x]", mem->dev.dev.flags); break; -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - case SNDRV_DMA_TYPE_PCI_SG: - if (mem->dev.dev.pci) { - len += sprintf(page + len, "%s [%04x:%04x]", - mem->dev.type == SNDRV_DMA_TYPE_PCI ? "PCI" : "PCI-SG", - mem->dev.dev.pci->vendor, - mem->dev.dev.pci->device); - } - break; -#endif #ifdef CONFIG_ISA case SNDRV_DMA_TYPE_ISA: len += sprintf(page + len, "ISA [%x]", mem->dev.dev.flags); @@ -925,6 +868,14 @@ len += sprintf(page + len, "SBUS [%x]", mem->dev.dev.sbus->slot); break; #endif + case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_SG: + if (mem->dev.dev.dev) { + len += sprintf(page + len, "%s [%s]", + mem->dev.type == SNDRV_DMA_TYPE_DEV_SG ? "DEV" : "DEV-SG", + mem->dev.dev.dev->bus_id); + } + break; default: len += sprintf(page + len, "UNKNOWN"); break; @@ -986,8 +937,12 @@ /* * exports */ +EXPORT_SYMBOL(snd_dma_device_init); + EXPORT_SYMBOL(snd_dma_alloc_pages); +EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); EXPORT_SYMBOL(snd_dma_free_pages); + EXPORT_SYMBOL(snd_dma_get_reserved); EXPORT_SYMBOL(snd_dma_free_reserved); EXPORT_SYMBOL(snd_dma_set_reserved); @@ -995,20 +950,3 @@ EXPORT_SYMBOL(snd_malloc_pages); EXPORT_SYMBOL(snd_malloc_pages_fallback); EXPORT_SYMBOL(snd_free_pages); -#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI) -EXPORT_SYMBOL(snd_malloc_isa_pages); -EXPORT_SYMBOL(snd_malloc_isa_pages_fallback); -#endif -#ifdef CONFIG_PCI -EXPORT_SYMBOL(snd_malloc_pci_pages); -EXPORT_SYMBOL(snd_malloc_pci_pages_fallback); -EXPORT_SYMBOL(snd_malloc_pci_page); -EXPORT_SYMBOL(snd_free_pci_pages); -EXPORT_SYMBOL(snd_malloc_sgbuf_pages); -EXPORT_SYMBOL(snd_free_sgbuf_pages); -#endif -#ifdef CONFIG_SBUS -EXPORT_SYMBOL(snd_malloc_sbus_pages); -EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback); -EXPORT_SYMBOL(snd_free_sbus_pages); -#endif Index: pcm_lib.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/core/pcm_lib.c,v retrieving revision 1.47 retrieving revision 1.48 diff -u -r1.47 -r1.48 --- pcm_lib.c 26 Jan 2004 14:04:35 -0000 1.47 +++ pcm_lib.c 2 Mar 2004 15:32:35 -0000 1.48 @@ -2659,20 +2659,6 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); +EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); EXPORT_SYMBOL(snd_pcm_lib_free_pages); -#ifdef CONFIG_ISA -EXPORT_SYMBOL(snd_pcm_lib_preallocate_isa_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_isa_pages_for_all); -#endif -#ifdef CONFIG_PCI -EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages_for_all); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all); -EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); -#endif -#ifdef CONFIG_SBUS -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages_for_all); -#endif Index: pcm_memory.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/core/pcm_memory.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -r1.23 -r1.24 --- pcm_memory.c 19 Jan 2004 19:00:27 -0000 1.23 +++ pcm_memory.c 2 Mar 2004 15:32:36 -0000 1.24 @@ -229,97 +229,78 @@ } /** - * snd_pcm_lib_preallocate_pages - pre-allocation for the continuous memory type + * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type * @substream: the pcm substream instance + * @type: DMA type (SNDRV_DMA_TYPE_*) + * @data: DMA type dependant data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size - * @flags: allocation condition, GFP_XXX * - * Do pre-allocation for the continuous memory type. + * Do pre-allocation for the given DMA type. * * Returns zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream, - size_t size, size_t max, - unsigned int flags) + int type, void *data, + size_t size, size_t max) { - substream->dma_device.type = SNDRV_DMA_TYPE_CONTINUOUS; - substream->dma_device.dev.flags = flags; + switch (type) { + case SNDRV_DMA_TYPE_ISA: + if ((unsigned long)data == 0) + data = snd_pcm_dma_flags(GFP_DMA|GFP_ATOMIC); + default: + substream->dma_device.type = type; + substream->dma_device.dev.data = data; + break; + } setup_pcm_id(substream); return snd_pcm_lib_preallocate_pages1(substream, size, max); } /** * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams) - * @pcm: pcm to assign the buffer + * @substream: the pcm substream instance + * @type: DMA type (SNDRV_DMA_TYPE_*) + * @data: DMA type dependant data * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * @flags: allocation condition, GFP_XXX + * @max: the max. allowed pre-allocation size * * Do pre-allocation to all substreams of the given pcm for the - * continuous memory type. + * specified DMA type. * * Returns zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm, - size_t size, size_t max, - unsigned int flags) + int type, void *data, + size_t size, size_t max) { snd_pcm_substream_t *substream; int stream, err; for (stream = 0; stream < 2; stream++) for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pages(substream, size, max, flags)) < 0) + if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0) return err; return 0; } -#ifdef CONFIG_ISA /** - * snd_pcm_lib_preallocate_isa_pages - pre-allocation for the ISA bus - * @substream: substream to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation for the ISA bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_ISA; - substream->dma_device.dev.flags = 0; /* FIXME: any good identifier? */ - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_isa_pages_for_all - pre-allocation for the ISA bus (all substreams) - * @pcm: pcm to assign the buffer - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation to all substreams of the given pcm for the - * ISA bus. + * snd_pcm_sgbuf_ops_page - get the page struct at the given offset + * @substream: the pcm substream instance + * @offset: the buffer offset * - * Returns zero if successful, or a negative error code on failure. + * Returns the page struct at the given buffer offset. + * Used as the page callback of PCM ops. */ -int snd_pcm_lib_preallocate_isa_pages_for_all(snd_pcm_t *pcm, - size_t size, size_t max) +struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) { - snd_pcm_substream_t *substream; - int stream, err; + struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_isa_pages(substream, size, max)) < 0) - return err; - return 0; + unsigned int idx = offset >> PAGE_SHIFT; + if (idx >= (unsigned int)sgbuf->pages) + return NULL; + return sgbuf->page_table[idx]; } -#endif /* CONFIG_ISA */ /** * snd_pcm_lib_malloc_pages - allocate the DMA buffer @@ -398,183 +379,6 @@ return 0; } -#ifdef CONFIG_PCI -/** - * snd_pcm_lib_preallocate_pci_pages - pre-allocation for the PCI bus - * - * @pci: pci device - * @substream: substream to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation for the PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_pci_pages(struct pci_dev *pci, - snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_PCI; - substream->dma_device.dev.pci = pci; - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_pci_pages_for_all - pre-allocation for the PCI bus (all substreams) - * @pci: pci device - * @pcm: pcm to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation to all substreams of the given pcm for the - * PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_pci_pages_for_all(struct pci_dev *pci, - snd_pcm_t *pcm, - size_t size, size_t max) -{ - snd_pcm_substream_t *substream; - int stream, err; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pci_pages(pci, substream, size, max)) < 0) - return err; - return 0; -} - -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_SBUS -/** - * snd_pcm_lib_preallocate_sbus_pages - pre-allocation for the SBUS bus - * - * @sbus: SBUS device - * @substream: substream to assign the buffer - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation for the SBUS. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev, - snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_SBUS; - substream->dma_device.dev.sbus = sdev; - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_sbus_pages_for_all - pre-allocation for the SBUS bus (all substreams) - * @sbus: SBUS device - * @pcm: pcm to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation to all substreams of the given pcm for the - * SUBS. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev, - snd_pcm_t *pcm, - size_t size, size_t max) -{ - snd_pcm_substream_t *substream; - int stream, err; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_sbus_pages(sdev, substream, size, max)) < 0) - return err; - return 0; -} - -#endif /* CONFIG_SBUS */ - - -#ifdef CONFIG_PCI -/** - * snd_pcm_lib_preallocate_sg_pages - initialize SG-buffer for the PCI bus - * - * @pci: pci device - * @substream: substream to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Initializes SG-buffer for the PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci, - snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_PCI_SG; - substream->dma_device.dev.pci = pci; - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_sg_pages_for_all - initialize SG-buffer for the PCI bus (all substreams) - * @pci: pci device - * @pcm: pcm to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Initialize the SG-buffer to all substreams of the given pcm for the - * PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci, - snd_pcm_t *pcm, - size_t size, size_t max) -{ - snd_pcm_substream_t *substream; - int stream, err; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_sg_pages(pci, substream, size, max)) < 0) - return err; - return 0; -} - -/** - * snd_pcm_sgbuf_ops_page - get the page struct at the given offset - * @substream: the pcm substream instance - * @offset: the buffer offset - * - * Returns the page struct at the given buffer offset. - * Used as the page callback of PCM ops. - */ -struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) -{ - struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - - unsigned int idx = offset >> PAGE_SHIFT; - if (idx >= (unsigned int)sgbuf->pages) - return NULL; - return sgbuf->page_table[idx]; -} - -#endif /* CONFIG_PCI */ - #ifndef MODULE /* format is: snd-pcm=preallocate_dma,maximum_substreams */ Index: sgbuf.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/core/sgbuf.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- sgbuf.c 8 May 2003 07:48:33 -0000 1.4 +++ sgbuf.c 2 Mar 2004 15:32:36 -0000 1.5 @@ -20,7 +20,6 @@ */ #include <linux/config.h> -#include <linux/pci.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/vmalloc.h> @@ -31,27 +30,44 @@ #define SGBUF_TBL_ALIGN 32 #define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN) +int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) +{ + struct snd_sg_buf *sgbuf = dmab->private_data; + struct snd_dma_buffer dmab; + int i; + + if (! sgbuf) + return -EINVAL; + + for (i = 0; i < sgbuf->pages; i++) { + dmab.area = sgbuf->table[i].buf; + dmab.addr = sgbuf->table[i].addr; + dmab.bytes = PAGE_SIZE; + snd_dma_free_pages(sgbuf->dev, &dmab); + } + if (dmab->area) + vunmap(dmab->area); + dmab->area = NULL; + + if (sgbuf->table) + kfree(sgbuf->table); + if (sgbuf->page_table) + kfree(sgbuf->page_table); + kfree(sgbuf); + dmab->private_data = NULL; + + return 0; +} -/** - * snd_malloc_sgbuf_pages - allocate the pages for the PCI SG buffer - * @pci: the pci device pointer - * @size: the requested buffer size in bytes - * @dmab: the buffer record to store - * - * Initializes the SG-buffer table and allocates the buffer pages - * for the given size. - * The pages are mapped to the virtually continuous memory. - * - * This function is usually called from the middle-level functions such as - * snd_pcm_lib_malloc_pages(). - * - * Returns the mapped virtual address of the buffer if allocation was - * successful, or NULL at error. - */ -void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab) +void *snd_malloc_sgbuf_pages(const struct snd_dma_device *dev, + size_t size, struct snd_dma_buffer *dmab, + size_t *res_size) { struct snd_sg_buf *sgbuf; unsigned int i, pages; + void *ptr; + dma_addr_t addr; + struct snd_dma_buffer dmab; dmab->area = NULL; dmab->addr = 0; @@ -59,7 +75,7 @@ if (! sgbuf) return NULL; memset(sgbuf, 0, sizeof(*sgbuf)); - sgbuf->pci = pci; + sgbuf->dev = dev; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); sgbuf->table = kmalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL); @@ -73,13 +89,14 @@ /* allocate each page */ for (i = 0; i < pages; i++) { - void *ptr; - dma_addr_t addr; - ptr = snd_malloc_pci_page(sgbuf->pci, &addr); - if (! ptr) - goto _failed; - sgbuf->table[i].buf = ptr; - sgbuf->table[i].addr = addr; + if (snd_dma_alloc_pages(dev, PAGE_SIZE, &dmab) < 0) { + if (res_size == NULL) + goto _failed; + *res_size = size = sgbuf->pages * PAGE_SIZE; + break; + } + sgbuf->table[i].buf = dmab.area; + sgbuf->table[i].addr = dmab.addr; sgbuf->page_table[i] = virt_to_page(ptr); sgbuf->pages++; } @@ -94,38 +111,3 @@ snd_free_sgbuf_pages(dmab); /* free the table */ return NULL; } - -/** - * snd_free_sgbuf_pages - free the sg buffer - * @dmab: buffer record - * - * Releases the pages and the SG-buffer table. - * - * This function is called usually from the middle-level function - * such as snd_pcm_lib_free_pages(). - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) -{ - struct snd_sg_buf *sgbuf = dmab->private_data; - int i; - - if (! sgbuf) - return -EINVAL; - - for (i = 0; i < sgbuf->pages; i++) - snd_free_pci_page(sgbuf->pci, sgbuf->table[i].buf, sgbuf->table[i].addr); - if (dmab->area) - vunmap(dmab->area); - dmab->area = NULL; - - if (sgbuf->table) - kfree(sgbuf->table); - if (sgbuf->page_table) - kfree(sgbuf->page_table); - kfree(sgbuf); - dmab->private_data = NULL; - - return 0; -} ------------------------------------------------------- SF.Net is sponsored by: Speed Start Your Linux Apps Now. Build and deploy apps & Web services for Linux with a free DVD software kit from IBM. Click Now! http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click _______________________________________________ Alsa-cvslog mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-cvslog