summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/nvmap/nvmap.c
diff options
context:
space:
mode:
authorPrajakta Gudadhe <pgudadhe@nvidia.com>2011-02-05 01:37:38 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:37:00 -0800
commit27d7d89e930ee195979f9f18c3db0c45f4e21fac (patch)
tree81eabe83b6d69db7176cbd8fa5caeea2fa8ac76f /drivers/video/tegra/nvmap/nvmap.c
parenta37e55b3364fe0e329dddd81cea3714010eeddea (diff)
tegra: host: move stale wait checking into the kernel
The kernel now receives wait tracking data (similar to gathers and relocs) and compares the current syncpt with the threshold value. If it's old, it gets a kernel mapping and rewrites the method data to use a kernel reserved syncpt that is always 0 (so trivially pops when seen by the HW). Patch has dependency to the user-space patches Submitted on behalf of: Chris Johnson <cjohnson@nvidia.com> original work by: Chris Johnson <cjohnson@nvidia.com> Change-Id: I4d4e5d3b49cab860485c4172f87247f5b4f5ea6e
Diffstat (limited to 'drivers/video/tegra/nvmap/nvmap.c')
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index 1a70f43d79f5..380f70ec187c 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -724,3 +724,53 @@ 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_wait(struct nvmap_client *client,
+ struct nvmap_handle *patch,
+ u32 patch_offset, u32 patch_value)
+{
+ unsigned long phys;
+ unsigned int pfn, last_pfn = 0;
+ void *addr;
+ pte_t **pte;
+
+ 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);
+
+ /* write PTE, so addr points to cmdbuf PFN */
+ if (pfn != last_pfn) {
+ pgprot_t prot = nvmap_pgprot(patch, pgprot_kernel);
+ unsigned long kaddr = (unsigned long)addr;
+ set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, prot));
+ flush_tlb_kernel_page(kaddr);
+ last_pfn = pfn;
+ }
+
+ /* write patch_value to addr + page offset */
+ __raw_writel(patch_value, addr + (phys & ~PAGE_MASK));
+
+ nvmap_free_pte(client->dev, pte);
+ wmb();
+ return 0;
+}