1840d47b4f81dc6aec3216d03bc3f9d2dbe0b92e
[linux-2.6.git] / drivers / video / tegra / host / nvhost_3dctx.c
1 /*
2  * drivers/video/tegra/host/nvhost_3dctx.c
3  *
4  * Tegra Graphics Host 3d hardware context
5  *
6  * Copyright (c) 2010, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  */
22
23 #include "nvhost_hwctx.h"
24 #include "dev.h"
25
26 #include <linux/slab.h>
27
28 const struct hwctx_reginfo ctxsave_regs_3d[] = {
29         HWCTX_REGINFO(0xe00, 16, DIRECT),
30         HWCTX_REGINFO(0xe10, 16, DIRECT),
31         HWCTX_REGINFO(0xe20, 1, DIRECT),
32         HWCTX_REGINFO(0xe21, 1, DIRECT),
33         HWCTX_REGINFO(0xe22, 1, DIRECT),
34         HWCTX_REGINFO(0xe25, 1, DIRECT),
35         HWCTX_REGINFO(0xe26, 1, DIRECT),
36         HWCTX_REGINFO(0xe28, 2, DIRECT),
37         HWCTX_REGINFO(0xe2a, 1, DIRECT),
38         HWCTX_REGINFO(0x1, 1, DIRECT),
39         HWCTX_REGINFO(0x2, 1, DIRECT),
40         HWCTX_REGINFO(0xc, 2, DIRECT),
41         HWCTX_REGINFO(0xe, 2, DIRECT),
42         HWCTX_REGINFO(0x10, 2, DIRECT),
43         HWCTX_REGINFO(0x12, 2, DIRECT),
44         HWCTX_REGINFO(0x14, 2, DIRECT),
45         HWCTX_REGINFO(0x100, 32, DIRECT),
46         HWCTX_REGINFO(0x120, 1, DIRECT),
47         HWCTX_REGINFO(0x121, 1, DIRECT),
48         HWCTX_REGINFO(0x124, 1, DIRECT),
49         HWCTX_REGINFO(0x125, 1, DIRECT),
50         HWCTX_REGINFO(0x200, 1, DIRECT),
51         HWCTX_REGINFO(0x201, 1, DIRECT),
52         HWCTX_REGINFO(0x202, 1, DIRECT),
53         HWCTX_REGINFO(0x203, 1, DIRECT),
54         HWCTX_REGINFO(0x204, 1, DIRECT),
55         HWCTX_REGINFO(0x207, 1024, INDIRECT),
56         HWCTX_REGINFO(0x209, 1, DIRECT),
57         HWCTX_REGINFO(0x300, 64, DIRECT),
58         HWCTX_REGINFO(0x343, 1, DIRECT),
59         HWCTX_REGINFO(0x344, 1, DIRECT),
60         HWCTX_REGINFO(0x345, 1, DIRECT),
61         HWCTX_REGINFO(0x346, 1, DIRECT),
62         HWCTX_REGINFO(0x347, 1, DIRECT),
63         HWCTX_REGINFO(0x348, 1, DIRECT),
64         HWCTX_REGINFO(0x349, 1, DIRECT),
65         HWCTX_REGINFO(0x34a, 1, DIRECT),
66         HWCTX_REGINFO(0x34b, 1, DIRECT),
67         HWCTX_REGINFO(0x34c, 1, DIRECT),
68         HWCTX_REGINFO(0x34d, 1, DIRECT),
69         HWCTX_REGINFO(0x34e, 1, DIRECT),
70         HWCTX_REGINFO(0x34f, 1, DIRECT),
71         HWCTX_REGINFO(0x350, 1, DIRECT),
72         HWCTX_REGINFO(0x351, 1, DIRECT),
73         HWCTX_REGINFO(0x352, 1, DIRECT),
74         HWCTX_REGINFO(0x353, 1, DIRECT),
75         HWCTX_REGINFO(0x354, 1, DIRECT),
76         HWCTX_REGINFO(0x355, 1, DIRECT),
77         HWCTX_REGINFO(0x356, 1, DIRECT),
78         HWCTX_REGINFO(0x357, 1, DIRECT),
79         HWCTX_REGINFO(0x358, 1, DIRECT),
80         HWCTX_REGINFO(0x359, 1, DIRECT),
81         HWCTX_REGINFO(0x35a, 1, DIRECT),
82         HWCTX_REGINFO(0x35b, 1, DIRECT),
83         HWCTX_REGINFO(0x363, 1, DIRECT),
84         HWCTX_REGINFO(0x364, 1, DIRECT),
85         HWCTX_REGINFO(0x400, 2, DIRECT),
86         HWCTX_REGINFO(0x402, 1, DIRECT),
87         HWCTX_REGINFO(0x403, 1, DIRECT),
88         HWCTX_REGINFO(0x404, 1, DIRECT),
89         HWCTX_REGINFO(0x405, 1, DIRECT),
90         HWCTX_REGINFO(0x406, 1, DIRECT),
91         HWCTX_REGINFO(0x407, 1, DIRECT),
92         HWCTX_REGINFO(0x408, 1, DIRECT),
93         HWCTX_REGINFO(0x409, 1, DIRECT),
94         HWCTX_REGINFO(0x40a, 1, DIRECT),
95         HWCTX_REGINFO(0x40b, 1, DIRECT),
96         HWCTX_REGINFO(0x40c, 1, DIRECT),
97         HWCTX_REGINFO(0x40d, 1, DIRECT),
98         HWCTX_REGINFO(0x40e, 1, DIRECT),
99         HWCTX_REGINFO(0x40f, 1, DIRECT),
100         HWCTX_REGINFO(0x411, 1, DIRECT),
101         HWCTX_REGINFO(0x500, 1, DIRECT),
102         HWCTX_REGINFO(0x501, 1, DIRECT),
103         HWCTX_REGINFO(0x502, 1, DIRECT),
104         HWCTX_REGINFO(0x503, 1, DIRECT),
105         HWCTX_REGINFO(0x520, 32, DIRECT),
106         HWCTX_REGINFO(0x540, 64, INDIRECT),
107         HWCTX_REGINFO(0x600, 0, INDIRECT_OFFSET),
108         HWCTX_REGINFO(0x602, 16, INDIRECT_DATA),
109         HWCTX_REGINFO(0x603, 128, INDIRECT),
110         HWCTX_REGINFO(0x608, 4, DIRECT),
111         HWCTX_REGINFO(0x60e, 1, DIRECT),
112         HWCTX_REGINFO(0x700, 64, INDIRECT),
113         HWCTX_REGINFO(0x710, 16, DIRECT),
114         HWCTX_REGINFO(0x720, 32, DIRECT),
115         HWCTX_REGINFO(0x740, 1, DIRECT),
116         HWCTX_REGINFO(0x741, 1, DIRECT),
117         HWCTX_REGINFO(0x800, 0, INDIRECT_OFFSET),
118         HWCTX_REGINFO(0x802, 16, INDIRECT_DATA),
119         HWCTX_REGINFO(0x803, 512, INDIRECT),
120         HWCTX_REGINFO(0x805, 64, INDIRECT),
121         HWCTX_REGINFO(0x820, 32, DIRECT),
122         HWCTX_REGINFO(0x900, 64, INDIRECT),
123         HWCTX_REGINFO(0x902, 1, DIRECT),
124         HWCTX_REGINFO(0x903, 1, DIRECT),
125         HWCTX_REGINFO(0xa02, 1, DIRECT),
126         HWCTX_REGINFO(0xa03, 1, DIRECT),
127         HWCTX_REGINFO(0xa04, 1, DIRECT),
128         HWCTX_REGINFO(0xa05, 1, DIRECT),
129         HWCTX_REGINFO(0xa06, 1, DIRECT),
130         HWCTX_REGINFO(0xa07, 1, DIRECT),
131         HWCTX_REGINFO(0xa08, 1, DIRECT),
132         HWCTX_REGINFO(0xa09, 1, DIRECT),
133         HWCTX_REGINFO(0xa0a, 1, DIRECT),
134         HWCTX_REGINFO(0xa0b, 1, DIRECT),
135         HWCTX_REGINFO(0x205, 1024, INDIRECT)
136 };
137
138
139 /*** restore ***/
140
141 static unsigned int context_restore_size = 0;
142
143 static void restore_begin(u32 *ptr, u32 waitbase)
144 {
145         /* set class to host */
146         ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
147                                         NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
148         /* increment sync point base */
149         ptr[1] = nvhost_class_host_incr_syncpt_base(waitbase, 1);
150         /* set class to 3D */
151         ptr[2] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
152         /* program PSEQ_QUAD_ID */
153         ptr[3] = nvhost_opcode_imm(0x545, 0);
154 }
155 #define RESTORE_BEGIN_SIZE 4
156
157 static void restore_end(u32 *ptr, u32 syncpt_id)
158 {
159         /* syncpt increment to track restore gather. */
160         ptr[0] = nvhost_opcode_imm(0x0, ((1UL << 8) | (u8)(syncpt_id & 0xff)));
161 }
162 #define RESTORE_END_SIZE 1
163
164 static void restore_direct(u32 *ptr, u32 start_reg, u32 count)
165 {
166         ptr[0] = nvhost_opcode_incr(start_reg, count);
167 }
168 #define RESTORE_DIRECT_SIZE 1
169
170 static void restore_indoffset(u32 *ptr, u32 offset_reg, u32 offset)
171 {
172         ptr[0] = nvhost_opcode_imm(offset_reg, offset);
173 }
174 #define RESTORE_INDOFFSET_SIZE 1
175
176 static void restore_inddata(u32 *ptr, u32 data_reg, u32 count)
177 {
178         ptr[0] = nvhost_opcode_nonincr(data_reg, count);
179 }
180 #define RESTORE_INDDATA_SIZE 1
181
182 static void restore_registers_from_fifo(u32 *ptr, unsigned int count,
183                                         struct nvhost_channel *channel,
184                                         unsigned int *pending)
185 {
186         void __iomem *chan_regs = channel->aperture;
187         unsigned int entries = *pending;
188         while (count) {
189                 unsigned int num;
190
191                 while (!entries) {
192                         /* query host for number of entries in fifo */
193                         entries = nvhost_channel_fifostat_outfentries(
194                                 readl(chan_regs + HOST1X_CHANNEL_FIFOSTAT));
195                         if (!entries)
196                                 cpu_relax();
197                         /* TODO: [ahowe 2010-06-14] timeout */
198                 }
199                 num = min(entries, count);
200                 entries -= num;
201                 count -= num;
202
203                 while (num & ~0x3) {
204                         u32 arr[4];
205                         arr[0] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
206                         arr[1] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
207                         arr[2] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
208                         arr[3] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
209                         memcpy(ptr, arr, 4*sizeof(u32));
210                         ptr += 4;
211                         num -= 4;
212                 }
213                 while (num--)
214                         *ptr++ = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
215         }
216         *pending = entries;
217 }
218
219 static void setup_restore(u32 *ptr, u32 waitbase)
220 {
221         const struct hwctx_reginfo *r;
222         const struct hwctx_reginfo *rend;
223
224         restore_begin(ptr, waitbase);
225         ptr += RESTORE_BEGIN_SIZE;
226
227         r = ctxsave_regs_3d;
228         rend = ctxsave_regs_3d + ARRAY_SIZE(ctxsave_regs_3d);
229         for ( ; r != rend; ++r) {
230                 u32 offset = r->offset;
231                 u32 count = r->count;
232                 switch (r->type) {
233                 case HWCTX_REGINFO_DIRECT:
234                         restore_direct(ptr, offset, count);
235                         ptr += RESTORE_DIRECT_SIZE;
236                         break;
237                 case HWCTX_REGINFO_INDIRECT:
238                         restore_indoffset(ptr, offset, 0);
239                         ptr += RESTORE_INDOFFSET_SIZE;
240                         restore_inddata(ptr, offset + 1, count);
241                         ptr += RESTORE_INDDATA_SIZE;
242                         break;
243                 case HWCTX_REGINFO_INDIRECT_OFFSET:
244                         restore_indoffset(ptr, offset, count);
245                         ptr += RESTORE_INDOFFSET_SIZE;
246                         continue; /* INDIRECT_DATA follows with real count */
247                 case HWCTX_REGINFO_INDIRECT_DATA:
248                         restore_inddata(ptr, offset, count);
249                         ptr += RESTORE_INDDATA_SIZE;
250                         break;
251                 }
252                 ptr += count;
253         }
254
255         restore_end(ptr, NVSYNCPT_3D);
256         wmb();
257 }
258
259 /*** save ***/
260
261 /* the same context save command sequence is used for all contexts. */
262 static struct nvmap_handle_ref *context_save_buf = NULL;
263 static u32 context_save_phys = 0;
264 static u32 *context_save_ptr = NULL;
265 static unsigned int context_save_size = 0;
266
267 static void save_begin(u32 *ptr, u32 syncpt_id, u32 waitbase)
268 {
269         /* set class to the unit to flush */
270         ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
271         /*
272          * Flush pipe and signal context read thread to start reading
273          * sync point increment
274          */
275         ptr[1] = nvhost_opcode_imm(0, 0x100 | syncpt_id);
276         ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
277                                         NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
278         /* wait for base+1 */
279         ptr[3] = nvhost_class_host_wait_syncpt_base(syncpt_id, waitbase, 1);
280         ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
281         ptr[5] = nvhost_opcode_imm(0, syncpt_id);
282         ptr[6] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, 0, 0);
283 }
284 #define SAVE_BEGIN_SIZE 7
285
286 static void save_direct(u32 *ptr, u32 start_reg, u32 count)
287 {
288         ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1);
289         ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
290                                                 start_reg, true);
291         ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
292 }
293 #define SAVE_DIRECT_SIZE 3
294
295 static void save_indoffset(u32 *ptr, u32 offset_reg, u32 offset)
296 {
297         ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1);
298         ptr[1] = nvhost_class_host_indoff_reg_write(NV_HOST_MODULE_GR3D,
299                                                 offset_reg, true);
300         ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, 1);
301         ptr[3] = offset;
302 }
303 #define SAVE_INDOFFSET_SIZE 4
304
305 static inline void save_inddata(u32 *ptr, u32 data_reg, u32 count)
306 {
307         ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1);
308         ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
309                                                 data_reg, false);
310         ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
311 }
312 #define SAVE_INDDDATA_SIZE 3
313
314 static void save_end(u32 *ptr, u32 syncpt_id, u32 waitbase)
315 {
316         /* Wait for context read service */
317         ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
318         ptr[1] = nvhost_class_host_wait_syncpt_base(syncpt_id, waitbase, 3);
319         /* Increment syncpoint base */
320         ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
321         ptr[3] = nvhost_class_host_incr_syncpt_base(waitbase, 3);
322         /* set class back to the unit */
323         ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
324 }
325 #define SAVE_END_SIZE 5
326
327 static void __init setup_save(
328         u32 *ptr, unsigned int *words_save, unsigned int *words_restore,
329         u32 syncpt_id, u32 waitbase)
330 {
331         const struct hwctx_reginfo *r;
332         const struct hwctx_reginfo *rend;
333         unsigned int save = SAVE_BEGIN_SIZE + SAVE_END_SIZE;
334         unsigned int restore = RESTORE_BEGIN_SIZE + RESTORE_END_SIZE;
335
336         if (ptr) {
337                 save_begin(ptr, syncpt_id, waitbase);
338                 ptr += SAVE_BEGIN_SIZE;
339         }
340
341         r = ctxsave_regs_3d;
342         rend = ctxsave_regs_3d + ARRAY_SIZE(ctxsave_regs_3d);
343         for ( ; r != rend; ++r) {
344                 u32 offset = r->offset;
345                 u32 count = r->count;
346                 switch (r->type) {
347                 case HWCTX_REGINFO_DIRECT:
348                         if (ptr) {
349                                 save_direct(ptr, offset, count);
350                                 ptr += SAVE_DIRECT_SIZE;
351                         }
352                         save += SAVE_DIRECT_SIZE;
353                         restore += RESTORE_DIRECT_SIZE;
354                         break;
355                 case HWCTX_REGINFO_INDIRECT:
356                         if (ptr) {
357                                 save_indoffset(ptr, offset, 0);
358                                 ptr += SAVE_INDOFFSET_SIZE;
359                                 save_inddata(ptr, offset + 1, count);
360                                 ptr += SAVE_INDDDATA_SIZE;
361                         }
362                         save += SAVE_INDOFFSET_SIZE;
363                         restore += RESTORE_INDOFFSET_SIZE;
364                         save += SAVE_INDDDATA_SIZE;
365                         restore += RESTORE_INDDATA_SIZE;
366                         break;
367                 case HWCTX_REGINFO_INDIRECT_OFFSET:
368                         if (ptr) {
369                                 save_indoffset(ptr, offset, count);
370                                 ptr += SAVE_INDOFFSET_SIZE;
371                         }
372                         save += SAVE_INDOFFSET_SIZE;
373                         restore += RESTORE_INDOFFSET_SIZE;
374                         continue; /* INDIRECT_DATA follows with real count */
375                 case HWCTX_REGINFO_INDIRECT_DATA:
376                         if (ptr) {
377                                 save_inddata(ptr, offset, count);
378                                 ptr += SAVE_INDDDATA_SIZE;
379                         }
380                         save += SAVE_INDDDATA_SIZE;
381                         restore += RESTORE_INDDATA_SIZE;
382                         break;
383                 }
384                 if (ptr) {
385                         memset(ptr, 0, count * 4);
386                         ptr += count;
387                 }
388                 save += count;
389                 restore += count;
390         }
391
392         if (ptr)
393                 save_end(ptr, syncpt_id, waitbase);
394
395         if (words_save)
396                 *words_save = save;
397         if (words_restore)
398                 *words_restore = restore;
399         wmb();
400 }
401
402 /*** ctx3d ***/
403
404 static struct nvhost_hwctx *ctx3d_alloc(struct nvhost_channel *ch)
405 {
406         struct nvhost_hwctx *ctx;
407         struct nvmap_client *nvmap = ch->dev->nvmap;
408
409         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
410         if (!ctx)
411                 return NULL;
412         ctx->restore = nvmap_alloc(nvmap, context_restore_size * 4, 32,
413                                    NVMAP_HANDLE_WRITE_COMBINE);
414
415         if (IS_ERR_OR_NULL(ctx->restore)) {
416                 kfree(ctx);
417                 return NULL;
418         }
419
420         ctx->save_cpu_data = nvmap_mmap(ctx->restore);
421         if (!ctx->save_cpu_data) {
422                 nvmap_free(nvmap, ctx->restore);
423                 kfree(ctx);
424                 return NULL;
425         }
426
427         setup_restore(ctx->save_cpu_data, NVWAITBASE_3D);
428         ctx->channel = ch;
429         ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
430         ctx->restore_size = context_restore_size;
431         ctx->save = context_save_buf;
432         ctx->save_phys = context_save_phys;
433         ctx->save_size = context_save_size;
434         ctx->save_incrs = 3;
435         ctx->restore_incrs = 1;
436         ctx->valid = false;
437         kref_init(&ctx->ref);
438         return ctx;
439 }
440
441 static void ctx3d_free(struct kref *ref)
442 {
443         struct nvhost_hwctx *ctx = container_of(ref, struct nvhost_hwctx, ref);
444         struct nvmap_client *nvmap = ctx->channel->dev->nvmap;
445
446         nvmap_munmap(ctx->restore, ctx->save_cpu_data);
447         nvmap_unpin(nvmap, ctx->restore);
448         nvmap_free(nvmap, ctx->restore);
449         kfree(ctx);
450 }
451
452 static void ctx3d_get(struct nvhost_hwctx *ctx)
453 {
454         kref_get(&ctx->ref);
455 }
456
457 static void ctx3d_put(struct nvhost_hwctx *ctx)
458 {
459         kref_put(&ctx->ref, ctx3d_free);
460 }
461
462 static void ctx3d_save_service(struct nvhost_hwctx *ctx)
463 {
464         const struct hwctx_reginfo *r;
465         const struct hwctx_reginfo *rend;
466         unsigned int pending = 0;
467         u32 *ptr = (u32 *)ctx->save_cpu_data + RESTORE_BEGIN_SIZE;
468
469         BUG_ON(!ctx->save_cpu_data);
470
471         r = ctxsave_regs_3d;
472         rend = ctxsave_regs_3d + ARRAY_SIZE(ctxsave_regs_3d);
473         for ( ; r != rend; ++r) {
474                 u32 count = r->count;
475                 switch (r->type) {
476                 case HWCTX_REGINFO_DIRECT:
477                         ptr += RESTORE_DIRECT_SIZE;
478                         break;
479                 case HWCTX_REGINFO_INDIRECT:
480                         ptr += RESTORE_INDOFFSET_SIZE + RESTORE_INDDATA_SIZE;
481                         break;
482                 case HWCTX_REGINFO_INDIRECT_OFFSET:
483                         ptr += RESTORE_INDOFFSET_SIZE;
484                         continue; /* INDIRECT_DATA follows with real count */
485                 case HWCTX_REGINFO_INDIRECT_DATA:
486                         ptr += RESTORE_INDDATA_SIZE;
487                         break;
488                 }
489                 restore_registers_from_fifo(ptr, count, ctx->channel, &pending);
490                 ptr += count;
491         }
492
493         BUG_ON((u32)((ptr + RESTORE_END_SIZE) - (u32*)ctx->save_cpu_data)
494                 != context_restore_size);
495
496         wmb();
497         nvhost_syncpt_cpu_incr(&ctx->channel->dev->syncpt, NVSYNCPT_3D);
498 }
499
500
501 /*** nvhost_3dctx ***/
502
503 int __init nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
504 {
505         struct nvhost_channel *ch;
506         struct nvmap_client *nvmap;
507
508         ch = container_of(h, struct nvhost_channel, ctxhandler);
509         nvmap = ch->dev->nvmap;
510
511         setup_save(NULL, &context_save_size, &context_restore_size, 0, 0);
512
513         context_save_buf = nvmap_alloc(nvmap, context_save_size * 4, 32,
514                                        NVMAP_HANDLE_WRITE_COMBINE);
515
516         if (IS_ERR(context_save_buf)) {
517                 int err = PTR_ERR(context_save_buf);
518                 context_save_buf = NULL;
519                 return err;
520         }
521
522         context_save_ptr = nvmap_mmap(context_save_buf);
523         if (!context_save_ptr) {
524                 nvmap_free(nvmap, context_save_buf);
525                 context_save_buf = NULL;
526                 return -ENOMEM;
527         }
528
529         context_save_phys = nvmap_pin(nvmap, context_save_buf);
530         setup_save(context_save_ptr, NULL, NULL, NVSYNCPT_3D, NVWAITBASE_3D);
531
532         h->alloc = ctx3d_alloc;
533         h->get = ctx3d_get;
534         h->put = ctx3d_put;
535         h->save_service = ctx3d_save_service;
536         return 0;
537 }
538
539 /* TODO: [ahatala 2010-05-27] */
540 int __init nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h)
541 {
542         return 0;
543 }