hc
2023-02-13 e440ec23c5a540cdd3f7464e8779219be6fd3d95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) Rockchip Electronics Co.Ltd
 * Author: Felix Zeng <felix.zeng@rock-chips.com>
 */
 
#ifndef __LINUX_RKNPU_GEM_H
#define __LINUX_RKNPU_GEM_H
 
#include <linux/mm_types.h>
#include <linux/version.h>
 
#include <drm/drm_device.h>
#include <drm/drm_vma_manager.h>
#include <drm/drm_gem.h>
#include <drm/drm_mode.h>
 
#if KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE
#include <drm/drm_mem_util.h>
#endif
 
#include "rknpu_mm.h"
 
#define to_rknpu_obj(x) container_of(x, struct rknpu_gem_object, base)
 
/*
 * rknpu drm buffer structure.
 *
 * @base: a gem object.
 *    - a new handle to this gem object would be created
 *    by drm_gem_handle_create().
 * @flags: indicate memory type to allocated buffer and cache attribute.
 * @size: size requested from user, in bytes and this size is aligned
 *    in page unit.
 * @cookie: cookie returned by dma_alloc_attrs
 * @kv_addr: kernel virtual address to allocated memory region.
 * @dma_addr: bus address(accessed by dma) to allocated memory region.
 *    - this address could be physical address without IOMMU and
 *    device address with IOMMU.
 * @pages: Array of backing pages.
 * @sgt: Imported sg_table.
 *
 * P.S. this object would be transferred to user as kms_bo.handle so
 *    user can access the buffer through kms_bo.handle.
 */
struct rknpu_gem_object {
   struct drm_gem_object base;
   unsigned int flags;
   unsigned long size;
   unsigned long sram_size;
   struct rknpu_mm_obj *sram_obj;
   dma_addr_t iova_start;
   unsigned long iova_size;
   void *cookie;
   void __iomem *kv_addr;
   dma_addr_t dma_addr;
   unsigned long dma_attrs;
   unsigned long num_pages;
   struct page **pages;
   struct sg_table *sgt;
   struct drm_mm_node mm_node;
};
 
/* create a new buffer with gem object */
struct rknpu_gem_object *rknpu_gem_object_create(struct drm_device *dev,
                        unsigned int flags,
                        unsigned long size,
                        unsigned long sram_size);
 
/* destroy a buffer with gem object */
void rknpu_gem_object_destroy(struct rknpu_gem_object *rknpu_obj);
 
/* request gem object creation and buffer allocation as the size */
int rknpu_gem_create_ioctl(struct drm_device *dev, void *data,
              struct drm_file *file_priv);
 
/* get fake-offset of gem object that can be used with mmap. */
int rknpu_gem_map_ioctl(struct drm_device *dev, void *data,
           struct drm_file *file_priv);
 
int rknpu_gem_destroy_ioctl(struct drm_device *dev, void *data,
               struct drm_file *file_priv);
 
/*
 * get rknpu drm object,
 * gem object reference count would be increased.
 */
static inline void rknpu_gem_object_get(struct drm_gem_object *obj)
{
#if KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE
   drm_gem_object_get(obj);
#else
   drm_gem_object_reference(obj);
#endif
}
 
/*
 * put rknpu drm object acquired from rknpu_gem_object_find() or rknpu_gem_object_get(),
 * gem object reference count would be decreased.
 */
static inline void rknpu_gem_object_put(struct drm_gem_object *obj)
{
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
   drm_gem_object_put(obj);
#elif KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE
   drm_gem_object_put_unlocked(obj);
#else
   drm_gem_object_unreference_unlocked(obj);
#endif
}
 
/*
 * get rknpu drm object from gem handle, this function could be used for
 * other drivers such as 2d/3d acceleration drivers.
 * with this function call, gem object reference count would be increased.
 */
static inline struct rknpu_gem_object *
rknpu_gem_object_find(struct drm_file *filp, unsigned int handle)
{
   struct drm_gem_object *obj;
 
   obj = drm_gem_object_lookup(filp, handle);
   if (!obj) {
       // DRM_ERROR("failed to lookup gem object.\n");
       return NULL;
   }
 
   rknpu_gem_object_put(obj);
 
   return to_rknpu_obj(obj);
}
 
/* get buffer information to memory region allocated by gem. */
int rknpu_gem_get_ioctl(struct drm_device *dev, void *data,
           struct drm_file *file_priv);
 
/* free gem object. */
void rknpu_gem_free_object(struct drm_gem_object *obj);
 
/* create memory region for drm framebuffer. */
int rknpu_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
             struct drm_mode_create_dumb *args);
 
#if KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE
/* map memory region for drm framebuffer to user space. */
int rknpu_gem_dumb_map_offset(struct drm_file *file_priv,
                 struct drm_device *dev, uint32_t handle,
                 uint64_t *offset);
#endif
 
/* page fault handler and mmap fault address(virtual) to physical memory. */
#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE
vm_fault_t rknpu_gem_fault(struct vm_fault *vmf);
#elif KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE
int rknpu_gem_fault(struct vm_fault *vmf);
#else
int rknpu_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
#endif
 
/* set vm_flags and we can change the vm attribute to other one at here. */
int rknpu_gem_mmap(struct file *filp, struct vm_area_struct *vma);
 
/* low-level interface prime helpers */
#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE
struct drm_gem_object *rknpu_gem_prime_import(struct drm_device *dev,
                         struct dma_buf *dma_buf);
#endif
struct sg_table *rknpu_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object *
rknpu_gem_prime_import_sg_table(struct drm_device *dev,
               struct dma_buf_attachment *attach,
               struct sg_table *sgt);
void *rknpu_gem_prime_vmap(struct drm_gem_object *obj);
void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
int rknpu_gem_prime_mmap(struct drm_gem_object *obj,
            struct vm_area_struct *vma);
 
int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
            struct drm_file *file_priv);
 
static inline void *rknpu_gem_alloc_page(size_t nr_pages)
{
#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE
   return kvmalloc_array(nr_pages, sizeof(struct page *),
                 GFP_KERNEL | __GFP_ZERO);
#else
   return drm_calloc_large(nr_pages, sizeof(struct page *));
#endif
}
 
static inline void rknpu_gem_free_page(void *pages)
{
#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE
   kvfree(pages);
#else
   drm_free_large(pages);
#endif
}
 
#endif