1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * Copyright (c) by Takashi Iwai <tiwai@suse.de> 5 * Copyright (c) by Scott McNab <sdm@fractalgraphics.com.au> 6 * 7 * Trident 4DWave-NX memory page allocation (TLB area) 8 * Trident chip can handle only 16MByte of the memory at the same time. 9 */ 10 11 #include <linux/io.h> 12 #include <linux/pci.h> 13 #include <linux/time.h> 14 #include <linux/mutex.h> 15 16 #include <sound/core.h> 17 #include "trident.h" 18 19 /* page arguments of these two macros are Trident page (4096 bytes), not like 20 * aligned pages in others 21 */ 22 #define __set_tlb_bus(trident,page,addr) \ 23 (trident)->tlb.entries[page] = cpu_to_le32((addr) & ~(SNDRV_TRIDENT_PAGE_SIZE-1)) 24 #define __tlb_to_addr(trident,page) \ 25 (dma_addr_t)le32_to_cpu((trident->tlb.entries[page]) & ~(SNDRV_TRIDENT_PAGE_SIZE - 1)) 26 27 #if PAGE_SIZE == 4096 28 /* page size == SNDRV_TRIDENT_PAGE_SIZE */ 29 #define ALIGN_PAGE_SIZE PAGE_SIZE /* minimum page size for allocation */ 30 #define MAX_ALIGN_PAGES SNDRV_TRIDENT_MAX_PAGES /* maxmium aligned pages */ 31 /* fill TLB entrie(s) corresponding to page with ptr */ 32 #define set_tlb_bus(trident,page,addr) __set_tlb_bus(trident,page,addr) 33 /* fill TLB entrie(s) corresponding to page with silence pointer */ 34 #define set_silent_tlb(trident,page) __set_tlb_bus(trident, page, trident->tlb.silent_page.addr) 35 /* get aligned page from offset address */ 36 #define get_aligned_page(offset) ((offset) >> 12) 37 /* get offset address from aligned page */ 38 #define aligned_page_offset(page) ((page) << 12) 39 /* get PCI physical address from aligned page */ 40 #define page_to_addr(trident,page) __tlb_to_addr(trident, page) 41 42 #elif PAGE_SIZE == 8192 43 /* page size == SNDRV_TRIDENT_PAGE_SIZE x 2*/ 44 #define ALIGN_PAGE_SIZE PAGE_SIZE 45 #define MAX_ALIGN_PAGES (SNDRV_TRIDENT_MAX_PAGES / 2) 46 #define get_aligned_page(offset) ((offset) >> 13) 47 #define aligned_page_offset(page) ((page) << 13) 48 #define page_to_addr(trident,page) __tlb_to_addr(trident, (page) << 1) 49 50 /* fill TLB entries -- we need to fill two entries */ 51 static inline void set_tlb_bus(struct snd_trident *trident, int page, 52 dma_addr_t addr) 53 { 54 page <<= 1; 55 __set_tlb_bus(trident, page, addr); 56 __set_tlb_bus(trident, page+1, addr + SNDRV_TRIDENT_PAGE_SIZE); 57 } 58 static inline void set_silent_tlb(struct snd_trident *trident, int page) 59 { 60 page <<= 1; 61 __set_tlb_bus(trident, page, trident->tlb.silent_page.addr); 62 __set_tlb_bus(trident, page+1, trident->tlb.silent_page.addr); 63 } 64 65 #else 66 /* arbitrary size */ 67 #define UNIT_PAGES (PAGE_SIZE / SNDRV_TRIDENT_PAGE_SIZE) 68 #define ALIGN_PAGE_SIZE (SNDRV_TRIDENT_PAGE_SIZE * UNIT_PAGES) 69 #define MAX_ALIGN_PAGES (SNDRV_TRIDENT_MAX_PAGES / UNIT_PAGES) 70 /* Note: if alignment doesn't match to the maximum size, the last few blocks 71 * become unusable. To use such blocks, you'll need to check the validity 72 * of accessing page in set_tlb_bus and set_silent_tlb. search_empty() 73 * should also check it, too. 74 */ 75 #define get_aligned_page(offset) ((offset) / ALIGN_PAGE_SIZE) 76 #define aligned_page_offset(page) ((page) * ALIGN_PAGE_SIZE) 77 #define page_to_addr(trident,page) __tlb_to_addr(trident, (page) * UNIT_PAGES) 78 79 /* fill TLB entries -- UNIT_PAGES entries must be filled */ 80 static inline void set_tlb_bus(struct snd_trident *trident, int page, 81 dma_addr_t addr) 82 { 83 int i; 84 page *= UNIT_PAGES; 85 for (i = 0; i < UNIT_PAGES; i++, page++) { 86 __set_tlb_bus(trident, page, addr); 87 addr += SNDRV_TRIDENT_PAGE_SIZE; 88 } 89 } 90 static inline void set_silent_tlb(struct snd_trident *trident, int page) 91 { 92 int i; 93 page *= UNIT_PAGES; 94 for (i = 0; i < UNIT_PAGES; i++, page++) 95 __set_tlb_bus(trident, page, trident->tlb.silent_page.addr); 96 } 97 98 #endif /* PAGE_SIZE */ 99 100 /* first and last (aligned) pages of memory block */ 101 #define firstpg(blk) (((struct snd_trident_memblk_arg *)snd_util_memblk_argptr(blk))->first_page) 102 #define lastpg(blk) (((struct snd_trident_memblk_arg *)snd_util_memblk_argptr(blk))->last_page) 103 104 /* 105 * search empty pages which may contain given size 106 */ 107 static struct snd_util_memblk * 108 search_empty(struct snd_util_memhdr *hdr, int size) 109 { 110 struct snd_util_memblk *blk; 111 int page, psize; 112 struct list_head *p; 113 114 psize = get_aligned_page(size + ALIGN_PAGE_SIZE -1); 115 page = 0; 116 list_for_each(p, &hdr->block) { 117 blk = list_entry(p, struct snd_util_memblk, list); 118 if (page + psize <= firstpg(blk)) 119 goto __found_pages; 120 page = lastpg(blk) + 1; 121 } 122 if (page + psize > MAX_ALIGN_PAGES) 123 return NULL; 124 125 __found_pages: 126 /* create a new memory block */ 127 blk = __snd_util_memblk_new(hdr, psize * ALIGN_PAGE_SIZE, p->prev); 128 if (blk == NULL) 129 return NULL; 130 blk->offset = aligned_page_offset(page); /* set aligned offset */ 131 firstpg(blk) = page; 132 lastpg(blk) = page + psize - 1; 133 return blk; 134 } 135 136 137 /* 138 * check if the given pointer is valid for pages 139 */ 140 static int is_valid_page(unsigned long ptr) 141 { 142 if (ptr & ~0x3fffffffUL) { 143 snd_printk(KERN_ERR "max memory size is 1GB!!\n"); 144 return 0; 145 } 146 if (ptr & (SNDRV_TRIDENT_PAGE_SIZE-1)) { 147 snd_printk(KERN_ERR "page is not aligned\n"); 148 return 0; 149 } 150 return 1; 151 } 152 153 /* 154 * page allocation for DMA (Scatter-Gather version) 155 */ 156 static struct snd_util_memblk * 157 snd_trident_alloc_sg_pages(struct snd_trident *trident, 158 struct snd_pcm_substream *substream) 159 { 160 struct snd_util_memhdr *hdr; 161 struct snd_util_memblk *blk; 162 struct snd_pcm_runtime *runtime = substream->runtime; 163 int idx, page; 164 165 if (snd_BUG_ON(runtime->dma_bytes <= 0 || 166 runtime->dma_bytes > SNDRV_TRIDENT_MAX_PAGES * 167 SNDRV_TRIDENT_PAGE_SIZE)) 168 return NULL; 169 hdr = trident->tlb.memhdr; 170 if (snd_BUG_ON(!hdr)) 171 return NULL; 172 173 174 175 mutex_lock(&hdr->block_mutex); 176 blk = search_empty(hdr, runtime->dma_bytes); 177 if (blk == NULL) { 178 mutex_unlock(&hdr->block_mutex); 179 return NULL; 180 } 181 182 /* set TLB entries */ 183 idx = 0; 184 for (page = firstpg(blk); page <= lastpg(blk); page++, idx++) { 185 unsigned long ofs = idx << PAGE_SHIFT; 186 dma_addr_t addr = snd_pcm_sgbuf_get_addr(substream, ofs); 187 if (! is_valid_page(addr)) { 188 __snd_util_mem_free(hdr, blk); 189 mutex_unlock(&hdr->block_mutex); 190 return NULL; 191 } 192 set_tlb_bus(trident, page, addr); 193 } 194 mutex_unlock(&hdr->block_mutex); 195 return blk; 196 } 197 198 /* 199 * page allocation for DMA (contiguous version) 200 */ 201 static struct snd_util_memblk * 202 snd_trident_alloc_cont_pages(struct snd_trident *trident, 203 struct snd_pcm_substream *substream) 204 { 205 struct snd_util_memhdr *hdr; 206 struct snd_util_memblk *blk; 207 int page; 208 struct snd_pcm_runtime *runtime = substream->runtime; 209 dma_addr_t addr; 210 211 if (snd_BUG_ON(runtime->dma_bytes <= 0 || 212 runtime->dma_bytes > SNDRV_TRIDENT_MAX_PAGES * 213 SNDRV_TRIDENT_PAGE_SIZE)) 214 return NULL; 215 hdr = trident->tlb.memhdr; 216 if (snd_BUG_ON(!hdr)) 217 return NULL; 218 219 mutex_lock(&hdr->block_mutex); 220 blk = search_empty(hdr, runtime->dma_bytes); 221 if (blk == NULL) { 222 mutex_unlock(&hdr->block_mutex); 223 return NULL; 224 } 225 226 /* set TLB entries */ 227 addr = runtime->dma_addr; 228 for (page = firstpg(blk); page <= lastpg(blk); page++, 229 addr += SNDRV_TRIDENT_PAGE_SIZE) { 230 if (! is_valid_page(addr)) { 231 __snd_util_mem_free(hdr, blk); 232 mutex_unlock(&hdr->block_mutex); 233 return NULL; 234 } 235 set_tlb_bus(trident, page, addr); 236 } 237 mutex_unlock(&hdr->block_mutex); 238 return blk; 239 } 240 241 /* 242 * page allocation for DMA 243 */ 244 struct snd_util_memblk * 245 snd_trident_alloc_pages(struct snd_trident *trident, 246 struct snd_pcm_substream *substream) 247 { 248 if (snd_BUG_ON(!trident || !substream)) 249 return NULL; 250 if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_SG) 251 return snd_trident_alloc_sg_pages(trident, substream); 252 else 253 return snd_trident_alloc_cont_pages(trident, substream); 254 } 255 256 257 /* 258 * release DMA buffer from page table 259 */ 260 int snd_trident_free_pages(struct snd_trident *trident, 261 struct snd_util_memblk *blk) 262 { 263 struct snd_util_memhdr *hdr; 264 int page; 265 266 if (snd_BUG_ON(!trident || !blk)) 267 return -EINVAL; 268 269 hdr = trident->tlb.memhdr; 270 mutex_lock(&hdr->block_mutex); 271 /* reset TLB entries */ 272 for (page = firstpg(blk); page <= lastpg(blk); page++) 273 set_silent_tlb(trident, page); 274 /* free memory block */ 275 __snd_util_mem_free(hdr, blk); 276 mutex_unlock(&hdr->block_mutex); 277 return 0; 278 } 279