Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 110923
b: refs/heads/master
c: 51e9f2e
h: refs/heads/master
i:
  110921: 60e90b5
  110919: d228659
v: v3
  • Loading branch information
Takashi Iwai authored and Jaroslav Kysela committed Aug 25, 2008
1 parent 358a230 commit f7e18bc
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4e184f8fc06411f35fdcf4b9bc6187c857bf7214
refs/heads/master: 51e9f2e665bf2b6a01be275d64c336d942c59a66
4 changes: 3 additions & 1 deletion trunk/include/sound/memalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
*/
static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
{
return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
dma_addr_t addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
addr &= PAGE_MASK;
return addr + offset % PAGE_SIZE;
}

/*
Expand Down
3 changes: 2 additions & 1 deletion trunk/include/sound/pcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,8 @@ snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)

struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
unsigned long offset);

unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
unsigned int ofs, unsigned int size);

/* handle mmap counter - PCM mmap callback should handle this counter properly */
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
Expand Down
26 changes: 26 additions & 0 deletions trunk/sound/core/pcm_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,32 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne

EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);

/*
* compute the max chunk size with continuous pages on sg-buffer
*/
unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
unsigned int ofs, unsigned int size)
{
struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
unsigned int start, end, pg;

start = ofs >> PAGE_SHIFT;
end = (ofs + size - 1) >> PAGE_SHIFT;
/* check page continuity */
pg = sg->table[start].addr >> PAGE_SHIFT;
for (;;) {
start++;
if (start > end)
break;
pg++;
if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
return (start << PAGE_SHIFT) - ofs;
}
/* ok, all on continuous pages */
return size;
}
EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);

/**
* snd_pcm_lib_malloc_pages - allocate the DMA buffer
* @substream: the substream to allocate the DMA buffer to
Expand Down
62 changes: 46 additions & 16 deletions trunk/sound/core/sgbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
tmpb.dev.dev = sgbuf->dev;
for (i = 0; i < sgbuf->pages; i++) {
if (!(sgbuf->table[i].addr & ~PAGE_MASK))
continue; /* continuous pages */
tmpb.area = sgbuf->table[i].buf;
tmpb.addr = sgbuf->table[i].addr;
tmpb.bytes = PAGE_SIZE;
tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
snd_dma_free_pages(&tmpb);
}
if (dmab->area)
Expand All @@ -58,13 +60,17 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
return 0;
}

#define MAX_ALLOC_PAGES 32

void *snd_malloc_sgbuf_pages(struct device *device,
size_t size, struct snd_dma_buffer *dmab,
size_t *res_size)
{
struct snd_sg_buf *sgbuf;
unsigned int i, pages;
unsigned int i, pages, chunk, maxpages;
struct snd_dma_buffer tmpb;
struct snd_sg_page *table;
struct page **pgtable;

dmab->area = NULL;
dmab->addr = 0;
Expand All @@ -74,31 +80,55 @@ void *snd_malloc_sgbuf_pages(struct device *device,
sgbuf->dev = device;
pages = snd_sgbuf_aligned_pages(size);
sgbuf->tblsize = sgbuf_align_table(pages);
sgbuf->table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->table), GFP_KERNEL);
if (! sgbuf->table)
table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
if (!table)
goto _failed;
sgbuf->page_table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->page_table), GFP_KERNEL);
if (! sgbuf->page_table)
sgbuf->table = table;
pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
if (!pgtable)
goto _failed;
sgbuf->page_table = pgtable;

/* allocate each page */
for (i = 0; i < pages; i++) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, device, PAGE_SIZE, &tmpb) < 0) {
if (res_size == NULL)
/* allocate pages */
maxpages = MAX_ALLOC_PAGES;
while (pages > 0) {
chunk = pages;
/* don't be too eager to take a huge chunk */
if (chunk > maxpages)
chunk = maxpages;
chunk <<= PAGE_SHIFT;
if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
chunk, &tmpb) < 0) {
if (!sgbuf->pages)
return NULL;
if (!res_size)
goto _failed;
*res_size = size = sgbuf->pages * PAGE_SIZE;
size = sgbuf->pages * PAGE_SIZE;
break;
}
sgbuf->table[i].buf = tmpb.area;
sgbuf->table[i].addr = tmpb.addr;
sgbuf->page_table[i] = virt_to_page(tmpb.area);
sgbuf->pages++;
chunk = tmpb.bytes >> PAGE_SHIFT;
for (i = 0; i < chunk; i++) {
table->buf = tmpb.area;
table->addr = tmpb.addr;
if (!i)
table->addr |= chunk; /* mark head */
table++;
*pgtable++ = virt_to_page(tmpb.area);
tmpb.area += PAGE_SIZE;
tmpb.addr += PAGE_SIZE;
}
sgbuf->pages += chunk;
pages -= chunk;
if (chunk < maxpages)
maxpages = chunk;
}

sgbuf->size = size;
dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
if (! dmab->area)
goto _failed;
if (res_size)
*res_size = sgbuf->size;
return dmab->area;

_failed:
Expand Down

0 comments on commit f7e18bc

Please sign in to comment.