1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/kernel.h>
24#include <linux/types.h>
25#include <linux/mm.h>
26#include <linux/highmem.h>
27#include <linux/io.h>
28#include <linux/sysfs.h>
29
30#include "hmm/hmm.h"
31#include "hmm/hmm_pool.h"
32#include "hmm/hmm_bo.h"
33
34#include "atomisp_internal.h"
35#include "asm/cacheflush.h"
36#include "mmu/isp_mmu.h"
37#include "mmu/sh_mmu_mrfld.h"
38
39struct hmm_bo_device bo_device;
40struct hmm_pool dynamic_pool;
41struct hmm_pool reserved_pool;
42static ia_css_ptr dummy_ptr;
43static bool hmm_initialized;
44struct _hmm_mem_stat hmm_mem_stat;
45
46
47
48
49
50
51
52static const char hmm_bo_type_string[] = "psui";
53
54static ssize_t bo_show(struct device *dev, struct device_attribute *attr,
55 char *buf, struct list_head *bo_list, bool active)
56{
57 ssize_t ret = 0;
58 struct hmm_buffer_object *bo;
59 unsigned long flags;
60 int i;
61 long total[HMM_BO_LAST] = { 0 };
62 long count[HMM_BO_LAST] = { 0 };
63 int index1 = 0;
64 int index2 = 0;
65
66 ret = scnprintf(buf, PAGE_SIZE, "type pgnr\n");
67 if (ret <= 0)
68 return 0;
69
70 index1 += ret;
71
72 spin_lock_irqsave(&bo_device.list_lock, flags);
73 list_for_each_entry(bo, bo_list, list) {
74 if ((active && (bo->status & HMM_BO_ALLOCED)) ||
75 (!active && !(bo->status & HMM_BO_ALLOCED))) {
76 ret = scnprintf(buf + index1, PAGE_SIZE - index1,
77 "%c %d\n",
78 hmm_bo_type_string[bo->type], bo->pgnr);
79
80 total[bo->type] += bo->pgnr;
81 count[bo->type]++;
82 if (ret > 0)
83 index1 += ret;
84 }
85 }
86 spin_unlock_irqrestore(&bo_device.list_lock, flags);
87
88 for (i = 0; i < HMM_BO_LAST; i++) {
89 if (count[i]) {
90 ret = scnprintf(buf + index1 + index2,
91 PAGE_SIZE - index1 - index2,
92 "%ld %c buffer objects: %ld KB\n",
93 count[i], hmm_bo_type_string[i],
94 total[i] * 4);
95 if (ret > 0)
96 index2 += ret;
97 }
98 }
99
100
101 return index1 + index2 + 1;
102}
103
104static ssize_t active_bo_show(struct device *dev, struct device_attribute *attr,
105 char *buf)
106{
107 return bo_show(dev, attr, buf, &bo_device.entire_bo_list, true);
108}
109
110static ssize_t free_bo_show(struct device *dev, struct device_attribute *attr,
111 char *buf)
112{
113 return bo_show(dev, attr, buf, &bo_device.entire_bo_list, false);
114}
115
116static ssize_t reserved_pool_show(struct device *dev,
117 struct device_attribute *attr,
118 char *buf)
119{
120 ssize_t ret = 0;
121
122 struct hmm_reserved_pool_info *pinfo = reserved_pool.pool_info;
123 unsigned long flags;
124
125 if (!pinfo || !pinfo->initialized)
126 return 0;
127
128 spin_lock_irqsave(&pinfo->list_lock, flags);
129 ret = scnprintf(buf, PAGE_SIZE, "%d out of %d pages available\n",
130 pinfo->index, pinfo->pgnr);
131 spin_unlock_irqrestore(&pinfo->list_lock, flags);
132
133 if (ret > 0)
134 ret++;
135
136 return ret;
137};
138
139static ssize_t dynamic_pool_show(struct device *dev,
140 struct device_attribute *attr,
141 char *buf)
142{
143 ssize_t ret = 0;
144
145 struct hmm_dynamic_pool_info *pinfo = dynamic_pool.pool_info;
146 unsigned long flags;
147
148 if (!pinfo || !pinfo->initialized)
149 return 0;
150
151 spin_lock_irqsave(&pinfo->list_lock, flags);
152 ret = scnprintf(buf, PAGE_SIZE, "%d (max %d) pages available\n",
153 pinfo->pgnr, pinfo->pool_size);
154 spin_unlock_irqrestore(&pinfo->list_lock, flags);
155
156 if (ret > 0)
157 ret++;
158
159 return ret;
160};
161
162static DEVICE_ATTR_RO(active_bo);
163static DEVICE_ATTR_RO(free_bo);
164static DEVICE_ATTR_RO(reserved_pool);
165static DEVICE_ATTR_RO(dynamic_pool);
166
167static struct attribute *sysfs_attrs_ctrl[] = {
168 &dev_attr_active_bo.attr,
169 &dev_attr_free_bo.attr,
170 &dev_attr_reserved_pool.attr,
171 &dev_attr_dynamic_pool.attr,
172 NULL
173};
174
175static struct attribute_group atomisp_attribute_group[] = {
176 {.attrs = sysfs_attrs_ctrl },
177};
178
179int hmm_init(void)
180{
181 int ret;
182
183 ret = hmm_bo_device_init(&bo_device, &sh_mmu_mrfld,
184 ISP_VM_START, ISP_VM_SIZE);
185 if (ret)
186 dev_err(atomisp_dev, "hmm_bo_device_init failed.\n");
187
188 hmm_initialized = true;
189
190
191
192
193
194
195
196
197 dummy_ptr = hmm_alloc(1, HMM_BO_PRIVATE, 0, NULL, 0);
198
199 if (!ret) {
200 ret = sysfs_create_group(&atomisp_dev->kobj,
201 atomisp_attribute_group);
202 if (ret)
203 dev_err(atomisp_dev,
204 "%s Failed to create sysfs\n", __func__);
205 }
206
207 return ret;
208}
209
210void hmm_cleanup(void)
211{
212 if (!dummy_ptr)
213 return;
214 sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group);
215
216
217 hmm_free(dummy_ptr);
218 dummy_ptr = 0;
219
220 hmm_bo_device_exit(&bo_device);
221 hmm_initialized = false;
222}
223
224ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type,
225 int from_highmem, const void __user *userptr,
226 const uint16_t attrs)
227{
228 unsigned int pgnr;
229 struct hmm_buffer_object *bo;
230 bool cached = attrs & ATOMISP_MAP_FLAG_CACHED;
231 int ret;
232
233 WARN_ON(attrs & ATOMISP_MAP_FLAG_CONTIGUOUS);
234
235
236
237
238
239
240 if (!hmm_initialized)
241 hmm_init();
242
243 pgnr = size_to_pgnr_ceil(bytes);
244
245
246 bo = hmm_bo_alloc(&bo_device, pgnr);
247 if (!bo) {
248 dev_err(atomisp_dev, "hmm_bo_create failed.\n");
249 goto create_bo_err;
250 }
251
252
253 ret = hmm_bo_alloc_pages(bo, type, from_highmem, userptr, cached);
254 if (ret) {
255 dev_err(atomisp_dev, "hmm_bo_alloc_pages failed.\n");
256 goto alloc_page_err;
257 }
258
259
260 ret = hmm_bo_bind(bo);
261 if (ret) {
262 dev_err(atomisp_dev, "hmm_bo_bind failed.\n");
263 goto bind_err;
264 }
265
266 hmm_mem_stat.tol_cnt += pgnr;
267
268 if (attrs & ATOMISP_MAP_FLAG_CLEARED)
269 hmm_set(bo->start, 0, bytes);
270
271 dev_dbg(atomisp_dev,
272 "%s: pages: 0x%08x (%ld bytes), type: %d from highmem %d, user ptr %p, cached %d\n",
273 __func__, bo->start, bytes, type, from_highmem, userptr, cached);
274
275 return bo->start;
276
277bind_err:
278 hmm_bo_free_pages(bo);
279alloc_page_err:
280 hmm_bo_unref(bo);
281create_bo_err:
282 return 0;
283}
284
285void hmm_free(ia_css_ptr virt)
286{
287 struct hmm_buffer_object *bo;
288
289 dev_dbg(atomisp_dev, "%s: free 0x%08x\n", __func__, virt);
290
291 WARN_ON(!virt);
292
293 bo = hmm_bo_device_search_start(&bo_device, (unsigned int)virt);
294
295 if (!bo) {
296 dev_err(atomisp_dev,
297 "can not find buffer object start with address 0x%x\n",
298 (unsigned int)virt);
299 return;
300 }
301
302 hmm_mem_stat.tol_cnt -= bo->pgnr;
303
304 hmm_bo_unbind(bo);
305 hmm_bo_free_pages(bo);
306 hmm_bo_unref(bo);
307}
308
309static inline int hmm_check_bo(struct hmm_buffer_object *bo, unsigned int ptr)
310{
311 if (!bo) {
312 dev_err(atomisp_dev,
313 "can not find buffer object contains address 0x%x\n",
314 ptr);
315 return -EINVAL;
316 }
317
318 if (!hmm_bo_page_allocated(bo)) {
319 dev_err(atomisp_dev,
320 "buffer object has no page allocated.\n");
321 return -EINVAL;
322 }
323
324 if (!hmm_bo_allocated(bo)) {
325 dev_err(atomisp_dev,
326 "buffer object has no virtual address space allocated.\n");
327 return -EINVAL;
328 }
329
330 return 0;
331}
332
333
334static int load_and_flush_by_kmap(ia_css_ptr virt, void *data,
335 unsigned int bytes)
336{
337 struct hmm_buffer_object *bo;
338 unsigned int idx, offset, len;
339 char *src, *des;
340 int ret;
341
342 bo = hmm_bo_device_search_in_range(&bo_device, virt);
343 ret = hmm_check_bo(bo, virt);
344 if (ret)
345 return ret;
346
347 des = (char *)data;
348 while (bytes) {
349 idx = (virt - bo->start) >> PAGE_SHIFT;
350 offset = (virt - bo->start) - (idx << PAGE_SHIFT);
351
352 src = (char *)kmap(bo->page_obj[idx].page) + offset;
353
354 if ((bytes + offset) >= PAGE_SIZE) {
355 len = PAGE_SIZE - offset;
356 bytes -= len;
357 } else {
358 len = bytes;
359 bytes = 0;
360 }
361
362 virt += len;
363
364 if (des) {
365 memcpy(des, src, len);
366 des += len;
367 }
368
369 clflush_cache_range(src, len);
370
371 kunmap(bo->page_obj[idx].page);
372 }
373
374 return 0;
375}
376
377
378static int load_and_flush(ia_css_ptr virt, void *data, unsigned int bytes)
379{
380 struct hmm_buffer_object *bo;
381 int ret;
382
383 bo = hmm_bo_device_search_in_range(&bo_device, virt);
384 ret = hmm_check_bo(bo, virt);
385 if (ret)
386 return ret;
387
388 if (bo->status & HMM_BO_VMAPED || bo->status & HMM_BO_VMAPED_CACHED) {
389 void *src = bo->vmap_addr;
390
391 src += (virt - bo->start);
392 memcpy(data, src, bytes);
393 if (bo->status & HMM_BO_VMAPED_CACHED)
394 clflush_cache_range(src, bytes);
395 } else {
396 void *vptr;
397
398 vptr = hmm_bo_vmap(bo, true);
399 if (!vptr)
400 return load_and_flush_by_kmap(virt, data, bytes);
401 else
402 vptr = vptr + (virt - bo->start);
403
404 memcpy(data, vptr, bytes);
405 clflush_cache_range(vptr, bytes);
406 hmm_bo_vunmap(bo);
407 }
408
409 return 0;
410}
411
412
413int hmm_load(ia_css_ptr virt, void *data, unsigned int bytes)
414{
415 if (!virt) {
416 dev_warn(atomisp_dev,
417 "hmm_store: address is NULL\n");
418 return -EINVAL;
419 }
420 if (!data) {
421 dev_err(atomisp_dev,
422 "hmm_store: data is a NULL argument\n");
423 return -EINVAL;
424 }
425 return load_and_flush(virt, data, bytes);
426}
427
428
429int hmm_flush(ia_css_ptr virt, unsigned int bytes)
430{
431 return load_and_flush(virt, NULL, bytes);
432}
433
434
435int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes)
436{
437 struct hmm_buffer_object *bo;
438 unsigned int idx, offset, len;
439 char *src, *des;
440 int ret;
441
442 if (!virt) {
443 dev_warn(atomisp_dev,
444 "hmm_store: address is NULL\n");
445 return -EINVAL;
446 }
447 if (!data) {
448 dev_err(atomisp_dev,
449 "hmm_store: data is a NULL argument\n");
450 return -EINVAL;
451 }
452
453 bo = hmm_bo_device_search_in_range(&bo_device, virt);
454 ret = hmm_check_bo(bo, virt);
455 if (ret)
456 return ret;
457
458 if (bo->status & HMM_BO_VMAPED || bo->status & HMM_BO_VMAPED_CACHED) {
459 void *dst = bo->vmap_addr;
460
461 dst += (virt - bo->start);
462 memcpy(dst, data, bytes);
463 if (bo->status & HMM_BO_VMAPED_CACHED)
464 clflush_cache_range(dst, bytes);
465 } else {
466 void *vptr;
467
468 vptr = hmm_bo_vmap(bo, true);
469 if (vptr) {
470 vptr = vptr + (virt - bo->start);
471
472 memcpy(vptr, data, bytes);
473 clflush_cache_range(vptr, bytes);
474 hmm_bo_vunmap(bo);
475 return 0;
476 }
477 }
478
479 src = (char *)data;
480 while (bytes) {
481 idx = (virt - bo->start) >> PAGE_SHIFT;
482 offset = (virt - bo->start) - (idx << PAGE_SHIFT);
483
484 if (in_atomic())
485 des = (char *)kmap_atomic(bo->page_obj[idx].page);
486 else
487 des = (char *)kmap(bo->page_obj[idx].page);
488
489 if (!des) {
490 dev_err(atomisp_dev,
491 "kmap buffer object page failed: pg_idx = %d\n",
492 idx);
493 return -EINVAL;
494 }
495
496 des += offset;
497
498 if ((bytes + offset) >= PAGE_SIZE) {
499 len = PAGE_SIZE - offset;
500 bytes -= len;
501 } else {
502 len = bytes;
503 bytes = 0;
504 }
505
506 virt += len;
507
508 memcpy(des, src, len);
509
510 src += len;
511
512 clflush_cache_range(des, len);
513
514 if (in_atomic())
515
516
517
518
519 kunmap_atomic(des - offset);
520 else
521 kunmap(bo->page_obj[idx].page);
522 }
523
524 return 0;
525}
526
527
528int hmm_set(ia_css_ptr virt, int c, unsigned int bytes)
529{
530 struct hmm_buffer_object *bo;
531 unsigned int idx, offset, len;
532 char *des;
533 int ret;
534
535 bo = hmm_bo_device_search_in_range(&bo_device, virt);
536 ret = hmm_check_bo(bo, virt);
537 if (ret)
538 return ret;
539
540 if (bo->status & HMM_BO_VMAPED || bo->status & HMM_BO_VMAPED_CACHED) {
541 void *dst = bo->vmap_addr;
542
543 dst += (virt - bo->start);
544 memset(dst, c, bytes);
545
546 if (bo->status & HMM_BO_VMAPED_CACHED)
547 clflush_cache_range(dst, bytes);
548 } else {
549 void *vptr;
550
551 vptr = hmm_bo_vmap(bo, true);
552 if (vptr) {
553 vptr = vptr + (virt - bo->start);
554 memset(vptr, c, bytes);
555 clflush_cache_range(vptr, bytes);
556 hmm_bo_vunmap(bo);
557 return 0;
558 }
559 }
560
561 while (bytes) {
562 idx = (virt - bo->start) >> PAGE_SHIFT;
563 offset = (virt - bo->start) - (idx << PAGE_SHIFT);
564
565 des = (char *)kmap(bo->page_obj[idx].page) + offset;
566
567 if ((bytes + offset) >= PAGE_SIZE) {
568 len = PAGE_SIZE - offset;
569 bytes -= len;
570 } else {
571 len = bytes;
572 bytes = 0;
573 }
574
575 virt += len;
576
577 memset(des, c, len);
578
579 clflush_cache_range(des, len);
580
581 kunmap(bo->page_obj[idx].page);
582 }
583
584 return 0;
585}
586
587
588phys_addr_t hmm_virt_to_phys(ia_css_ptr virt)
589{
590 unsigned int idx, offset;
591 struct hmm_buffer_object *bo;
592
593 bo = hmm_bo_device_search_in_range(&bo_device, virt);
594 if (!bo) {
595 dev_err(atomisp_dev,
596 "can not find buffer object contains address 0x%x\n",
597 virt);
598 return -1;
599 }
600
601 idx = (virt - bo->start) >> PAGE_SHIFT;
602 offset = (virt - bo->start) - (idx << PAGE_SHIFT);
603
604 return page_to_phys(bo->page_obj[idx].page) + offset;
605}
606
607int hmm_mmap(struct vm_area_struct *vma, ia_css_ptr virt)
608{
609 struct hmm_buffer_object *bo;
610
611 bo = hmm_bo_device_search_start(&bo_device, virt);
612 if (!bo) {
613 dev_err(atomisp_dev,
614 "can not find buffer object start with address 0x%x\n",
615 virt);
616 return -EINVAL;
617 }
618
619 return hmm_bo_mmap(vma, bo);
620}
621
622
623void *hmm_vmap(ia_css_ptr virt, bool cached)
624{
625 struct hmm_buffer_object *bo;
626 void *ptr;
627
628 bo = hmm_bo_device_search_in_range(&bo_device, virt);
629 if (!bo) {
630 dev_err(atomisp_dev,
631 "can not find buffer object contains address 0x%x\n",
632 virt);
633 return NULL;
634 }
635
636 ptr = hmm_bo_vmap(bo, cached);
637 if (ptr)
638 return ptr + (virt - bo->start);
639 else
640 return NULL;
641}
642
643
644void hmm_flush_vmap(ia_css_ptr virt)
645{
646 struct hmm_buffer_object *bo;
647
648 bo = hmm_bo_device_search_in_range(&bo_device, virt);
649 if (!bo) {
650 dev_warn(atomisp_dev,
651 "can not find buffer object contains address 0x%x\n",
652 virt);
653 return;
654 }
655
656 hmm_bo_flush_vmap(bo);
657}
658
659void hmm_vunmap(ia_css_ptr virt)
660{
661 struct hmm_buffer_object *bo;
662
663 bo = hmm_bo_device_search_in_range(&bo_device, virt);
664 if (!bo) {
665 dev_warn(atomisp_dev,
666 "can not find buffer object contains address 0x%x\n",
667 virt);
668 return;
669 }
670
671 hmm_bo_vunmap(bo);
672}
673
674int hmm_pool_register(unsigned int pool_size, enum hmm_pool_type pool_type)
675{
676#if 0
677 switch (pool_type) {
678 case HMM_POOL_TYPE_RESERVED:
679 reserved_pool.pops = &reserved_pops;
680 return reserved_pool.pops->pool_init(&reserved_pool.pool_info,
681 pool_size);
682 case HMM_POOL_TYPE_DYNAMIC:
683 dynamic_pool.pops = &dynamic_pops;
684 return dynamic_pool.pops->pool_init(&dynamic_pool.pool_info,
685 pool_size);
686 default:
687 dev_err(atomisp_dev, "invalid pool type.\n");
688 return -EINVAL;
689 }
690#else
691 return 0;
692#endif
693}
694
695void hmm_pool_unregister(enum hmm_pool_type pool_type)
696{
697#if 0
698 switch (pool_type) {
699 case HMM_POOL_TYPE_RESERVED:
700 if (reserved_pool.pops && reserved_pool.pops->pool_exit)
701 reserved_pool.pops->pool_exit(&reserved_pool.pool_info);
702 break;
703 case HMM_POOL_TYPE_DYNAMIC:
704 if (dynamic_pool.pops && dynamic_pool.pops->pool_exit)
705 dynamic_pool.pops->pool_exit(&dynamic_pool.pool_info);
706 break;
707 default:
708 dev_err(atomisp_dev, "invalid pool type.\n");
709 break;
710 }
711#endif
712
713 return;
714}
715
716void *hmm_isp_vaddr_to_host_vaddr(ia_css_ptr ptr, bool cached)
717{
718 return hmm_vmap(ptr, cached);
719
720}
721
722ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr)
723{
724 struct hmm_buffer_object *bo;
725
726 bo = hmm_bo_device_search_vmap_start(&bo_device, ptr);
727 if (bo)
728 return bo->start;
729
730 dev_err(atomisp_dev,
731 "can not find buffer object whose kernel virtual address is %p\n",
732 ptr);
733 return 0;
734}
735
736void hmm_show_mem_stat(const char *func, const int line)
737{
738 pr_info("tol_cnt=%d usr_size=%d res_size=%d res_cnt=%d sys_size=%d dyc_thr=%d dyc_size=%d.\n",
739 hmm_mem_stat.tol_cnt,
740 hmm_mem_stat.usr_size, hmm_mem_stat.res_size,
741 hmm_mem_stat.res_cnt, hmm_mem_stat.sys_size,
742 hmm_mem_stat.dyc_thr, hmm_mem_stat.dyc_size);
743}
744
745void hmm_init_mem_stat(int res_pgnr, int dyc_en, int dyc_pgnr)
746{
747 hmm_mem_stat.res_size = res_pgnr;
748
749 if (hmm_mem_stat.res_size == 0) {
750 hmm_mem_stat.res_size = -1;
751 hmm_mem_stat.res_cnt = -1;
752 }
753
754
755 if (!dyc_en) {
756 hmm_mem_stat.dyc_size = -1;
757 hmm_mem_stat.dyc_thr = -1;
758 } else {
759 hmm_mem_stat.dyc_size = 0;
760 hmm_mem_stat.dyc_thr = dyc_pgnr;
761 }
762 hmm_mem_stat.usr_size = 0;
763 hmm_mem_stat.sys_size = 0;
764 hmm_mem_stat.tol_cnt = 0;
765}
766