video: tegra: host: change nvhost_clk_rate_args
[linux-3.10.git] / drivers / video / tegra / host / bus_client.c
1 /*
2  * drivers/video/tegra/host/bus_client.c
3  *
4  * Tegra Graphics Host Client Module
5  *
6  * Copyright (c) 2010-2013, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/slab.h>
22 #include <linux/string.h>
23 #include <linux/spinlock.h>
24 #include <linux/fs.h>
25 #include <linux/cdev.h>
26 #include <linux/uaccess.h>
27 #include <linux/file.h>
28 #include <linux/clk.h>
29 #include <linux/hrtimer.h>
30 #include <linux/export.h>
31 #include <linux/firmware.h>
32
33 #include <trace/events/nvhost.h>
34
35 #include <linux/io.h>
36 #include <linux/string.h>
37
38 #include <linux/nvhost.h>
39 #include <linux/nvhost_ioctl.h>
40
41 #include <mach/gpufuse.h>
42 #include <mach/hardware.h>
43 #include <mach/iomap.h>
44
45 #include "debug.h"
46 #include "bus_client.h"
47 #include "dev.h"
48 #include "nvhost_memmgr.h"
49 #include "chip_support.h"
50 #include "nvhost_acm.h"
51
52 #include "nvhost_channel.h"
53 #include "nvhost_job.h"
54 #include "nvhost_hwctx.h"
55
56 static int validate_reg(struct platform_device *ndev, u32 offset, int count)
57 {
58         struct resource *r = platform_get_resource(ndev, IORESOURCE_MEM, 0);
59         int err = 0;
60
61         if (offset + 4 * count > resource_size(r)
62                         || (offset + 4 * count < offset))
63                 err = -EPERM;
64
65         return err;
66 }
67
68 int nvhost_read_module_regs(struct platform_device *ndev,
69                         u32 offset, int count, u32 *values)
70 {
71         struct nvhost_device_data *pdata = platform_get_drvdata(ndev);
72         void __iomem *p = pdata->aperture + offset;
73         int err;
74
75         /* verify offset */
76         err = validate_reg(ndev, offset, count);
77         if (err)
78                 return err;
79
80         nvhost_module_busy(ndev);
81         while (count--) {
82                 *(values++) = readl(p);
83                 p += 4;
84         }
85         rmb();
86         nvhost_module_idle(ndev);
87
88         return 0;
89 }
90
91 int nvhost_write_module_regs(struct platform_device *ndev,
92                         u32 offset, int count, const u32 *values)
93 {
94         void __iomem *p;
95         int err;
96         struct nvhost_device_data *pdata = platform_get_drvdata(ndev);
97
98         p = pdata->aperture + offset;
99
100         /* verify offset */
101         err = validate_reg(ndev, offset, count);
102         if (err)
103                 return err;
104
105         nvhost_module_busy(ndev);
106         while (count--) {
107                 writel(*(values++), p);
108                 p += 4;
109         }
110         wmb();
111         nvhost_module_idle(ndev);
112
113         return 0;
114 }
115
116 struct nvhost_channel_userctx {
117         struct nvhost_channel *ch;
118         struct nvhost_hwctx *hwctx;
119         struct nvhost_submit_hdr_ext hdr;
120         int num_relocshifts;
121         struct nvhost_job *job;
122         struct mem_mgr *memmgr;
123         u32 timeout;
124         u32 priority;
125         int clientid;
126 };
127
128 static int nvhost_channelrelease(struct inode *inode, struct file *filp)
129 {
130         struct nvhost_channel_userctx *priv = filp->private_data;
131
132         trace_nvhost_channel_release(dev_name(&priv->ch->dev->dev));
133
134         filp->private_data = NULL;
135
136         nvhost_module_remove_client(priv->ch->dev, priv);
137         nvhost_putchannel(priv->ch, priv->hwctx);
138
139         if (priv->hwctx)
140                 priv->ch->ctxhandler->put(priv->hwctx);
141
142         if (priv->job)
143                 nvhost_job_put(priv->job);
144
145         nvhost_memmgr_put_mgr(priv->memmgr);
146         kfree(priv);
147         return 0;
148 }
149
150 static int nvhost_channelopen(struct inode *inode, struct file *filp)
151 {
152         struct nvhost_channel_userctx *priv;
153         struct nvhost_channel *ch;
154
155         ch = container_of(inode->i_cdev, struct nvhost_channel, cdev);
156         ch = nvhost_getchannel(ch);
157         if (!ch)
158                 return -ENOMEM;
159         trace_nvhost_channel_open(dev_name(&ch->dev->dev));
160
161         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
162         if (!priv) {
163                 nvhost_putchannel(ch, NULL);
164                 return -ENOMEM;
165         }
166         filp->private_data = priv;
167         priv->ch = ch;
168         if(nvhost_module_add_client(ch->dev, priv))
169                 goto fail;
170
171         if (ch->ctxhandler && ch->ctxhandler->alloc) {
172                 priv->hwctx = ch->ctxhandler->alloc(ch->ctxhandler, ch);
173                 if (!priv->hwctx)
174                         goto fail;
175         }
176         priv->priority = NVHOST_PRIORITY_MEDIUM;
177         priv->clientid = atomic_add_return(1,
178                         &nvhost_get_host(ch->dev)->clientid);
179         priv->timeout = CONFIG_TEGRA_GRHOST_DEFAULT_TIMEOUT;
180
181         return 0;
182 fail:
183         nvhost_channelrelease(inode, filp);
184         return -ENOMEM;
185 }
186
187 static int set_submit(struct nvhost_channel_userctx *ctx)
188 {
189         struct platform_device *ndev = ctx->ch->dev;
190         struct nvhost_master *host = nvhost_get_host(ndev);
191
192         /* submit should have at least 1 cmdbuf */
193         if (!ctx->hdr.num_cmdbufs ||
194                         !nvhost_syncpt_is_valid(&host->syncpt,
195                                 ctx->hdr.syncpt_id))
196                 return -EIO;
197
198         if (!ctx->memmgr) {
199                 dev_err(&ndev->dev, "no nvmap context set\n");
200                 return -EFAULT;
201         }
202
203         if (ctx->job) {
204                 dev_warn(&ndev->dev, "performing channel submit when a job already exists\n");
205                 nvhost_job_put(ctx->job);
206         }
207         ctx->job = nvhost_job_alloc(ctx->ch,
208                         ctx->hwctx,
209                         ctx->hdr.num_cmdbufs,
210                         ctx->hdr.num_relocs,
211                         ctx->hdr.num_waitchks,
212                         ctx->memmgr);
213         if (!ctx->job)
214                 return -ENOMEM;
215         ctx->job->timeout = ctx->timeout;
216         ctx->job->syncpt_id = ctx->hdr.syncpt_id;
217         ctx->job->syncpt_incrs = ctx->hdr.syncpt_incrs;
218         ctx->job->priority = ctx->priority;
219         ctx->job->clientid = ctx->clientid;
220
221         if (ctx->hdr.submit_version >= NVHOST_SUBMIT_VERSION_V2)
222                 ctx->num_relocshifts = ctx->hdr.num_relocs;
223
224         return 0;
225 }
226
227 static void reset_submit(struct nvhost_channel_userctx *ctx)
228 {
229         ctx->hdr.num_cmdbufs = 0;
230         ctx->hdr.num_relocs = 0;
231         ctx->num_relocshifts = 0;
232         ctx->hdr.num_waitchks = 0;
233
234         if (ctx->job) {
235                 nvhost_job_put(ctx->job);
236                 ctx->job = NULL;
237         }
238 }
239
240 static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
241                                 size_t count, loff_t *offp)
242 {
243         struct nvhost_channel_userctx *priv = filp->private_data;
244         size_t remaining = count;
245         int err = 0;
246         struct nvhost_job *job = priv->job;
247         struct nvhost_submit_hdr_ext *hdr = &priv->hdr;
248         const char *chname = priv->ch->dev->name;
249
250         if (!job)
251                 return -EIO;
252
253         while (remaining) {
254                 size_t consumed;
255                 if (!hdr->num_relocs &&
256                     !priv->num_relocshifts &&
257                     !hdr->num_cmdbufs &&
258                     !hdr->num_waitchks) {
259                         consumed = sizeof(struct nvhost_submit_hdr);
260                         if (remaining < consumed)
261                                 break;
262                         if (copy_from_user(hdr, buf, consumed)) {
263                                 err = -EFAULT;
264                                 break;
265                         }
266                         hdr->submit_version = NVHOST_SUBMIT_VERSION_V0;
267                         err = set_submit(priv);
268                         if (err)
269                                 break;
270                         trace_nvhost_channel_write_submit(chname,
271                           count, hdr->num_cmdbufs, hdr->num_relocs,
272                           hdr->syncpt_id, hdr->syncpt_incrs);
273                 } else if (hdr->num_cmdbufs) {
274                         struct nvhost_cmdbuf cmdbuf;
275                         consumed = sizeof(cmdbuf);
276                         if (remaining < consumed)
277                                 break;
278                         if (copy_from_user(&cmdbuf, buf, consumed)) {
279                                 err = -EFAULT;
280                                 break;
281                         }
282                         trace_nvhost_channel_write_cmdbuf(chname,
283                                 cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
284                         nvhost_job_add_gather(job,
285                                 cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
286                         hdr->num_cmdbufs--;
287                 } else if (hdr->num_relocs) {
288                         int numrelocs = remaining / sizeof(struct nvhost_reloc);
289                         if (!numrelocs)
290                                 break;
291                         numrelocs = min_t(int, numrelocs, priv->hdr.num_relocs);
292                         consumed = numrelocs * sizeof(struct nvhost_reloc);
293                         if (copy_from_user(&job->relocarray[job->num_relocs],
294                                         buf, consumed)) {
295                                 err = -EFAULT;
296                                 break;
297                         }
298                         while (numrelocs) {
299                                 struct nvhost_reloc *reloc =
300                                         &job->relocarray[job->num_relocs];
301                                 trace_nvhost_channel_write_reloc(chname,
302                                         reloc->cmdbuf_mem,
303                                         reloc->cmdbuf_offset,
304                                         reloc->target,
305                                         reloc->target_offset);
306                                 job->num_relocs++;
307                                 hdr->num_relocs--;
308                                 numrelocs--;
309                         }
310                 } else if (hdr->num_waitchks) {
311                         int numwaitchks =
312                                 (remaining / sizeof(struct nvhost_waitchk));
313                         if (!numwaitchks)
314                                 break;
315                         numwaitchks = min_t(int,
316                                 numwaitchks, hdr->num_waitchks);
317                         consumed = numwaitchks * sizeof(struct nvhost_waitchk);
318                         if (copy_from_user(&job->waitchk[job->num_waitchk],
319                                         buf, consumed)) {
320                                 err = -EFAULT;
321                                 break;
322                         }
323                         trace_nvhost_channel_write_waitchks(
324                           chname, numwaitchks);
325                         job->num_waitchk += numwaitchks;
326                         hdr->num_waitchks -= numwaitchks;
327                 } else if (priv->num_relocshifts) {
328                         int next_shift =
329                                 job->num_relocs - priv->num_relocshifts;
330                         int num =
331                                 (remaining / sizeof(struct nvhost_reloc_shift));
332                         if (!num)
333                                 break;
334                         num = min_t(int, num, priv->num_relocshifts);
335                         consumed = num * sizeof(struct nvhost_reloc_shift);
336                         if (copy_from_user(&job->relocshiftarray[next_shift],
337                                         buf, consumed)) {
338                                 err = -EFAULT;
339                                 break;
340                         }
341                         priv->num_relocshifts -= num;
342                 } else {
343                         err = -EFAULT;
344                         break;
345                 }
346                 remaining -= consumed;
347                 buf += consumed;
348         }
349
350         if (err < 0) {
351                 dev_err(&priv->ch->dev->dev, "channel write error\n");
352                 reset_submit(priv);
353                 return err;
354         }
355
356         return count - remaining;
357 }
358
359 static int nvhost_ioctl_channel_flush(
360         struct nvhost_channel_userctx *ctx,
361         struct nvhost_get_param_args *args,
362         int null_kickoff)
363 {
364         struct platform_device *ndev = to_platform_device(&ctx->ch->dev->dev);
365         int err;
366
367         trace_nvhost_ioctl_channel_flush(ctx->ch->dev->name);
368
369         if (!ctx->job ||
370             ctx->hdr.num_relocs ||
371             ctx->hdr.num_cmdbufs ||
372             ctx->hdr.num_waitchks) {
373                 reset_submit(ctx);
374                 dev_err(&ndev->dev, "channel submit out of sync\n");
375                 return -EFAULT;
376         }
377
378         err = nvhost_job_pin(ctx->job, &nvhost_get_host(ndev)->syncpt);
379         if (err) {
380                 dev_warn(&ndev->dev, "nvhost_job_pin failed: %d\n", err);
381                 goto fail;
382         }
383
384         if (nvhost_debug_null_kickoff_pid == current->tgid)
385                 null_kickoff = 1;
386         ctx->job->null_kickoff = null_kickoff;
387
388         if ((nvhost_debug_force_timeout_pid == current->tgid) &&
389             (nvhost_debug_force_timeout_channel == ctx->ch->chid)) {
390                 ctx->timeout = nvhost_debug_force_timeout_val;
391         }
392
393         /* context switch if needed, and submit user's gathers to the channel */
394         err = nvhost_channel_submit(ctx->job);
395         args->value = ctx->job->syncpt_end;
396
397 fail:
398         if (err)
399                 nvhost_job_unpin(ctx->job);
400
401         nvhost_job_put(ctx->job);
402         ctx->job = NULL;
403
404         return err;
405 }
406
407 static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
408                 struct nvhost_submit_args *args)
409 {
410         struct nvhost_job *job;
411         int num_cmdbufs = args->num_cmdbufs;
412         int num_relocs = args->num_relocs;
413         int num_waitchks = args->num_waitchks;
414         struct nvhost_cmdbuf __user *cmdbufs = args->cmdbufs;
415         struct nvhost_reloc __user *relocs = args->relocs;
416         struct nvhost_reloc_shift __user *reloc_shifts = args->reloc_shifts;
417         struct nvhost_waitchk __user *waitchks = args->waitchks;
418         struct nvhost_syncpt_incr syncpt_incr;
419         struct nvhost_master *host = nvhost_get_host(ctx->ch->dev);
420         int err;
421
422         /* We don't yet support other than one nvhost_syncpt_incrs per submit */
423         if (args->num_syncpt_incrs != 1)
424                 return -EINVAL;
425
426         job = nvhost_job_alloc(ctx->ch,
427                         ctx->hwctx,
428                         args->num_cmdbufs,
429                         args->num_relocs,
430                         args->num_waitchks,
431                         ctx->memmgr);
432         if (!job)
433                 return -ENOMEM;
434
435         job->num_relocs = args->num_relocs;
436         job->num_waitchk = args->num_waitchks;
437         job->priority = ctx->priority;
438         job->clientid = ctx->clientid;
439
440         while (num_cmdbufs) {
441                 struct nvhost_cmdbuf cmdbuf;
442                 err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf));
443                 if (err)
444                         goto fail;
445                 nvhost_job_add_gather(job,
446                                 cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
447                 num_cmdbufs--;
448                 cmdbufs++;
449         }
450
451         err = copy_from_user(job->relocarray,
452                         relocs, sizeof(*relocs) * num_relocs);
453         if (err)
454                 goto fail;
455
456         err = copy_from_user(job->relocshiftarray,
457                         reloc_shifts, sizeof(*reloc_shifts) * num_relocs);
458         if (err)
459                 goto fail;
460
461         err = copy_from_user(job->waitchk,
462                         waitchks, sizeof(*waitchks) * num_waitchks);
463         if (err)
464                 goto fail;
465
466         err = copy_from_user(&syncpt_incr,
467                         args->syncpt_incrs, sizeof(syncpt_incr));
468         if (err)
469                 goto fail;
470         job->syncpt_id = syncpt_incr.syncpt_id;
471         if (job->syncpt_id > host->info.nb_pts) {
472                 err = -EINVAL;
473                 goto fail;
474         }
475         job->syncpt_incrs = syncpt_incr.syncpt_incrs;
476
477         trace_nvhost_channel_submit(ctx->ch->dev->name,
478                 job->num_gathers, job->num_relocs, job->num_waitchk,
479                 job->syncpt_id, job->syncpt_incrs);
480
481         err = nvhost_job_pin(job, &nvhost_get_host(ctx->ch->dev)->syncpt);
482         if (err)
483                 goto fail;
484
485         if (args->timeout)
486                 job->timeout = min(ctx->timeout, args->timeout);
487         else
488                 job->timeout = ctx->timeout;
489
490         err = nvhost_channel_submit(job);
491         if (err)
492                 goto fail_submit;
493
494         args->fence = job->syncpt_end;
495
496         nvhost_job_put(job);
497
498         return 0;
499
500 fail_submit:
501         nvhost_job_unpin(job);
502 fail:
503         nvhost_job_put(job);
504         return err;
505 }
506
507 static int nvhost_ioctl_channel_read_3d_reg(struct nvhost_channel_userctx *ctx,
508         struct nvhost_read_3d_reg_args *args)
509 {
510         return nvhost_channel_read_reg(ctx->ch, ctx->hwctx,
511                         args->offset, &args->value);
512 }
513
514 static int moduleid_to_index(struct platform_device *dev, u32 moduleid)
515 {
516         int i;
517         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
518
519         for (i = 0; i < NVHOST_MODULE_MAX_CLOCKS; i++) {
520                 if (pdata->clocks[i].moduleid == moduleid)
521                         return i;
522         }
523
524         /* Old user space is sending a random number in args. Return clock
525          * zero in these cases. */
526         return 0;
527 }
528
529 static int nvhost_ioctl_channel_set_rate(struct nvhost_channel_userctx *ctx,
530         struct nvhost_clk_rate_args *arg)
531 {
532         u32 moduleid = (arg->moduleid >> NVHOST_MODULE_ID_BIT_POS)
533                         & ((1 << NVHOST_MODULE_ID_BIT_WIDTH) - 1);
534         u32 attr = (arg->moduleid >> NVHOST_CLOCK_ATTR_BIT_POS)
535                         & ((1 << NVHOST_CLOCK_ATTR_BIT_WIDTH) - 1);
536         int index = moduleid ?
537                         moduleid_to_index(ctx->ch->dev, moduleid) : 0;
538
539         return nvhost_module_set_rate(ctx->ch->dev,
540                         ctx, arg->rate, index, attr);
541 }
542
543 static int nvhost_ioctl_channel_get_rate(struct nvhost_channel_userctx *ctx,
544         u32 moduleid, u32 *rate)
545 {
546         int index = moduleid ? moduleid_to_index(ctx->ch->dev, moduleid) : 0;
547
548         return nvhost_module_get_rate(ctx->ch->dev,
549                         (unsigned long *)rate, index);
550 }
551
552 static int nvhost_ioctl_channel_module_regrdwr(
553         struct nvhost_channel_userctx *ctx,
554         struct nvhost_ctrl_module_regrdwr_args *args)
555 {
556         u32 num_offsets = args->num_offsets;
557         u32 *offsets = args->offsets;
558         u32 *values = args->values;
559         u32 vals[64];
560         struct platform_device *ndev;
561
562         trace_nvhost_ioctl_channel_module_regrdwr(args->id,
563                 args->num_offsets, args->write);
564
565         /* Check that there is something to read and that block size is
566          * u32 aligned */
567         if (num_offsets == 0 || args->block_size & 3)
568                 return -EINVAL;
569
570         ndev = ctx->ch->dev;
571
572         while (num_offsets--) {
573                 int err;
574                 u32 offs;
575                 int remaining = args->block_size >> 2;
576
577                 if (get_user(offs, offsets))
578                         return -EFAULT;
579
580                 offsets++;
581                 while (remaining) {
582                         int batch = min(remaining, 64);
583                         if (args->write) {
584                                 if (copy_from_user(vals, values,
585                                                 batch * sizeof(u32)))
586                                         return -EFAULT;
587
588                                 err = nvhost_write_module_regs(ndev,
589                                         offs, batch, vals);
590                                 if (err)
591                                         return err;
592                         } else {
593                                 err = nvhost_read_module_regs(ndev,
594                                                 offs, batch, vals);
595                                 if (err)
596                                         return err;
597
598                                 if (copy_to_user(values, vals,
599                                                 batch * sizeof(u32)))
600                                         return -EFAULT;
601                         }
602
603                         remaining -= batch;
604                         offs += batch * sizeof(u32);
605                         values += batch;
606                 }
607         }
608
609         return 0;
610 }
611
612 static u32 create_mask(u32 *words, int num)
613 {
614         int i;
615         u32 word = 0;
616         for (i = 0; i < num && words[i] && words[i] < BITS_PER_LONG; i++)
617                 word |= BIT(words[i]);
618
619         return word;
620 }
621
622 static long nvhost_channelctl(struct file *filp,
623         unsigned int cmd, unsigned long arg)
624 {
625         struct nvhost_channel_userctx *priv = filp->private_data;
626         u8 buf[NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE];
627         int err = 0;
628
629         if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
630                 (_IOC_NR(cmd) == 0) ||
631                 (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST) ||
632                 (_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE))
633                 return -EFAULT;
634
635         if (_IOC_DIR(cmd) & _IOC_WRITE) {
636                 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
637                         return -EFAULT;
638         }
639
640         switch (cmd) {
641         case NVHOST_IOCTL_CHANNEL_FLUSH:
642                 err = nvhost_ioctl_channel_flush(priv, (void *)buf, 0);
643                 break;
644         case NVHOST_IOCTL_CHANNEL_NULL_KICKOFF:
645                 err = nvhost_ioctl_channel_flush(priv, (void *)buf, 1);
646                 break;
647         case NVHOST_IOCTL_CHANNEL_SUBMIT_EXT:
648         {
649                 struct nvhost_submit_hdr_ext *hdr;
650
651                 if (priv->hdr.num_relocs ||
652                     priv->num_relocshifts ||
653                     priv->hdr.num_cmdbufs ||
654                     priv->hdr.num_waitchks) {
655                         reset_submit(priv);
656                         dev_err(&priv->ch->dev->dev,
657                                 "channel submit out of sync\n");
658                         err = -EIO;
659                         break;
660                 }
661
662                 hdr = (struct nvhost_submit_hdr_ext *)buf;
663                 if (hdr->submit_version > NVHOST_SUBMIT_VERSION_MAX_SUPPORTED) {
664                         dev_err(&priv->ch->dev->dev,
665                                 "submit version %d > max supported %d\n",
666                                 hdr->submit_version,
667                                 NVHOST_SUBMIT_VERSION_MAX_SUPPORTED);
668                         err = -EINVAL;
669                         break;
670                 }
671                 memcpy(&priv->hdr, hdr, sizeof(struct nvhost_submit_hdr_ext));
672                 err = set_submit(priv);
673                 trace_nvhost_ioctl_channel_submit(priv->ch->dev->name,
674                         priv->hdr.submit_version,
675                         priv->hdr.num_cmdbufs, priv->hdr.num_relocs,
676                         priv->hdr.num_waitchks,
677                         priv->hdr.syncpt_id, priv->hdr.syncpt_incrs);
678                 break;
679         }
680         case NVHOST_IOCTL_CHANNEL_GET_SYNCPOINTS:
681         {
682                 struct nvhost_device_data *pdata = \
683                         platform_get_drvdata(priv->ch->dev);
684                 ((struct nvhost_get_param_args *)buf)->value =
685                         create_mask(pdata->syncpts, NVHOST_MODULE_MAX_SYNCPTS);
686                 break;
687         }
688         case NVHOST_IOCTL_CHANNEL_GET_SYNCPOINT:
689         {
690                 struct nvhost_device_data *pdata = \
691                         platform_get_drvdata(priv->ch->dev);
692                 struct nvhost_get_param_arg *arg =
693                         (struct nvhost_get_param_arg *)buf;
694                 if (arg->param >= NVHOST_MODULE_MAX_SYNCPTS
695                                 || !pdata->syncpts[arg->param])
696                         return -EINVAL;
697                 arg->value = pdata->syncpts[arg->param];
698                 break;
699         }
700         case NVHOST_IOCTL_CHANNEL_GET_WAITBASES:
701         {
702                 struct nvhost_device_data *pdata = \
703                         platform_get_drvdata(priv->ch->dev);
704                 ((struct nvhost_get_param_args *)buf)->value =
705                         create_mask(pdata->waitbases,
706                                         NVHOST_MODULE_MAX_WAITBASES);
707                 break;
708         }
709         case NVHOST_IOCTL_CHANNEL_GET_WAITBASE:
710         {
711                 struct nvhost_device_data *pdata = \
712                         platform_get_drvdata(priv->ch->dev);
713                 struct nvhost_get_param_arg *arg =
714                         (struct nvhost_get_param_arg *)buf;
715                 if (arg->param >= NVHOST_MODULE_MAX_WAITBASES
716                                 || !pdata->waitbases[arg->param])
717                         return -EINVAL;
718                 arg->value = pdata->waitbases[arg->param];
719                 break;
720         }
721         case NVHOST_IOCTL_CHANNEL_GET_MODMUTEXES:
722         {
723                 struct nvhost_device_data *pdata = \
724                         platform_get_drvdata(priv->ch->dev);
725                 ((struct nvhost_get_param_args *)buf)->value =
726                         create_mask(pdata->modulemutexes,
727                                         NVHOST_MODULE_MAX_MODMUTEXES);
728                 break;
729         }
730         case NVHOST_IOCTL_CHANNEL_GET_MODMUTEX:
731         {
732                 struct nvhost_device_data *pdata = \
733                         platform_get_drvdata(priv->ch->dev);
734                 struct nvhost_get_param_arg *arg =
735                         (struct nvhost_get_param_arg *)buf;
736                 if (arg->param >= NVHOST_MODULE_MAX_MODMUTEXES
737                                 || !pdata->modulemutexes[arg->param])
738                         return -EINVAL;
739                 arg->value = pdata->modulemutexes[arg->param];
740                 break;
741         }
742         case NVHOST_IOCTL_CHANNEL_SET_NVMAP_FD:
743         {
744                 int fd = (int)((struct nvhost_set_nvmap_fd_args *)buf)->fd;
745                 struct mem_mgr *new_client = nvhost_memmgr_get_mgr_file(fd);
746
747                 if (IS_ERR(new_client)) {
748                         err = PTR_ERR(new_client);
749                         break;
750                 }
751
752                 if (priv->memmgr)
753                         nvhost_memmgr_put_mgr(priv->memmgr);
754
755                 priv->memmgr = new_client;
756                 break;
757         }
758         case NVHOST_IOCTL_CHANNEL_READ_3D_REG:
759                 err = nvhost_ioctl_channel_read_3d_reg(priv, (void *)buf);
760                 break;
761         case NVHOST_IOCTL_CHANNEL_GET_CLK_RATE:
762         {
763                 struct nvhost_clk_rate_args *arg =
764                                 (struct nvhost_clk_rate_args *)buf;
765
766                 err = nvhost_ioctl_channel_get_rate(priv,
767                                 arg->moduleid, &arg->rate);
768                 break;
769         }
770         case NVHOST_IOCTL_CHANNEL_SET_CLK_RATE:
771         {
772                 struct nvhost_clk_rate_args *arg =
773                                 (struct nvhost_clk_rate_args *)buf;
774
775                 err = nvhost_ioctl_channel_set_rate(priv, arg);
776                 break;
777         }
778         case NVHOST_IOCTL_CHANNEL_SET_TIMEOUT:
779                 priv->timeout =
780                         (u32)((struct nvhost_set_timeout_args *)buf)->timeout;
781                 dev_dbg(&priv->ch->dev->dev,
782                         "%s: setting buffer timeout (%d ms) for userctx 0x%p\n",
783                         __func__, priv->timeout, priv);
784                 break;
785         case NVHOST_IOCTL_CHANNEL_GET_TIMEDOUT:
786                 ((struct nvhost_get_param_args *)buf)->value =
787                                 priv->hwctx->has_timedout;
788                 break;
789         case NVHOST_IOCTL_CHANNEL_SET_PRIORITY:
790                 priv->priority =
791                         (u32)((struct nvhost_set_priority_args *)buf)->priority;
792                 break;
793         case NVHOST_IOCTL_CHANNEL_MODULE_REGRDWR:
794                 err = nvhost_ioctl_channel_module_regrdwr(priv, (void *)buf);
795                 break;
796         case NVHOST_IOCTL_CHANNEL_SUBMIT:
797                 err = nvhost_ioctl_channel_submit(priv, (void *)buf);
798                 break;
799         default:
800                 err = -ENOTTY;
801                 break;
802         }
803
804         if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
805                 err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd));
806
807         return err;
808 }
809
810 static const struct file_operations nvhost_channelops = {
811         .owner = THIS_MODULE,
812         .release = nvhost_channelrelease,
813         .open = nvhost_channelopen,
814         .write = nvhost_channelwrite,
815         .unlocked_ioctl = nvhost_channelctl
816 };
817
818 int nvhost_client_user_init(struct platform_device *dev)
819 {
820         int err, devno;
821         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
822
823         struct nvhost_channel *ch = pdata->channel;
824         err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
825         if (err < 0) {
826                 dev_err(&dev->dev, "failed to allocate devno\n");
827                 goto fail;
828         }
829
830         cdev_init(&ch->cdev, &nvhost_channelops);
831         ch->cdev.owner = THIS_MODULE;
832
833         err = cdev_add(&ch->cdev, devno, 1);
834         if (err < 0) {
835                 dev_err(&dev->dev,
836                         "failed to add chan %i cdev\n", pdata->index);
837                 goto fail;
838         }
839         ch->node = device_create(nvhost_get_host(dev)->nvhost_class,
840                         NULL, devno, NULL,
841                         IFACE_NAME "-%s", dev_name(&dev->dev));
842         if (IS_ERR(ch->node)) {
843                 err = PTR_ERR(ch->node);
844                 dev_err(&dev->dev,
845                         "failed to create %s channel device\n",
846                         dev_name(&dev->dev));
847                 goto fail;
848         }
849
850         return 0;
851 fail:
852         return err;
853 }
854
855 int nvhost_client_device_init(struct platform_device *dev)
856 {
857         int err;
858         struct nvhost_master *nvhost_master = nvhost_get_host(dev);
859         struct nvhost_channel *ch;
860         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
861
862         ch = nvhost_alloc_channel(dev);
863         if (ch == NULL)
864                 return -ENODEV;
865
866         /* store the pointer to this device for channel */
867         ch->dev = dev;
868
869         err = nvhost_channel_init(ch, nvhost_master, pdata->index);
870         if (err)
871                 goto fail;
872
873         err = nvhost_client_user_init(dev);
874         if (err)
875                 goto fail;
876
877         err = nvhost_module_init(dev);
878         if (err)
879                 goto fail;
880
881         if (tickctrl_op().init_channel)
882                 tickctrl_op().init_channel(dev);
883
884         err = nvhost_device_list_add(dev);
885         if (err)
886                 goto fail;
887
888         nvhost_device_debug_init(dev);
889
890         dev_info(&dev->dev, "initialized\n");
891
892         return 0;
893
894 fail:
895         /* Add clean-up */
896         nvhost_free_channel(ch);
897         return err;
898 }
899
900 int nvhost_client_device_suspend(struct platform_device *dev)
901 {
902         int ret = 0;
903         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
904
905         ret = nvhost_channel_suspend(pdata->channel);
906         if (ret)
907                 return ret;
908
909         dev_info(&dev->dev, "suspend status: %d\n", ret);
910
911         return ret;
912 }
913
914 int nvhost_client_device_get_resources(struct platform_device *dev)
915 {
916         struct resource *r = NULL;
917         void __iomem *regs = NULL;
918         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
919
920         r = platform_get_resource(dev, IORESOURCE_MEM, 0);
921         if (!r)
922                 goto fail;
923
924         regs = devm_request_and_ioremap(&dev->dev, r);
925         if (!regs)
926                 goto fail;
927
928         pdata->aperture = regs;
929
930         return 0;
931
932 fail:
933         dev_err(&dev->dev, "failed to get register memory\n");
934
935         return -ENXIO;
936 }
937
938 /* This is a simple wrapper around request_firmware that takes
939  * 'fw_name' and if available applies a SOC relative path prefix to it.
940  * The caller is responsible for calling release_firmware later.
941  */
942 const struct firmware *
943 nvhost_client_request_firmware(struct platform_device *dev, const char *fw_name)
944 {
945         struct nvhost_chip_support *op = nvhost_get_chip_ops();
946         const struct firmware *fw;
947         char *fw_path = NULL;
948         int path_len, err;
949
950         if (!fw_name)
951                 return NULL;
952
953         if (op->soc_name) {
954                 path_len = strlen(fw_name) + strlen(op->soc_name);
955                 path_len += 2; /* for the path separator and zero terminator*/
956
957                 fw_path = kzalloc(sizeof(*fw_path) * path_len,
958                                      GFP_KERNEL);
959                 if (!fw_path)
960                         return NULL;
961
962                 sprintf(fw_path, "%s/%s", op->soc_name, fw_name);
963                 fw_name = fw_path;
964         }
965
966         err = request_firmware(&fw, fw_name, &dev->dev);
967         kfree(fw_path);
968         if (err) {
969                 dev_err(&dev->dev, "failed to get firmware\n");
970                 return NULL;
971         }
972
973         /* note: caller must release_firmware */
974         return fw;
975 }