1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/pagemap.h>
15
16#include <drm/drm.h>
17#include <drm/drm_vma_manager.h>
18
19#include "psb_drv.h"
20
21static vm_fault_t psb_gem_fault(struct vm_fault *vmf);
22
23static void psb_gem_free_object(struct drm_gem_object *obj)
24{
25 struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);
26
27
28 drm_gem_free_mmap_offset(obj);
29 drm_gem_object_release(obj);
30
31
32 psb_gtt_free_range(obj->dev, gtt);
33}
34
35static const struct vm_operations_struct psb_gem_vm_ops = {
36 .fault = psb_gem_fault,
37 .open = drm_gem_vm_open,
38 .close = drm_gem_vm_close,
39};
40
41const struct drm_gem_object_funcs psb_gem_object_funcs = {
42 .free = psb_gem_free_object,
43 .vm_ops = &psb_gem_vm_ops,
44};
45
46
47
48
49
50
51
52
53
54
55
56
57int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size,
58 u32 *handlep, int stolen, u32 align)
59{
60 struct gtt_range *r;
61 int ret;
62 u32 handle;
63
64 size = roundup(size, PAGE_SIZE);
65
66
67
68 r = psb_gtt_alloc_range(dev, size, "gem", 0, PAGE_SIZE);
69 if (r == NULL) {
70 dev_err(dev->dev, "no memory for %lld byte GEM object\n", size);
71 return -ENOSPC;
72 }
73 r->gem.funcs = &psb_gem_object_funcs;
74
75 if (drm_gem_object_init(dev, &r->gem, size) != 0) {
76 psb_gtt_free_range(dev, r);
77
78 dev_err(dev->dev, "GEM init failed for %lld\n", size);
79 return -ENOMEM;
80 }
81
82 mapping_set_gfp_mask(r->gem.filp->f_mapping, GFP_KERNEL | __GFP_DMA32);
83
84 ret = drm_gem_handle_create(file, &r->gem, &handle);
85 if (ret) {
86 dev_err(dev->dev, "GEM handle failed for %p, %lld\n",
87 &r->gem, size);
88 drm_gem_object_release(&r->gem);
89 psb_gtt_free_range(dev, r);
90 return ret;
91 }
92
93 drm_gem_object_put(&r->gem);
94 *handlep = handle;
95 return 0;
96}
97
98
99
100
101
102
103
104
105
106
107
108int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
109 struct drm_mode_create_dumb *args)
110{
111 args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64);
112 args->size = args->pitch * args->height;
113 return psb_gem_create(file, dev, args->size, &args->handle, 0,
114 PAGE_SIZE);
115}
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134static vm_fault_t psb_gem_fault(struct vm_fault *vmf)
135{
136 struct vm_area_struct *vma = vmf->vma;
137 struct drm_gem_object *obj;
138 struct gtt_range *r;
139 int err;
140 vm_fault_t ret;
141 unsigned long pfn;
142 pgoff_t page_offset;
143 struct drm_device *dev;
144 struct drm_psb_private *dev_priv;
145
146 obj = vma->vm_private_data;
147 dev = obj->dev;
148 dev_priv = dev->dev_private;
149
150 r = container_of(obj, struct gtt_range, gem);
151
152
153
154 mutex_lock(&dev_priv->mmap_mutex);
155
156
157
158 if (r->mmapping == 0) {
159 err = psb_gtt_pin(r);
160 if (err < 0) {
161 dev_err(dev->dev, "gma500: pin failed: %d\n", err);
162 ret = vmf_error(err);
163 goto fail;
164 }
165 r->mmapping = 1;
166 }
167
168
169
170 page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
171
172
173 if (r->stolen)
174 pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT;
175 else
176 pfn = page_to_pfn(r->pages[page_offset]);
177 ret = vmf_insert_pfn(vma, vmf->address, pfn);
178fail:
179 mutex_unlock(&dev_priv->mmap_mutex);
180
181 return ret;
182}
183