diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index f01a4be5a886..63dc0e883873 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1427,8 +1427,10 @@ static int adreno_probe(struct platform_device *pdev) * check the GPU capabilities here and modify mmu->secured accordingly */ +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) if (!ADRENO_FEATURE(adreno_dev, ADRENO_CONTENT_PROTECTION)) device->mmu.secured = false; +#endif if (ADRENO_FEATURE(adreno_dev, ADRENO_IOCOHERENT)) device->mmu.features |= KGSL_MMU_IO_COHERENT; diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 2af76acb1200..03a59ce24408 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -312,16 +312,14 @@ static int ctx_print(struct seq_file *s, void *unused) static int ctx_open(struct inode *inode, struct file *file) { int ret; - unsigned int id = (unsigned int)(unsigned long)inode->i_private; - struct kgsl_context *context; + struct adreno_context *ctx = inode->i_private; - context = kgsl_context_get(kgsl_get_device(KGSL_DEVICE_3D0), id); - if (context == NULL) + if (!_kgsl_context_get(&ctx->base)) return -ENODEV; - ret = single_open(file, ctx_print, context); + ret = single_open(file, ctx_print, &ctx->base); if (ret) - kgsl_context_put(context); + kgsl_context_put(&ctx->base); return ret; } @@ -350,11 +348,16 @@ adreno_context_debugfs_init(struct adreno_device *adreno_dev, { unsigned char name[16]; + /* + * Get the context here to make sure it still exists for the life of the + * file + */ + _kgsl_context_get(&ctx->base); + snprintf(name, sizeof(name), "%d", ctx->base.id); ctx->debug_root = debugfs_create_file(name, 0444, - adreno_dev->ctx_d_debugfs, - (void *)(unsigned long)ctx->base.id, &ctx_fops); + adreno_dev->ctx_d_debugfs, ctx, &ctx_fops); } void adreno_debugfs_init(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index 2f7f98db3b8f..ab9ad91bdea4 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -478,6 +478,8 @@ void adreno_drawctxt_detach(struct kgsl_context *context) } debugfs_remove_recursive(drawctxt->debug_root); + /* The debugfs file has a reference, release it */ + kgsl_context_put(context); /* * internal_timestamp is set in adreno_ringbuffer_addcmds, diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index c0d30706053a..18767bbdbd12 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4551,169 +4551,94 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private, return addr; } -static unsigned long _gpu_find_svm(struct kgsl_process_private *private, - unsigned long start, unsigned long end, unsigned long len, - unsigned int align) +static unsigned long get_align(struct kgsl_mem_entry *entry) { - uint64_t addr = kgsl_mmu_find_svm_region(private->pagetable, - (uint64_t) start, (uint64_t)end, (uint64_t) len, align); + int bit = kgsl_memdesc_get_align(&entry->memdesc); - WARN(!IS_ERR_VALUE((unsigned long)addr) && (addr > ULONG_MAX), - "Couldn't find range\n"); + if (bit >= ilog2(SZ_2M)) + return SZ_2M; + else if (bit >= ilog2(SZ_1M)) + return SZ_1M; + else if (bit >= ilog2(SZ_64K)) + return SZ_64K; - return (unsigned long) addr; + return SZ_4K; } -/* Search top down in the CPU VM region for a free address */ -static unsigned long _cpu_get_unmapped_area(unsigned long bottom, - unsigned long top, unsigned long len, unsigned long align) -{ - struct vm_unmapped_area_info info; - unsigned long addr, err; - - info.flags = VM_UNMAPPED_AREA_TOPDOWN; - info.low_limit = bottom; - info.high_limit = top; - info.length = len; - info.align_offset = 0; - info.align_mask = align - 1; - - addr = vm_unmapped_area(&info); - - if (IS_ERR_VALUE(addr)) - return addr; - - err = security_mmap_addr(addr); - return err ? err : addr; -} - -static unsigned long _search_range(struct kgsl_process_private *private, +static unsigned long set_svm_area(struct file *file, struct kgsl_mem_entry *entry, - unsigned long start, unsigned long end, - unsigned long len, uint64_t align) + unsigned long addr, unsigned long len, + unsigned long flags) { - unsigned long cpu, gpu = end, result = -ENOMEM; + struct kgsl_device_private *dev_priv = file->private_data; + struct kgsl_process_private *private = dev_priv->process_priv; + unsigned long ret; - while (gpu > start) { - /* find a new empty spot on the CPU below the last one */ - cpu = _cpu_get_unmapped_area(start, gpu, len, - (unsigned long) align); - if (IS_ERR_VALUE(cpu)) { - result = cpu; - break; - } - /* try to map it on the GPU */ - result = _gpu_set_svm_region(private, entry, cpu, len); - if (!IS_ERR_VALUE(result)) - break; - - trace_kgsl_mem_unmapped_area_collision(entry, cpu, len); - - if (cpu <= start) { - result = -ENOMEM; - break; - } - - /* move downward to the next empty spot on the GPU */ - gpu = _gpu_find_svm(private, start, cpu, len, align); - if (IS_ERR_VALUE(gpu)) { - result = gpu; - break; - } - - /* Check that_gpu_find_svm doesn't put us in a loop */ - if (gpu >= cpu) { - result = -ENOMEM; - break; - } - - /* Break if the recommended GPU address is out of range */ - if (gpu < start) { - result = -ENOMEM; - break; - } - - /* - * Add the length of the chunk to the GPU address to yield the - * upper bound for the CPU search - */ - gpu += len; - } - return result; -} - -static unsigned long _get_svm_area(struct kgsl_process_private *private, - struct kgsl_mem_entry *entry, unsigned long hint, - unsigned long len, unsigned long flags) -{ - uint64_t start, end; - int align_shift = kgsl_memdesc_get_align(&entry->memdesc); - uint64_t align; - unsigned long result; - unsigned long addr; - - if (align_shift >= ilog2(SZ_2M)) - align = SZ_2M; - else if (align_shift >= ilog2(SZ_1M)) - align = SZ_1M; - else if (align_shift >= ilog2(SZ_64K)) - align = SZ_64K; - else - align = SZ_4K; - - align = max_t(uint64_t, align, PAGE_SIZE); - - /* get the GPU pagetable's SVM range */ - if (kgsl_mmu_svm_range(private->pagetable, &start, &end, - entry->memdesc.flags)) - return -ERANGE; - - /* now clamp the range based on the CPU's requirements */ - start = max_t(uint64_t, start, mmap_min_addr); - end = min_t(uint64_t, end, current->mm->mmap_base); - if (start >= end) - return -ERANGE; - - if (flags & MAP_FIXED) { - /* We must honor alignment requirements */ - if (!IS_ALIGNED(hint, align)) - return -EINVAL; - - /* we must use addr 'hint' or fail */ - return _gpu_set_svm_region(private, entry, hint, len); - } else if (hint != 0) { - struct vm_area_struct *vma; - - /* - * See if the hint is usable, if not we will use - * it as the start point for searching. - */ - addr = clamp_t(unsigned long, hint & ~(align - 1), - start, (end - len) & ~(align - 1)); - - vma = find_vma(current->mm, addr); - - if (vma == NULL || ((addr + len) <= vma->vm_start)) { - result = _gpu_set_svm_region(private, entry, addr, len); - - /* On failure drop down to keep searching */ - if (!IS_ERR_VALUE(result)) - return result; - } - } else { - /* no hint, start search at the top and work down */ - addr = end & ~(align - 1); - } + /* Make sure there isn't a vma conflict in the chosen range */ + if (find_vma_intersection(current->mm, addr, addr + len - 1)) + return -ENOMEM; /* - * Search downwards from the hint first. If that fails we - * must try to search above it. + * Do additoinal constraints checking on the address. Passing MAP_FIXED + * ensures that the address we want gets checked */ - result = _search_range(private, entry, start, addr, len, align); - if (IS_ERR_VALUE(result) && hint != 0) - result = _search_range(private, entry, addr, end, len, align); + ret = current->mm->get_unmapped_area(file, addr, len, 0, + flags & MAP_FIXED); - return result; + /* If it passes, attempt to set the region in the SVM */ + if (!IS_ERR_VALUE(ret)) + return _gpu_set_svm_region(private, entry, addr, len); + + return ret; +} + +static unsigned long get_svm_unmapped_area(struct file *file, + struct kgsl_mem_entry *entry, + unsigned long addr, unsigned long len, + unsigned long flags) +{ + struct kgsl_device_private *dev_priv = file->private_data; + struct kgsl_process_private *private = dev_priv->process_priv; + unsigned long align = get_align(entry); + unsigned long ret, iova; + u64 start = 0, end = 0; + + if (flags & MAP_FIXED) { + /* Even fixed addresses need to obey alignment */ + if (!IS_ALIGNED(addr, align)) + return -EINVAL; + + return set_svm_area(file, entry, addr, len, flags); + } + + /* If a hint was provided, try to use that first */ + if (addr) { + if (IS_ALIGNED(addr, align)) { + ret = set_svm_area(file, entry, addr, len, flags); + if (!IS_ERR_VALUE(ret)) + return ret; + } + } + + /* Get the SVM range for the current process */ + if (kgsl_mmu_svm_range(private->pagetable, &start, &end, + entry->memdesc.flags)) + return -ERANGE; + + /* Find the first gap in the iova map */ + iova = kgsl_mmu_find_svm_region(private->pagetable, start, end, + len, align); + + while (!IS_ERR_VALUE(iova)) { + ret = set_svm_area(file, entry, iova, len, flags); + if (!IS_ERR_VALUE(ret)) + return ret; + + iova = kgsl_mmu_find_svm_region(private->pagetable, + start, iova - 1, len, align); + } + + return -ENOMEM; } static unsigned long @@ -4737,28 +4662,26 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr, /* Do not allow CPU mappings for secure buffers */ if (kgsl_memdesc_is_secured(&entry->memdesc)) { - val = -EPERM; - goto put; + kgsl_mem_entry_put(entry); + return (unsigned long) -EPERM; } if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) { - val = get_unmapped_area(NULL, addr, len, 0, flags); + val = current->mm->get_unmapped_area(file, addr, len, 0, flags); if (IS_ERR_VALUE(val)) dev_err_ratelimited(device->dev, "get_unmapped_area: pid %d addr %lx pgoff %lx len %ld failed error %d\n", private->pid, addr, pgoff, len, (int) val); } else { - val = _get_svm_area(private, entry, addr, len, flags); + val = get_svm_unmapped_area(file, entry, addr, len, flags); if (IS_ERR_VALUE(val)) dev_err_ratelimited(device->dev, - "_get_svm_area: pid %d mmap_base %lx addr %lx pgoff %lx len %ld failed error %d\n", - private->pid, - current->mm->mmap_base, addr, - pgoff, len, (int) val); + "_get_svm_area: pid %d addr %lx pgoff %lx len %ld failed error %d\n", + private->pid, addr, pgoff, len, + (int) val); } -put: kgsl_mem_entry_put(entry); return val; } @@ -5078,7 +5001,7 @@ void kgsl_device_platform_remove(struct kgsl_device *device) kgsl_exit_page_pools(); - kgsl_pwrctrl_uninit_sysfs(device); + kobject_put(device->gpu_sysfs_kobj); idr_destroy(&device->context_idr); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 7b9874a2c3ac..dd4310cd06f3 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -579,6 +579,7 @@ static inline int kgsl_copy_from_user(void *dest, void __user *src, return copy_from_user(dest, src, copy) ? -EFAULT : 0; } +#ifndef MODULE static inline void kgsl_gpu_sysfs_add_link(struct kobject *dst, struct kobject *src, const char *src_name, const char *dst_name) @@ -594,6 +595,13 @@ static inline void kgsl_gpu_sysfs_add_link(struct kobject *dst, kernfs_create_link(dst->sd, dst_name, old); } +#else +static inline void kgsl_gpu_sysfs_add_link(struct kobject *dst, + struct kobject *src, const char *src_name, + const char *dst_name) +{ +} +#endif static inline bool kgsl_is_compat_task(void) { diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index a302f3e0ec97..58c6e62e73b7 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1003,6 +1003,7 @@ done: return ret; } +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) static int _init_secure_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) { struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); @@ -1011,7 +1012,6 @@ static int _init_secure_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE]; int secure_vmid = VMID_CP_PIXEL; - unsigned int cb_num; if (!mmu->secured) return -EPERM; @@ -1036,23 +1036,17 @@ static int _init_secure_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) iommu_set_fault_handler(iommu_pt->domain, kgsl_iommu_fault_handler, pt); - ret = iommu_domain_get_attr(iommu_pt->domain, - DOMAIN_ATTR_CONTEXT_BANK, &cb_num); - if (ret) { - dev_err(device->dev, "get DOMAIN_ATTR_PROCID failed: %d\n", - ret); - goto done; - } - - ctx->cb_num = cb_num; - ctx->regbase = iommu->regbase + KGSL_IOMMU_CB0_OFFSET - + (cb_num << KGSL_IOMMU_CB_SHIFT); - done: if (ret) _free_pt(ctx, pt); return ret; } +#else +static int _init_secure_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) +{ + return -EPERM; +} +#endif static int _init_per_process_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) { @@ -1335,7 +1329,6 @@ static int _setup_secure_context(struct kgsl_mmu *mmu) int ret; struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE]; - unsigned int cb_num; struct kgsl_iommu_pt *iommu_pt; @@ -1348,22 +1341,12 @@ static int _setup_secure_context(struct kgsl_mmu *mmu) iommu_pt = mmu->securepagetable->priv; ret = _attach_pt(iommu_pt, ctx); - if (ret) - goto done; - - ctx->default_pt = mmu->securepagetable; - - ret = iommu_domain_get_attr(iommu_pt->domain, DOMAIN_ATTR_CONTEXT_BANK, - &cb_num); - if (ret) { - dev_err(KGSL_MMU_DEVICE(mmu)->dev, - "get CONTEXT_BANK attr, err %d\n", ret); - goto done; + if (!ret) { + ctx->default_pt = mmu->securepagetable; + return 0; } - ctx->cb_num = cb_num; -done: - if (ret) - _detach_context(ctx); + + _detach_context(ctx); return ret; } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 31c367777758..c09d17456f70 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1191,45 +1191,41 @@ static const struct attribute *pwrctrl_attr_list[] = { NULL, }; -struct sysfs_link { - const char *src; - const char *dst; -}; +static DEVICE_ATTR(gpu_busy, 0200, gpu_busy_percentage_show, NULL); +static DEVICE_ATTR(gpu_min_clock, 0644, min_clock_mhz_show, + min_clock_mhz_store); +static DEVICE_ATTR(gpu_max_clock, 0644, max_clock_mhz_show, + max_clock_mhz_store); +static DEVICE_ATTR(gpu_clock, 0200, clock_mhz_show, NULL); +static DEVICE_ATTR(gpu_freq_table, 0200, freq_table_mhz_show, NULL); +static DEVICE_ATTR(gpu_tmu, 0200, temp_show, NULL); -static struct sysfs_link link_names[] = { - { "gpu_model", "gpu_model",}, - { "gpu_busy_percentage", "gpu_busy",}, - { "min_clock_mhz", "gpu_min_clock",}, - { "max_clock_mhz", "gpu_max_clock",}, - { "clock_mhz", "gpu_clock",}, - { "freq_table_mhz", "gpu_freq_table",}, - { "temp", "gpu_tmu",}, +static const struct attribute *pwrctrl_gpu_attr_list[] = { + &dev_attr_gpu_model.attr, + &dev_attr_gpu_busy.attr, + &dev_attr_gpu_min_clock.attr, + &dev_attr_gpu_max_clock.attr, + &dev_attr_gpu_clock.attr, + &dev_attr_gpu_freq_table.attr, + &dev_attr_gpu_tmu.attr, + NULL, }; int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device) { - int i, ret; + int ret; ret = sysfs_create_files(&device->dev->kobj, pwrctrl_attr_list); if (ret) return ret; device->gpu_sysfs_kobj = kobject_create_and_add("gpu", kernel_kobj); - if (IS_ERR_OR_NULL(device->gpu_sysfs_kobj)) - return (device->gpu_sysfs_kobj == NULL) ? - -ENOMEM : PTR_ERR(device->gpu_sysfs_kobj); - for (i = 0; i < ARRAY_SIZE(link_names); i++) - kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj, - &device->dev->kobj, link_names[i].src, - link_names[i].dst); + if (!device->gpu_sysfs_kobj) + return 0; - return 0; -} - -void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device) -{ - sysfs_remove_files(&device->dev->kobj, pwrctrl_attr_list); + return sysfs_create_files(device->gpu_sysfs_kobj, + pwrctrl_gpu_attr_list); } /* diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 5b0fe861cad3..659dcb38818a 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -165,7 +165,6 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device, bool on); int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device); -void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device); int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state); int kgsl_clk_set_rate(struct kgsl_device *device, unsigned int pwrlevel); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index ea39e39b66c1..fa3f7fdb8950 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "kgsl_device.h" #include "kgsl_sharedmem.h" @@ -404,6 +403,10 @@ done: mutex_unlock(&kernel_map_global_lock); } +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) + +#include + static int lock_sgt(struct sg_table *sgt, u64 size) { struct scatterlist *sg; @@ -460,6 +463,7 @@ static int unlock_sgt(struct sg_table *sgt) ClearPagePrivate(sg_page_iter_page(&sg_iter)); return 0; } +#endif static int kgsl_paged_map_kernel(struct kgsl_memdesc *memdesc) { @@ -712,6 +716,7 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) memdesc->ops->free(memdesc); } +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) void kgsl_free_secure_page(struct page *page) { struct sg_table sgt; @@ -758,6 +763,16 @@ struct page *kgsl_alloc_secure_page(void) } return page; } +#else +void kgsl_free_secure_page(struct page *page) +{ +} + +struct page *kgsl_alloc_secure_page(void) +{ + return NULL; +} +#endif int kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc, @@ -1029,6 +1044,7 @@ static void kgsl_contiguous_free(struct kgsl_memdesc *memdesc) _kgsl_contiguous_free(memdesc); } +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) static void kgsl_free_secure_pool_pages(struct kgsl_memdesc *memdesc) { int ret = unlock_sgt(memdesc->sgt); @@ -1054,6 +1070,7 @@ static void kgsl_free_secure_pool_pages(struct kgsl_memdesc *memdesc) memdesc->sgt = NULL; } +#endif static void kgsl_free_pool_pages(struct kgsl_memdesc *memdesc) { @@ -1076,11 +1093,12 @@ static struct kgsl_memdesc_ops kgsl_contiguous_ops = { .vmfault = kgsl_contiguous_vmfault, }; - +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) static struct kgsl_memdesc_ops kgsl_secure_pool_ops = { .free = kgsl_free_secure_pool_pages, /* FIXME: Make sure vmflags / vmfault does the right thing here */ }; +#endif static struct kgsl_memdesc_ops kgsl_pool_ops = { .free = kgsl_free_pool_pages, @@ -1090,6 +1108,7 @@ static struct kgsl_memdesc_ops kgsl_pool_ops = { .unmap_kernel = kgsl_paged_unmap_kernel, }; +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) static int kgsl_alloc_secure_pages(struct kgsl_device *device, struct kgsl_memdesc *memdesc, u64 size, u64 flags, u32 priv) { @@ -1145,6 +1164,7 @@ static int kgsl_alloc_secure_pages(struct kgsl_device *device, return 0; } +#endif static int kgsl_alloc_pages(struct kgsl_device *device, struct kgsl_memdesc *memdesc, u64 size, u64 flags, u32 priv) @@ -1229,11 +1249,19 @@ static int kgsl_alloc_contiguous(struct kgsl_device *device, return ret; } +#if IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) static int kgsl_allocate_secure(struct kgsl_device *device, struct kgsl_memdesc *memdesc, u64 size, u64 flags, u32 priv) { return kgsl_alloc_secure_pages(device, memdesc, size, flags, priv); } +#else +static int kgsl_allocate_secure(struct kgsl_device *device, + struct kgsl_memdesc *memdesc, u64 size, u64 flags, u32 priv) +{ + return -ENODEV; +} +#endif int kgsl_allocate_user(struct kgsl_device *device, struct kgsl_memdesc *memdesc, u64 size, u64 flags, u32 priv)