summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/host/bus_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/bus_client.c')
-rw-r--r--drivers/video/tegra/host/bus_client.c195
1 files changed, 108 insertions, 87 deletions
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index b49c26e04f29..0137793b39ee 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -36,7 +36,6 @@
#include <linux/nvhost.h>
#include <linux/nvhost_ioctl.h>
-#include <mach/nvmap.h>
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <mach/iomap.h>
@@ -44,11 +43,36 @@
#include "debug.h"
#include "bus_client.h"
#include "dev.h"
+#include "nvhost_memmgr.h"
+#include "chip_support.h"
+#include "nvhost_acm.h"
-void nvhost_read_module_regs(struct nvhost_device *ndev,
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
+
+static int validate_reg(struct nvhost_device *ndev, u32 offset, int count)
+{
+ struct resource *r = nvhost_get_resource(ndev, IORESOURCE_MEM, 0);
+ int err = 0;
+
+ if (offset + 4 * count > resource_size(r)
+ || (offset + 4 * count < offset))
+ err = -EPERM;
+
+ return err;
+}
+
+int nvhost_read_module_regs(struct nvhost_device *ndev,
u32 offset, int count, u32 *values)
{
void __iomem *p = ndev->aperture + offset;
+ int err;
+
+ /* verify offset */
+ err = validate_reg(ndev, offset, count);
+ if (err)
+ return err;
nvhost_module_busy(ndev);
while (count--) {
@@ -57,12 +81,20 @@ void nvhost_read_module_regs(struct nvhost_device *ndev,
}
rmb();
nvhost_module_idle(ndev);
+
+ return 0;
}
-void nvhost_write_module_regs(struct nvhost_device *ndev,
+int nvhost_write_module_regs(struct nvhost_device *ndev,
u32 offset, int count, const u32 *values)
{
void __iomem *p = ndev->aperture + offset;
+ int err;
+
+ /* verify offset */
+ err = validate_reg(ndev, offset, count);
+ if (err)
+ return err;
nvhost_module_busy(ndev);
while (count--) {
@@ -71,6 +103,8 @@ void nvhost_write_module_regs(struct nvhost_device *ndev,
}
wmb();
nvhost_module_idle(ndev);
+
+ return 0;
}
struct nvhost_channel_userctx {
@@ -79,51 +113,12 @@ struct nvhost_channel_userctx {
struct nvhost_submit_hdr_ext hdr;
int num_relocshifts;
struct nvhost_job *job;
- struct nvmap_client *nvmap;
+ struct mem_mgr *memmgr;
u32 timeout;
u32 priority;
int clientid;
};
-/*
- * Write cmdbuf to ftrace output. Checks if cmdbuf contents should be output
- * and mmaps the cmdbuf contents if required.
- */
-static void trace_write_cmdbufs(struct nvhost_job *job)
-{
- struct nvmap_handle_ref handle;
- void *mem = NULL;
- int i = 0;
-
- for (i = 0; i < job->num_gathers; i++) {
- struct nvhost_channel_gather *gather = &job->gathers[i];
- if (nvhost_debug_trace_cmdbuf) {
- handle.handle = nvmap_id_to_handle(gather->mem_id);
- mem = nvmap_mmap(&handle);
- if (IS_ERR_OR_NULL(mem))
- mem = NULL;
- };
-
- if (mem) {
- u32 i;
- /*
- * Write in batches of 128 as there seems to be a limit
- * of how much you can output to ftrace at once.
- */
- for (i = 0; i < gather->words; i += TRACE_MAX_LENGTH) {
- trace_nvhost_channel_write_cmdbuf_data(
- job->ch->dev->name,
- gather->mem_id,
- min(gather->words - i,
- TRACE_MAX_LENGTH),
- gather->offset + i * sizeof(u32),
- mem);
- }
- nvmap_munmap(&handle, mem);
- }
- }
-}
-
static int nvhost_channelrelease(struct inode *inode, struct file *filp)
{
struct nvhost_channel_userctx *priv = filp->private_data;
@@ -141,7 +136,7 @@ static int nvhost_channelrelease(struct inode *inode, struct file *filp)
if (priv->job)
nvhost_job_put(priv->job);
- nvmap_client_put(priv->nvmap);
+ mem_op().put_mgr(priv->memmgr);
kfree(priv);
return 0;
}
@@ -174,11 +169,7 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
priv->priority = NVHOST_PRIORITY_MEDIUM;
priv->clientid = atomic_add_return(1,
&nvhost_get_host(ch->dev)->clientid);
-
- priv->job = nvhost_job_alloc(ch, priv->hwctx, &priv->hdr,
- NULL, priv->priority, priv->clientid);
- if (!priv->job)
- goto fail;
+ priv->timeout = CONFIG_TEGRA_GRHOST_DEFAULT_TIMEOUT;
return 0;
fail:
@@ -188,21 +179,24 @@ fail:
static int set_submit(struct nvhost_channel_userctx *ctx)
{
- struct device *device = &ctx->ch->dev->dev;
+ struct nvhost_device *ndev = ctx->ch->dev;
+ struct nvhost_master *host = nvhost_get_host(ndev);
/* submit should have at least 1 cmdbuf */
- if (!ctx->hdr.num_cmdbufs)
+ if (!ctx->hdr.num_cmdbufs ||
+ !nvhost_syncpt_is_valid(&host->syncpt,
+ ctx->hdr.syncpt_id))
return -EIO;
- if (!ctx->nvmap) {
- dev_err(device, "no nvmap context set\n");
+ if (!ctx->memmgr) {
+ dev_err(&ndev->dev, "no nvmap context set\n");
return -EFAULT;
}
- ctx->job = nvhost_job_realloc(ctx->job,
+ ctx->job = nvhost_job_alloc(ctx->ch,
ctx->hwctx,
&ctx->hdr,
- ctx->nvmap,
+ ctx->memmgr,
ctx->priority,
ctx->clientid);
if (!ctx->job)
@@ -221,6 +215,11 @@ static void reset_submit(struct nvhost_channel_userctx *ctx)
ctx->hdr.num_relocs = 0;
ctx->num_relocshifts = 0;
ctx->hdr.num_waitchks = 0;
+
+ if (ctx->job) {
+ nvhost_job_put(ctx->job);
+ ctx->job = NULL;
+ }
}
static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
@@ -271,17 +270,28 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
hdr->num_cmdbufs--;
} else if (hdr->num_relocs) {
- consumed = sizeof(struct nvhost_reloc);
- if (remaining < consumed)
+ int numrelocs = remaining / sizeof(struct nvhost_reloc);
+ if (!numrelocs)
break;
- if (copy_from_user(&job->pinarray[job->num_pins],
+ numrelocs = min_t(int, numrelocs, priv->hdr.num_relocs);
+ consumed = numrelocs * sizeof(struct nvhost_reloc);
+ if (copy_from_user(&job->relocarray[job->num_relocs],
buf, consumed)) {
err = -EFAULT;
break;
}
- trace_nvhost_channel_write_reloc(chname);
- job->num_pins++;
- hdr->num_relocs--;
+ while (numrelocs) {
+ struct nvhost_reloc *reloc =
+ &job->relocarray[job->num_relocs];
+ trace_nvhost_channel_write_reloc(chname,
+ reloc->cmdbuf_mem,
+ reloc->cmdbuf_offset,
+ reloc->target,
+ reloc->target_offset);
+ job->num_relocs++;
+ hdr->num_relocs--;
+ numrelocs--;
+ }
} else if (hdr->num_waitchks) {
int numwaitchks =
(remaining / sizeof(struct nvhost_waitchk));
@@ -302,17 +312,19 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
hdr->num_waitchks -= numwaitchks;
} else if (priv->num_relocshifts) {
int next_shift =
- job->num_pins - priv->num_relocshifts;
- consumed = sizeof(struct nvhost_reloc_shift);
- if (remaining < consumed)
+ job->num_relocs - priv->num_relocshifts;
+ int num =
+ (remaining / sizeof(struct nvhost_reloc_shift));
+ if (!num)
break;
- if (copy_from_user(
- &job->pinarray[next_shift].reloc_shift,
+ num = min_t(int, num, priv->num_relocshifts);
+ consumed = num * sizeof(struct nvhost_reloc_shift);
+ if (copy_from_user(&job->relocshiftarray[next_shift],
buf, consumed)) {
err = -EFAULT;
break;
}
- priv->num_relocshifts--;
+ priv->num_relocshifts -= num;
} else {
err = -EFAULT;
break;
@@ -335,7 +347,7 @@ static int nvhost_ioctl_channel_flush(
struct nvhost_get_param_args *args,
int null_kickoff)
{
- struct device *device = &ctx->ch->dev->dev;
+ struct nvhost_device *ndev = to_nvhost_device(&ctx->ch->dev->dev);
int err;
trace_nvhost_ioctl_channel_flush(ctx->ch->dev->name);
@@ -345,13 +357,13 @@ static int nvhost_ioctl_channel_flush(
ctx->hdr.num_cmdbufs ||
ctx->hdr.num_waitchks) {
reset_submit(ctx);
- dev_err(device, "channel submit out of sync\n");
+ dev_err(&ndev->dev, "channel submit out of sync\n");
return -EFAULT;
}
- err = nvhost_job_pin(ctx->job);
+ err = nvhost_job_pin(ctx->job, &nvhost_get_host(ndev)->syncpt);
if (err) {
- dev_warn(device, "nvhost_job_pin failed: %d\n", err);
+ dev_warn(&ndev->dev, "nvhost_job_pin failed: %d\n", err);
return err;
}
@@ -364,23 +376,23 @@ static int nvhost_ioctl_channel_flush(
ctx->timeout = nvhost_debug_force_timeout_val;
}
- trace_write_cmdbufs(ctx->job);
-
/* context switch if needed, and submit user's gathers to the channel */
err = nvhost_channel_submit(ctx->job);
args->value = ctx->job->syncpt_end;
if (err)
nvhost_job_unpin(ctx->job);
+ nvhost_job_put(ctx->job);
+ ctx->job = NULL;
+
return err;
}
-static int nvhost_ioctl_channel_read_3d_reg(
- struct nvhost_channel_userctx *ctx,
+static int nvhost_ioctl_channel_read_3d_reg(struct nvhost_channel_userctx *ctx,
struct nvhost_read_3d_reg_args *args)
{
- BUG_ON(!channel_op(ctx->ch).read3dreg);
- return channel_op(ctx->ch).read3dreg(ctx->ch, ctx->hwctx,
+ BUG_ON(!channel_op().read3dreg);
+ return channel_op().read3dreg(ctx->ch, ctx->hwctx,
args->offset, &args->value);
}
@@ -393,11 +405,10 @@ static long nvhost_channelctl(struct file *filp,
if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
(_IOC_NR(cmd) == 0) ||
- (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST))
+ (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST) ||
+ (_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE))
return -EFAULT;
- BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE);
-
if (_IOC_DIR(cmd) & _IOC_WRITE) {
if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
return -EFAULT;
@@ -460,17 +471,17 @@ static long nvhost_channelctl(struct file *filp,
case NVHOST_IOCTL_CHANNEL_SET_NVMAP_FD:
{
int fd = (int)((struct nvhost_set_nvmap_fd_args *)buf)->fd;
- struct nvmap_client *new_client = nvmap_client_get_file(fd);
+ struct mem_mgr *new_client = mem_op().get_mgr_file(fd);
if (IS_ERR(new_client)) {
err = PTR_ERR(new_client);
break;
}
- if (priv->nvmap)
- nvmap_client_put(priv->nvmap);
+ if (priv->memmgr)
+ mem_op().put_mgr(priv->memmgr);
- priv->nvmap = new_client;
+ priv->memmgr = new_client;
break;
}
case NVHOST_IOCTL_CHANNEL_READ_3D_REG:
@@ -535,18 +546,23 @@ int nvhost_client_user_init(struct nvhost_device *dev)
int err, devno;
struct nvhost_channel *ch = dev->channel;
+ err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
+ if (err < 0) {
+ dev_err(&dev->dev, "failed to allocate devno\n");
+ goto fail;
+ }
cdev_init(&ch->cdev, &nvhost_channelops);
ch->cdev.owner = THIS_MODULE;
- devno = MKDEV(nvhost_major, nvhost_minor + dev->index);
err = cdev_add(&ch->cdev, devno, 1);
if (err < 0) {
dev_err(&dev->dev,
"failed to add chan %i cdev\n", dev->index);
goto fail;
}
- ch->node = device_create(nvhost_get_host(dev)->nvhost_class, NULL, devno, NULL,
+ ch->node = device_create(nvhost_get_host(dev)->nvhost_class,
+ NULL, devno, NULL,
IFACE_NAME "-%s", dev->name);
if (IS_ERR(ch->node)) {
err = PTR_ERR(ch->node);
@@ -564,7 +580,11 @@ int nvhost_client_device_init(struct nvhost_device *dev)
{
int err;
struct nvhost_master *nvhost_master = nvhost_get_host(dev);
- struct nvhost_channel *ch = &nvhost_master->channels[dev->index];
+ struct nvhost_channel *ch;
+
+ ch = nvhost_alloc_channel(dev);
+ if (ch == NULL)
+ return -ENODEV;
/* store the pointer to this device for channel */
ch->dev = dev;
@@ -587,6 +607,7 @@ int nvhost_client_device_init(struct nvhost_device *dev)
fail:
/* Add clean-up */
+ nvhost_free_channel(ch);
return err;
}