/* 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) { nvmap_free_pte(client->dev, pte); return -EPERM; } 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_addr_t nvmap_handle_address(struct nvmap_client *c, unsigned long id) { struct nvmap_handle *h; phys_addr_t phys; h = nvmap_get_handle_id(c, id); if (!h) return -EPERM; mutex_lock(&h->lock); phys = handle_phys(h); mutex_unlock(&h->lock); nvmap_handle_put(h); return phys; }
/* Overlay window manipulation */ static int tegra_overlay_pin_window(struct tegra_overlay_info *overlay, struct tegra_overlay_flip_win *flip_win, struct nvmap_client *user_nvmap) { struct nvmap_handle_ref *win_dupe; struct nvmap_handle *win_handle; unsigned long buff_id = flip_win->attr.buff_id; if (!buff_id) return 0; win_handle = nvmap_get_handle_id(user_nvmap, buff_id); if (win_handle == NULL) { dev_err(&overlay->ndev->dev, "%s: flip invalid " "handle %08lx\n", current->comm, buff_id); return -EPERM; } /* duplicate the new framebuffer's handle into the fb driver's * nvmap context, to ensure that the handle won't be freed as * long as it is in-use by the fb driver */ win_dupe = nvmap_duplicate_handle_id(overlay->overlay_nvmap, buff_id); nvmap_handle_put(win_handle); if (IS_ERR(win_dupe)) { dev_err(&overlay->ndev->dev, "couldn't duplicate handle\n"); return PTR_ERR(win_dupe); } flip_win->handle = win_dupe; flip_win->phys_addr = nvmap_pin(overlay->overlay_nvmap, win_dupe); if (IS_ERR((void *)flip_win->phys_addr)) { dev_err(&overlay->ndev->dev, "couldn't pin handle\n"); nvmap_free(overlay->overlay_nvmap, win_dupe); return PTR_ERR((void *)flip_win->phys_addr); } return 0; }