void *nvmap_kmap(struct nvmap_handle_ref *ref, unsigned int pagenum) { struct nvmap_handle *h; phys_addr_t paddr; unsigned long kaddr; pgprot_t prot; pte_t **pte; BUG_ON(!ref); h = nvmap_handle_get(ref->handle); if (!h) return NULL; BUG_ON(pagenum >= h->size >> PAGE_SHIFT); prot = nvmap_pgprot(h, pgprot_kernel); pte = nvmap_alloc_pte(nvmap_dev, (void **)&kaddr); if (!pte) goto out; if (h->heap_pgalloc) paddr = page_to_phys(h->pgalloc.pages[pagenum]); else paddr = h->carveout->base + pagenum * PAGE_SIZE; set_pte_at(&init_mm, kaddr, *pte, pfn_pte(__phys_to_pfn(paddr), prot)); flush_tlb_kernel_page(kaddr); return (void *)kaddr; out: nvmap_handle_put(ref->handle); return NULL; }
/* 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 {