1 /*
2  * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef _OSAL_MMZ_H
17 #define _OSAL_MMZ_H
18 
19 #include "hi_osal.h"
20 
21 #define CACHE_LINE_SIZE            0x40
22 #define HIL_MMZ_NAME_LEN           32
23 #define HIL_MMB_NAME_LEN           32
24 
25 struct hil_media_memory_zone {
26     char name[HIL_MMZ_NAME_LEN];
27 
28     unsigned long gfp;
29 
30     unsigned long phys_start;
31     unsigned long nbytes;
32 
33     struct osal_list_head list;
34     union {
35         struct device *cma_dev;
36         unsigned char *bitmap;
37     };
38     struct osal_list_head mmb_list;
39 
40     unsigned int alloc_type;
41     unsigned long block_align;
42 
43     void (*destructor)(const void *);
44 };
45 typedef struct hil_media_memory_zone hil_mmz_t;
46 
47 #define HIL_MMZ_FMT_S              "PHYS(0x%08lX, 0x%08lX), GFP=%lu, nBYTES=%luKB,    NAME=\"%s\""
48 #define hil_mmz_fmt_arg(p) (p)->phys_start, (p)->phys_start + (p)->nbytes - 1, (p)->gfp, (p)->nbytes / SZ_1K, (p)->name
49 
50 struct hil_media_memory_block {
51 #ifndef MMZ_V2_SUPPORT
52     unsigned int id;
53 #endif
54     char name[HIL_MMB_NAME_LEN];
55     struct hil_media_memory_zone *zone;
56     struct osal_list_head list;
57 
58     unsigned long phys_addr;
59     void *kvirt;
60     unsigned long length;
61 
62     unsigned long flags;
63 
64     unsigned int order;
65 
66     int phy_ref;
67     int map_ref;
68 };
69 typedef struct hil_media_memory_block hil_mmb_t;
70 
71 #define hil_mmb_kvirt(p) ({hil_mmb_t *__mmb=(p); OSAL_BUG_ON(__mmb==NULL); __mmb->kvirt; })
72 #define hil_mmb_phys(p) ({hil_mmb_t *__mmb=(p); OSAL_BUG_ON(__mmb==NULL); __mmb->phys_addr; })
73 #define hil_mmb_length(p) ({hil_mmb_t *__mmb=(p); OSAL_BUG_ON(__mmb==NULL); __mmb->length; })
74 #define hil_mmb_name(p) ({hil_mmb_t *__mmb=(p); OSAL_BUG_ON(__mmb==NULL); __mmb->name; })
75 #define hil_mmb_zone(p) ({hil_mmb_t *__mmb=(p); OSAL_BUG_ON(__mmb==NULL); __mmb->zone; })
76 
77 #define HIL_MMB_MAP2KERN           (1 << 0)
78 #define HIL_MMB_MAP2KERN_CACHED    (1 << 1)
79 #define HIL_MMB_RELEASED           (1 << 2)
80 
81 #define HIL_MMB_FMT_S              "phys(0x%08lX, 0x%08lX), kvirt=0x%08lX, flags=0x%08lX, length=%luKB,    name=\"%s\""
82 #define hil_mmb_fmt_arg(p) \
83     (p)->phys_addr, mmz_grain_align((p)->phys_addr + (p)->length) - 1, \
84     (unsigned long)(uintptr_t)((p)->kvirt), (p)->flags, (p)->length / SZ_1K, (p)->name
85 
86 #define DEFAULT_ALLOC              0
87 #define SLAB_ALLOC                 1
88 #define EQ_BLOCK_ALLOC             2
89 
90 #define LOW_TO_HIGH                0
91 #define HIGH_TO_LOW                1
92 
93 #define MMZ_DBG_LEVEL              0x0
94 #define MMZ_WARN_LEVEL              4
95 #define MMZ_ERR_LEVEL               1
96 
97 #define mmz_trace(level, s, params...)                                             \
98     do {                                                                           \
99         if (level & MMZ_DBG_LEVEL)                                                 \
100             printk(KERN_INFO "[%s, %d]: " s "\n", __FUNCTION__, __LINE__, params); \
101     } while (0)
102 
103 #define mmz_trace_func() mmz_trace(0x02, "%s", __FILE__)
104 
105 #define MMZ_GRAIN                  PAGE_SIZE
106 #define mmz_bitmap_size(p) (mmz_align2(mmz_length2grain((p)->nbytes), 8) / 8)
107 
108 #define mmz_get_bit(p, n) (((p)->bitmap[(n) / 8] >> ((n) & 0x7)) & 0x1)
109 #define mmz_set_bit(p, n) ((p)->bitmap[(n) / 8] |= 1 << ((n) & 0x7))
110 #define mmz_clr_bit(p, n) ((p)->bitmap[(n) / 8] &= ~(1 << ((n) & 0x7)))
111 
112 #define mmz_pos2phy_addr(p, n) ((p)->phys_start + (n) * MMZ_GRAIN)
113 #define mmz_phy_addr2pos(p, a) (((a) - (p)->phys_start) / MMZ_GRAIN)
114 
115 #define mmz_align2low(x, g) (((x) / (g)) * (g))
116 #define mmz_align2(x, g) ((((x) + (g) - 1) / (g)) * (g))
117 #define mmz_grain_align(x) mmz_align2(x, MMZ_GRAIN)
118 #define mmz_length2grain(len) (mmz_grain_align(len) / MMZ_GRAIN)
119 
120 #define begin_list_for_each_mmz(p, gfp, mmz_name)        \
121     list_for_each_entry(p, &g_mmz_list, list)              \
122     {                                                    \
123         if ((gfp) == 0 ? 0 : (p)->gfp != (gfp)) {        \
124             continue;                                       \
125         }                                                   \
126         if (((mmz_name) == NULL) || (*(mmz_name) == '\0')) { \
127             if (anony == 1) {                            \
128                 if (strcmp("anonymous", (p)->name)) {    \
129                     continue;                            \
130                 }                                        \
131             } else {                                     \
132                 break;                                   \
133             }                                            \
134         } else {                                         \
135             if (strcmp(mmz_name, (p)->name)) {           \
136                 continue;                                \
137             }                                            \
138         }                                                \
139         mmz_trace(1, HIL_MMZ_FMT_S, hil_mmz_fmt_arg(p));
140 #define end_list_for_each_mmz() }
141 
142 #if defined(KERNEL_BIT_64) && defined(USER_BIT_32)
143 #define __phys_addr_type__         unsigned long long
144 #define __phys_len_type__          unsigned long long
145 #define __phys_addr_align__        __attribute__((aligned(8)))
146 #else
147 #define __phys_addr_type__         unsigned long
148 #define __phys_len_type__          unsigned long
149 #define __phys_addr_align__        __attribute__((aligned(sizeof(long))))
150 #endif
151 
152 struct mmb_info {
153     __phys_addr_type__ phys_addr; /* phys-memory address */
154     __phys_addr_type__ __phys_addr_align__ align; /* if you need your phys-memory have special align size */
155     __phys_len_type__ __phys_addr_align__ size; /* length of memory you need, in bytes */
156     unsigned int __phys_addr_align__ order;
157 
158     void *__phys_addr_align__ mapped; /* userspace mapped ptr */
159 
160     union {
161         struct {
162             unsigned long prot : 8; /* PROT_READ or PROT_WRITE */
163             unsigned long flags : 12; /* MAP_SHARED or MAP_PRIVATE */
164 
165 #ifdef __KERNEL__
166             unsigned long reserved : 8; /* reserved, do not use */
167             unsigned long delayed_free : 1;
168             unsigned long map_cached : 1;
169 #endif
170         };
171         unsigned long w32_stuf;
172     } __phys_addr_align__;
173 
174     char mmb_name[HIL_MMB_NAME_LEN];
175     char mmz_name[HIL_MMZ_NAME_LEN];
176     unsigned long __phys_addr_align__ gfp; /* reserved, do set to 0 */
177 
178 #ifdef __KERNEL__
179     int map_ref;
180     int mmb_ref;
181 
182     struct osal_list_head list;
183     hil_mmb_t *mmb;
184 #endif
185 } __attribute__((aligned(8)));
186 
187 struct dirty_area {
188     __phys_addr_type__ dirty_phys_start; /* dirty physical address */
189     void *__phys_addr_align__ dirty_virt_start; /* dirty virtual  address,
190                        must be coherent with dirty_phys_addr */
191     __phys_len_type__ __phys_addr_align__ dirty_size;
192 } __phys_addr_align__;
193 
194 #define IOC_MMB_ALLOC              _IOWR('m', 10, struct mmb_info)
195 #define IOC_MMB_ATTR               _IOR('m', 11, struct mmb_info)
196 #define IOC_MMB_FREE               _IOW('m', 12, struct mmb_info)
197 #define IOC_MMB_ALLOC_V2           _IOWR('m', 13, struct mmb_info)
198 
199 #define IOC_MMB_USER_REMAP         _IOWR('m', 20, struct mmb_info)
200 #define IOC_MMB_USER_REMAP_CACHED  _IOWR('m', 21, struct mmb_info)
201 #define IOC_MMB_USER_UNMAP         _IOWR('m', 22, struct mmb_info)
202 
203 #define IOC_MMB_VIRT_GET_PHYS      _IOWR('m', 23, struct mmb_info)
204 
205 #define IOC_MMB_SYS_FLUSH_CACHE    _IOW('m', 24, struct mmb_info)
206 #define IOC_MMB_BASE_CHECK_ADDR    _IOW('m', 25, struct mmb_info)
207 #define IOC_MMB_INVALID_CACHE      _IOW('m', 26, struct mmb_info)
208 #define IOC_MMB_CHECK_PHY_ALLOC    _IOWR('m', 27, struct mmb_info)
209 #define IOC_MMB_MMF_REMAP          _IOWR('m', 28, struct mmb_info)
210 #define IOC_MMB_MMF_REMAP_CACHED   _IOWR('m', 29, struct mmb_info)
211 #define IOC_MMB_MMF_UNMAP          _IOWR('m', 30, struct mmb_info)
212 
213 #define IOC_MMB_ADD_REF            _IO('r', 30) /* ioctl(file, cmd, arg), arg is mmb_addr */
214 #define IOC_MMB_DEC_REF            _IO('r', 31) /* ioctl(file, cmd, arg), arg is mmb_addr */
215 
216 #define IOC_MMB_FLUSH_DCACHE       _IO('c', 40)
217 
218 #define IOC_MMB_FLUSH_DCACHE_DIRTY _IOW('d', 50, struct dirty_area)
219 #define IOC_MMB_TEST_CACHE         _IOW('t', 11, struct mmb_info)
220 
221 #define MMZ_SETUP_CMDLINE_LEN      256
222 typedef struct hiMMZ_MODULE_PARAMS_S {
223     char mmz[MMZ_SETUP_CMDLINE_LEN];
224     char map_mmz[MMZ_SETUP_CMDLINE_LEN];
225     int anony;
226 } MMZ_MODULE_PARAMS_S;
227 
228 /*
229  * APIs
230  */
231 extern hil_mmz_t *hil_mmz_create(const char *name, unsigned long gfp, unsigned long phys_start,
232                                  unsigned long nbytes);
233 extern hil_mmz_t *hil_mmz_create_v2(const char *name, unsigned long gfp, unsigned long phys_start,
234                                     unsigned long nbytes, unsigned int alloc_type, unsigned long block_align);
235 
236 extern int hil_mmz_destroy(hil_mmz_t *zone);
237 
238 extern int hil_mmz_register(hil_mmz_t *zone);
239 extern int hil_mmz_unregister(hil_mmz_t *zone);
240 extern hil_mmz_t *hil_mmz_find(unsigned long gfp, const char *mmz_name);
241 
242 extern hil_mmb_t *hil_mmb_alloc(const char *name, unsigned long size, unsigned long align,
243                                 unsigned long gfp, const char *mmz_name);
244 extern hil_mmb_t *hil_mmb_alloc_v2(const char *name, unsigned long size, unsigned long align,
245                                    unsigned long gfp, const char *mmz_name, unsigned int order);
246 extern int hil_mmb_free(hil_mmb_t *mmb);
247 extern hil_mmb_t *hil_mmb_getby_phys(unsigned long addr);
248 extern hil_mmb_t *hil_mmb_getby_phys_2(unsigned long addr, unsigned long *out_offset);
249 extern hil_mmb_t *hil_mmb_getby_kvirt(void *virt);
250 extern unsigned long usr_virt_to_phys(unsigned long virt);
251 
252 extern int hil_map_mmz_check_phys(unsigned long addr_start, unsigned long addr_len);
253 extern int hil_is_phys_in_mmz(unsigned long addr_start, unsigned long addr_len);
254 
255 extern int hil_vma_check(unsigned long vm_start, unsigned long vm_end);
256 extern int hil_mmb_flush_dcache_byaddr_safe(void *kvirt, unsigned long phys_addr, unsigned long length);
257 
258 extern unsigned long hil_mmz_get_phys(const char *zone_name);
259 
260 extern hil_mmb_t *hil_mmb_alloc_in(const char *name, unsigned long size, unsigned long align,
261                                    hil_mmz_t *_user_mmz);
262 extern hil_mmb_t *hil_mmb_alloc_in_v2(const char *name, unsigned long size, unsigned long align,
263                                       hil_mmz_t *_user_mmz, unsigned int order);
264 
265 #define hil_mmb_freeby_phys(phys_addr) hil_mmb_free(hil_mmb_getby_phys(phys_addr))
266 #define hil_mmb_freeby_kvirt(kvirt) hil_mmb_free(hil_mmb_getby_kvirt(kvirt))
267 
268 extern void *hil_mmb_map2kern(hil_mmb_t *mmb);
269 extern void *hil_mmb_map2kern_cached(hil_mmb_t *mmb);
270 
271 extern int hil_mmb_flush_dcache_byaddr(void *kvirt, unsigned long phys_addr, unsigned long length);
272 extern int hil_mmb_invalid_cache_byaddr(void *kvirt, unsigned long phys_addr, unsigned long length);
273 
274 extern int hil_mmb_unmap(hil_mmb_t *mmb);
275 extern int hil_mmb_get(hil_mmb_t *mmb);
276 extern int hil_mmb_put(hil_mmb_t *mmb);
277 
278 extern void *hil_mmf_map2kern_nocache(unsigned long phys, int len);
279 extern void *hil_mmf_map2kern_cache(unsigned long phys, int len);
280 extern void hil_mmf_unmap(void *virt);
281 
282 /* for mmz userdev */
283 int mmz_userdev_init(void);
284 void mmz_userdev_exit(void);
285 int mmz_flush_dcache_all(void);
286 
287 #endif
288