sgbuf.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Scatter-Gather buffer
  4. *
  5. * Copyright (c) by Takashi Iwai <tiwai@suse.de>
  6. */
  7. #include <linux/slab.h>
  8. #include <linux/mm.h>
  9. #include <linux/vmalloc.h>
  10. #include <linux/export.h>
  11. #include <sound/memalloc.h>
  12. /* table entries are align to 32 */
  13. #define SGBUF_TBL_ALIGN 32
  14. #define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN)
  15. int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
  16. {
  17. struct snd_sg_buf *sgbuf = dmab->private_data;
  18. struct snd_dma_buffer tmpb;
  19. int i;
  20. if (! sgbuf)
  21. return -EINVAL;
  22. vunmap(dmab->area);
  23. dmab->area = NULL;
  24. tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
  25. if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG)
  26. tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC;
  27. tmpb.dev.dev = sgbuf->dev;
  28. for (i = 0; i < sgbuf->pages; i++) {
  29. if (!(sgbuf->table[i].addr & ~PAGE_MASK))
  30. continue; /* continuous pages */
  31. tmpb.area = sgbuf->table[i].buf;
  32. tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
  33. tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
  34. snd_dma_free_pages(&tmpb);
  35. }
  36. kfree(sgbuf->table);
  37. kfree(sgbuf->page_table);
  38. kfree(sgbuf);
  39. dmab->private_data = NULL;
  40. return 0;
  41. }
  42. #define MAX_ALLOC_PAGES 32
  43. void *snd_malloc_sgbuf_pages(struct device *device,
  44. size_t size, struct snd_dma_buffer *dmab,
  45. size_t *res_size)
  46. {
  47. struct snd_sg_buf *sgbuf;
  48. unsigned int i, pages, chunk, maxpages;
  49. struct snd_dma_buffer tmpb;
  50. struct snd_sg_page *table;
  51. struct page **pgtable;
  52. int type = SNDRV_DMA_TYPE_DEV;
  53. pgprot_t prot = PAGE_KERNEL;
  54. dmab->area = NULL;
  55. dmab->addr = 0;
  56. dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
  57. if (! sgbuf)
  58. return NULL;
  59. if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) {
  60. type = SNDRV_DMA_TYPE_DEV_UC;
  61. #ifdef pgprot_noncached
  62. prot = pgprot_noncached(PAGE_KERNEL);
  63. #endif
  64. }
  65. sgbuf->dev = device;
  66. pages = snd_sgbuf_aligned_pages(size);
  67. sgbuf->tblsize = sgbuf_align_table(pages);
  68. table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
  69. if (!table)
  70. goto _failed;
  71. sgbuf->table = table;
  72. pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
  73. if (!pgtable)
  74. goto _failed;
  75. sgbuf->page_table = pgtable;
  76. /* allocate pages */
  77. maxpages = MAX_ALLOC_PAGES;
  78. while (pages > 0) {
  79. chunk = pages;
  80. /* don't be too eager to take a huge chunk */
  81. if (chunk > maxpages)
  82. chunk = maxpages;
  83. chunk <<= PAGE_SHIFT;
  84. if (snd_dma_alloc_pages_fallback(type, device,
  85. chunk, &tmpb) < 0) {
  86. if (!sgbuf->pages)
  87. goto _failed;
  88. if (!res_size)
  89. goto _failed;
  90. size = sgbuf->pages * PAGE_SIZE;
  91. break;
  92. }
  93. chunk = tmpb.bytes >> PAGE_SHIFT;
  94. for (i = 0; i < chunk; i++) {
  95. table->buf = tmpb.area;
  96. table->addr = tmpb.addr;
  97. if (!i)
  98. table->addr |= chunk; /* mark head */
  99. table++;
  100. *pgtable++ = virt_to_page(tmpb.area);
  101. tmpb.area += PAGE_SIZE;
  102. tmpb.addr += PAGE_SIZE;
  103. }
  104. sgbuf->pages += chunk;
  105. pages -= chunk;
  106. if (chunk < maxpages)
  107. maxpages = chunk;
  108. }
  109. sgbuf->size = size;
  110. dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
  111. if (! dmab->area)
  112. goto _failed;
  113. if (res_size)
  114. *res_size = sgbuf->size;
  115. return dmab->area;
  116. _failed:
  117. snd_free_sgbuf_pages(dmab); /* free the table */
  118. return NULL;
  119. }
  120. /*
  121. * compute the max chunk size with continuous pages on sg-buffer
  122. */
  123. unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
  124. unsigned int ofs, unsigned int size)
  125. {
  126. struct snd_sg_buf *sg = dmab->private_data;
  127. unsigned int start, end, pg;
  128. if (!sg)
  129. return size;
  130. start = ofs >> PAGE_SHIFT;
  131. end = (ofs + size - 1) >> PAGE_SHIFT;
  132. /* check page continuity */
  133. pg = sg->table[start].addr >> PAGE_SHIFT;
  134. for (;;) {
  135. start++;
  136. if (start > end)
  137. break;
  138. pg++;
  139. if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
  140. return (start << PAGE_SHIFT) - ofs;
  141. }
  142. /* ok, all on continuous pages */
  143. return size;
  144. }
  145. EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);