1 /*
2 * udma_mem.c
3 * This file provides udma memory functionality to user space applications
4 * to use the udma kernel driver.
5 *
6 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
19 * distribution.
20 *
21 * Neither the name of Texas Instruments Incorporated nor the names of
22 * its contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
39 #include <internal/udma_internal.h>
41 #define align(num, align) (((num) + (align) - 1) & (~((align) - 1)))
43 static int udma_page_size = -1;
44 static void *udma_mem_start = NULL;
45 static void *udma_mem_end = NULL;
46 static struct udma_atom udma_mem_avail;
48 int udma_mem_init(unsigned long mem_size)
49 {
50 void *udma_mem;
52 udma_page_size = getpagesize();
54 udma_mem = mmap(0, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED,
55 udma_fd, 0);
56 if (udma_mem == MAP_FAILED)
57 return -ENOMEM;
59 udma_mem_start = udma_mem;
60 udma_mem_end = udma_mem + mem_size;
61 udma_atom_set_ptr(&udma_mem_avail, udma_mem_start);
63 return 0;
64 }
66 void udma_mem_shutdown(void)
67 {
68 munmap(udma_mem_start, udma_mem_end - udma_mem_start);
69 udma_mem_start = udma_mem_end = NULL;
70 udma_atom_set_ptr(&udma_mem_avail, NULL);
71 }
73 void *udma_mem_alloc(unsigned long size)
74 {
75 void *memstart, *memend;
76 enum udma_atom_status status;
78 size = align(size, udma_page_size);
80 do {
81 memstart = udma_atom_get_ptr(&udma_mem_avail);
82 memend = memstart + size;
83 if (memend > udma_mem_end)
84 return NULL;
85 status = udma_atom_cas_ptr(&udma_mem_avail, memstart, memend);
86 } while (status != UDMA_ATOM_CAS_SUCCESS);
88 return memstart;
89 }
91 int udma_mem_free(void *mem, unsigned long size)
92 {
93 void *memstart = mem, *memend, *avail;
94 enum udma_atom_status status;
96 size = align(size, udma_page_size);
97 memend = memstart + size;
99 do {
100 avail = udma_atom_get_ptr(&udma_mem_avail);
101 if (avail != memend)
102 return -EINVAL;
103 status = udma_atom_cas_ptr(&udma_mem_avail, memend, memstart);
104 } while (status != UDMA_ATOM_CAS_SUCCESS);
106 return 0;
107 }
109 struct udma_mem_part *udma_mem_part_create(unsigned nblocks, unsigned blocksize)
110 {
111 struct udma_mem_part *part;
112 unsigned total;
113 void *mem;
115 part = udma_malloc(sizeof(struct udma_mem_part));
116 if (!part)
117 return NULL;
119 part->blocksize = align(blocksize, 4);
120 total = part->blocksize * nblocks;
121 nblocks = total / part->blocksize;
123 mem = udma_mem_alloc(total);
124 if (!mem) {
125 udma_free(part);
126 return NULL;
127 }
129 part->memstart = mem;
130 part->memend = mem + total;
132 udma_atom_set(&part->used, 0);
133 udma_lifo_init(&part->free);
135 for (; nblocks; nblocks--, mem += part->blocksize)
136 udma_lifo_put(&part->free, mem);
138 return part;
139 }
141 void udma_mem_part_destroy(struct udma_mem_part *part)
142 {
143 udma_mem_free(part->memstart, part->memend - part->memstart);
144 udma_free(part);
145 }
147 void *udma_mem_block_alloc(struct udma_mem_part *part)
148 {
149 void *block;
151 block = udma_lifo_get(&part->free);
152 if (block)
153 udma_atom_inc(&part->used);
154 return block;
155 }
157 void udma_mem_block_free(struct udma_mem_part *part, void* block)
158 {
159 if (block < part->memstart || block >= part->memend)
160 return;
161 udma_lifo_put(&part->free, block);
162 udma_atom_dec(&part->used);
163 }