summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
diff options
context:
space:
mode:
authorTom Cherry <tcherry@nvidia.com>2012-05-30 18:18:17 -0700
committerTom Cherry <tcherry@nvidia.com>2012-05-30 18:18:17 -0700
commit7af2c7ce772882f6e85e2a357711bf822f066bfa (patch)
tree2a1307a8096a62d4252a7c382f43204da3325401 /drivers/video/tegra
parentd92da78335899834f8f667eb7c865aaf47bdff48 (diff)
parentc9d3eda2af45736e73f0dfd2261257e083f3758a (diff)
Merge commit 'main-ics-2012.05.30-A1' into dev-jb-staging
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r--drivers/video/tegra/dc/dc.c17
-rw-r--r--drivers/video/tegra/dc/dc_reg.h2
-rw-r--r--drivers/video/tegra/dc/dsi.c17
-rw-r--r--drivers/video/tegra/fb.c12
-rw-r--r--drivers/video/tegra/host/bus_client.c56
-rw-r--r--drivers/video/tegra/host/chip_support.h12
-rw-r--r--drivers/video/tegra/host/debug.c67
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.c2
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.c2
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.c2
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.c20
-rw-r--r--drivers/video/tegra/host/host1x/host1x_debug.c132
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.c64
-rw-r--r--drivers/video/tegra/host/mpe/mpe.c2
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c45
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.h7
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c24
-rw-r--r--drivers/video/tegra/host/nvhost_channel.h8
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c10
-rw-r--r--drivers/video/tegra/host/nvhost_job.c347
-rw-r--r--drivers/video/tegra/host/nvhost_job.h37
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c30
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.h18
-rw-r--r--drivers/video/tegra/host/t30/t30.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c268
-rw-r--r--drivers/video/tegra/nvmap/nvmap.h86
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c19
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c73
28 files changed, 581 insertions, 800 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 55d3fcc..df54578 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -583,6 +583,23 @@ static unsigned int tegra_dc_has_multiple_dc(void)
return (cnt > 1);
}
+/* get the stride size of a window.
+ * return: stride size in bytes for window win. or 0 if unavailble. */
+int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win)
+{
+ u32 tmp;
+ u32 stride;
+
+ if (!dc->enabled)
+ return 0;
+ BUG_ON(win > DC_N_WINDOWS);
+ tegra_dc_writel(dc, WINDOW_A_SELECT << win,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+ tmp = tegra_dc_readl(dc, DC_WIN_LINE_STRIDE);
+ return GET_LINE_STRIDE(tmp);
+}
+EXPORT_SYMBOL(tegra_dc_get_stride);
+
struct tegra_dc *tegra_dc_get_dc(unsigned idx)
{
if (idx < TEGRA_MAX_DC)
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
index ded64de..0b628fc 100644
--- a/drivers/video/tegra/dc/dc_reg.h
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -431,6 +431,8 @@
#define DC_WIN_LINE_STRIDE 0x70a
#define LINE_STRIDE(x) (x)
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
+#define GET_LINE_STRIDE(x) ((x) & 0xffff)
+#define GET_UV_LINE_STRIDE(x) (((x) >> 16) & 0xffff)
#define DC_WIN_BUF_STRIDE 0x70b
#define DC_WIN_UV_BUF_STRIDE 0x70c
#define DC_WIN_BUFFER_ADDR_MODE 0x70d
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index 69cc60f..e402c41 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -1,7 +1,7 @@
/*
* drivers/video/tegra/dc/dsi.c
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -31,6 +31,7 @@
#include <mach/dc.h>
#include <mach/fb.h>
#include <mach/csi.h>
+#include <mach/iomap.h>
#include <linux/nvhost.h>
#include "dc_reg.h"
@@ -38,6 +39,9 @@
#include "dsi_regs.h"
#include "dsi.h"
+#define APB_MISC_GP_MIPI_PAD_CTRL_0 (TEGRA_APB_MISC_BASE + 0x820)
+#define DSIB_MODE_ENABLE 0x2
+
#define DSI_USE_SYNC_POINTS 1
#define S_TO_MS(x) (1000 * (x))
@@ -1621,6 +1625,15 @@ static void tegra_dsi_pad_calibration(struct tegra_dc_dsi_data *dsi)
tegra_vi_csi_writel(val, CSI_CIL_PAD_CONFIG);
}
+static void tegra_dsi_panelB_enable()
+{
+ unsigned int val;
+
+ val = readl(IO_ADDRESS(APB_MISC_GP_MIPI_PAD_CTRL_0));
+ val |= DSIB_MODE_ENABLE;
+ writel(val, (IO_ADDRESS(APB_MISC_GP_MIPI_PAD_CTRL_0)));
+}
+
static int tegra_dsi_init_hw(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi)
{
@@ -1634,7 +1647,7 @@ static int tegra_dsi_init_hw(struct tegra_dc *dc,
tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_lp_clk_khz);
if (dsi->info.dsi_instance) {
- /* TODO:Set the misc register*/
+ tegra_dsi_panelB_enable();
}
/* TODO: only need to change the timing for bta */
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 50aa9b3..1193a2e 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -44,7 +44,7 @@
#include "dc/dc_priv.h"
/* Pad pitch to 16-byte boundary. */
-#define TEGRA_LINEAR_PITCH_ALIGNMENT 16
+#define TEGRA_LINEAR_PITCH_ALIGNMENT 32
struct tegra_fb_info {
struct tegra_dc_win *win;
@@ -527,6 +527,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
unsigned long fb_size = 0;
unsigned long fb_phys = 0;
int ret = 0;
+ unsigned stride;
win = tegra_dc_get_window(dc, fb_data->win);
if (!win) {
@@ -560,6 +561,11 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
tegra_fb->valid = true;
}
+ stride = tegra_dc_get_stride(dc, 0);
+ if (!stride) /* default to pad the stride to 16-byte boundary. */
+ stride = round_up(info->fix.line_length,
+ TEGRA_LINEAR_PITCH_ALIGNMENT);
+
info->fbops = &tegra_fb_ops;
info->pseudo_palette = pseudo_palette;
info->screen_base = fb_base;
@@ -574,9 +580,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->fix.smem_start = fb_phys;
info->fix.smem_len = fb_size;
info->fix.line_length = fb_data->xres * fb_data->bits_per_pixel / 8;
- /* Pad the stride to 16-byte boundary. */
- info->fix.line_length = round_up(info->fix.line_length,
- TEGRA_LINEAR_PITCH_ALIGNMENT);
+ info->fix.line_length = stride;
info->var.xres = fb_data->xres;
info->var.yres = fb_data->yres;
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index fd632a6..87aa9c6 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -141,12 +141,6 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
priv->clientid = atomic_add_return(1,
&nvhost_get_host(ch->dev)->clientid);
priv->timeout = MAX_STUCK_CHECK_COUNT * SYNCPT_CHECK_PERIOD;
-
- priv->job = nvhost_job_alloc(ch, priv->hwctx, &priv->hdr,
- NULL, priv->priority, priv->clientid);
- if (!priv->job)
- goto fail;
-
return 0;
fail:
nvhost_channelrelease(inode, filp);
@@ -166,7 +160,7 @@ static int set_submit(struct nvhost_channel_userctx *ctx)
return -EFAULT;
}
- ctx->job = nvhost_job_realloc(ctx->job,
+ ctx->job = nvhost_job_alloc(ctx->ch,
ctx->hwctx,
&ctx->hdr,
ctx->nvmap,
@@ -238,17 +232,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));
@@ -269,17 +274,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;
@@ -302,7 +309,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);
@@ -312,13 +319,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;
}
@@ -337,6 +344,9 @@ static int nvhost_ioctl_channel_flush(
if (err)
nvhost_job_unpin(ctx->job);
+ nvhost_job_put(ctx->job);
+ ctx->job = NULL;
+
return err;
}
diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h
index edc5f6a..d69e1c4 100644
--- a/drivers/video/tegra/host/chip_support.h
+++ b/drivers/video/tegra/host/chip_support.h
@@ -28,10 +28,9 @@ struct output;
struct nvhost_master;
struct nvhost_intr;
struct nvhost_syncpt;
-struct nvhost_waitchk;
struct nvhost_userctx_timeout;
struct nvhost_channel;
-struct nvmap_handle;
+struct nvmap_handle_ref;
struct nvmap_client;
struct nvhost_hwctx;
struct nvhost_cdma;
@@ -77,7 +76,7 @@ struct nvhost_chip_support {
void (*destroy)(struct push_buffer *);
void (*push_to)(struct push_buffer *,
struct nvmap_client *,
- struct nvmap_handle *,
+ struct nvmap_handle_ref *,
u32 op1, u32 op2);
void (*pop_from)(struct push_buffer *,
unsigned int slots);
@@ -106,11 +105,8 @@ struct nvhost_chip_support {
void (*read_wait_base)(struct nvhost_syncpt *, u32 id);
u32 (*update_min)(struct nvhost_syncpt *, u32 id);
void (*cpu_incr)(struct nvhost_syncpt *, u32 id);
- int (*wait_check)(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 waitchk_mask,
- struct nvhost_waitchk *wait,
- int num_waitchk);
+ int (*patch_wait)(struct nvhost_syncpt *sp,
+ void *patch_addr);
void (*debug)(struct nvhost_syncpt *);
const char * (*name)(struct nvhost_syncpt *, u32 id);
int (*mutex_try_lock)(struct nvhost_syncpt *,
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index 8a26f92..820eac8 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -106,13 +106,53 @@ static void show_all(struct nvhost_master *m, struct output *o)
nvhost_get_chip_ops()->debug.show_mlocks(m, o);
show_syncpts(m, o);
nvhost_debug_output(o, "---- channels ----\n");
- bus_for_each_dev(&(nvhost_bus_get())->nvhost_bus_type, NULL, o, show_channels);
+ bus_for_each_dev(&(nvhost_bus_get())->nvhost_bus_type, NULL, o,
+ show_channels);
nvhost_module_idle(m->dev);
}
#ifdef CONFIG_DEBUG_FS
-static int nvhost_debug_show(struct seq_file *s, void *unused)
+static int show_channels_no_fifo(struct device *dev, void *data)
+{
+ struct nvhost_channel *ch;
+ struct nvhost_device *nvdev = to_nvhost_device(dev);
+ struct output *o = data;
+ struct nvhost_master *m;
+
+ if (nvdev == NULL)
+ return 0;
+
+ m = nvhost_get_host(nvdev);
+ ch = nvdev->channel;
+ if (ch) {
+ mutex_lock(&ch->reflock);
+ if (ch->refcount) {
+ mutex_lock(&ch->cdma.lock);
+ nvhost_get_chip_ops()->debug.show_channel_cdma(m,
+ ch, o, nvdev->index);
+ mutex_unlock(&ch->cdma.lock);
+ }
+ mutex_unlock(&ch->reflock);
+ }
+
+ return 0;
+}
+
+static void show_all_no_fifo(struct nvhost_master *m, struct output *o)
+{
+ nvhost_module_busy(m->dev);
+
+ nvhost_get_chip_ops()->debug.show_mlocks(m, o);
+ show_syncpts(m, o);
+ nvhost_debug_output(o, "---- channels ----\n");
+ bus_for_each_dev(&(nvhost_bus_get())->nvhost_bus_type, NULL, o,
+ show_channels_no_fifo);
+
+ nvhost_module_idle(m->dev);
+}
+
+static int nvhost_debug_show_all(struct seq_file *s, void *unused)
{
struct output o = {
.fn = write_to_seqfile,
@@ -121,6 +161,27 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
show_all(s->private, &o);
return 0;
}
+static int nvhost_debug_show(struct seq_file *s, void *unused)
+{
+ struct output o = {
+ .fn = write_to_seqfile,
+ .ctx = s
+ };
+ show_all_no_fifo(s->private, &o);
+ return 0;
+}
+
+static int nvhost_debug_open_all(struct inode *inode, struct file *file)
+{
+ return single_open(file, nvhost_debug_show_all, inode->i_private);
+}
+
+static const struct file_operations nvhost_debug_all_fops = {
+ .open = nvhost_debug_open_all,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
static int nvhost_debug_open(struct inode *inode, struct file *file)
{
@@ -140,6 +201,8 @@ void nvhost_debug_init(struct nvhost_master *master)
debugfs_create_file("status", S_IRUGO, de,
master, &nvhost_debug_fops);
+ debugfs_create_file("status_all", S_IRUGO, de,
+ master, &nvhost_debug_all_fops);
debugfs_create_u32("null_kickoff_pid", S_IRUGO|S_IWUSR, de,
&nvhost_debug_null_kickoff_pid);
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.c b/drivers/video/tegra/host/gr3d/gr3d_t20.c
index c0efac0..5645f5b 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t20.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.c
@@ -138,7 +138,7 @@ static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
nvhost_cdma_push_gather(cdma,
nvhost_get_host(nctx->channel->dev)->nvmap,
- p->save_buf->handle,
+ p->save_buf,
0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c
index 93d98dfa..57f4c779 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t30.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c
@@ -145,7 +145,7 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
/* gather the save buffer */
nvhost_cdma_push_gather(cdma,
nvhost_get_host(nctx->channel->dev)->nvmap,
- p->save_buf->handle,
+ p->save_buf,
0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.c b/drivers/video/tegra/host/host1x/host1x_cdma.c
index fcb1f05..4569c3d 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.c
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.c
@@ -137,7 +137,7 @@ static void push_buffer_destroy(struct push_buffer *pb)
*/
static void push_buffer_push_to(struct push_buffer *pb,
struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2)
+ struct nvmap_handle_ref *handle, u32 op1, u32 op2)
{
u32 cur = pb->cur;
u32 *p = (u32 *)((u32)pb->mapped + cur);
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c
index 8c4a7a5..c72e647 100644
--- a/drivers/video/tegra/host/host1x/host1x_channel.c
+++ b/drivers/video/tegra/host/host1x/host1x_channel.c
@@ -143,7 +143,7 @@ static void submit_ctxrestore(struct nvhost_job *job)
/* Send restore buffer to channel */
nvhost_cdma_push_gather(&ch->cdma,
host->nvmap,
- nvmap_ref_to_handle(ctx->restore),
+ ctx->restore,
0,
nvhost_opcode_gather(ctx->restore_size),
ctx->restore_phys);
@@ -188,7 +188,7 @@ void submit_gathers(struct nvhost_job *job)
u32 op2 = job->gathers[i].mem;
nvhost_cdma_push_gather(&job->ch->cdma,
job->nvmap,
- nvmap_id_to_handle(job->gathers[i].mem_id),
+ job->gathers[i].ref,
job->gathers[i].offset,
op1, op2);
}
@@ -242,22 +242,6 @@ int host1x_channel_submit(struct nvhost_job *job)
goto error;
}
- /* remove stale waits */
- if (job->num_waitchk) {
- err = nvhost_syncpt_wait_check(sp,
- job->nvmap,
- job->waitchk_mask,
- job->waitchk,
- job->num_waitchk);
- if (err) {
- dev_warn(&ch->dev->dev,
- "nvhost_syncpt_wait_check failed: %d\n", err);
- mutex_unlock(&ch->submitlock);
- nvhost_module_idle(ch->dev);
- goto error;
- }
- }
-
/* begin a CDMA submit */
err = nvhost_cdma_begin(&ch->cdma, job);
if (err) {
diff --git a/drivers/video/tegra/host/host1x/host1x_debug.c b/drivers/video/tegra/host/host1x/host1x_debug.c
index 76483d8..7de3422 100644
--- a/drivers/video/tegra/host/host1x/host1x_debug.c
+++ b/drivers/video/tegra/host/host1x/host1x_debug.c
@@ -28,8 +28,8 @@
#include "host1x_hardware.h"
#include "nvhost_cdma.h"
#include "nvhost_channel.h"
-#include "../../nvmap/nvmap.h"
#include "host1x_cdma.h"
+#include "nvhost_job.h"
#define NVHOST_DEBUG_MAX_PAGE_OFFSET 102400
@@ -160,6 +160,34 @@ static void show_channel_word(struct output *o, int *state, int *count,
}
}
+static void do_show_channel_gather(struct output *o,
+ phys_addr_t phys_addr,
+ u32 words, struct nvhost_cdma *cdma,
+ phys_addr_t pin_addr, u32 *map_addr)
+{
+ /* Map dmaget cursor to corresponding nvmap_handle */
+ u32 offset;
+ int state, count, i;
+
+ offset = phys_addr - pin_addr;
+ /*
+ * Sometimes we're given different hardware address to the same
+ * page - in these cases the offset will get an invalid number and
+ * we just have to bail out.
+ */
+ if (offset > NVHOST_DEBUG_MAX_PAGE_OFFSET) {
+ nvhost_debug_output(o, "[address mismatch]\n");
+ } else {
+ /* GATHER buffer starts always with commands */
+ state = NVHOST_DBG_STATE_CMD;
+ for (i = 0; i < words; i++)
+ show_channel_word(o, &state, &count,
+ phys_addr + i * 4,
+ *(map_addr + offset/4 + i),
+ cdma);
+ }
+}
+
static void show_channel_gather(struct output *o, u32 addr,
phys_addr_t phys_addr,
u32 words, struct nvhost_cdma *cdma)
@@ -169,81 +197,36 @@ static void show_channel_gather(struct output *o, u32 addr,
struct push_buffer *pb = &cdma->push_buffer;
u32 cur = addr - pb->phys;
struct nvmap_client_handle *nvmap = &pb->nvmap[cur/8];
- struct nvmap_handle_ref ref;
u32 *map_addr, offset;
phys_addr_t pin_addr;
- int state, count, i;
- if (!nvmap->handle || !nvmap->client
- || atomic_read(&nvmap->handle->ref) < 1) {
+ if (!nvmap || !nvmap->handle || !nvmap->client) {
nvhost_debug_output(o, "[already deallocated]\n");
return;
}
- /* Create a fake nvmap_handle_ref - nvmap requires it
- * but accesses only the first field - nvmap_handle */
- ref.handle = nvmap->handle;
-
- map_addr = nvmap_mmap(&ref);
+ map_addr = nvmap_mmap(nvmap->handle);
if (!map_addr) {
nvhost_debug_output(o, "[could not mmap]\n");
return;
}
/* Get base address from nvmap */
- pin_addr = nvmap_pin(nvmap->client, &ref);
+ pin_addr = nvmap_pin(nvmap->client, nvmap->handle);
if (IS_ERR_VALUE(pin_addr)) {
nvhost_debug_output(o, "[couldn't pin]\n");
- nvmap_munmap(&ref, map_addr);
+ nvmap_munmap(nvmap->handle, map_addr);
return;
}
offset = phys_addr - pin_addr;
- /*
- * Sometimes we're given different hardware address to the same
- * page - in these cases the offset will get an invalid number and
- * we just have to bail out.
- */
- if (offset > NVHOST_DEBUG_MAX_PAGE_OFFSET) {
- nvhost_debug_output(o, "[address mismatch]\n");
- } else {
- /* GATHER buffer starts always with commands */
- state = NVHOST_DBG_STATE_CMD;
- for (i = 0; i < words; i++)
- show_channel_word(o, &state, &count,
- phys_addr + i * 4,
- *(map_addr + offset/4 + i),
- cdma);
- }
- nvmap_unpin(nvmap->client, &ref);
- nvmap_munmap(&ref, map_addr);
+ do_show_channel_gather(o, phys_addr, words, cdma,
+ pin_addr, map_addr);
+ nvmap_unpin(nvmap->client, nvmap->handle);
+ nvmap_munmap(nvmap->handle, map_addr);
#endif
}
-static void show_channel_pair(struct output *o, u32 addr,
- u32 w0, u32 w1, struct nvhost_cdma *cdma)
-{
- int state = NVHOST_DBG_STATE_CMD;
- int count;
-
- show_channel_word(o, &state, &count, addr, w0, cdma);
- show_channel_word(o, &state, &count, addr+4, w1, cdma);
-}
-
-/**
- * Retrieve the op pair at a slot offset from a DMA address
- */
-static void cdma_peek(struct nvhost_cdma *cdma,
- u32 dmaget, int slot, u32 *out)
-{
- u32 offset = dmaget - cdma->push_buffer.phys;
- u32 *p = cdma->push_buffer.mapped;
-
- offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
- out[0] = p[offset];
- out[1] = p[offset + 1];
-}
-
u32 previous_oppair(struct nvhost_cdma *cdma, u32 cur)
{
u32 pb = cdma->push_buffer.phys;
@@ -253,6 +236,42 @@ u32 previous_oppair(struct nvhost_cdma *cdma, u32 cur)
return prev;
}
+void show_channel_gathers(struct output *o, struct nvhost_cdma *cdma)
+{
+ struct nvhost_job *job;
+
+ list_for_each_entry(job, &cdma->sync_queue, list) {
+ int i;
+ nvhost_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d,"
+ " first_get=%08x, timeout=%d, ctx=%p,"
+ " num_slots=%d, num_handles=%d\n",
+ job,
+ job->syncpt_id,
+ job->syncpt_end,
+ job->first_get,
+ job->timeout,
+ job->hwctx,
+ job->num_slots,
+ job->num_unpins);
+
+ for (i = 0; i < job->num_gathers; i++) {
+ struct nvhost_job_gather *g = &job->gathers[i];
+ u32 *mapped = nvmap_mmap(g->ref);
+ if (!mapped) {
+ nvhost_debug_output(o, "[could not mmap]\n");
+ continue;
+ }
+
+ nvhost_debug_output(o, " GATHER at %08x, %d words\n",
+ g->mem, g->words);
+
+ do_show_channel_gather(o, g->mem + g->offset,
+ g->words, cdma, g->mem, mapped);
+ nvmap_munmap(g->ref, mapped);
+ }
+ }
+}
+
static void t20_debug_show_channel_cdma(struct nvhost_master *m,
struct nvhost_channel *ch, struct output *o, int chid)
{
@@ -261,7 +280,6 @@ static void t20_debug_show_channel_cdma(struct nvhost_master *m,
u32 dmaput, dmaget, dmactrl;
u32 cbstat, cbread;
u32 val, base, baseval;
- u32 pbw[2];
dmaput = readl(channel->aperture + HOST1X_CHANNEL_DMAPUT);
dmaget = readl(channel->aperture + HOST1X_CHANNEL_DMAGET);
@@ -310,9 +328,7 @@ static void t20_debug_show_channel_cdma(struct nvhost_master *m,
dmaput, dmaget, dmactrl);
nvhost_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
- cdma_peek(cdma, dmaget, -1, pbw);
- show_channel_pair(o, previous_oppair(cdma, dmaget),
- pbw[0], pbw[1], &channel->cdma);
+ show_channel_gathers(o, cdma);
nvhost_debug_output(o, "\n");
}
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.c b/drivers/video/tegra/host/host1x/host1x_syncpt.c
index b7d6587..4cc8e9e 100644
--- a/drivers/video/tegra/host/host1x/host1x_syncpt.c
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.c
@@ -103,62 +103,14 @@ static void t20_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
wmb();
}
-/* check for old WAITs to be removed (avoiding a wrap) */
-static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 waitchk_mask,
- struct nvhost_waitchk *wait,
- int num_waitchk)
+/* remove a wait pointed to by patch_addr */
+static int host1x_syncpt_patch_wait(struct nvhost_syncpt *sp,
+ void *patch_addr)
{
- u32 idx;
- int err = 0;
-
- /* get current syncpt values */
- for (idx = 0; idx < NV_HOST1X_SYNCPT_NB_PTS; idx++) {
- if (BIT(idx) & waitchk_mask)
- nvhost_syncpt_update_min(sp, idx);
- }
-
- BUG_ON(!wait && !num_waitchk);
-
- /* compare syncpt vs wait threshold */
- while (num_waitchk) {
- u32 override;
-
- BUG_ON(wait->syncpt_id >= NV_HOST1X_SYNCPT_NB_PTS);
- trace_nvhost_syncpt_wait_check(wait->mem, wait->offset,
- wait->syncpt_id, wait->thresh);
- if (nvhost_syncpt_is_expired(sp,
- wait->syncpt_id, wait->thresh)) {
- /*
- * NULL an already satisfied WAIT_SYNCPT host method,
- * by patching its args in the command stream. The
- * method data is changed to reference a reserved
- * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
- * syncpt with a matching threshold value of 0, so
- * is guaranteed to be popped by the host HW.
- */
- dev_dbg(&syncpt_to_dev(sp)->dev->dev,
- "drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
- wait->syncpt_id,
- syncpt_op().name(sp, wait->syncpt_id),
- wait->thresh,
- nvhost_syncpt_read_min(sp, wait->syncpt_id));
-
- /* patch the wait */
- override = nvhost_class_host_wait_syncpt(
- NVSYNCPT_GRAPHICS_HOST, 0);
- err = nvmap_patch_word(nvmap,
- (struct nvmap_handle *)wait->mem,
- wait->offset, override);
- if (err)
- break;
- }
-
- wait++;
- num_waitchk--;
- }
- return err;
+ u32 override = nvhost_class_host_wait_syncpt(
+ NVSYNCPT_GRAPHICS_HOST, 0);
+ __raw_writel(override, patch_addr);
+ return 0;
}
@@ -241,7 +193,7 @@ int host1x_init_syncpt_support(struct nvhost_master *host,
op->syncpt.read_wait_base = t20_syncpt_read_wait_base;
op->syncpt.update_min = t20_syncpt_update_min;
op->syncpt.cpu_incr = t20_syncpt_cpu_incr;
- op->syncpt.wait_check = t20_syncpt_wait_check;
+ op->syncpt.patch_wait = host1x_syncpt_patch_wait;
op->syncpt.debug = t20_syncpt_debug;
op->syncpt.name = t20_syncpt_name;
op->syncpt.mutex_try_lock = syncpt_mutex_try_lock;
diff --git a/drivers/video/tegra/host/mpe/mpe.c b/drivers/video/tegra/host/mpe/mpe.c
index d8c9da7..3fe2fcd 100644
--- a/drivers/video/tegra/host/mpe/mpe.c
+++ b/drivers/video/tegra/host/mpe/mpe.c
@@ -502,7 +502,7 @@ static void ctxmpe_save_push(struct nvhost_hwctx *nctx,
struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
nvhost_cdma_push_gather(cdma,
nvhost_get_host(nctx->channel->dev)->nvmap,
- h->save_buf->handle,
+ h->save_buf,
0,
nvhost_opcode_gather(h->save_size),
h->save_phys);
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
index a72e18f..c87415b 100644
--- a/drivers/video/tegra/host/nvhost_cdma.c
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -53,6 +53,18 @@ static void add_to_sync_queue(struct nvhost_cdma *cdma,
job->num_slots = nr_slots;
nvhost_job_get(job);
list_add_tail(&job->list, &cdma->sync_queue);
+
+ switch (job->priority) {
+ case NVHOST_PRIORITY_HIGH:
+ cdma->high_prio_count++;
+ break;
+ case NVHOST_PRIORITY_MEDIUM:
+ cdma->med_prio_count++;
+ break;
+ case NVHOST_PRIORITY_LOW:
+ cdma->low_prio_count++;
+ break;
+ }
}
/**
@@ -200,6 +212,19 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
}
list_del(&job->list);
+
+ switch (job->priority) {
+ case NVHOST_PRIORITY_HIGH:
+ cdma->high_prio_count--;
+ break;
+ case NVHOST_PRIORITY_MEDIUM:
+ cdma->med_prio_count--;
+ break;
+ case NVHOST_PRIORITY_LOW:
+ cdma->low_prio_count--;
+ break;
+ }
+
nvhost_job_put(job);
}
@@ -371,15 +396,13 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
}
static void trace_write_gather(struct nvhost_cdma *cdma,
- struct nvmap_handle *handle,
+ struct nvmap_handle_ref *ref,
u32 offset, u32 words)
{
- struct nvmap_handle_ref ref;
void *mem = NULL;
if (nvhost_debug_trace_cmdbuf) {
- ref.handle = handle;
- mem = nvmap_mmap(&ref);
+ mem = nvmap_mmap(ref);
if (IS_ERR_OR_NULL(mem))
mem = NULL;
};
@@ -393,12 +416,12 @@ static void trace_write_gather(struct nvhost_cdma *cdma,
for (i = 0; i < words; i += TRACE_MAX_LENGTH) {
trace_nvhost_cdma_push_gather(
cdma_to_channel(cdma)->dev->name,
- (u32)handle,
+ (u32)ref->handle,
min(words - i, TRACE_MAX_LENGTH),
offset + i * sizeof(u32),
mem);
}
- nvmap_munmap(&ref, mem);
+ nvmap_munmap(ref, mem);
}
}
@@ -421,7 +444,7 @@ void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
*/
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
struct nvmap_client *client,
- struct nvmap_handle *handle,
+ struct nvmap_handle_ref *handle,
u32 offset, u32 op1, u32 op2)
{
u32 slots_free = cdma->slots_free;
@@ -468,6 +491,12 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
if (job->timeout && was_idle)
cdma_start_timer_locked(cdma, job);
+ trace_nvhost_cdma_end(job->ch->dev->name,
+ job->priority,
+ job->ch->cdma.high_prio_count,
+ job->ch->cdma.med_prio_count,
+ job->ch->cdma.low_prio_count);
+
mutex_unlock(&cdma->lock);
}
@@ -492,6 +521,8 @@ int nvhost_cdma_flush(struct nvhost_cdma *cdma, int timeout)
unsigned int space, err = 0;
unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
+ trace_nvhost_cdma_flush(cdma_to_channel(cdma)->dev->name, timeout);
+
/*
* Wait for at most timeout ms. Recalculate timeout at each iteration
* to better keep within given timeout.
diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h
index e6f5117..2056774 100644
--- a/drivers/video/tegra/host/nvhost_cdma.h
+++ b/drivers/video/tegra/host/nvhost_cdma.h
@@ -48,7 +48,7 @@ struct nvhost_job;
struct nvmap_client_handle {
struct nvmap_client *client;
- struct nvmap_handle *handle;
+ struct nvmap_handle_ref *handle;
};
struct push_buffer {
@@ -99,6 +99,9 @@ struct nvhost_cdma {
struct buffer_timeout timeout; /* channel's timeout state/wq */
bool running;
bool torndown;
+ int high_prio_count;
+ int med_prio_count;
+ int low_prio_count;
};
#define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
@@ -113,7 +116,7 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job);
void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2);
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
struct nvmap_client *client,
- struct nvmap_handle *handle, u32 offset, u32 op1, u32 op2);
+ struct nvmap_handle_ref *handle, u32 offset, u32 op1, u32 op2);
void nvhost_cdma_end(struct nvhost_cdma *cdma,
struct nvhost_job *job);
void nvhost_cdma_update(struct nvhost_cdma *cdma);
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
index ef8886f..ad303cf 100644
--- a/drivers/video/tegra/host/nvhost_channel.c
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -51,10 +51,26 @@ int nvhost_channel_init(struct nvhost_channel *ch,
int nvhost_channel_submit(struct nvhost_job *job)
{
- /* Low priority submits wait until sync queue is empty. Ignores result
- * from nvhost_cdma_flush, as we submit either when push buffer is
- * empty or when we reach the timeout. */
- if (job->priority < NVHOST_PRIORITY_MEDIUM)
+ /*
+ * Check if queue has higher priority jobs running. If so, wait until
+ * queue is empty. Ignores result from nvhost_cdma_flush, as we submit
+ * either when push buffer is empty or when we reach the timeout.
+ */
+ int higher_count = 0;
+
+ switch (job->priority) {
+ case NVHOST_PRIORITY_HIGH:
+ higher_count = 0;
+ break;
+ case NVHOST_PRIORITY_MEDIUM:
+ higher_count = job->ch->cdma.high_prio_count;
+ break;
+ case NVHOST_PRIORITY_LOW:
+ higher_count = job->ch->cdma.high_prio_count
+ + job->ch->cdma.med_prio_count;
+ break;
+ }
+ if (higher_count > 0)
(void)nvhost_cdma_flush(&job->ch->cdma,
NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
diff --git a/drivers/video/tegra/host/nvhost_channel.h b/drivers/video/tegra/host/nvhost_channel.h
index eac5173..b3a904d 100644
--- a/drivers/video/tegra/host/nvhost_channel.h
+++ b/drivers/video/tegra/host/nvhost_channel.h
@@ -31,18 +31,10 @@
#define NVHOST_MAX_POWERGATE_IDS 2
struct nvhost_master;
-struct nvhost_waitchk;
struct nvhost_device;
struct nvhost_channel;
struct nvhost_hwctx;
-struct nvhost_channel_gather {
- u32 words;
- phys_addr_t mem;
- u32 mem_id;
- int offset;
-};
-
struct nvhost_channel {
int refcount;
int chid;
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index ba821f6..af2e3ad 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -128,12 +128,16 @@ static void action_submit_complete(struct nvhost_waitlist *waiter)
struct nvhost_channel *channel = waiter->data;
int nr_completed = waiter->count;
+ nvhost_cdma_update(&channel->cdma);
+ nvhost_module_idle_mult(channel->dev, nr_completed);
+
/* Add nr_completed to trace */
trace_nvhost_channel_submit_complete(channel->dev->name,
- nr_completed, waiter->thresh);
+ nr_completed, waiter->thresh,
+ channel->cdma.high_prio_count,
+ channel->cdma.med_prio_count,
+ channel->cdma.low_prio_count);
- nvhost_cdma_update(&channel->cdma);
- nvhost_module_idle_mult(channel->dev, nr_completed);
}
static void action_ctxsave(struct nvhost_waitlist *waiter)
diff --git a/drivers/video/tegra/host/nvhost_job.c b/drivers/video/tegra/host/nvhost_job.c
index 71f2ab0e..e029449 100644
--- a/drivers/video/tegra/host/nvhost_job.c
+++ b/drivers/video/tegra/host/nvhost_job.c
@@ -23,9 +23,11 @@
#include <linux/err.h>
#include <linux/vmalloc.h>
#include <linux/nvmap.h>
+#include <trace/events/nvhost.h>
#include "nvhost_channel.h"
#include "nvhost_job.h"
#include "nvhost_hwctx.h"
+#include "nvhost_syncpt.h"
#include "dev.h"
/* Magic to use to fill freed handle slots */
@@ -33,128 +35,44 @@
static int job_size(struct nvhost_submit_hdr_ext *hdr)
{
- int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
+ int num_relocs = hdr ? hdr->num_relocs : 0;
int num_waitchks = hdr ? hdr->num_waitchks : 0;
+ int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
+ int num_unpins = num_cmdbufs + num_relocs;
return sizeof(struct nvhost_job)
- + num_pins * sizeof(struct nvmap_pinarray_elem)
- + num_pins * sizeof(struct nvmap_handle *)
- + num_waitchks * sizeof(struct nvhost_waitchk);
-}
-
-static int gather_size(int num_cmdbufs)
-{
- return num_cmdbufs * sizeof(struct nvhost_channel_gather);
-}
-
-static void free_gathers(struct nvhost_job *job)
-{
- if (job->gathers) {
- nvmap_munmap(job->gather_mem, job->gathers);
- job->gathers = NULL;
- }
- if (job->gather_mem) {
- nvmap_free(job->nvmap, job->gather_mem);
- job->gather_mem = NULL;
- }
-}
-
-static int alloc_gathers(struct nvhost_job *job,
- int num_cmdbufs)
-{
- int err = 0;
-
- job->gather_mem = NULL;
- job->gathers = NULL;
- job->gather_mem_size = 0;
-
- if (num_cmdbufs) {
- /* Allocate memory */
- job->gather_mem = nvmap_alloc(job->nvmap,
- gather_size(num_cmdbufs),
- 32, NVMAP_HANDLE_CACHEABLE, 0);
- if (IS_ERR_OR_NULL(job->gather_mem)) {
- err = job->gather_mem ? PTR_ERR(job->gather_mem) : -ENOMEM;
- job->gather_mem = NULL;
- goto error;
- }
- job->gather_mem_size = gather_size(num_cmdbufs);
-
- /* Map memory to kernel */
- job->gathers = nvmap_mmap(job->gather_mem);
- if (IS_ERR_OR_NULL(job->gathers)) {
- err = job->gathers ? PTR_ERR(job->gathers) : -ENOMEM;
- job->gathers = NULL;
- goto error;
- }
- }
-
- return 0;
-
-error:
- free_gathers(job);
- return err;
-}
-
-static int realloc_gathers(struct nvhost_job *oldjob,
- struct nvhost_job *newjob,
- int num_cmdbufs)
-{
- int err = 0;
-
- /* Check if we can reuse gather buffer */
- if (oldjob->gather_mem_size < gather_size(num_cmdbufs)
- || oldjob->nvmap != newjob->nvmap) {
- free_gathers(oldjob);
- err = alloc_gathers(newjob, num_cmdbufs);
- } else {
- newjob->gather_mem = oldjob->gather_mem;
- newjob->gathers = oldjob->gathers;
- newjob->gather_mem_size = oldjob->gather_mem_size;
-
- oldjob->gather_mem = NULL;
- oldjob->gathers = NULL;
- oldjob->gather_mem_size = 0;
- }
- return err;
+ + num_relocs * sizeof(struct nvhost_reloc)
+ + num_relocs * sizeof(struct nvhost_reloc_shift)
+ + num_unpins * sizeof(struct nvmap_handle_ref *)
+ + num_waitchks * sizeof(struct nvhost_waitchk)
+ + num_cmdbufs * sizeof(struct nvhost_job_gather);
}
static void init_fields(struct nvhost_job *job,
struct nvhost_submit_hdr_ext *hdr,
int priority, int clientid)
{
- int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
+ int num_relocs = hdr ? hdr->num_relocs : 0;
int num_waitchks = hdr ? hdr->num_waitchks : 0;
+ int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
+ int num_unpins = num_cmdbufs + num_relocs;
void *mem = job;
/* First init state to zero */
- job->num_gathers = 0;
- job->num_pins = 0;
- job->num_unpins = 0;
- job->num_waitchk = 0;
- job->waitchk_mask = 0;
- job->syncpt_id = 0;
- job->syncpt_incrs = 0;
- job->syncpt_end = 0;
job->priority = priority;
job->clientid = clientid;
- job->null_kickoff = false;
- job->first_get = 0;
- job->num_slots = 0;
/* Redistribute memory to the structs */
mem += sizeof(struct nvhost_job);
- if (num_pins) {
- job->pinarray = mem;
- mem += num_pins * sizeof(struct nvmap_pinarray_elem);
- job->unpins = mem;
- mem += num_pins * sizeof(struct nvmap_handle *);
- } else {
- job->pinarray = NULL;
- job->unpins = NULL;
- }
-
+ job->relocarray = num_relocs ? mem : NULL;
+ mem += num_relocs * sizeof(struct nvhost_reloc);
+ job->relocshiftarray = num_relocs ? mem : NULL;
+ mem += num_relocs * sizeof(struct nvhost_reloc_shift);
+ job->unpins = num_unpins ? mem : NULL;
+ mem += num_unpins * sizeof(struct nvmap_handle_ref *);
job->waitchk = num_waitchks ? mem : NULL;
+ mem += num_waitchks * sizeof(struct nvhost_waitchk);
+ job->gathers = num_cmdbufs ? mem : NULL;
/* Copy information from header */
if (hdr) {
@@ -172,8 +90,6 @@ struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
int clientid)
{
struct nvhost_job *job = NULL;
- int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
- int err = 0;
job = vzalloc(job_size(hdr));
if (!job)
@@ -186,10 +102,6 @@ struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
hwctx->h->get(hwctx);
job->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
- err = alloc_gathers(job, num_cmdbufs);
- if (err)
- goto error;
-
init_fields(job, hdr, priority, clientid);
return job;
@@ -200,46 +112,6 @@ error:
return NULL;
}
-struct nvhost_job *nvhost_job_realloc(
- struct nvhost_job *oldjob,
- struct nvhost_hwctx *hwctx,
- struct nvhost_submit_hdr_ext *hdr,
- struct nvmap_client *nvmap,
- int priority, int clientid)
-{
- struct nvhost_job *newjob = NULL;
- int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
- int err = 0;
-
- newjob = vzalloc(job_size(hdr));
- if (!newjob)
- goto error;
- kref_init(&newjob->ref);
- newjob->ch = oldjob->ch;
- newjob->hwctx = hwctx;
- if (hwctx)
- newjob->hwctx->h->get(newjob->hwctx);
- newjob->timeout = oldjob->timeout;
- newjob->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
-
- err = realloc_gathers(oldjob, newjob, num_cmdbufs);
- if (err)
- goto error;
-
- nvhost_job_put(oldjob);
-
- init_fields(newjob, hdr, priority, clientid);
-
- return newjob;
-
-error:
- if (newjob)
- nvhost_job_put(newjob);
- if (oldjob)
- nvhost_job_put(oldjob);
- return NULL;
-}
-
void nvhost_job_get(struct nvhost_job *job)
{
kref_get(&job->ref);
@@ -253,10 +125,6 @@ static void job_free(struct kref *ref)
job->hwctxref->h->put(job->hwctxref);
if (job->hwctx)
job->hwctx->h->put(job->hwctx);
- if (job->gathers)
- nvmap_munmap(job->gather_mem, job->gathers);
- if (job->gather_mem)
- nvmap_free(job->nvmap, job->gather_mem);
if (job->nvmap)
nvmap_client_put(job->nvmap);
vfree(job);
@@ -280,42 +148,177 @@ void nvhost_job_put(struct nvhost_job *job)
void nvhost_job_add_gather(struct nvhost_job *job,
u32 mem_id, u32 words, u32 offset)
{
- struct nvmap_pinarray_elem *pin;
- struct nvhost_channel_gather *cur_gather =
+ struct nvhost_job_gather *cur_gather =
&job->gathers[job->num_gathers];
- pin = &job->pinarray[job->num_pins++];
- pin->patch_mem = (u32)nvmap_ref_to_handle(job->gather_mem);
- pin->patch_offset = (void *)&(cur_gather->mem) - (void *)job->gathers;
- pin->pin_mem = nvmap_convert_handle_u2k(mem_id);
- pin->pin_offset = offset;
cur_gather->words = words;
cur_gather->mem_id = mem_id;
cur_gather->offset = offset;
job->num_gathers += 1;
}
-int nvhost_job_pin(struct nvhost_job *job)
+static int do_relocs(struct nvhost_job *job, u32 cmdbuf_mem, void *cmdbuf_addr)
{
- int err = 0;
+ phys_addr_t target_phys;
+ int i;
+ u32 mem_id = 0;
+ struct nvmap_handle_ref *target_ref = NULL;
+
+ /* pin & patch the relocs for one gather */
+ for (i = 0; i < job->num_relocs; i++) {
+ struct nvhost_reloc *reloc = &job->relocarray[i];
+ struct nvhost_reloc_shift *shift = &job->relocshiftarray[i];
+
+ /* skip all other gathers */
+ if (cmdbuf_mem != reloc->cmdbuf_mem)
+ continue;
+
+ /* check if pin-mem is same as previous */
+ if (reloc->target != mem_id) {
+ target_ref = nvmap_duplicate_handle_id(job->nvmap,
+ reloc->target);
+ if (IS_ERR(target_ref))
+ return PTR_ERR(target_ref);
+
+ target_phys = nvmap_pin(job->nvmap, target_ref);
+ if (IS_ERR((void *)target_phys)) {
+ nvmap_free(job->nvmap, target_ref);
+ return target_phys;
+ }
+
+ mem_id = reloc->target;
+ job->unpins[job->num_unpins++] = target_ref;
+ }
- /* pin mem handles and patch physical addresses */
- job->num_unpins = nvmap_pin_array(job->nvmap,
- nvmap_ref_to_handle(job->gather_mem),
- job->pinarray, job->num_pins,
- job->unpins);
- if (job->num_unpins < 0)
- err = job->num_unpins;
+ __raw_writel(
+ (target_phys + reloc->target_offset) >> shift->shift,
+ (cmdbuf_addr + reloc->cmdbuf_offset));
+
+ /* Different gathers might have same mem_id. This ensures we
+ * perform reloc only once per gather memid. */
+ reloc->cmdbuf_mem = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Check driver supplied waitchk structs for syncpt thresholds
+ * that have already been satisfied and NULL the comparison (to
+ * avoid a wrap condition in the HW).
+ */
+static int do_waitchks(struct nvhost_job *job, struct nvhost_syncpt *sp,
+ u32 patch_mem, void *patch_addr)
+{
+ int i;
+
+ /* compare syncpt vs wait threshold */
+ for (i = 0; i < job->num_waitchk; i++) {
+ struct nvhost_waitchk *wait = &job->waitchk[i];
+
+ /* skip all other gathers */
+ if (patch_mem != wait->mem)
+ continue;
+
+ trace_nvhost_syncpt_wait_check(wait->mem, wait->offset,
+ wait->syncpt_id, wait->thresh,
+ nvhost_syncpt_read(sp, wait->syncpt_id));
+ if (nvhost_syncpt_is_expired(sp,
+ wait->syncpt_id, wait->thresh)) {
+ /*
+ * NULL an already satisfied WAIT_SYNCPT host method,
+ * by patching its args in the command stream. The
+ * method data is changed to reference a reserved
+ * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
+ * syncpt with a matching threshold value of 0, so
+ * is guaranteed to be popped by the host HW.
+ */
+ dev_dbg(&syncpt_to_dev(sp)->dev->dev,
+ "drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
+ wait->syncpt_id,
+ syncpt_op().name(sp, wait->syncpt_id),
+ wait->thresh,
+ nvhost_syncpt_read_min(sp, wait->syncpt_id));
+
+ /* patch the wait */
+ nvhost_syncpt_patch_wait(sp,
+ (patch_addr + wait->offset));
+ }
+
+ wait->mem = 0;
+ }
+ return 0;
+}
+
+int nvhost_job_pin(struct nvhost_job *job, struct nvhost_syncpt *sp)
+{
+ int err = 0, i = 0;
+ phys_addr_t gather_phys = 0;
+ void *gather_addr = NULL;
+ unsigned long waitchk_mask = job->waitchk_mask;
+
+ /* get current syncpt values for waitchk */
+ for_each_set_bit(i, &waitchk_mask, sizeof(job->waitchk_mask))
+ nvhost_syncpt_update_min(sp, i);
+
+ /* pin gathers */
+ for (i = 0; i < job->num_gathers; i++) {
+ struct nvhost_job_gather *g = &job->gathers[i];
+
+ /* process each gather mem only once */
+ if (!g->ref) {
+ g->ref = nvmap_duplicate_handle_id(job->nvmap,
+ job->gathers[i].mem_id);
+ if (IS_ERR(g->ref)) {
+ err = PTR_ERR(g->ref);
+ g->ref = NULL;
+ break;
+ }
+
+ gather_phys = nvmap_pin(job->nvmap, g->ref);
+ if (IS_ERR((void *)gather_phys)) {
+ nvmap_free(job->nvmap, g->ref);
+ err = gather_phys;
+ break;
+ }
+
+ /* store the gather ref into unpin array */
+ job->unpins[job->num_unpins++] = g->ref;
+
+ gather_addr = nvmap_mmap(g->ref);
+ if (!gather_addr) {
+ err = -ENOMEM;
+ break;
+ }
+
+ err = do_relocs(job, g->mem_id, gather_addr);
+ if (!err)
+ err = do_waitchks(job, sp,
+ g->mem_id, gather_addr);
+ nvmap_munmap(g->ref, gather_addr);
+
+ if (err)
+ break;
+ }
+ g->mem = gather_phys + g->offset;
+ }
+ wmb();
return err;
}
void nvhost_job_unpin(struct nvhost_job *job)
{
- nvmap_unpin_handles(job->nvmap, job->unpins,
- job->num_unpins);
+ int i;
+
+ for (i = 0; i < job->num_unpins; i++) {
+ nvmap_unpin(job->nvmap, job->unpins[i]);
+ nvmap_free(job->nvmap, job->unpins[i]);
+ }
+
memset(job->unpins, BAD_MAGIC,
- job->num_unpins * sizeof(struct nvmap_handle *));
+ job->num_unpins * sizeof(struct nvmap_handle_ref *));
+ job->num_unpins = 0;
}
/**
diff --git a/drivers/video/tegra/host/nvhost_job.h b/drivers/video/tegra/host/nvhost_job.h
index ad9d1af..ec13663 100644
--- a/drivers/video/tegra/host/nvhost_job.h
+++ b/drivers/video/tegra/host/nvhost_job.h
@@ -27,7 +27,15 @@ struct nvhost_channel;
struct nvhost_hwctx;
struct nvmap_client;
struct nvhost_waitchk;
-struct nvmap_handle;
+struct nvhost_syncpt;
+
+struct nvhost_job_gather {
+ u32 words;
+ phys_addr_t mem;
+ u32 mem_id;
+ int offset;
+ struct nvmap_handle_ref *ref;
+};
/*
* Each submit is tracked as a nvhost_job.
@@ -50,10 +58,8 @@ struct nvhost_job {
struct nvmap_client *nvmap;
/* Gathers and their memory */
- struct nvmap_handle_ref *gather_mem;
- struct nvhost_channel_gather *gathers;
+ struct nvhost_job_gather *gathers;
int num_gathers;
- int gather_mem_size;
/* Wait checks to be processed at submit time */
struct nvhost_waitchk *waitchk;
@@ -61,9 +67,10 @@ struct nvhost_job {
u32 waitchk_mask;
/* Array of handles to be pinned & unpinned */
- struct nvmap_pinarray_elem *pinarray;
- int num_pins;
- struct nvmap_handle **unpins;
+ struct nvhost_reloc *relocarray;
+ struct nvhost_reloc_shift *relocshiftarray;
+ int num_relocs;
+ struct nvmap_handle_ref **unpins;
int num_unpins;
/* Sync point id, number of increments and end related to the submit */
@@ -99,17 +106,6 @@ struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
int priority, int clientid);
/*
- * Allocate memory for a job. Just enough memory will be allocated to
- * accomodate the submit announced in submit header. Gather memory from
- * oldjob will be reused, and nvhost_job_put() will be called to it.
- */
-struct nvhost_job *nvhost_job_realloc(struct nvhost_job *oldjob,
- struct nvhost_hwctx *hwctx,
- struct nvhost_submit_hdr_ext *hdr,
- struct nvmap_client *nvmap,
- int priority, int clientid);
-
-/*
* Add a gather to a job.
*/
void nvhost_job_add_gather(struct nvhost_job *job,
@@ -134,8 +130,11 @@ void nvhost_job_put(struct nvhost_job *job);
* Pin memory related to job. This handles relocation of addresses to the
* host1x address space. Handles both the gather memory and any other memory
* referred to from the gather buffers.
+ *
+ * Handles also patching out host waits that would wait for an expired sync
+ * point value.
*/
-int nvhost_job_pin(struct nvhost_job *job);
+int nvhost_job_pin(struct nvhost_job *job, struct nvhost_syncpt *sp);
/*
* Unpin memory related to job.
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 4835d22..7550512 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -74,7 +74,7 @@ u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
BUG_ON(!syncpt_op().update_min);
- return syncpt_op().update_min(sp, id);
+ val = syncpt_op().update_min(sp, id);
trace_nvhost_syncpt_update_min(id, val);
return val;
@@ -130,6 +130,19 @@ void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id)
}
/**
+ * Updated sync point form hardware, and returns true if syncpoint is expired,
+ * false if we may need to wait
+ */
+static bool syncpt_update_min_is_expired(
+ struct nvhost_syncpt *sp,
+ u32 id,
+ u32 thresh)
+{
+ syncpt_op().update_min(sp, id);
+ return nvhost_syncpt_is_expired(sp, id, thresh);
+}
+
+/**
* Main entrypoint for syncpoint value waits.
*/
int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
@@ -190,9 +203,9 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
while (timeout) {
u32 check = min_t(u32, SYNCPT_CHECK_PERIOD, timeout);
int remain = wait_event_interruptible_timeout(wq,
- nvhost_syncpt_is_expired(sp, id, thresh),
+ syncpt_update_min_is_expired(sp, id, thresh),
check);
- if (remain > 0) {
+ if (remain > 0 || nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = nvhost_syncpt_read_min(sp, id);
err = 0;
@@ -317,15 +330,10 @@ void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx)
atomic_dec(&sp->lock_counts[idx]);
}
-/* check for old WAITs to be removed (avoiding a wrap) */
-int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 waitchk_mask,
- struct nvhost_waitchk *wait,
- int num_waitchk)
+/* remove a wait pointed to by patch_addr */
+int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr)
{
- return syncpt_op().wait_check(sp, nvmap,
- waitchk_mask, wait, num_waitchk);
+ return syncpt_op().patch_wait(sp, patch_addr);
}
/* Displays the current value of the sync point via sysfs */
diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h
index b770ed9..b58921b 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.h
+++ b/drivers/video/tegra/host/nvhost_syncpt.h
@@ -136,23 +136,7 @@ static inline int nvhost_syncpt_wait(struct nvhost_syncpt *sp, u32 id, u32 thres
MAX_SCHEDULE_TIMEOUT, NULL);
}
-/*
- * Check driver supplied waitchk structs for syncpt thresholds
- * that have already been satisfied and NULL the comparison (to
- * avoid a wrap condition in the HW).
- *
- * @param: sp - global shadowed syncpt struct
- * @param: nvmap - needed to access command buffer
- * @param: mask - bit mask of syncpt IDs referenced in WAITs
- * @param: wait - start of filled in array of waitchk structs
- * @param: waitend - end ptr (one beyond last valid waitchk)
- */
-struct nvhost_waitchk;
-int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
- struct nvmap_client *nvmap,
- u32 mask,
- struct nvhost_waitchk *wait,
- int num_waitchk);
+int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr);
void nvhost_syncpt_debug(struct nvhost_syncpt *sp);
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
index 257ba08..b276874 100644
--- a/drivers/video/tegra/host/t30/t30.c
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -95,7 +95,7 @@ struct nvhost_device t30_devices[] = {
.waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
.modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
- .clocks = { {"gr2d", UINT_MAX},
+ .clocks = { {"gr2d", 0},
{"epp", 0},
{"emc", 300000000} },
NVHOST_MODULE_NO_POWERGATE_IDS,
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index a0c4156..b7fd695d 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -352,225 +352,6 @@ static phys_addr_t handle_phys(struct nvmap_handle *h)
return addr;
}
-/* stores the physical address (+offset) of each handle relocation entry
- * into its output location. see nvmap_pin_array for more details.
- *
- * each entry in arr (i.e., each relocation request) specifies two handles:
- * the handle to pin (pin), and the handle where the address of pin should be
- * written (patch). in pseudocode, this loop basically looks like:
- *
- * for (i = 0; i < nr; i++) {
- * (pin, pin_offset, patch, patch_offset) = arr[i];
- * patch[patch_offset] = address_of(pin) + pin_offset;
- * }
- */
-static int nvmap_reloc_pin_array(struct nvmap_client *client,
- const struct nvmap_pinarray_elem *arr,
- int nr, struct nvmap_handle *gather)
-{
- struct nvmap_handle *last_patch = NULL;
- unsigned int last_pfn = 0;
- pte_t **pte;
- void *addr;
- int i;
-
- pte = nvmap_alloc_pte(client->dev, &addr);
- if (IS_ERR(pte))
- return PTR_ERR(pte);
-
- for (i = 0; i < nr; i++) {
- struct nvmap_handle *patch;
- struct nvmap_handle *pin;
- phys_addr_t reloc_addr;
- phys_addr_t phys;
- unsigned int pfn;
-
- /* all of the handles are validated and get'ted prior to
- * calling this function, so casting is safe here */
- pin = (struct nvmap_handle *)arr[i].pin_mem;
-
- if (arr[i].patch_mem == (unsigned long)last_patch) {
- patch = last_patch;
- } else if (arr[i].patch_mem == (unsigned long)gather) {
- patch = gather;
- } else {
- if (last_patch)
- nvmap_handle_put(last_patch);
-
- patch = nvmap_get_handle_id(client, arr[i].patch_mem);
- if (!patch) {
- nvmap_free_pte(client->dev, pte);
- return -EPERM;
- }
- last_patch = patch;
- }
-
- if (patch->heap_pgalloc) {
- unsigned int page = arr[i].patch_offset >> PAGE_SHIFT;
- phys = page_to_phys(patch->pgalloc.pages[page]);
- phys += (arr[i].patch_offset & ~PAGE_MASK);
- } else {
- phys = patch->carveout->base + arr[i].patch_offset;
- }
-
- pfn = __phys_to_pfn(phys);
- if (pfn != last_pfn) {
- pgprot_t prot = nvmap_pgprot(patch, pgprot_kernel);
- phys_addr_t kaddr = (phys_addr_t)addr;
- set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, prot));
- flush_tlb_kernel_page(kaddr);
- last_pfn = pfn;
- }
-
- reloc_addr = handle_phys(pin) + arr[i].pin_offset;
- reloc_addr >>= arr[i].reloc_shift;
- __raw_writel(reloc_addr, addr + (phys & ~PAGE_MASK));
- }
-
- nvmap_free_pte(client->dev, pte);
-
- if (last_patch)
- nvmap_handle_put(last_patch);
-
- wmb();
-
- return 0;
-}
-
-static int nvmap_validate_get_pin_array(struct nvmap_client *client,
- const struct nvmap_pinarray_elem *arr,
- int nr, struct nvmap_handle **h)
-{
- int i;
- int ret = 0;
- int count = 0;
-
- nvmap_ref_lock(client);
-
- for (i = 0; i < nr; i++) {
- struct nvmap_handle_ref *ref;
-
- if (need_resched()) {
- nvmap_ref_unlock(client);
- schedule();
- nvmap_ref_lock(client);
- }
-
- ref = _nvmap_validate_id_locked(client, arr[i].pin_mem);
-
- if (!ref)
- nvmap_warn(client, "falied to validate id\n");
- else if (!ref->handle)
- nvmap_warn(client, "id had no associated handle\n");
- else if (!ref->handle->alloc)
- nvmap_warn(client, "handle had no allocation\n");
-
- if (!ref || !ref->handle || !ref->handle->alloc) {
- ret = -EPERM;
- break;
- }
-
- /* a handle may be referenced multiple times in arr, but
- * it will only be pinned once; this ensures that the
- * minimum number of sync-queue slots in the host driver
- * are dedicated to storing unpin lists, which allows
- * for greater parallelism between the CPU and graphics
- * processor */
- if (ref->handle->flags & NVMAP_HANDLE_VISITED)
- continue;
-
- ref->handle->flags |= NVMAP_HANDLE_VISITED;
-
- h[count] = nvmap_handle_get(ref->handle);
- BUG_ON(!h[count]);
- count++;
- }
-
- nvmap_ref_unlock(client);
-
- if (ret) {
- for (i = 0; i < count; i++) {
- h[i]->flags &= ~NVMAP_HANDLE_VISITED;
- nvmap_handle_put(h[i]);
- }
- }
-
- return ret ?: count;
-}
-
-/* a typical mechanism host1x clients use for using the Tegra graphics
- * processor is to build a command buffer which contains relocatable
- * memory handle commands, and rely on the kernel to convert these in-place
- * to addresses which are understood by the GPU hardware.
- *
- * this is implemented by having clients provide a sideband array
- * of relocatable handles (+ offsets) and the location in the command
- * buffer handle to patch with the GPU address when the client submits
- * its command buffer to the host1x driver.
- *
- * the host driver also uses this relocation mechanism internally to
- * relocate the client's (unpinned) command buffers into host-addressable
- * memory.
- *
- * @client: nvmap_client which should be used for validation; should be
- * owned by the process which is submitting command buffers
- * @gather: special handle for relocated command buffer outputs used
- * internally by the host driver. if this handle is encountered
- * as an output handle in the relocation array, it is assumed
- * to be a known-good output and is not validated.
- * @arr: array of ((relocatable handle, offset), (output handle, offset))
- * tuples.
- * @nr: number of entries in arr
- * @unique_arr: list of nvmap_handle objects which were pinned by
- * nvmap_pin_array. must be unpinned by the caller after the
- * command buffers referenced in gather have completed.
- */
-int nvmap_pin_array(struct nvmap_client *client, struct nvmap_handle *gather,
- const struct nvmap_pinarray_elem *arr, int nr,
- struct nvmap_handle **unique_arr)
-{
- int count = 0;
- int ret = 0;
- int i;
-
- if (mutex_lock_interruptible(&client->share->pin_lock)) {
- nvmap_warn(client, "%s interrupted when acquiring pin lock\n",
- current->group_leader->comm);
- return -EINTR;
- }
-
- count = nvmap_validate_get_pin_array(client, arr, nr, unique_arr);
- if (count < 0) {
- mutex_unlock(&client->share->pin_lock);
- nvmap_warn(client, "failed to validate pin array\n");
- return count;
- }
-
- for (i = 0; i < count; i++)
- unique_arr[i]->flags &= ~NVMAP_HANDLE_VISITED;
-
- ret = wait_pin_array_locked(client, unique_arr, count);
-
- mutex_unlock(&client->share->pin_lock);
-
- if (!ret)
- ret = nvmap_reloc_pin_array(client, arr, nr, gather);
-
- if (WARN_ON(ret)) {
- for (i = 0; i < count; i++)
- nvmap_handle_put(unique_arr[i]);
- return ret;
- } else {
- for (i = 0; i < count; i++) {
- if (unique_arr[i]->heap_pgalloc &&
- unique_arr[i]->pgalloc.dirty)
- map_iovmm_area(unique_arr[i]);
- }
- }
-
- return count;
-}
-
phys_addr_t nvmap_pin(struct nvmap_client *client,
struct nvmap_handle_ref *ref)
{
@@ -820,52 +601,3 @@ void nvmap_free(struct nvmap_client *client, struct nvmap_handle_ref *r)
nvmap_free_handle_id(client, nvmap_ref_to_id(r));
}
-
-/*
- * create a mapping to the user's buffer and write it
- * (uses similar logic from nvmap_reloc_pin_array to map the cmdbuf)
- */
-int nvmap_patch_word(struct nvmap_client *client,
- struct nvmap_handle *patch,
- u32 patch_offset, u32 patch_value)
-{
- phys_addr_t phys;
- unsigned long kaddr;
- unsigned int pfn;
- void *addr;
- pte_t **pte;
- pgprot_t prot;
-
- if (patch_offset >= patch->size) {
- nvmap_warn(client, "read/write outside of handle\n");
- return -EFAULT;
- }
-
- pte = nvmap_alloc_pte(client->dev, &addr);
- if (IS_ERR(pte))
- return PTR_ERR(pte);
-
- /* derive physaddr of cmdbuf WAIT to patch */
- if (patch->heap_pgalloc) {
- unsigned int page = patch_offset >> PAGE_SHIFT;
- phys = page_to_phys(patch->pgalloc.pages[page]);
- phys += (patch_offset & ~PAGE_MASK);
- } else {
- phys = patch->carveout->base + patch_offset;
- }
-
- pfn = __phys_to_pfn(phys);
- prot = nvmap_pgprot(patch, pgprot_kernel);
- kaddr = (unsigned long)addr;
-
- /* write PTE, so addr points to cmdbuf PFN */
- set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, prot));
- flush_tlb_kernel_page(kaddr);
-
- /* write patch_value to addr + page offset */
- __raw_writel(patch_value, addr + (phys & ~PAGE_MASK));
-
- nvmap_free_pte(client->dev, pte);
- wmb();
- return 0;
-}
diff --git a/drivers/video/tegra/nvmap/nvmap.h b/drivers/video/tegra/nvmap/nvmap.h
index b0fb70f..25403f5 100644
--- a/drivers/video/tegra/nvmap/nvmap.h
+++ b/drivers/video/tegra/nvmap/nvmap.h
@@ -37,6 +37,8 @@ struct nvmap_device;
struct page;
struct tegra_iovmm_area;
+void _nvmap_handle_free(struct nvmap_handle *h);
+
#if defined(CONFIG_TEGRA_NVMAP)
#define nvmap_err(_client, _fmt, ...) \
dev_err(nvmap_client_to_device(_client), \
@@ -162,7 +164,46 @@ static inline void nvmap_ref_unlock(struct nvmap_client *priv)
{
mutex_unlock(&priv->ref_lock);
}
-#endif /* CONFIG_TEGRA_NVMAP */
+
+static inline struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h)
+{
+ if (unlikely(atomic_inc_return(&h->ref) <= 1)) {
+ pr_err("%s: %s getting a freed handle\n",
+ __func__, current->group_leader->comm);
+ if (atomic_read(&h->ref) <= 0)
+ return NULL;
+ }
+ return h;
+}
+
+static inline void nvmap_handle_put(struct nvmap_handle *h)
+{
+ int cnt = atomic_dec_return(&h->ref);
+
+ if (WARN_ON(cnt < 0)) {
+ pr_err("%s: %s put to negative references\n",
+ __func__, current->comm);
+ } else if (cnt == 0)
+ _nvmap_handle_free(h);
+}
+
+static inline pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot)
+{
+ if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
+ return pgprot_noncached(prot);
+ else if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
+ return pgprot_writecombine(prot);
+ else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
+ return pgprot_inner_writeback(prot);
+ return prot;
+}
+
+#else /* CONFIG_TEGRA_NVMAP */
+struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h);
+void nvmap_handle_put(struct nvmap_handle *h);
+pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot);
+
+#endif /* !CONFIG_TEGRA_NVMAP */
struct device *nvmap_client_to_device(struct nvmap_client *client);
@@ -216,51 +257,10 @@ int nvmap_pin_ids(struct nvmap_client *client,
void nvmap_unpin_ids(struct nvmap_client *priv,
unsigned int nr, const unsigned long *ids);
-void _nvmap_handle_free(struct nvmap_handle *h);
-
int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h);
void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h);
-#if defined(CONFIG_TEGRA_NVMAP)
-static inline struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h)
-{
- if (unlikely(atomic_inc_return(&h->ref) <= 1)) {
- pr_err("%s: %s getting a freed handle\n",
- __func__, current->group_leader->comm);
- if (atomic_read(&h->ref) <= 0)
- return NULL;
- }
- return h;
-}
-
-static inline void nvmap_handle_put(struct nvmap_handle *h)
-{
- int cnt = atomic_dec_return(&h->ref);
-
- if (WARN_ON(cnt < 0)) {
- pr_err("%s: %s put to negative references\n",
- __func__, current->comm);
- } else if (cnt == 0)
- _nvmap_handle_free(h);
-}
-
-static inline pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot)
-{
- if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
- return pgprot_noncached(prot);
- else if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
- return pgprot_writecombine(prot);
- else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
- return pgprot_inner_writeback(prot);
- return prot;
-}
-#else /* CONFIG_TEGRA_NVMAP */
-struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h);
-void nvmap_handle_put(struct nvmap_handle *h);
-pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot);
-#endif /* !CONFIG_TEGRA_NVMAP */
-
int is_nvmap_vma(struct vm_area_struct *vma);
struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client,
@@ -268,4 +268,4 @@ struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client,
void nvmap_free_iovm(struct nvmap_client *client, struct nvmap_handle_ref *r);
-#endif
+#endif /* __VIDEO_TEGRA_NVMAP_NVMAP_H */
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index c78818711..9ecce7e 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -973,20 +973,17 @@ static void client_stringify(struct nvmap_client *client, struct seq_file *s)
}
static void allocations_stringify(struct nvmap_client *client,
- struct seq_file *s)
+ struct seq_file *s, bool iovmm)
{
- unsigned long base = 0;
struct rb_node *n = rb_first(&client->handle_refs);
for (; n != NULL; n = rb_next(n)) {
struct nvmap_handle_ref *ref =
rb_entry(n, struct nvmap_handle_ref, node);
struct nvmap_handle *handle = ref->handle;
- if (handle->alloc && !handle->heap_pgalloc) {
- seq_printf(s, "%-18s %-18s %8lx %10u %8x\n", "", "",
- (unsigned long)(handle->carveout->base),
- handle->size, handle->userflags);
- } else if (handle->alloc && handle->heap_pgalloc) {
+ if (handle->alloc && handle->heap_pgalloc == iovmm) {
+ unsigned long base = iovmm ? 0:
+ (unsigned long)(handle->carveout->base);
seq_printf(s, "%-18s %-18s %8lx %10u %8x\n", "", "",
base, handle->size, handle->userflags);
}
@@ -1010,7 +1007,7 @@ static int nvmap_debug_allocations_show(struct seq_file *s, void *unused)
get_client_from_carveout_commit(node, commit);
client_stringify(client, s);
seq_printf(s, " %10u\n", commit->commit);
- allocations_stringify(client, s);
+ allocations_stringify(client, s, false);
seq_printf(s, "\n");
total += commit->commit;
}
@@ -1111,14 +1108,14 @@ static int nvmap_debug_iovmm_allocations_show(struct seq_file *s, void *unused)
struct nvmap_device *dev = s->private;
spin_lock_irqsave(&dev->clients_lock, flags);
- seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
- "SIZE");
+ seq_printf(s, "%-18s %18s %8s %10s %8s\n", "CLIENT", "PROCESS", "PID",
+ "SIZE", "FLAGS");
seq_printf(s, "%-18s %18s %8s %10s\n", "", "",
"BASE", "SIZE");
list_for_each_entry(client, &dev->clients, list) {
client_stringify(client, s);
seq_printf(s, " %10u\n", atomic_read(&client->iovm_commit));
- allocations_stringify(client, s);
+ allocations_stringify(client, s, true);
seq_printf(s, "\n");
total += atomic_read(&client->iovm_commit);
}
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 2f24ba5..56e2dab 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -38,22 +38,12 @@
#include <mach/iovmm.h>
#include <linux/nvmap.h>
-#include <linux/vmstat.h>
-#include <linux/swap.h>
#include <linux/shrinker.h>
#include <linux/moduleparam.h>
-
#include "nvmap.h"
#include "nvmap_mru.h"
#include "nvmap_common.h"
-#define PRINT_CARVEOUT_CONVERSION 0
-#if PRINT_CARVEOUT_CONVERSION
-#define PR_INFO pr_info
-#else
-#define PR_INFO(...)
-#endif
-
#define NVMAP_SECURE_HEAPS (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_IOVMM | \
NVMAP_HEAP_CARVEOUT_VPR)
#ifdef CONFIG_NVMAP_HIGHMEM_ONLY
@@ -646,36 +636,19 @@ fail:
static void alloc_handle(struct nvmap_client *client,
struct nvmap_handle *h, unsigned int type)
{
+ unsigned int carveout_mask = NVMAP_HEAP_CARVEOUT_MASK;
+ unsigned int iovmm_mask = NVMAP_HEAP_IOVMM;
+
BUG_ON(type & (type - 1));
#ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
-#define __NVMAP_HEAP_CARVEOUT (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_CARVEOUT_VPR)
-#define __NVMAP_HEAP_IOVMM (NVMAP_HEAP_IOVMM | NVMAP_HEAP_CARVEOUT_GENERIC)
- if (type & NVMAP_HEAP_CARVEOUT_GENERIC) {
-#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
- if (h->size <= PAGE_SIZE) {
- PR_INFO("###CARVEOUT CONVERTED TO SYSMEM "
- "0x%x bytes %s(%d)###\n",
- h->size, current->comm, current->pid);
- goto sysheap;
- }
-#endif
- PR_INFO("###CARVEOUT CONVERTED TO IOVM "
- "0x%x bytes %s(%d)###\n",
- h->size, current->comm, current->pid);
- }
-#else
-#define __NVMAP_HEAP_CARVEOUT NVMAP_HEAP_CARVEOUT_MASK
-#define __NVMAP_HEAP_IOVMM NVMAP_HEAP_IOVMM
+ /* Convert generic carveout requests to iovmm requests. */
+ carveout_mask &= ~NVMAP_HEAP_CARVEOUT_GENERIC;
+ iovmm_mask |= NVMAP_HEAP_CARVEOUT_GENERIC;
#endif
- if (type & __NVMAP_HEAP_CARVEOUT) {
+ if (type & carveout_mask) {
struct nvmap_heap_block *b;
-#ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
- PR_INFO("###IRAM REQUEST RETAINED "
- "0x%x bytes %s(%d)###\n",
- h->size, current->comm, current->pid);
-#endif
/* Protect handle from relocation */
nvmap_usecount_inc(h);
@@ -689,7 +662,7 @@ static void alloc_handle(struct nvmap_client *client,
}
nvmap_usecount_dec(h);
- } else if (type & __NVMAP_HEAP_IOVMM) {
+ } else if (type & iovmm_mask) {
size_t reserved = PAGE_ALIGN(h->size);
int commit = 0;
int ret;
@@ -713,10 +686,6 @@ static void alloc_handle(struct nvmap_client *client,
}
} else if (type & NVMAP_HEAP_SYSMEM) {
-#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM) && \
- defined(CONFIG_NVMAP_ALLOW_SYSMEM)
-sysheap:
-#endif
if (handle_page_alloc(client, h, true) == 0) {
BUG_ON(!h->pgalloc.contig);
h->heap_pgalloc = true;
@@ -751,10 +720,6 @@ static const unsigned int heap_policy_large[] = {
0,
};
-/* Do not override single page policy if there is not much space to
-avoid invoking system oom killer. */
-#define NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD 50000000
-
int nvmap_alloc_handle_id(struct nvmap_client *client,
unsigned long id, unsigned int heap_mask,
size_t align, unsigned int flags)
@@ -779,32 +744,22 @@ int nvmap_alloc_handle_id(struct nvmap_client *client,
h->align = max_t(size_t, align, L1_CACHE_BYTES);
#ifndef CONFIG_TEGRA_IOVMM
+ /* convert iovmm requests to generic carveout. */
if (heap_mask & NVMAP_HEAP_IOVMM) {
- heap_mask &= NVMAP_HEAP_IOVMM;
- heap_mask |= NVMAP_HEAP_CARVEOUT_GENERIC;
+ heap_mask = heap_mask & ~NVMAP_HEAP_IOVMM |
+ NVMAP_HEAP_CARVEOUT_GENERIC;
}
#endif
-#ifndef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
/* Allow single pages allocations in system memory to save
* carveout space and avoid extra iovm mappings */
if (nr_page == 1) {
- if (heap_mask & NVMAP_HEAP_IOVMM)
+ if (heap_mask &
+ (NVMAP_HEAP_IOVMM | NVMAP_HEAP_CARVEOUT_GENERIC))
heap_mask |= NVMAP_HEAP_SYSMEM;
- else if (heap_mask & NVMAP_HEAP_CARVEOUT_GENERIC) {
- /* Calculate size of free physical pages
- * managed by kernel */
- unsigned long freeMem =
- (global_page_state(NR_FREE_PAGES) +
- global_page_state(NR_FILE_PAGES) -
- total_swapcache_pages) << PAGE_SHIFT;
-
- if (freeMem > NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD)
- heap_mask |= NVMAP_HEAP_SYSMEM;
- }
}
#endif
-
+#ifndef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
/* This restriction is deprecated as alignments greater than
PAGE_SIZE are now correctly handled, but it is retained for
AP20 compatibility. */