From 08f87f769b595151be1afeff53e144f543faa614 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 06 Dec 2023 09:51:13 +0000 Subject: [PATCH] add dts config --- kernel/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c | 1749 +++++++++++++++++++++++++++++++++++---------------------- 1 files changed, 1,077 insertions(+), 672 deletions(-) diff --git a/kernel/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c b/kernel/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c index 52c040a..12d6cc8 100644 --- a/kernel/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c +++ b/kernel/drivers/gpu/arm/bifrost/mali_kbase_core_linux.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2010-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -31,7 +31,8 @@ #include <ipa/mali_kbase_ipa_debugfs.h> #endif /* CONFIG_DEVFREQ_THERMAL */ #endif /* CONFIG_MALI_BIFROST_DEVFREQ */ -#include "mali_kbase_mem_profile_debugfs_buf_size.h" +#include "backend/gpu/mali_kbase_model_linux.h" +#include "uapi/gpu/arm/bifrost/mali_kbase_mem_profile_debugfs_buf_size.h" #include "mali_kbase_mem.h" #include "mali_kbase_mem_pool_debugfs.h" #include "mali_kbase_mem_pool_group.h" @@ -50,15 +51,16 @@ #if !MALI_USE_CSF #include "mali_kbase_kinstr_jm.h" #endif -#include "mali_kbase_hwcnt_context.h" -#include "mali_kbase_hwcnt_virtualizer.h" -#include "mali_kbase_hwcnt_legacy.h" +#include "hwcnt/mali_kbase_hwcnt_context.h" +#include "hwcnt/mali_kbase_hwcnt_virtualizer.h" +#include "mali_kbase_kinstr_prfcnt.h" #include "mali_kbase_vinstr.h" #if MALI_USE_CSF #include "csf/mali_kbase_csf_firmware.h" #include "csf/mali_kbase_csf_tiler_heap.h" #include "csf/mali_kbase_csf_csg_debugfs.h" #include "csf/mali_kbase_csf_cpu_queue_debugfs.h" +#include "csf/mali_kbase_csf_event.h" #endif #ifdef CONFIG_MALI_ARBITER_SUPPORT #include "arbiter/mali_kbase_arbiter_pm.h" @@ -71,6 +73,9 @@ #endif #include "backend/gpu/mali_kbase_pm_internal.h" #include "mali_kbase_dvfs_debugfs.h" +#if IS_ENABLED(CONFIG_DEBUG_FS) +#include "mali_kbase_pbha_debugfs.h" +#endif #include <linux/module.h> #include <linux/init.h> @@ -78,6 +83,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/of_platform.h> #include <linux/miscdevice.h> @@ -86,14 +92,16 @@ #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/mm.h> #include <linux/compat.h> /* is_compat_task/in_compat_syscall */ #include <linux/mman.h> #include <linux/version.h> +#include <linux/version_compat_defs.h> #include <mali_kbase_hw.h> -#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) +#if IS_ENABLED(CONFIG_SYNC_FILE) #include <mali_kbase_sync.h> -#endif /* CONFIG_SYNC || CONFIG_SYNC_FILE */ +#endif /* CONFIG_SYNC_FILE */ #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/delay.h> @@ -113,11 +121,6 @@ #include <mali_kbase_caps.h> -/* GPU IRQ Tags */ -#define JOB_IRQ_TAG 0 -#define MMU_IRQ_TAG 1 -#define GPU_IRQ_TAG 2 - #define KERNEL_SIDE_DDK_VERSION_STRING "K:" MALI_RELEASE_NAME "(GPL)" /** @@ -129,16 +132,16 @@ (((minor) & 0xFFF) << 8) | \ ((0 & 0xFF) << 0)) -#define KBASE_API_MIN(api_version) ((api_version >> 8) & 0xFFF) -#define KBASE_API_MAJ(api_version) ((api_version >> 20) & 0xFFF) - /** - * typedef mali_kbase_capability_def - kbase capabilities table + * struct mali_kbase_capability_def - kbase capabilities table + * + * @required_major: required major + * @required_minor: required minor */ -typedef struct mali_kbase_capability_def { +struct mali_kbase_capability_def { u16 required_major; u16 required_minor; -} mali_kbase_capability_def; +}; /* * This must be kept in-sync with mali_kbase_cap @@ -146,32 +149,46 @@ * TODO: The alternative approach would be to embed the cap enum values * in the table. Less efficient but potentially safer. */ -static mali_kbase_capability_def kbase_caps_table[MALI_KBASE_NUM_CAPS] = { +static const struct mali_kbase_capability_def kbase_caps_table[MALI_KBASE_NUM_CAPS] = { #if MALI_USE_CSF - { 1, 0 }, /* SYSTEM_MONITOR */ - { 1, 0 }, /* JIT_PRESSURE_LIMIT */ - { 1, 0 }, /* MEM_GROW_ON_GPF */ - { 1, 0 } /* MEM_PROTECTED */ + { 1, 0 }, /* SYSTEM_MONITOR */ + { 1, 0 }, /* JIT_PRESSURE_LIMIT */ + { 1, 0 }, /* MEM_GROW_ON_GPF */ + { 1, 0 } /* MEM_PROTECTED */ #else - { 11, 15 }, /* SYSTEM_MONITOR */ - { 11, 25 }, /* JIT_PRESSURE_LIMIT */ - { 11, 2 }, /* MEM_GROW_ON_GPF */ - { 11, 2 } /* MEM_PROTECTED */ + { 11, 15 }, /* SYSTEM_MONITOR */ + { 11, 25 }, /* JIT_PRESSURE_LIMIT */ + { 11, 2 }, /* MEM_GROW_ON_GPF */ + { 11, 2 } /* MEM_PROTECTED */ #endif }; + +#if (KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE) +/* Mutex to synchronize the probe of multiple kbase instances */ +static struct mutex kbase_probe_mutex; +#endif + +#ifndef CONFIG_MALI_BIFROST_DEVFREQ +static inline int kbase_devfreq_opp_helper(struct dev_pm_set_opp_data *data) +{ + return -EOPNOTSUPP; +} +#endif /** * mali_kbase_supports_cap - Query whether a kbase capability is supported * - * @api_version: API version to convert - * @cap: Capability to query for - see mali_kbase_caps.h + * @api_version: API version to convert + * @cap: Capability to query for - see mali_kbase_caps.h + * + * Return: true if the capability is supported */ -bool mali_kbase_supports_cap(unsigned long api_version, mali_kbase_cap cap) +bool mali_kbase_supports_cap(unsigned long api_version, enum mali_kbase_cap cap) { bool supported = false; unsigned long required_ver; - mali_kbase_capability_def const *cap_def; + struct mali_kbase_capability_def const *cap_def; if (WARN_ON(cap < 0)) return false; @@ -198,7 +215,7 @@ * address space) and no API version number. Both must be assigned before * kbase_file_get_kctx_if_setup_complete() can be used successfully. * - * @return Address of an object representing a simulated device file, or NULL + * Return: Address of an object representing a simulated device file, or NULL * on failure. */ static struct kbase_file *kbase_file_new(struct kbase_device *const kbdev, @@ -297,10 +314,9 @@ * * @kfile: A device file created by kbase_file_new() * - * This function returns an error code (encoded with ERR_PTR) if no context - * has been created for the given @kfile. This makes it safe to use in - * circumstances where the order of initialization cannot be enforced, but - * only if the caller checks the return value. + * This function returns NULL if no context has been created for the given @kfile. + * This makes it safe to use in circumstances where the order of initialization + * cannot be enforced, but only if the caller checks the return value. * * Return: Address of the kernel base context associated with the @kfile, or * NULL if no context exists. @@ -339,15 +355,6 @@ #if IS_ENABLED(CONFIG_DEBUG_FS) kbasep_mem_profile_debugfs_remove(kctx); #endif - - mutex_lock(&kctx->legacy_hwcnt_lock); - /* If this client was performing hardware counter dumping and - * did not explicitly detach itself, destroy it now - */ - kbase_hwcnt_legacy_client_destroy(kctx->legacy_hwcnt_cli); - kctx->legacy_hwcnt_cli = NULL; - mutex_unlock(&kctx->legacy_hwcnt_lock); - kbase_context_debugfs_term(kctx); kbase_destroy_context(kctx); @@ -404,6 +411,22 @@ return -EPERM; } +static int kbase_api_kinstr_prfcnt_enum_info( + struct kbase_file *kfile, + struct kbase_ioctl_kinstr_prfcnt_enum_info *prfcnt_enum_info) +{ + return kbase_kinstr_prfcnt_enum_info(kfile->kbdev->kinstr_prfcnt_ctx, + prfcnt_enum_info); +} + +static int kbase_api_kinstr_prfcnt_setup( + struct kbase_file *kfile, + union kbase_ioctl_kinstr_prfcnt_setup *prfcnt_setup) +{ + return kbase_kinstr_prfcnt_setup(kfile->kbdev->kinstr_prfcnt_ctx, + prfcnt_setup); +} + static struct kbase_device *to_kbase_device(struct device *dev) { return dev_get_drvdata(dev); @@ -411,6 +434,12 @@ int assign_irqs(struct kbase_device *kbdev) { + static const char *const irq_names_caps[] = { "JOB", "MMU", "GPU" }; + +#if IS_ENABLED(CONFIG_OF) + static const char *const irq_names[] = { "job", "mmu", "gpu" }; +#endif + struct platform_device *pdev; int i; @@ -418,34 +447,31 @@ return -ENODEV; pdev = to_platform_device(kbdev->dev); - /* 3 IRQ resources */ - for (i = 0; i < 3; i++) { - struct resource *irq_res; - int irqtag; - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, i); - if (!irq_res) { - dev_err(kbdev->dev, "No IRQ resource at index %d\n", i); - return -ENOENT; - } + for (i = 0; i < ARRAY_SIZE(irq_names_caps); i++) { + int irq; #if IS_ENABLED(CONFIG_OF) - if (!strncasecmp(irq_res->name, "JOB", 4)) { - irqtag = JOB_IRQ_TAG; - } else if (!strncasecmp(irq_res->name, "MMU", 4)) { - irqtag = MMU_IRQ_TAG; - } else if (!strncasecmp(irq_res->name, "GPU", 4)) { - irqtag = GPU_IRQ_TAG; - } else { - dev_err(&pdev->dev, "Invalid irq res name: '%s'\n", - irq_res->name); - return -EINVAL; - } + /* We recommend using Upper case for the irq names in dts, but if + * there are devices in the world using Lower case then we should + * avoid breaking support for them. So try using names in Upper case + * first then try using Lower case names. If both attempts fail then + * we assume there is no IRQ resource specified for the GPU. + */ + irq = platform_get_irq_byname(pdev, irq_names_caps[i]); + if (irq < 0) + irq = platform_get_irq_byname(pdev, irq_names[i]); #else - irqtag = i; + irq = platform_get_irq(pdev, i); #endif /* CONFIG_OF */ - kbdev->irqs[irqtag].irq = irq_res->start; - kbdev->irqs[irqtag].flags = irq_res->flags & IRQF_TRIGGER_MASK; + + if (irq < 0) { + dev_err(kbdev->dev, "No IRQ resource '%s'\n", irq_names_caps[i]); + return irq; + } + + kbdev->irqs[i].irq = irq; + kbdev->irqs[i].flags = irqd_get_trigger_type(irq_get_irq_data(irq)); } return 0; @@ -481,27 +507,6 @@ EXPORT_SYMBOL(kbase_release_device); #if IS_ENABLED(CONFIG_DEBUG_FS) -#if KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE && \ - !(KERNEL_VERSION(4, 4, 28) <= LINUX_VERSION_CODE && \ - KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) -/* - * Older versions, before v4.6, of the kernel doesn't have - * kstrtobool_from_user(), except longterm 4.4.y which had it added in 4.4.28 - */ -static int kstrtobool_from_user(const char __user *s, size_t count, bool *res) -{ - char buf[4]; - - count = min(count, sizeof(buf) - 1); - - if (copy_from_user(buf, s, count)) - return -EFAULT; - buf[count] = '\0'; - - return strtobool(buf, res); -} -#endif - static ssize_t write_ctx_infinite_cache(struct file *f, const char __user *ubuf, size_t size, loff_t *off) { struct kbase_context *kctx = f->private_data; @@ -613,13 +618,8 @@ kbdev = kfile->kbdev; -#if (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) kctx = kbase_create_context(kbdev, in_compat_syscall(), flags, kfile->api_version, kfile->filp); -#else - kctx = kbase_create_context(kbdev, is_compat_task(), - flags, kfile->api_version, kfile->filp); -#endif /* (KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE) */ /* if bad flags, will stay stuck in setup mode */ if (!kctx) @@ -629,7 +629,8 @@ kbase_ctx_flag_set(kctx, KCTX_INFINITE_CACHE); #if IS_ENABLED(CONFIG_DEBUG_FS) - snprintf(kctx_name, 64, "%d_%d", kctx->tgid, kctx->id); + if (unlikely(!scnprintf(kctx_name, 64, "%d_%d", kctx->tgid, kctx->id))) + return -ENOMEM; mutex_init(&kctx->mem_profile_lock); @@ -640,16 +641,8 @@ /* we don't treat this as a fail - just warn about it */ dev_warn(kbdev->dev, "couldn't create debugfs dir for kctx\n"); } else { -#if (KERNEL_VERSION(4, 7, 0) > LINUX_VERSION_CODE) - /* prevent unprivileged use of debug file system - * in old kernel version - */ - debugfs_create_file("infinite_cache", 0600, kctx->kctx_dentry, - kctx, &kbase_infinite_cache_fops); -#else debugfs_create_file("infinite_cache", 0644, kctx->kctx_dentry, kctx, &kbase_infinite_cache_fops); -#endif debugfs_create_file("force_same_va", 0600, kctx->kctx_dentry, kctx, &kbase_force_same_va_fops); @@ -675,6 +668,11 @@ if (!kbdev) return -ENODEV; + +#if (KERNEL_VERSION(6, 0, 0) > LINUX_VERSION_CODE) + /* Set address space operations for page migration */ + kbase_mem_migrate_set_address_space_ops(kbdev, filp); +#endif /* Device-wide firmware load is moved here from probing to comply with * Android GKI vendor guideline. @@ -770,14 +768,14 @@ } #endif /* !MALI_USE_CSF */ -static int kbase_api_get_gpuprops(struct kbase_context *kctx, +static int kbase_api_get_gpuprops(struct kbase_file *kfile, struct kbase_ioctl_get_gpuprops *get_props) { - struct kbase_gpu_props *kprops = &kctx->kbdev->gpu_props; + struct kbase_gpu_props *kprops = &kfile->kbdev->gpu_props; int err; if (get_props->flags != 0) { - dev_err(kctx->kbdev->dev, "Unsupported flags to get_gpuprops"); + dev_err(kfile->kbdev->dev, "Unsupported flags to get_gpuprops"); return -EINVAL; } @@ -802,23 +800,134 @@ } #endif /* !MALI_USE_CSF */ -static int kbase_api_mem_alloc(struct kbase_context *kctx, - union kbase_ioctl_mem_alloc *alloc) +#if MALI_USE_CSF +static int kbase_api_mem_alloc_ex(struct kbase_context *kctx, + union kbase_ioctl_mem_alloc_ex *alloc_ex) +{ + struct kbase_va_region *reg; + u64 flags = alloc_ex->in.flags; + u64 gpu_va; + + /* Calls to this function are inherently asynchronous, with respect to + * MMU operations. + */ + const enum kbase_caller_mmu_sync_info mmu_sync_info = CALLER_MMU_ASYNC; + + bool gpu_executable = (flags & BASE_MEM_PROT_GPU_EX) && kbase_has_exec_va_zone(kctx); + bool fixed_or_fixable = (flags & (BASE_MEM_FIXED | BASE_MEM_FIXABLE)); + + if (!kbase_mem_allow_alloc(kctx)) + return -EINVAL; + + /* The driver counts the number of FIXABLE and FIXED allocations because + * they're not supposed to happen at the same time. However, that is not + * a security concern: nothing bad happens if the two types of allocations + * are made at the same time. The only reason why the driver is guarding + * against them is because there's no client use case that is supposed + * to need both of them at the same time, and the driver wants to help + * the user space catch some obvious mistake. + * + * The driver is able to switch from FIXABLE allocations to FIXED and + * vice versa, if all the allocations of one kind are freed before trying + * to create allocations of a different kind. + */ + if ((flags & BASE_MEM_FIXED) && (atomic64_read(&kctx->num_fixable_allocs) > 0)) + return -EINVAL; + + if ((flags & BASE_MEM_FIXABLE) && (atomic64_read(&kctx->num_fixed_allocs) > 0)) + return -EINVAL; + + if (flags & BASEP_MEM_FLAGS_KERNEL_ONLY) + return -ENOMEM; + + /* The fixed_address parameter must be either a non-zero, page-aligned + * value for FIXED allocations or zero for any other kind of allocation. + */ + if (flags & BASE_MEM_FIXED) { + u64 aligned_fixed_address = alloc_ex->in.fixed_address & PAGE_MASK; + + if ((aligned_fixed_address == 0) || + (aligned_fixed_address != alloc_ex->in.fixed_address)) + return -EINVAL; + + gpu_va = aligned_fixed_address; + } else if (alloc_ex->in.fixed_address != 0) { + return -EINVAL; + } + + /* For 64-bit clients, force SAME_VA up to 2^(47)-1. + * For 32-bit clients, force SAME_VA up to 2^(32)-1. + * + * In both cases, the executable and fixed/fixable zones, and + * the executable+fixed/fixable zone, are all above this range. + */ + if ((!kbase_ctx_flag(kctx, KCTX_COMPAT)) && + kbase_ctx_flag(kctx, KCTX_FORCE_SAME_VA)) { + if (!gpu_executable && !fixed_or_fixable) + flags |= BASE_MEM_SAME_VA; + } + + /* If CSF event memory allocation, need to force certain flags. + * SAME_VA - GPU address needs to be used as a CPU address, explicit + * mmap has to be avoided. + * CACHED_CPU - Frequent access to the event memory by CPU. + * COHERENT_SYSTEM - No explicit cache maintenance around the access + * to event memory so need to leverage the coherency support. + */ + if (flags & BASE_MEM_CSF_EVENT) { + /* We cannot honor this request */ + if (gpu_executable || fixed_or_fixable) + return -ENOMEM; + + flags |= (BASE_MEM_SAME_VA | + BASE_MEM_CACHED_CPU | + BASE_MEM_COHERENT_SYSTEM); + } + + reg = kbase_mem_alloc(kctx, alloc_ex->in.va_pages, alloc_ex->in.commit_pages, + alloc_ex->in.extension, &flags, &gpu_va, mmu_sync_info); + + if (!reg) + return -ENOMEM; + + alloc_ex->out.flags = flags; + alloc_ex->out.gpu_va = gpu_va; + + return 0; +} + +static int kbase_api_mem_alloc(struct kbase_context *kctx, union kbase_ioctl_mem_alloc *alloc) +{ + int ret; + union kbase_ioctl_mem_alloc_ex mem_alloc_ex = { { 0 } }; + + mem_alloc_ex.in.va_pages = alloc->in.va_pages; + mem_alloc_ex.in.commit_pages = alloc->in.commit_pages; + mem_alloc_ex.in.extension = alloc->in.extension; + mem_alloc_ex.in.flags = alloc->in.flags; + mem_alloc_ex.in.fixed_address = 0; + + ret = kbase_api_mem_alloc_ex(kctx, &mem_alloc_ex); + + alloc->out.flags = mem_alloc_ex.out.flags; + alloc->out.gpu_va = mem_alloc_ex.out.gpu_va; + + return ret; +} +#else +static int kbase_api_mem_alloc(struct kbase_context *kctx, union kbase_ioctl_mem_alloc *alloc) { struct kbase_va_region *reg; u64 flags = alloc->in.flags; u64 gpu_va; - rcu_read_lock(); - /* Don't allow memory allocation until user space has set up the - * tracking page (which sets kctx->process_mm). Also catches when we've - * forked. + /* Calls to this function are inherently asynchronous, with respect to + * MMU operations. */ - if (rcu_dereference(kctx->process_mm) != current->mm) { - rcu_read_unlock(); + const enum kbase_caller_mmu_sync_info mmu_sync_info = CALLER_MMU_ASYNC; + + if (!kbase_mem_allow_alloc(kctx)) return -EINVAL; - } - rcu_read_unlock(); if (flags & BASEP_MEM_FLAGS_KERNEL_ONLY) return -ENOMEM; @@ -828,29 +937,13 @@ * has been initialized. In that case, GPU-executable memory may * or may not be SAME_VA. */ - if ((!kbase_ctx_flag(kctx, KCTX_COMPAT)) && - kbase_ctx_flag(kctx, KCTX_FORCE_SAME_VA)) { + if ((!kbase_ctx_flag(kctx, KCTX_COMPAT)) && kbase_ctx_flag(kctx, KCTX_FORCE_SAME_VA)) { if (!(flags & BASE_MEM_PROT_GPU_EX) || !kbase_has_exec_va_zone(kctx)) flags |= BASE_MEM_SAME_VA; } -#if MALI_USE_CSF - /* If CSF event memory allocation, need to force certain flags. - * SAME_VA - GPU address needs to be used as a CPU address, explicit - * mmap has to be avoided. - * CACHED_CPU - Frequent access to the event memory by CPU. - * COHERENT_SYSTEM - No explicit cache maintenance around the access - * to event memory so need to leverage the coherency support. - */ - if (flags & BASE_MEM_CSF_EVENT) { - flags |= (BASE_MEM_SAME_VA | - BASE_MEM_CACHED_CPU | - BASE_MEM_COHERENT_SYSTEM); - } -#endif - - reg = kbase_mem_alloc(kctx, alloc->in.va_pages, alloc->in.commit_pages, - alloc->in.extension, &flags, &gpu_va); + reg = kbase_mem_alloc(kctx, alloc->in.va_pages, alloc->in.commit_pages, alloc->in.extension, + &flags, &gpu_va, mmu_sync_info); if (!reg) return -ENOMEM; @@ -860,6 +953,7 @@ return 0; } +#endif /* MALI_USE_CSF */ static int kbase_api_mem_query(struct kbase_context *kctx, union kbase_ioctl_mem_query *query) @@ -888,69 +982,13 @@ return kbase_vinstr_hwcnt_reader_setup(kctx->kbdev->vinstr_ctx, setup); } -static int kbase_api_hwcnt_enable(struct kbase_context *kctx, - struct kbase_ioctl_hwcnt_enable *enable) -{ - int ret; - - mutex_lock(&kctx->legacy_hwcnt_lock); - if (enable->dump_buffer != 0) { - /* Non-zero dump buffer, so user wants to create the client */ - if (kctx->legacy_hwcnt_cli == NULL) { - ret = kbase_hwcnt_legacy_client_create( - kctx->kbdev->hwcnt_gpu_virt, - enable, - &kctx->legacy_hwcnt_cli); - } else { - /* This context already has a client */ - ret = -EBUSY; - } - } else { - /* Zero dump buffer, so user wants to destroy the client */ - if (kctx->legacy_hwcnt_cli != NULL) { - kbase_hwcnt_legacy_client_destroy( - kctx->legacy_hwcnt_cli); - kctx->legacy_hwcnt_cli = NULL; - ret = 0; - } else { - /* This context has no client to destroy */ - ret = -EINVAL; - } - } - mutex_unlock(&kctx->legacy_hwcnt_lock); - - return ret; -} - -static int kbase_api_hwcnt_dump(struct kbase_context *kctx) -{ - int ret; - - mutex_lock(&kctx->legacy_hwcnt_lock); - ret = kbase_hwcnt_legacy_client_dump(kctx->legacy_hwcnt_cli); - mutex_unlock(&kctx->legacy_hwcnt_lock); - - return ret; -} - -static int kbase_api_hwcnt_clear(struct kbase_context *kctx) -{ - int ret; - - mutex_lock(&kctx->legacy_hwcnt_lock); - ret = kbase_hwcnt_legacy_client_clear(kctx->legacy_hwcnt_cli); - mutex_unlock(&kctx->legacy_hwcnt_lock); - - return ret; -} - static int kbase_api_get_cpu_gpu_timeinfo(struct kbase_context *kctx, union kbase_ioctl_get_cpu_gpu_timeinfo *timeinfo) { u32 flags = timeinfo->in.request_flags; - struct timespec64 ts; - u64 timestamp; - u64 cycle_cnt; + struct timespec64 ts = { 0 }; + u64 timestamp = 0; + u64 cycle_cnt = 0; kbase_pm_context_active(kctx->kbdev); @@ -975,6 +1013,13 @@ return 0; } +#if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) +static int kbase_api_hwcnt_set(struct kbase_context *kctx, + struct kbase_ioctl_hwcnt_values *values) +{ + return gpu_model_set_dummy_prfcnt_user_sample(u64_to_user_ptr(values->data), values->size); +} +#endif /* CONFIG_MALI_BIFROST_NO_MALI */ static int kbase_api_disjoint_query(struct kbase_context *kctx, struct kbase_ioctl_disjoint_query *query) @@ -1006,51 +1051,10 @@ return len; } -/* Defaults for legacy just-in-time memory allocator initialization - * kernel calls - */ -#define DEFAULT_MAX_JIT_ALLOCATIONS 255 -#define JIT_LEGACY_TRIM_LEVEL (0) /* No trimming */ - -static int kbase_api_mem_jit_init_10_2(struct kbase_context *kctx, - struct kbase_ioctl_mem_jit_init_10_2 *jit_init) -{ - kctx->jit_version = 1; - - /* since no phys_pages parameter, use the maximum: va_pages */ - return kbase_region_tracker_init_jit(kctx, jit_init->va_pages, - DEFAULT_MAX_JIT_ALLOCATIONS, - JIT_LEGACY_TRIM_LEVEL, BASE_MEM_GROUP_DEFAULT, - jit_init->va_pages); -} - -static int kbase_api_mem_jit_init_11_5(struct kbase_context *kctx, - struct kbase_ioctl_mem_jit_init_11_5 *jit_init) -{ - int i; - - kctx->jit_version = 2; - - for (i = 0; i < sizeof(jit_init->padding); i++) { - /* Ensure all padding bytes are 0 for potential future - * extension - */ - if (jit_init->padding[i]) - return -EINVAL; - } - - /* since no phys_pages parameter, use the maximum: va_pages */ - return kbase_region_tracker_init_jit(kctx, jit_init->va_pages, - jit_init->max_allocations, jit_init->trim_level, - jit_init->group_id, jit_init->va_pages); -} - static int kbase_api_mem_jit_init(struct kbase_context *kctx, struct kbase_ioctl_mem_jit_init *jit_init) { int i; - - kctx->jit_version = 3; for (i = 0; i < sizeof(jit_init->padding); i++) { /* Ensure all padding bytes are 0 for potential future @@ -1209,7 +1213,7 @@ static int kbase_api_stream_create(struct kbase_context *kctx, struct kbase_ioctl_stream_create *stream) { -#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) +#if IS_ENABLED(CONFIG_SYNC_FILE) int fd, ret; /* Name must be NULL-terminated and padded with NULLs, so check last @@ -1231,7 +1235,7 @@ static int kbase_api_fence_validate(struct kbase_context *kctx, struct kbase_ioctl_fence_validate *validate) { -#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) +#if IS_ENABLED(CONFIG_SYNC_FILE) return kbase_sync_fence_validate(validate->fd); #else return -ENOENT; @@ -1245,12 +1249,18 @@ int err; if (data->len > KBASE_MEM_PROFILE_MAX_BUF_SIZE) { - dev_err(kctx->kbdev->dev, "mem_profile_add: buffer too big\n"); + dev_err(kctx->kbdev->dev, "mem_profile_add: buffer too big"); return -EINVAL; } + if (!data->len) { + dev_err(kctx->kbdev->dev, "mem_profile_add: buffer size is 0"); + /* Should return -EINVAL, but returning -ENOMEM for backwards compat */ + return -ENOMEM; + } + buf = kmalloc(data->len, GFP_KERNEL); - if (ZERO_OR_NULL_PTR(buf)) + if (!buf) return -ENOMEM; err = copy_from_user(buf, u64_to_user_ptr(data->buffer), @@ -1398,6 +1408,30 @@ return kbase_csf_queue_kick(kctx, kick); } +static int kbasep_cs_queue_group_create_1_6( + struct kbase_context *kctx, + union kbase_ioctl_cs_queue_group_create_1_6 *create) +{ + union kbase_ioctl_cs_queue_group_create + new_create = { .in = { + .tiler_mask = create->in.tiler_mask, + .fragment_mask = + create->in.fragment_mask, + .compute_mask = create->in.compute_mask, + .cs_min = create->in.cs_min, + .priority = create->in.priority, + .tiler_max = create->in.tiler_max, + .fragment_max = create->in.fragment_max, + .compute_max = create->in.compute_max, + } }; + + int ret = kbase_csf_queue_group_create(kctx, &new_create); + + create->out.group_handle = new_create.out.group_handle; + create->out.group_uid = new_create.out.group_uid; + + return ret; +} static int kbasep_cs_queue_group_create(struct kbase_context *kctx, union kbase_ioctl_cs_queue_group_create *create) { @@ -1433,12 +1467,31 @@ static int kbasep_cs_tiler_heap_init(struct kbase_context *kctx, union kbase_ioctl_cs_tiler_heap_init *heap_init) { + if (heap_init->in.group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS) + return -EINVAL; + kctx->jit_group_id = heap_init->in.group_id; return kbase_csf_tiler_heap_init(kctx, heap_init->in.chunk_size, - heap_init->in.initial_chunks, heap_init->in.max_chunks, - heap_init->in.target_in_flight, - &heap_init->out.gpu_heap_va, &heap_init->out.first_chunk_va); + heap_init->in.initial_chunks, heap_init->in.max_chunks, + heap_init->in.target_in_flight, heap_init->in.buf_desc_va, + &heap_init->out.gpu_heap_va, + &heap_init->out.first_chunk_va); +} + +static int kbasep_cs_tiler_heap_init_1_13(struct kbase_context *kctx, + union kbase_ioctl_cs_tiler_heap_init_1_13 *heap_init) +{ + if (heap_init->in.group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS) + return -EINVAL; + + kctx->jit_group_id = heap_init->in.group_id; + + return kbase_csf_tiler_heap_init(kctx, heap_init->in.chunk_size, + heap_init->in.initial_chunks, heap_init->in.max_chunks, + heap_init->in.target_in_flight, 0, + &heap_init->out.gpu_heap_va, + &heap_init->out.first_chunk_va); } static int kbasep_cs_tiler_heap_term(struct kbase_context *kctx, @@ -1520,6 +1573,30 @@ cpu_queue_info->size); } +static int kbase_ioctl_read_user_page(struct kbase_context *kctx, + union kbase_ioctl_read_user_page *user_page) +{ + struct kbase_device *kbdev = kctx->kbdev; + unsigned long flags; + + /* As of now, only LATEST_FLUSH is supported */ + if (unlikely(user_page->in.offset != LATEST_FLUSH)) + return -EINVAL; + + /* Validating padding that must be zero */ + if (unlikely(user_page->in.padding != 0)) + return -EINVAL; + + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + if (!kbdev->pm.backend.gpu_powered) + user_page->out.val_lo = POWER_DOWN_LATEST_FLUSH_VALUE; + else + user_page->out.val_lo = kbase_reg_read(kbdev, USER_REG(LATEST_FLUSH)); + user_page->out.val_hi = 0; + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + + return 0; +} #endif /* MALI_USE_CSF */ static int kbasep_ioctl_context_priority_check(struct kbase_context *kctx, @@ -1644,6 +1721,24 @@ struct kbase_ioctl_set_flags, kfile); break; + + case KBASE_IOCTL_KINSTR_PRFCNT_ENUM_INFO: + KBASE_HANDLE_IOCTL_INOUT( + KBASE_IOCTL_KINSTR_PRFCNT_ENUM_INFO, + kbase_api_kinstr_prfcnt_enum_info, + struct kbase_ioctl_kinstr_prfcnt_enum_info, kfile); + break; + + case KBASE_IOCTL_KINSTR_PRFCNT_SETUP: + KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_KINSTR_PRFCNT_SETUP, + kbase_api_kinstr_prfcnt_setup, + union kbase_ioctl_kinstr_prfcnt_setup, + kfile); + break; + case KBASE_IOCTL_GET_GPUPROPS: + KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_GET_GPUPROPS, kbase_api_get_gpuprops, + struct kbase_ioctl_get_gpuprops, kfile); + break; } kctx = kbase_file_get_kctx_if_setup_complete(kfile); @@ -1660,12 +1755,6 @@ kctx); break; #endif /* !MALI_USE_CSF */ - case KBASE_IOCTL_GET_GPUPROPS: - KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_GET_GPUPROPS, - kbase_api_get_gpuprops, - struct kbase_ioctl_get_gpuprops, - kctx); - break; #if !MALI_USE_CSF case KBASE_IOCTL_POST_TERM: KBASE_HANDLE_IOCTL(KBASE_IOCTL_POST_TERM, @@ -1679,6 +1768,12 @@ union kbase_ioctl_mem_alloc, kctx); break; +#if MALI_USE_CSF + case KBASE_IOCTL_MEM_ALLOC_EX: + KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_MEM_ALLOC_EX, kbase_api_mem_alloc_ex, + union kbase_ioctl_mem_alloc_ex, kctx); + break; +#endif case KBASE_IOCTL_MEM_QUERY: KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_MEM_QUERY, kbase_api_mem_query, @@ -1701,18 +1796,6 @@ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_GET_DDK_VERSION, kbase_api_get_ddk_version, struct kbase_ioctl_get_ddk_version, - kctx); - break; - case KBASE_IOCTL_MEM_JIT_INIT_10_2: - KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_JIT_INIT_10_2, - kbase_api_mem_jit_init_10_2, - struct kbase_ioctl_mem_jit_init_10_2, - kctx); - break; - case KBASE_IOCTL_MEM_JIT_INIT_11_5: - KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_JIT_INIT_11_5, - kbase_api_mem_jit_init_11_5, - struct kbase_ioctl_mem_jit_init_11_5, kctx); break; case KBASE_IOCTL_MEM_JIT_INIT: @@ -1842,28 +1925,20 @@ struct kbase_ioctl_hwcnt_reader_setup, kctx); break; - case KBASE_IOCTL_HWCNT_ENABLE: - KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_HWCNT_ENABLE, - kbase_api_hwcnt_enable, - struct kbase_ioctl_hwcnt_enable, - kctx); - break; - case KBASE_IOCTL_HWCNT_DUMP: - KBASE_HANDLE_IOCTL(KBASE_IOCTL_HWCNT_DUMP, - kbase_api_hwcnt_dump, - kctx); - break; - case KBASE_IOCTL_HWCNT_CLEAR: - KBASE_HANDLE_IOCTL(KBASE_IOCTL_HWCNT_CLEAR, - kbase_api_hwcnt_clear, - kctx); - break; case KBASE_IOCTL_GET_CPU_GPU_TIMEINFO: KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_GET_CPU_GPU_TIMEINFO, kbase_api_get_cpu_gpu_timeinfo, union kbase_ioctl_get_cpu_gpu_timeinfo, kctx); break; +#if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) + case KBASE_IOCTL_HWCNT_SET: + KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_HWCNT_SET, + kbase_api_hwcnt_set, + struct kbase_ioctl_hwcnt_values, + kctx); + break; +#endif /* CONFIG_MALI_BIFROST_NO_MALI */ #ifdef CONFIG_MALI_CINSTR_GWT case KBASE_IOCTL_CINSTR_GWT_START: KBASE_HANDLE_IOCTL(KBASE_IOCTL_CINSTR_GWT_START, @@ -1918,6 +1993,12 @@ struct kbase_ioctl_cs_queue_kick, kctx); break; + case KBASE_IOCTL_CS_QUEUE_GROUP_CREATE_1_6: + KBASE_HANDLE_IOCTL_INOUT( + KBASE_IOCTL_CS_QUEUE_GROUP_CREATE_1_6, + kbasep_cs_queue_group_create_1_6, + union kbase_ioctl_cs_queue_group_create_1_6, kctx); + break; case KBASE_IOCTL_CS_QUEUE_GROUP_CREATE: KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_CS_QUEUE_GROUP_CREATE, kbasep_cs_queue_group_create, @@ -1954,6 +2035,11 @@ union kbase_ioctl_cs_tiler_heap_init, kctx); break; + case KBASE_IOCTL_CS_TILER_HEAP_INIT_1_13: + KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_CS_TILER_HEAP_INIT_1_13, + kbasep_cs_tiler_heap_init_1_13, + union kbase_ioctl_cs_tiler_heap_init_1_13, kctx); + break; case KBASE_IOCTL_CS_TILER_HEAP_TERM: KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_CS_TILER_HEAP_TERM, kbasep_cs_tiler_heap_term, @@ -1971,6 +2057,11 @@ kbasep_ioctl_cs_cpu_queue_dump, struct kbase_ioctl_cs_cpu_queue_info, kctx); + break; + /* This IOCTL will be kept for backward compatibility */ + case KBASE_IOCTL_READ_USER_PAGE: + KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_READ_USER_PAGE, kbase_ioctl_read_user_page, + union kbase_ioctl_read_user_page, kctx); break; #endif /* MALI_USE_CSF */ #if MALI_UNIT_TEST @@ -2014,10 +2105,13 @@ if (unlikely(!kctx)) return -EPERM; + if (count < data_size) + return -ENOBUFS; + if (atomic_read(&kctx->event_count)) read_event = true; else - read_error = kbase_csf_read_error(kctx, &event_data); + read_error = kbase_csf_event_read_error(kctx, &event_data); if (!read_event && !read_error) { bool dump = kbase_csf_cpu_queue_read_dump_req(kctx, @@ -2059,6 +2153,8 @@ if (count < sizeof(uevent)) return -ENOBUFS; + memset(&uevent, 0, sizeof(uevent)); + do { while (kbase_event_dequeue(kctx, &uevent)) { if (out_count > 0) @@ -2090,18 +2186,28 @@ } #endif /* MALI_USE_CSF */ -static unsigned int kbase_poll(struct file *filp, poll_table *wait) +static __poll_t kbase_poll(struct file *filp, poll_table *wait) { struct kbase_file *const kfile = filp->private_data; struct kbase_context *const kctx = kbase_file_get_kctx_if_setup_complete(kfile); - if (unlikely(!kctx)) + if (unlikely(!kctx)) { +#if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE) return POLLERR; +#else + return EPOLLERR; +#endif + } poll_wait(filp, &kctx->event_queue, wait); - if (kbase_event_pending(kctx)) + if (kbase_event_pending(kctx)) { +#if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE) return POLLIN | POLLRDNORM; +#else + return EPOLLIN | EPOLLRDNORM; +#endif + } return 0; } @@ -2119,16 +2225,22 @@ #if MALI_USE_CSF int kbase_event_pending(struct kbase_context *ctx) { - WARN_ON_ONCE(!ctx); + KBASE_DEBUG_ASSERT(ctx); + + if (unlikely(!ctx)) + return -EPERM; return (atomic_read(&ctx->event_count) != 0) || - kbase_csf_error_pending(ctx) || + kbase_csf_event_error_pending(ctx) || kbase_csf_cpu_queue_dump_needed(ctx); } #else int kbase_event_pending(struct kbase_context *ctx) { KBASE_DEBUG_ASSERT(ctx); + + if (unlikely(!ctx)) + return -EPERM; return (atomic_read(&ctx->event_count) != 0) || (atomic_read(&ctx->event_closed) != 0); @@ -2188,19 +2300,19 @@ }; /** - * show_policy - Show callback for the power_policy sysfs file. - * - * This function is called to get the contents of the power_policy sysfs - * file. This is a list of the available policies with the currently active one - * surrounded by square brackets. + * power_policy_show - Show callback for the power_policy sysfs file. * * @dev: The device this sysfs file is for * @attr: The attributes of the sysfs file * @buf: The output buffer for the sysfs file contents * + * This function is called to get the contents of the power_policy sysfs + * file. This is a list of the available policies with the currently active one + * surrounded by square brackets. + * * Return: The number of bytes output to @buf. */ -static ssize_t show_policy(struct device *dev, struct device_attribute *attr, char *const buf) +static ssize_t power_policy_show(struct device *dev, struct device_attribute *attr, char *const buf) { struct kbase_device *kbdev; const struct kbase_pm_policy *current_policy; @@ -2237,21 +2349,21 @@ } /** - * set_policy - Store callback for the power_policy sysfs file. - * - * This function is called when the power_policy sysfs file is written to. - * It matches the requested policy against the available policies and if a - * matching policy is found calls kbase_pm_set_policy() to change the - * policy. + * power_policy_store - Store callback for the power_policy sysfs file. * * @dev: The device with sysfs file is for * @attr: The attributes of the sysfs file * @buf: The value written to the sysfs file * @count: The number of bytes to write to the sysfs file * + * This function is called when the power_policy sysfs file is written to. + * It matches the requested policy against the available policies and if a + * matching policy is found calls kbase_pm_set_policy() to change the + * policy. + * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_policy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t power_policy_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; const struct kbase_pm_policy *new_policy = NULL; @@ -2290,20 +2402,20 @@ * determining which policy is currently active, and changing the active * policy. */ -static DEVICE_ATTR(power_policy, S_IRUGO | S_IWUSR, show_policy, set_policy); +static DEVICE_ATTR_RW(power_policy); /* - * show_core_mask - Show callback for the core_mask sysfs file. - * - * This function is called to get the contents of the core_mask sysfs file. + * core_mask_show - Show callback for the core_mask sysfs file. * * @dev: The device this sysfs file is for * @attr: The attributes of the sysfs file * @buf: The output buffer for the sysfs file contents * + * This function is called to get the contents of the core_mask sysfs file. + * * Return: The number of bytes output to @buf. */ -static ssize_t show_core_mask(struct device *dev, struct device_attribute *attr, char * const buf) +static ssize_t core_mask_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; unsigned long flags; @@ -2348,18 +2460,18 @@ } /** - * set_core_mask - Store callback for the core_mask sysfs file. - * - * This function is called when the core_mask sysfs file is written to. + * core_mask_store - Store callback for the core_mask sysfs file. * * @dev: The device with sysfs file is for * @attr: The attributes of the sysfs file * @buf: The value written to the sysfs file * @count: The number of bytes to write to the sysfs file * + * This function is called when the core_mask sysfs file is written to. + * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_core_mask(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t core_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; #if MALI_USE_CSF @@ -2489,11 +2601,11 @@ * Reading it will show the current core mask and the mask of cores available. * Writing to it will set the current core mask. */ -static DEVICE_ATTR(core_mask, S_IRUGO | S_IWUSR, show_core_mask, set_core_mask); +static DEVICE_ATTR_RW(core_mask); #if !MALI_USE_CSF /** - * set_soft_job_timeout - Store callback for the soft_job_timeout sysfs + * soft_job_timeout_store - Store callback for the soft_job_timeout sysfs * file. * * @dev: The device this sysfs file is for. @@ -2509,7 +2621,7 @@ * * Return: count if the function succeeded. An error code on failure. */ -static ssize_t set_soft_job_timeout(struct device *dev, +static ssize_t soft_job_timeout_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -2531,18 +2643,18 @@ } /** - * show_soft_job_timeout - Show callback for the soft_job_timeout sysfs + * soft_job_timeout_show - Show callback for the soft_job_timeout sysfs * file. - * - * This will return the timeout for the software jobs. * * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The output buffer for the sysfs file contents. * + * This will return the timeout for the software jobs. + * * Return: The number of bytes output to buf. */ -static ssize_t show_soft_job_timeout(struct device *dev, +static ssize_t soft_job_timeout_show(struct device *dev, struct device_attribute *attr, char * const buf) { @@ -2556,14 +2668,14 @@ atomic_read(&kbdev->js_data.soft_job_timeout_ms)); } -static DEVICE_ATTR(soft_job_timeout, S_IRUGO | S_IWUSR, - show_soft_job_timeout, set_soft_job_timeout); +static DEVICE_ATTR_RW(soft_job_timeout); static u32 timeout_ms_to_ticks(struct kbase_device *kbdev, long timeout_ms, int default_ticks, u32 old_ticks) { if (timeout_ms > 0) { u64 ticks = timeout_ms * 1000000ULL; + do_div(ticks, kbdev->js_data.scheduling_period_ns); if (!ticks) return 1; @@ -2576,7 +2688,12 @@ } /** - * set_js_timeouts - Store callback for the js_timeouts sysfs file. + * js_timeouts_store - Store callback for the js_timeouts sysfs file. + * + * @dev: The device with sysfs file is for + * @attr: The attributes of the sysfs file + * @buf: The value written to the sysfs file + * @count: The number of bytes to write to the sysfs file * * This function is called to get the contents of the js_timeouts sysfs * file. This file contains five values separated by whitespace. The values @@ -2589,14 +2706,9 @@ * use by the job scheduler to get override. Note that a value needs to * be other than 0 for it to override the current job scheduler value. * - * @dev: The device with sysfs file is for - * @attr: The attributes of the sysfs file - * @buf: The value written to the sysfs file - * @count: The number of bytes to write to the sysfs file - * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_js_timeouts(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t js_timeouts_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; int items; @@ -2676,19 +2788,20 @@ } /** - * show_js_timeouts - Show callback for the js_timeouts sysfs file. + * js_timeouts_show - Show callback for the js_timeouts sysfs file. + * + * @dev: The device this sysfs file is for + * @attr: The attributes of the sysfs file + * @buf: The output buffer for the sysfs file contents * * This function is called to get the contents of the js_timeouts sysfs * file. It returns the last set values written to the js_timeouts sysfs file. * If the file didn't get written yet, the values will be current setting in * use. - * @dev: The device this sysfs file is for - * @attr: The attributes of the sysfs file - * @buf: The output buffer for the sysfs file contents * * Return: The number of bytes output to @buf. */ -static ssize_t show_js_timeouts(struct device *dev, struct device_attribute *attr, char * const buf) +static ssize_t js_timeouts_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; ssize_t ret; @@ -2751,7 +2864,7 @@ * JS_RESET_TICKS_CL * JS_RESET_TICKS_DUMPING. */ -static DEVICE_ATTR(js_timeouts, S_IRUGO | S_IWUSR, show_js_timeouts, set_js_timeouts); +static DEVICE_ATTR_RW(js_timeouts); static u32 get_new_js_timeout( u32 old_period, @@ -2759,12 +2872,13 @@ u32 new_scheduling_period_ns) { u64 ticks = (u64)old_period * (u64)old_ticks; + do_div(ticks, new_scheduling_period_ns); return ticks?ticks:1; } /** - * set_js_scheduling_period - Store callback for the js_scheduling_period sysfs + * js_scheduling_period_store - Store callback for the js_scheduling_period sysfs * file * @dev: The device the sysfs file is for * @attr: The attributes of the sysfs file @@ -2777,7 +2891,7 @@ * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_js_scheduling_period(struct device *dev, +static ssize_t js_scheduling_period_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; @@ -2846,7 +2960,7 @@ } /** - * show_js_scheduling_period - Show callback for the js_scheduling_period sysfs + * js_scheduling_period_show - Show callback for the js_scheduling_period sysfs * entry. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. @@ -2857,7 +2971,7 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t show_js_scheduling_period(struct device *dev, +static ssize_t js_scheduling_period_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; @@ -2876,12 +2990,11 @@ return ret; } -static DEVICE_ATTR(js_scheduling_period, S_IRUGO | S_IWUSR, - show_js_scheduling_period, set_js_scheduling_period); +static DEVICE_ATTR_RW(js_scheduling_period); #ifdef CONFIG_MALI_BIFROST_DEBUG -static ssize_t set_js_softstop_always(struct device *dev, +static ssize_t js_softstop_always_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; @@ -2906,7 +3019,7 @@ return count; } -static ssize_t show_js_softstop_always(struct device *dev, +static ssize_t js_softstop_always_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; @@ -2933,7 +3046,7 @@ * used for debug and unit-testing purposes. * (see CL t6xx_stress_1 unit-test as an example whereby this feature is used.) */ -static DEVICE_ATTR(js_softstop_always, S_IRUGO | S_IWUSR, show_js_softstop_always, set_js_softstop_always); +static DEVICE_ATTR_RW(js_softstop_always); #endif /* CONFIG_MALI_BIFROST_DEBUG */ #endif /* !MALI_USE_CSF */ @@ -2952,7 +3065,7 @@ kbasep_debug_command_func *func; }; -void kbasep_ktrace_dump_wrapper(struct kbase_device *kbdev) +static void kbasep_ktrace_dump_wrapper(struct kbase_device *kbdev) { KBASE_KTRACE_DUMP(kbdev); } @@ -2960,24 +3073,24 @@ /* Debug commands supported by the driver */ static const struct kbasep_debug_command debug_commands[] = { { - .str = "dumptrace", - .func = &kbasep_ktrace_dump_wrapper, - } + .str = "dumptrace", + .func = &kbasep_ktrace_dump_wrapper, + } }; /** - * show_debug - Show callback for the debug_command sysfs file. - * - * This function is called to get the contents of the debug_command sysfs - * file. This is a list of the available debug commands, separated by newlines. + * debug_command_show - Show callback for the debug_command sysfs file. * * @dev: The device this sysfs file is for * @attr: The attributes of the sysfs file * @buf: The output buffer for the sysfs file contents * + * This function is called to get the contents of the debug_command sysfs + * file. This is a list of the available debug commands, separated by newlines. + * * Return: The number of bytes output to @buf. */ -static ssize_t show_debug(struct device *dev, struct device_attribute *attr, char * const buf) +static ssize_t debug_command_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; int i; @@ -3001,21 +3114,21 @@ } /** - * issue_debug - Store callback for the debug_command sysfs file. - * - * This function is called when the debug_command sysfs file is written to. - * It matches the requested command against the available commands, and if - * a matching command is found calls the associated function from - * @debug_commands to issue the command. + * debug_command_store - Store callback for the debug_command sysfs file. * * @dev: The device with sysfs file is for * @attr: The attributes of the sysfs file * @buf: The value written to the sysfs file * @count: The number of bytes written to the sysfs file * + * This function is called when the debug_command sysfs file is written to. + * It matches the requested command against the available commands, and if + * a matching command is found calls the associated function from + * @debug_commands to issue the command. + * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t issue_debug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t debug_command_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; int i; @@ -3043,11 +3156,11 @@ * Reading it will produce a list of debug commands, separated by newlines. * Writing to it with one of those commands will issue said command. */ -static DEVICE_ATTR(debug_command, S_IRUGO | S_IWUSR, show_debug, issue_debug); +static DEVICE_ATTR_RW(debug_command); #endif /* CONFIG_MALI_BIFROST_DEBUG */ /** - * kbase_show_gpuinfo - Show callback for the gpuinfo sysfs entry. + * gpuinfo_show - Show callback for the gpuinfo sysfs entry. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The output buffer to receive the GPU information. @@ -3061,57 +3174,63 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t kbase_show_gpuinfo(struct device *dev, +static ssize_t gpuinfo_show(struct device *dev, struct device_attribute *attr, char *buf) { static const struct gpu_product_id_name { - unsigned id; + unsigned int id; char *name; } gpu_product_id_names[] = { - { .id = GPU_ID2_PRODUCT_TMIX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TMIX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G71" }, - { .id = GPU_ID2_PRODUCT_THEX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_THEX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G72" }, - { .id = GPU_ID2_PRODUCT_TSIX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TSIX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G51" }, - { .id = GPU_ID2_PRODUCT_TNOX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TNOX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G76" }, - { .id = GPU_ID2_PRODUCT_TDVX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TDVX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G31" }, - { .id = GPU_ID2_PRODUCT_TGOX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TGOX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G52" }, - { .id = GPU_ID2_PRODUCT_TTRX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TTRX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G77" }, - { .id = GPU_ID2_PRODUCT_TBEX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TBEX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G78" }, - { .id = GPU_ID2_PRODUCT_TBAX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TBAX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G78AE" }, - { .id = GPU_ID2_PRODUCT_LBEX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_LBEX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G68" }, - { .id = GPU_ID2_PRODUCT_TNAX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TNAX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G57" }, - { .id = GPU_ID2_PRODUCT_TODX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TODX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G710" }, - { .id = GPU_ID2_PRODUCT_LODX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_LODX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G610" }, - { .id = GPU_ID2_PRODUCT_TGRX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TGRX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G510" }, - { .id = GPU_ID2_PRODUCT_TVAX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, + { .id = GPU_ID2_PRODUCT_TVAX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, .name = "Mali-G310" }, + { .id = GPU_ID2_PRODUCT_TTIX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, + .name = "Mali-TTIX" }, + { .id = GPU_ID2_PRODUCT_LTIX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, + .name = "Mali-LTIX" }, }; const char *product_name = "(Unknown Mali GPU)"; struct kbase_device *kbdev; u32 gpu_id; - unsigned product_id, product_id_mask; - unsigned i; + unsigned int product_id, product_id_mask; + unsigned int i; + struct kbase_gpu_props *gpu_props; kbdev = to_kbase_device(dev); if (!kbdev) return -ENODEV; - gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; - product_id = gpu_id >> GPU_ID_VERSION_PRODUCT_ID_SHIFT; - product_id_mask = GPU_ID2_PRODUCT_MODEL >> GPU_ID_VERSION_PRODUCT_ID_SHIFT; + gpu_props = &kbdev->gpu_props; + gpu_id = gpu_props->props.raw_props.gpu_id; + product_id = gpu_id >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT; + product_id_mask = GPU_ID2_PRODUCT_MODEL >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT; for (i = 0; i < ARRAY_SIZE(gpu_product_id_names); ++i) { const struct gpu_product_id_name *p = &gpu_product_id_names[i]; @@ -3123,16 +3242,42 @@ } } - return scnprintf(buf, PAGE_SIZE, "%s %d cores r%dp%d 0x%04X\n", - product_name, kbdev->gpu_props.num_cores, - (gpu_id & GPU_ID_VERSION_MAJOR) >> GPU_ID_VERSION_MAJOR_SHIFT, - (gpu_id & GPU_ID_VERSION_MINOR) >> GPU_ID_VERSION_MINOR_SHIFT, - product_id); +#if MALI_USE_CSF + if ((product_id & product_id_mask) == + ((GPU_ID2_PRODUCT_TTUX >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT) & product_id_mask)) { + const bool rt_supported = + GPU_FEATURES_RAY_TRACING_GET(gpu_props->props.raw_props.gpu_features); + const u8 nr_cores = gpu_props->num_cores; + + /* Mali-G715-Immortalis if 10 < number of cores with ray tracing supproted. + * Mali-G715 if 10 < number of cores without ray tracing supported. + * Mali-G715 if 7 <= number of cores <= 10 regardless ray tracing. + * Mali-G615 if number of cores < 7. + */ + if ((nr_cores > 10) && rt_supported) + product_name = "Mali-G715-Immortalis"; + else if (nr_cores >= 7) + product_name = "Mali-G715"; + + if (nr_cores < 7) { + dev_warn(kbdev->dev, "nr_cores(%u) GPU ID must be G615", nr_cores); + product_name = "Mali-G615"; + } else + dev_dbg(kbdev->dev, "GPU ID_Name: %s, nr_cores(%u)\n", product_name, + nr_cores); + } +#endif /* MALI_USE_CSF */ + + return scnprintf(buf, PAGE_SIZE, "%s %d cores r%dp%d 0x%04X\n", product_name, + kbdev->gpu_props.num_cores, + (gpu_id & GPU_ID_VERSION_MAJOR) >> KBASE_GPU_ID_VERSION_MAJOR_SHIFT, + (gpu_id & GPU_ID_VERSION_MINOR) >> KBASE_GPU_ID_VERSION_MINOR_SHIFT, + product_id); } -static DEVICE_ATTR(gpuinfo, S_IRUGO, kbase_show_gpuinfo, NULL); +static DEVICE_ATTR_RO(gpuinfo); /** - * set_dvfs_period - Store callback for the dvfs_period sysfs file. + * dvfs_period_store - Store callback for the dvfs_period sysfs file. * @dev: The device with sysfs file is for * @attr: The attributes of the sysfs file * @buf: The value written to the sysfs file @@ -3143,7 +3288,7 @@ * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_dvfs_period(struct device *dev, +static ssize_t dvfs_period_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; @@ -3168,7 +3313,7 @@ } /** - * show_dvfs_period - Show callback for the dvfs_period sysfs entry. + * dvfs_period_show - Show callback for the dvfs_period sysfs entry. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The output buffer to receive the GPU information. @@ -3178,7 +3323,7 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t show_dvfs_period(struct device *dev, +static ssize_t dvfs_period_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; @@ -3193,11 +3338,50 @@ return ret; } -static DEVICE_ATTR(dvfs_period, S_IRUGO | S_IWUSR, show_dvfs_period, - set_dvfs_period); +static DEVICE_ATTR_RW(dvfs_period); + +int kbase_pm_lowest_gpu_freq_init(struct kbase_device *kbdev) +{ + /* Uses default reference frequency defined in below macro */ + u64 lowest_freq_khz = DEFAULT_REF_TIMEOUT_FREQ_KHZ; + + /* Only check lowest frequency in cases when OPPs are used and + * present in the device tree. + */ +#ifdef CONFIG_PM_OPP + struct dev_pm_opp *opp_ptr; + unsigned long found_freq = 0; + + /* find lowest frequency OPP */ + opp_ptr = dev_pm_opp_find_freq_ceil(kbdev->dev, &found_freq); + if (IS_ERR(opp_ptr)) { + dev_err(kbdev->dev, "No OPPs found in device tree! Scaling timeouts using %llu kHz", + (unsigned long long)lowest_freq_khz); + } else { +#if KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE + dev_pm_opp_put(opp_ptr); /* decrease OPP refcount */ +#endif + /* convert found frequency to KHz */ + found_freq /= 1000; + + /* If lowest frequency in OPP table is still higher + * than the reference, then keep the reference frequency + * as the one to use for scaling . + */ + if (found_freq < lowest_freq_khz) + lowest_freq_khz = found_freq; + } +#else + dev_err(kbdev->dev, "No operating-points-v2 node or operating-points property in DT"); +#endif + + kbdev->lowest_gpu_freq_khz = lowest_freq_khz; + dev_dbg(kbdev->dev, "Lowest frequency identified is %llu kHz", kbdev->lowest_gpu_freq_khz); + return 0; +} /** - * set_pm_poweroff - Store callback for the pm_poweroff sysfs file. + * pm_poweroff_store - Store callback for the pm_poweroff sysfs file. * @dev: The device with sysfs file is for * @attr: The attributes of the sysfs file * @buf: The value written to the sysfs file @@ -3213,7 +3397,7 @@ * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_pm_poweroff(struct device *dev, +static ssize_t pm_poweroff_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; @@ -3252,7 +3436,7 @@ } /** - * show_pm_poweroff - Show callback for the pm_poweroff sysfs entry. + * pm_poweroff_show - Show callback for the pm_poweroff sysfs entry. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The output buffer to receive the GPU information. @@ -3262,7 +3446,7 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t show_pm_poweroff(struct device *dev, +static ssize_t pm_poweroff_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; @@ -3286,80 +3470,10 @@ return ret; } -static DEVICE_ATTR(pm_poweroff, S_IRUGO | S_IWUSR, show_pm_poweroff, - set_pm_poweroff); - -#if MALI_USE_CSF -/** - * set_idle_hysteresis_time - Store callback for CSF idle_hysteresis_time - * sysfs file. - * @dev: The device with sysfs file is for - * @attr: The attributes of the sysfs file - * @buf: The value written to the sysfs file - * @count: The number of bytes written to the sysfs file - * - * This function is called when the idle_hysteresis_time sysfs file is - * written to. - * - * This file contains values of the idle idle hysteresis duration. - * - * Return: @count if the function succeeded. An error code on failure. - */ -static ssize_t set_idle_hysteresis_time(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct kbase_device *kbdev; - u32 dur; - - kbdev = to_kbase_device(dev); - if (!kbdev) - return -ENODEV; - - if (kstrtou32(buf, 0, &dur)) { - dev_err(kbdev->dev, "Couldn't process idle_hysteresis_time write operation.\n" - "Use format <idle_hysteresis_time>\n"); - return -EINVAL; - } - - kbase_csf_firmware_set_gpu_idle_hysteresis_time(kbdev, dur); - - return count; -} +static DEVICE_ATTR_RW(pm_poweroff); /** - * show_idle_hysteresis_time - Show callback for CSF idle_hysteresis_time - * sysfs entry. - * @dev: The device this sysfs file is for. - * @attr: The attributes of the sysfs file. - * @buf: The output buffer to receive the GPU information. - * - * This function is called to get the current idle hysteresis duration in ms. - * - * Return: The number of bytes output to @buf. - */ -static ssize_t show_idle_hysteresis_time(struct device *dev, - struct device_attribute *attr, char * const buf) -{ - struct kbase_device *kbdev; - ssize_t ret; - u32 dur; - - kbdev = to_kbase_device(dev); - if (!kbdev) - return -ENODEV; - - dur = kbase_csf_firmware_get_gpu_idle_hysteresis_time(kbdev); - ret = scnprintf(buf, PAGE_SIZE, "%u\n", dur); - - return ret; -} - -static DEVICE_ATTR(idle_hysteresis_time, S_IRUGO | S_IWUSR, - show_idle_hysteresis_time, set_idle_hysteresis_time); -#endif - -/** - * set_reset_timeout - Store callback for the reset_timeout sysfs file. + * reset_timeout_store - Store callback for the reset_timeout sysfs file. * @dev: The device with sysfs file is for * @attr: The attributes of the sysfs file * @buf: The value written to the sysfs file @@ -3370,7 +3484,7 @@ * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_reset_timeout(struct device *dev, +static ssize_t reset_timeout_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *kbdev; @@ -3395,7 +3509,7 @@ } /** - * show_reset_timeout - Show callback for the reset_timeout sysfs entry. + * reset_timeout_show - Show callback for the reset_timeout sysfs entry. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The output buffer to receive the GPU information. @@ -3404,7 +3518,7 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t show_reset_timeout(struct device *dev, +static ssize_t reset_timeout_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; @@ -3419,11 +3533,9 @@ return ret; } -static DEVICE_ATTR(reset_timeout, S_IRUGO | S_IWUSR, show_reset_timeout, - set_reset_timeout); +static DEVICE_ATTR_RW(reset_timeout); - -static ssize_t show_mem_pool_size(struct device *dev, +static ssize_t mem_pool_size_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3436,7 +3548,7 @@ kbase_mem_pool_debugfs_size); } -static ssize_t set_mem_pool_size(struct device *dev, +static ssize_t mem_pool_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3452,10 +3564,9 @@ return err ? err : count; } -static DEVICE_ATTR(mem_pool_size, S_IRUGO | S_IWUSR, show_mem_pool_size, - set_mem_pool_size); +static DEVICE_ATTR_RW(mem_pool_size); -static ssize_t show_mem_pool_max_size(struct device *dev, +static ssize_t mem_pool_max_size_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3468,7 +3579,7 @@ kbase_mem_pool_debugfs_max_size); } -static ssize_t set_mem_pool_max_size(struct device *dev, +static ssize_t mem_pool_max_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3484,11 +3595,10 @@ return err ? err : count; } -static DEVICE_ATTR(mem_pool_max_size, S_IRUGO | S_IWUSR, show_mem_pool_max_size, - set_mem_pool_max_size); +static DEVICE_ATTR_RW(mem_pool_max_size); /** - * show_lp_mem_pool_size - Show size of the large memory pages pool. + * lp_mem_pool_size_show - Show size of the large memory pages pool. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The output buffer to receive the pool size. @@ -3497,7 +3607,7 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t show_lp_mem_pool_size(struct device *dev, +static ssize_t lp_mem_pool_size_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3511,7 +3621,7 @@ } /** - * set_lp_mem_pool_size - Set size of the large memory pages pool. + * lp_mem_pool_size_store - Set size of the large memory pages pool. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The value written to the sysfs file. @@ -3522,7 +3632,7 @@ * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_lp_mem_pool_size(struct device *dev, +static ssize_t lp_mem_pool_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3538,11 +3648,10 @@ return err ? err : count; } -static DEVICE_ATTR(lp_mem_pool_size, S_IRUGO | S_IWUSR, show_lp_mem_pool_size, - set_lp_mem_pool_size); +static DEVICE_ATTR_RW(lp_mem_pool_size); /** - * show_lp_mem_pool_max_size - Show maximum size of the large memory pages pool. + * lp_mem_pool_max_size_show - Show maximum size of the large memory pages pool. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The output buffer to receive the pool size. @@ -3551,7 +3660,7 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t show_lp_mem_pool_max_size(struct device *dev, +static ssize_t lp_mem_pool_max_size_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3565,7 +3674,7 @@ } /** - * set_lp_mem_pool_max_size - Set maximum size of the large memory pages pool. + * lp_mem_pool_max_size_store - Set maximum size of the large memory pages pool. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. * @buf: The value written to the sysfs file. @@ -3575,7 +3684,7 @@ * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_lp_mem_pool_max_size(struct device *dev, +static ssize_t lp_mem_pool_max_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_device *const kbdev = to_kbase_device(dev); @@ -3591,8 +3700,7 @@ return err ? err : count; } -static DEVICE_ATTR(lp_mem_pool_max_size, S_IRUGO | S_IWUSR, show_lp_mem_pool_max_size, - set_lp_mem_pool_max_size); +static DEVICE_ATTR_RW(lp_mem_pool_max_size); /** * show_simplified_mem_pool_max_size - Show the maximum size for the memory @@ -3793,7 +3901,7 @@ #if !MALI_USE_CSF /** - * show_js_ctx_scheduling_mode - Show callback for js_ctx_scheduling_mode sysfs + * js_ctx_scheduling_mode_show - Show callback for js_ctx_scheduling_mode sysfs * entry. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. @@ -3803,7 +3911,7 @@ * * Return: The number of bytes output to @buf. */ -static ssize_t show_js_ctx_scheduling_mode(struct device *dev, +static ssize_t js_ctx_scheduling_mode_show(struct device *dev, struct device_attribute *attr, char * const buf) { struct kbase_device *kbdev; @@ -3816,7 +3924,7 @@ } /** - * set_js_ctx_scheduling_mode - Set callback for js_ctx_scheduling_mode sysfs + * js_ctx_scheduling_mode_store - Set callback for js_ctx_scheduling_mode sysfs * entry. * @dev: The device this sysfs file is for. * @attr: The attributes of the sysfs file. @@ -3829,7 +3937,7 @@ * * Return: @count if the function succeeded. An error code on failure. */ -static ssize_t set_js_ctx_scheduling_mode(struct device *dev, +static ssize_t js_ctx_scheduling_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kbase_context *kctx; @@ -3871,11 +3979,7 @@ return count; } -static DEVICE_ATTR(js_ctx_scheduling_mode, S_IRUGO | S_IWUSR, - show_js_ctx_scheduling_mode, - set_js_ctx_scheduling_mode); - -#ifdef MALI_KBASE_BUILD +static DEVICE_ATTR_RW(js_ctx_scheduling_mode); /* Number of entries in serialize_jobs_settings[] */ #define NR_SERIALIZE_JOBS_SETTINGS 5 @@ -3899,14 +4003,14 @@ * update_serialize_jobs_setting - Update the serialization setting for the * submission of GPU jobs. * - * This function is called when the serialize_jobs sysfs/debugfs file is - * written to. It matches the requested setting against the available settings - * and if a matching setting is found updates kbdev->serialize_jobs. - * * @kbdev: An instance of the GPU platform device, allocated from the probe * method of the driver. * @buf: Buffer containing the value written to the sysfs/debugfs file. * @count: The number of bytes to write to the sysfs/debugfs file. + * + * This function is called when the serialize_jobs sysfs/debugfs file is + * written to. It matches the requested setting against the available settings + * and if a matching setting is found updates kbdev->serialize_jobs. * * Return: @count if the function succeeded. An error code on failure. */ @@ -4029,13 +4133,13 @@ /** * show_serialize_jobs_sysfs - Show callback for serialize_jobs sysfs file. * - * This function is called to get the contents of the serialize_jobs sysfs - * file. This is a list of the available settings with the currently active - * one surrounded by square brackets. - * * @dev: The device this sysfs file is for * @attr: The attributes of the sysfs file * @buf: The output buffer for the sysfs file contents + * + * This function is called to get the contents of the serialize_jobs sysfs + * file. This is a list of the available settings with the currently active + * one surrounded by square brackets. * * Return: The number of bytes output to @buf. */ @@ -4071,14 +4175,14 @@ /** * store_serialize_jobs_sysfs - Store callback for serialize_jobs sysfs file. * - * This function is called when the serialize_jobs sysfs file is written to. - * It matches the requested setting against the available settings and if a - * matching setting is found updates kbdev->serialize_jobs. - * * @dev: The device this sysfs file is for * @attr: The attributes of the sysfs file * @buf: The value written to the sysfs file * @count: The number of bytes to write to the sysfs file + * + * This function is called when the serialize_jobs sysfs file is written to. + * It matches the requested setting against the available settings and if a + * matching setting is found updates kbdev->serialize_jobs. * * Return: @count if the function succeeded. An error code on failure. */ @@ -4091,7 +4195,6 @@ static DEVICE_ATTR(serialize_jobs, 0600, show_serialize_jobs_sysfs, store_serialize_jobs_sysfs); -#endif /* MALI_KBASE_BUILD */ #endif /* !MALI_USE_CSF */ static void kbasep_protected_mode_hwcnt_disable_worker(struct work_struct *data) @@ -4187,6 +4290,15 @@ kfree(kbdev->protected_dev); } +#if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) +static int kbase_common_reg_map(struct kbase_device *kbdev) +{ + return 0; +} +static void kbase_common_reg_unmap(struct kbase_device * const kbdev) +{ +} +#else /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */ static int kbase_common_reg_map(struct kbase_device *kbdev) { int err = 0; @@ -4222,6 +4334,7 @@ kbdev->reg_size = 0; } } +#endif /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */ int registers_map(struct kbase_device * const kbdev) { @@ -4350,8 +4463,8 @@ kbase_pm_register_access_enable(kbdev); gpu_id = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID)); kbase_pm_register_access_disable(kbdev); - product_id = KBASE_UBFX32(gpu_id, - GPU_ID_VERSION_PRODUCT_ID_SHIFT, 16); + product_id = + KBASE_UBFX32(gpu_id, KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT, 16); gpu_model_id = GPU_ID2_MODEL_MATCH_VALUE(product_id); if (gpu_model_id != GPU_ID2_PRODUCT_TGOX @@ -4403,10 +4516,9 @@ int err = 0; unsigned int i; #if defined(CONFIG_REGULATOR) - static const char *regulator_names[] = { - "mali", "shadercores" + static const char * const regulator_names[] = { + "mali", "mem" }; - BUILD_BUG_ON(ARRAY_SIZE(regulator_names) < BASE_MAX_NR_CLOCKS_REGULATORS); #endif /* CONFIG_REGULATOR */ if (!kbdev) @@ -4422,17 +4534,17 @@ * Any other error is ignored and the driver will continue * operating with a partial initialization of regulators. */ - for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) { + for (i = 0; i < ARRAY_SIZE(regulator_names); i++) { kbdev->regulators[i] = regulator_get_optional(kbdev->dev, regulator_names[i]); - if (IS_ERR_OR_NULL(kbdev->regulators[i])) { + if (IS_ERR(kbdev->regulators[i])) { err = PTR_ERR(kbdev->regulators[i]); kbdev->regulators[i] = NULL; break; } } if (err == -EPROBE_DEFER) { - while ((i > 0) && (i < BASE_MAX_NR_CLOCKS_REGULATORS)) + while (i > 0) regulator_put(kbdev->regulators[--i]); return err; } @@ -4453,7 +4565,7 @@ */ for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) { kbdev->clocks[i] = of_clk_get(kbdev->dev->of_node, i); - if (IS_ERR_OR_NULL(kbdev->clocks[i])) { + if (IS_ERR(kbdev->clocks[i])) { err = PTR_ERR(kbdev->clocks[i]); kbdev->clocks[i] = NULL; break; @@ -4469,8 +4581,8 @@ } } if (err == -EPROBE_DEFER) { - while ((i > 0) && (i < BASE_MAX_NR_CLOCKS_REGULATORS)) { - clk_unprepare(kbdev->clocks[--i]); + while (i > 0) { + clk_disable_unprepare(kbdev->clocks[--i]); clk_put(kbdev->clocks[i]); } goto clocks_probe_defer; @@ -4485,13 +4597,39 @@ * from completing its initialization. */ #if defined(CONFIG_PM_OPP) -#if ((KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE) && \ - defined(CONFIG_REGULATOR)) +#if defined(CONFIG_REGULATOR) +#if (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) if (kbdev->nr_regulators > 0) { - kbdev->opp_table = dev_pm_opp_set_regulators(kbdev->dev, - regulator_names, BASE_MAX_NR_CLOCKS_REGULATORS); + kbdev->token = dev_pm_opp_set_regulators(kbdev->dev, regulator_names); + + if (kbdev->token < 0) { + err = kbdev->token; + goto regulators_probe_defer; + } + } -#endif /* (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE */ +#elif (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE) + if (kbdev->nr_regulators > 0) { + kbdev->opp_table = + dev_pm_opp_set_regulators(kbdev->dev, regulator_names, + kbdev->nr_regulators); + if (IS_ERR(kbdev->opp_table)) { + dev_err(kbdev->dev, "Failed to set regulators\n"); + return 0; + } + kbdev->opp_table = + dev_pm_opp_register_set_opp_helper(kbdev->dev, + kbase_devfreq_opp_helper); + if (IS_ERR(kbdev->opp_table)) { + dev_pm_opp_put_regulators(kbdev->opp_table); + kbdev->opp_table = NULL; + dev_err(kbdev->dev, "Failed to set opp helper\n"); + return 0; + } + } +#endif /* (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) */ +#endif /* CONFIG_REGULATOR */ + #ifdef CONFIG_ARCH_ROCKCHIP err = kbase_platform_rk_init_opp_table(kbdev); if (err) @@ -4502,6 +4640,19 @@ #endif #endif /* CONFIG_PM_OPP */ return 0; + +#if defined(CONFIG_PM_OPP) && \ + ((KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE) && defined(CONFIG_REGULATOR)) + for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) { + if (kbdev->clocks[i]) { + if (__clk_is_enabled(kbdev->clocks[i])) + clk_disable_unprepare(kbdev->clocks[i]); + clk_put(kbdev->clocks[i]); + kbdev->clocks[i] = NULL; + } else + break; + } +#endif clocks_probe_defer: #if defined(CONFIG_REGULATOR) @@ -4518,11 +4669,17 @@ #if defined(CONFIG_PM_OPP) dev_pm_opp_of_remove_table(kbdev->dev); -#if ((KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE) && \ - defined(CONFIG_REGULATOR)) +#if defined(CONFIG_REGULATOR) +#if (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) + if (kbdev->token > -EPERM) { + dev_pm_opp_unregister_set_opp_helper(kbdev->opp_table); + dev_pm_opp_put_regulators(kbdev->token); + } +#elif (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE) if (!IS_ERR_OR_NULL(kbdev->opp_table)) dev_pm_opp_put_regulators(kbdev->opp_table); -#endif /* (KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE */ +#endif /* (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) */ +#endif /* CONFIG_REGULATOR */ #endif /* CONFIG_PM_OPP */ for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) { @@ -4544,7 +4701,6 @@ #endif } -#ifdef MALI_KBASE_BUILD #if IS_ENABLED(CONFIG_DEBUG_FS) static void trigger_reset(struct kbase_device *kbdev) @@ -4562,43 +4718,48 @@ kbdev = (struct kbase_device *)data; \ kbdev->hw_quirks_##type = (u32)val; \ trigger_reset(kbdev); \ - return 0;\ + return 0; \ } \ \ static int type##_quirks_get(void *data, u64 *val) \ { \ - struct kbase_device *kbdev;\ - kbdev = (struct kbase_device *)data;\ - *val = kbdev->hw_quirks_##type;\ - return 0;\ + struct kbase_device *kbdev; \ + kbdev = (struct kbase_device *)data; \ + *val = kbdev->hw_quirks_##type; \ + return 0; \ } \ -DEFINE_SIMPLE_ATTRIBUTE(fops_##type##_quirks, type##_quirks_get,\ - type##_quirks_set, "%llu\n") +DEFINE_DEBUGFS_ATTRIBUTE(fops_##type##_quirks, type##_quirks_get, \ + type##_quirks_set, "%llu\n") MAKE_QUIRK_ACCESSORS(sc); MAKE_QUIRK_ACCESSORS(tiler); MAKE_QUIRK_ACCESSORS(mmu); MAKE_QUIRK_ACCESSORS(gpu); -static ssize_t kbase_device_debugfs_reset_write(struct file *file, - const char __user *ubuf, size_t count, loff_t *ppos) +/** + * kbase_device_debugfs_reset_write() - Reset the GPU + * + * @data: Pointer to the Kbase device. + * @wait_for_reset: Value written to the file. + * + * This function will perform the GPU reset, and if the value written to + * the file is 1 it will also wait for the reset to complete. + * + * Return: 0 in case of no error otherwise a negative value. + */ +static int kbase_device_debugfs_reset_write(void *data, u64 wait_for_reset) { - struct kbase_device *kbdev = file->private_data; - CSTD_UNUSED(ubuf); - CSTD_UNUSED(count); - CSTD_UNUSED(ppos); + struct kbase_device *kbdev = data; trigger_reset(kbdev); - return count; + if (wait_for_reset == 1) + return kbase_reset_gpu_wait(kbdev); + + return 0; } -static const struct file_operations fops_trigger_reset = { - .owner = THIS_MODULE, - .open = simple_open, - .write = kbase_device_debugfs_reset_write, - .llseek = default_llseek, -}; +DEFINE_DEBUGFS_ATTRIBUTE(fops_trigger_reset, NULL, &kbase_device_debugfs_reset_write, "%llu\n"); /** * debugfs_protected_debug_mode_read - "protected_debug_mode" debugfs read @@ -4682,57 +4843,84 @@ .release = single_release, }; -int kbase_device_debugfs_init(struct kbase_device *kbdev) +/** + * debugfs_ctx_defaults_init - Create the default configuration of new contexts in debugfs + * @kbdev: An instance of the GPU platform device, allocated from the probe method of the driver. + * Return: A pointer to the last dentry that it tried to create, whether successful or not. + * Could be NULL or encode another error value. + */ +static struct dentry *debugfs_ctx_defaults_init(struct kbase_device *const kbdev) { - struct dentry *debugfs_ctx_defaults_directory; - int err; /* prevent unprivileged use of debug file system * in old kernel version */ -#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE) - /* only for newer kernel version debug file system is safe */ const mode_t mode = 0644; -#else - const mode_t mode = 0600; -#endif + struct dentry *dentry = debugfs_create_dir("defaults", kbdev->debugfs_ctx_directory); + struct dentry *debugfs_ctx_defaults_directory = dentry; - kbdev->mali_debugfs_directory = debugfs_create_dir(kbdev->devname, - NULL); - if (!kbdev->mali_debugfs_directory) { + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Couldn't create mali debugfs ctx defaults directory\n"); + return dentry; + } + + debugfs_create_bool("infinite_cache", mode, + debugfs_ctx_defaults_directory, + &kbdev->infinite_cache_active_default); + + dentry = debugfs_create_file("mem_pool_max_size", mode, debugfs_ctx_defaults_directory, + &kbdev->mem_pool_defaults.small, + &kbase_device_debugfs_mem_pool_max_size_fops); + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create mem_pool_max_size debugfs entry\n"); + return dentry; + } + + dentry = debugfs_create_file("lp_mem_pool_max_size", mode, debugfs_ctx_defaults_directory, + &kbdev->mem_pool_defaults.large, + &kbase_device_debugfs_mem_pool_max_size_fops); + if (IS_ERR_OR_NULL(dentry)) + dev_err(kbdev->dev, "Unable to create lp_mem_pool_max_size debugfs entry\n"); + + return dentry; +} + +/** + * init_debugfs - Create device-wide debugfs directories and files for the Mali driver + * @kbdev: An instance of the GPU platform device, allocated from the probe method of the driver. + * Return: A pointer to the last dentry that it tried to create, whether successful or not. + * Could be NULL or encode another error value. + */ +static struct dentry *init_debugfs(struct kbase_device *kbdev) +{ + struct dentry *dentry = debugfs_create_dir(kbdev->devname, NULL); + + kbdev->mali_debugfs_directory = dentry; + if (IS_ERR_OR_NULL(dentry)) { dev_err(kbdev->dev, "Couldn't create mali debugfs directory: %s\n", kbdev->devname); - err = -ENOMEM; - goto out; + return dentry; } - kbdev->debugfs_ctx_directory = debugfs_create_dir("ctx", - kbdev->mali_debugfs_directory); - if (!kbdev->debugfs_ctx_directory) { + dentry = debugfs_create_dir("ctx", kbdev->mali_debugfs_directory); + kbdev->debugfs_ctx_directory = dentry; + if (IS_ERR_OR_NULL(dentry)) { dev_err(kbdev->dev, "Couldn't create mali debugfs ctx directory\n"); - err = -ENOMEM; - goto out; + return dentry; } - kbdev->debugfs_instr_directory = debugfs_create_dir("instrumentation", - kbdev->mali_debugfs_directory); - if (!kbdev->debugfs_instr_directory) { + dentry = debugfs_create_dir("instrumentation", kbdev->mali_debugfs_directory); + kbdev->debugfs_instr_directory = dentry; + if (IS_ERR_OR_NULL(dentry)) { dev_err(kbdev->dev, "Couldn't create mali debugfs instrumentation directory\n"); - err = -ENOMEM; - goto out; - } - - debugfs_ctx_defaults_directory = debugfs_create_dir("defaults", - kbdev->debugfs_ctx_directory); - if (!debugfs_ctx_defaults_directory) { - dev_err(kbdev->dev, "Couldn't create mali debugfs ctx defaults directory\n"); - err = -ENOMEM; - goto out; + return dentry; } kbasep_regs_history_debugfs_init(kbdev); -#if !MALI_USE_CSF +#if MALI_USE_CSF + kbase_debug_csf_fault_debugfs_init(kbdev); +#else /* MALI_USE_CSF */ kbase_debug_job_fault_debugfs_init(kbdev); #endif /* !MALI_USE_CSF */ @@ -4741,67 +4929,99 @@ #ifdef CONFIG_MALI_PRFCNT_SET_SELECT_VIA_DEBUG_FS kbase_instr_backend_debugfs_init(kbdev); #endif + kbase_pbha_debugfs_init(kbdev); + /* fops_* variables created by invocations of macro * MAKE_QUIRK_ACCESSORS() above. */ - debugfs_create_file("quirks_sc", 0644, + dentry = debugfs_create_file("quirks_sc", 0644, kbdev->mali_debugfs_directory, kbdev, &fops_sc_quirks); - debugfs_create_file("quirks_tiler", 0644, - kbdev->mali_debugfs_directory, kbdev, - &fops_tiler_quirks); - debugfs_create_file("quirks_mmu", 0644, - kbdev->mali_debugfs_directory, kbdev, - &fops_mmu_quirks); - debugfs_create_file("quirks_gpu", 0644, kbdev->mali_debugfs_directory, - kbdev, &fops_gpu_quirks); - - debugfs_create_bool("infinite_cache", mode, - debugfs_ctx_defaults_directory, - &kbdev->infinite_cache_active_default); - - debugfs_create_file("mem_pool_max_size", mode, - debugfs_ctx_defaults_directory, - &kbdev->mem_pool_defaults.small, - &kbase_device_debugfs_mem_pool_max_size_fops); - - debugfs_create_file("lp_mem_pool_max_size", mode, - debugfs_ctx_defaults_directory, - &kbdev->mem_pool_defaults.large, - &kbase_device_debugfs_mem_pool_max_size_fops); - - if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_DEBUG_MODE)) { - debugfs_create_file("protected_debug_mode", S_IRUGO, - kbdev->mali_debugfs_directory, kbdev, - &fops_protected_debug_mode); + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create quirks_sc debugfs entry\n"); + return dentry; } - debugfs_create_file("reset", 0644, + dentry = debugfs_create_file("quirks_tiler", 0644, + kbdev->mali_debugfs_directory, kbdev, + &fops_tiler_quirks); + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create quirks_tiler debugfs entry\n"); + return dentry; + } + + dentry = debugfs_create_file("quirks_mmu", 0644, + kbdev->mali_debugfs_directory, kbdev, + &fops_mmu_quirks); + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create quirks_mmu debugfs entry\n"); + return dentry; + } + + dentry = debugfs_create_file("quirks_gpu", 0644, kbdev->mali_debugfs_directory, + kbdev, &fops_gpu_quirks); + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create quirks_gpu debugfs entry\n"); + return dentry; + } + + dentry = debugfs_ctx_defaults_init(kbdev); + if (IS_ERR_OR_NULL(dentry)) + return dentry; + + if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_DEBUG_MODE)) { + dentry = debugfs_create_file("protected_debug_mode", 0444, + kbdev->mali_debugfs_directory, kbdev, + &fops_protected_debug_mode); + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create protected_debug_mode debugfs entry\n"); + return dentry; + } + } + + dentry = debugfs_create_file("reset", 0644, kbdev->mali_debugfs_directory, kbdev, &fops_trigger_reset); + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create reset debugfs entry\n"); + return dentry; + } kbase_ktrace_debugfs_init(kbdev); #ifdef CONFIG_MALI_BIFROST_DEVFREQ #if IS_ENABLED(CONFIG_DEVFREQ_THERMAL) - if (kbdev->devfreq && !kbdev->model_data) + if (kbdev->devfreq && !kbdev->model_data && + !kbdev->dfc_power.dyn_power_coeff) kbase_ipa_debugfs_init(kbdev); #endif /* CONFIG_DEVFREQ_THERMAL */ #endif /* CONFIG_MALI_BIFROST_DEVFREQ */ #if !MALI_USE_CSF - debugfs_create_file("serialize_jobs", S_IRUGO | S_IWUSR, + dentry = debugfs_create_file("serialize_jobs", 0644, kbdev->mali_debugfs_directory, kbdev, &kbasep_serialize_jobs_debugfs_fops); - + if (IS_ERR_OR_NULL(dentry)) { + dev_err(kbdev->dev, "Unable to create serialize_jobs debugfs entry\n"); + return dentry; + } + kbase_timeline_io_debugfs_init(kbdev); #endif kbase_dvfs_status_debugfs_init(kbdev); - return 0; -out: - debugfs_remove_recursive(kbdev->mali_debugfs_directory); - return err; + return dentry; +} + +int kbase_device_debugfs_init(struct kbase_device *kbdev) +{ + struct dentry *dentry = init_debugfs(kbdev); + + if (IS_ERR_OR_NULL(dentry)) { + debugfs_remove_recursive(kbdev->mali_debugfs_directory); + return IS_ERR(dentry) ? PTR_ERR(dentry) : -ENOMEM; + } + return 0; } void kbase_device_debugfs_term(struct kbase_device *kbdev) @@ -4809,7 +5029,6 @@ debugfs_remove_recursive(kbdev->mali_debugfs_directory); } #endif /* CONFIG_DEBUG_FS */ -#endif /* MALI_KBASE_BUILD */ int kbase_device_coherency_init(struct kbase_device *kbdev) { @@ -4817,12 +5036,13 @@ u32 supported_coherency_bitmap = kbdev->gpu_props.props.raw_props.coherency_mode; const void *coherency_override_dts; + bool dma_coherent; u32 override_coherency, gpu_id; unsigned int prod_id; gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; gpu_id &= GPU_ID_VERSION_PRODUCT_ID; - prod_id = gpu_id >> GPU_ID_VERSION_PRODUCT_ID_SHIFT; + prod_id = gpu_id >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT; /* Only for tMIx : * (COHERENCY_ACE_LITE | COHERENCY_ACE) was incorrectly @@ -4841,12 +5061,23 @@ /* device tree may override the coherency */ #if IS_ENABLED(CONFIG_OF) + /* treat "dma-coherency" as a synonym for ACE-lite */ + dma_coherent = of_dma_is_coherent(kbdev->dev->of_node); coherency_override_dts = of_get_property(kbdev->dev->of_node, "system-coherency", NULL); - if (coherency_override_dts) { - - override_coherency = be32_to_cpup(coherency_override_dts); + if (coherency_override_dts || dma_coherent) { + if (coherency_override_dts) { + override_coherency = be32_to_cpup(coherency_override_dts); + if (dma_coherent && override_coherency != COHERENCY_ACE_LITE) { + dev_err(kbdev->dev, + "system-coherency needs to be 0 when dma-coherent is set\n"); + return -EINVAL; + } + } else { + /* dma-coherent set and system-coherency not specified */ + override_coherency = COHERENCY_ACE_LITE; + } #if MALI_USE_CSF && !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) /* ACE coherency mode is not supported by Driver on CSF GPUs. @@ -4954,8 +5185,7 @@ return ret; } -static DEVICE_ATTR(csg_scheduling_period, 0644, csg_scheduling_period_show, - csg_scheduling_period_store); +static DEVICE_ATTR_RW(csg_scheduling_period); /** * fw_timeout_store - Store callback for the fw_timeout sysfs file. @@ -4983,10 +5213,11 @@ ret = kstrtouint(buf, 0, &fw_timeout); if (ret || fw_timeout == 0) { - dev_err(kbdev->dev, "%s\n%s\n%u", - "Couldn't process fw_timeout write operation.", - "Use format 'fw_timeout_ms', and fw_timeout_ms > 0", - FIRMWARE_PING_INTERVAL_MS); + dev_err(kbdev->dev, + "Couldn't process fw_timeout write operation.\n" + "Use format 'fw_timeout_ms', and fw_timeout_ms > 0\n" + "Default fw_timeout: %u", + kbase_get_timeout_ms(kbdev, CSF_FIRMWARE_PING_TIMEOUT)); return -EINVAL; } @@ -5023,7 +5254,133 @@ return ret; } -static DEVICE_ATTR(fw_timeout, 0644, fw_timeout_show, fw_timeout_store); +static DEVICE_ATTR_RW(fw_timeout); + +/** + * idle_hysteresis_time_store - Store callback for CSF idle_hysteresis_time + * sysfs file. + * @dev: The device with sysfs file is for + * @attr: The attributes of the sysfs file + * @buf: The value written to the sysfs file + * @count: The number of bytes written to the sysfs file + * + * This function is called when the idle_hysteresis_time sysfs file is + * written to. + * + * This file contains values of the idle hysteresis duration. + * + * Return: @count if the function succeeded. An error code on failure. + */ +static ssize_t idle_hysteresis_time_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct kbase_device *kbdev; + u32 dur = 0; + + kbdev = to_kbase_device(dev); + if (!kbdev) + return -ENODEV; + + if (kstrtou32(buf, 0, &dur)) { + dev_err(kbdev->dev, "Couldn't process idle_hysteresis_time write operation.\n" + "Use format <idle_hysteresis_time>\n"); + return -EINVAL; + } + + kbase_csf_firmware_set_gpu_idle_hysteresis_time(kbdev, dur); + + return count; +} + +/** + * idle_hysteresis_time_show - Show callback for CSF idle_hysteresis_time + * sysfs entry. + * @dev: The device this sysfs file is for. + * @attr: The attributes of the sysfs file. + * @buf: The output buffer to receive the GPU information. + * + * This function is called to get the current idle hysteresis duration in ms. + * + * Return: The number of bytes output to @buf. + */ +static ssize_t idle_hysteresis_time_show(struct device *dev, + struct device_attribute *attr, char * const buf) +{ + struct kbase_device *kbdev; + ssize_t ret; + u32 dur; + + kbdev = to_kbase_device(dev); + if (!kbdev) + return -ENODEV; + + dur = kbase_csf_firmware_get_gpu_idle_hysteresis_time(kbdev); + ret = scnprintf(buf, PAGE_SIZE, "%u\n", dur); + + return ret; +} + +static DEVICE_ATTR_RW(idle_hysteresis_time); + +/** + * mcu_shader_pwroff_timeout_show - Get the MCU shader Core power-off time value. + * + * @dev: The device this sysfs file is for. + * @attr: The attributes of the sysfs file. + * @buf: The output buffer for the sysfs file contents + * + * Get the internally recorded MCU shader Core power-off (nominal) timeout value. + * The unit of the value is in micro-seconds. + * + * Return: The number of bytes output to @buf if the + * function succeeded. A Negative value on failure. + */ +static ssize_t mcu_shader_pwroff_timeout_show(struct device *dev, struct device_attribute *attr, + char *const buf) +{ + struct kbase_device *kbdev = dev_get_drvdata(dev); + u32 pwroff; + + if (!kbdev) + return -ENODEV; + + pwroff = kbase_csf_firmware_get_mcu_core_pwroff_time(kbdev); + return scnprintf(buf, PAGE_SIZE, "%u\n", pwroff); +} + +/** + * mcu_shader_pwroff_timeout_store - Set the MCU shader core power-off time value. + * + * @dev: The device with sysfs file is for + * @attr: The attributes of the sysfs file + * @buf: The value written to the sysfs file + * @count: The number of bytes to write to the sysfs file + * + * The duration value (unit: micro-seconds) for configuring MCU Shader Core + * timer, when the shader cores' power transitions are delegated to the + * MCU (normal operational mode) + * + * Return: @count if the function succeeded. An error code on failure. + */ +static ssize_t mcu_shader_pwroff_timeout_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct kbase_device *kbdev = dev_get_drvdata(dev); + u32 dur; + + if (!kbdev) + return -ENODEV; + + if (kstrtouint(buf, 0, &dur)) + return -EINVAL; + + kbase_csf_firmware_set_mcu_core_pwroff_time(kbdev, dur); + + return count; +} + +static DEVICE_ATTR_RW(mcu_shader_pwroff_timeout); + #endif /* MALI_USE_CSF */ static struct attribute *kbase_scheduling_attrs[] = { @@ -5047,15 +5404,14 @@ &dev_attr_gpuinfo.attr, &dev_attr_dvfs_period.attr, &dev_attr_pm_poweroff.attr, -#if MALI_USE_CSF - &dev_attr_idle_hysteresis_time.attr, -#endif &dev_attr_reset_timeout.attr, #if !MALI_USE_CSF &dev_attr_js_scheduling_period.attr, #else &dev_attr_csg_scheduling_period.attr, &dev_attr_fw_timeout.attr, + &dev_attr_idle_hysteresis_time.attr, + &dev_attr_mcu_shader_pwroff_timeout.attr, #endif /* !MALI_USE_CSF */ &dev_attr_power_policy.attr, &dev_attr_core_mask.attr, @@ -5186,8 +5542,15 @@ } kbdev->dev = &pdev->dev; - dev_set_drvdata(kbdev->dev, kbdev); +#if (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) + kbdev->token = -EPERM; +#endif /* (KERNEL_VERSION(6, 0, 0) <= LINUX_VERSION_CODE) */ + + dev_set_drvdata(kbdev->dev, kbdev); +#if (KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE) + mutex_lock(&kbase_probe_mutex); +#endif err = kbase_device_init(kbdev); if (err) { @@ -5199,12 +5562,16 @@ dev_set_drvdata(kbdev->dev, NULL); kbase_device_free(kbdev); +#if (KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE) + mutex_unlock(&kbase_probe_mutex); +#endif } else { -#ifdef MALI_KBASE_BUILD dev_info(kbdev->dev, "Probed as %s\n", dev_name(kbdev->mdev.this_device)); -#endif /* MALI_KBASE_BUILD */ kbase_increment_device_id(); +#if (KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE) + mutex_unlock(&kbase_probe_mutex); +#endif #ifdef CONFIG_MALI_ARBITER_SUPPORT mutex_lock(&kbdev->pm.lock); kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_INITIALIZED_EVT); @@ -5220,11 +5587,11 @@ /** * kbase_device_suspend - Suspend callback from the OS. * - * This is called by Linux when the device should suspend. - * * @dev: The device to suspend * - * Return: A standard Linux error code + * This is called by Linux when the device should suspend. + * + * Return: A standard Linux error code on failure, 0 otherwise. */ static int kbase_device_suspend(struct device *dev) { @@ -5233,7 +5600,10 @@ if (!kbdev) return -ENODEV; - kbase_pm_suspend(kbdev); + if (kbase_pm_suspend(kbdev)) { + dev_warn(kbdev->dev, "Abort suspend as GPU suspension failed"); + return -EBUSY; + } #ifdef CONFIG_MALI_BIFROST_DVFS kbase_pm_metrics_stop(kbdev); @@ -5246,15 +5616,27 @@ flush_workqueue(kbdev->devfreq_queue.workq); } #endif + +#ifdef CONFIG_ARCH_ROCKCHIP + kbase_platform_rk_enable_regulator(kbdev); +#endif + +#ifdef KBASE_PM_RUNTIME + if (kbdev->is_runtime_resumed) { + if (kbdev->pm.backend.callback_power_runtime_off) + kbdev->pm.backend.callback_power_runtime_off(kbdev); + } +#endif /* KBASE_PM_RUNTIME */ + return 0; } /** * kbase_device_resume - Resume callback from the OS. * - * This is called by Linux when the device should resume from suspension. - * * @dev: The device to resume + * + * This is called by Linux when the device should resume from suspension. * * Return: A standard Linux error code */ @@ -5265,6 +5647,13 @@ if (!kbdev) return -ENODEV; +#ifdef KBASE_PM_RUNTIME + if (kbdev->is_runtime_resumed) { + if (kbdev->pm.backend.callback_power_runtime_on) + kbdev->pm.backend.callback_power_runtime_on(kbdev); + } +#endif /* KBASE_PM_RUNTIME */ + kbase_pm_resume(kbdev); #ifdef CONFIG_MALI_BIFROST_DVFS @@ -5273,25 +5662,25 @@ #ifdef CONFIG_MALI_BIFROST_DEVFREQ dev_dbg(dev, "Callback %s\n", __func__); - if (kbdev->devfreq) { - mutex_lock(&kbdev->pm.lock); - if (kbdev->pm.active_count > 0) - kbase_devfreq_enqueue_work(kbdev, DEVFREQ_WORK_RESUME); - mutex_unlock(&kbdev->pm.lock); - flush_workqueue(kbdev->devfreq_queue.workq); - } + if (kbdev->devfreq) + kbase_devfreq_enqueue_work(kbdev, DEVFREQ_WORK_RESUME); #endif + +#if !MALI_USE_CSF + kbase_enable_quick_reset(kbdev); +#endif + return 0; } /** * kbase_device_runtime_suspend - Runtime suspend callback from the OS. * + * @dev: The device to suspend + * * This is called by Linux when the device should prepare for a condition in * which it will not be able to communicate with the CPU(s) and RAM due to * power management. - * - * @dev: The device to suspend * * Return: A standard Linux error code */ @@ -5299,11 +5688,19 @@ static int kbase_device_runtime_suspend(struct device *dev) { struct kbase_device *kbdev = to_kbase_device(dev); + int ret = 0; if (!kbdev) return -ENODEV; dev_dbg(dev, "Callback %s\n", __func__); + KBASE_KTRACE_ADD(kbdev, PM_RUNTIME_SUSPEND_CALLBACK, NULL, 0); + +#if MALI_USE_CSF + ret = kbase_pm_handle_runtime_suspend(kbdev); + if (ret) + return ret; +#endif #ifdef CONFIG_MALI_BIFROST_DVFS kbase_pm_metrics_stop(kbdev); @@ -5316,18 +5713,19 @@ if (kbdev->pm.backend.callback_power_runtime_off) { kbdev->pm.backend.callback_power_runtime_off(kbdev); + kbdev->is_runtime_resumed = false; dev_dbg(dev, "runtime suspend\n"); } - return 0; + return ret; } #endif /* KBASE_PM_RUNTIME */ /** * kbase_device_runtime_resume - Runtime resume callback from the OS. * - * This is called by Linux when the device should go into a fully active state. - * * @dev: The device to suspend + * + * This is called by Linux when the device should go into a fully active state. * * Return: A standard Linux error code */ @@ -5342,8 +5740,10 @@ return -ENODEV; dev_dbg(dev, "Callback %s\n", __func__); + // KBASE_KTRACE_ADD(kbdev, PM_RUNTIME_RESUME_CALLBACK, NULL, 0); if (kbdev->pm.backend.callback_power_runtime_on) { ret = kbdev->pm.backend.callback_power_runtime_on(kbdev); + kbdev->is_runtime_resumed = true; dev_dbg(dev, "runtime resume\n"); } @@ -5405,10 +5805,11 @@ }; #if IS_ENABLED(CONFIG_OF) -static const struct of_device_id kbase_dt_ids[] = { - { .compatible = "arm,mali-bifrost" }, - { /* sentinel */ } -}; +static const struct of_device_id kbase_dt_ids[] = { { .compatible = "arm,malit6xx" }, + { .compatible = "arm,mali-midgard" }, + { .compatible = "arm,mali-bifrost" }, + { .compatible = "arm,mali-valhall" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, kbase_dt_ids); #endif @@ -5423,26 +5824,29 @@ }, }; -/* - * The driver will not provide a shortcut to create the Mali platform device - * anymore when using Device Tree. - */ -#if IS_ENABLED(CONFIG_OF) +#if (KERNEL_VERSION(5, 3, 0) > LINUX_VERSION_CODE) && IS_ENABLED(CONFIG_OF) module_platform_driver(kbase_platform_driver); #else - static int __init kbase_driver_init(void) { int ret; +#if (KERNEL_VERSION(5, 3, 0) <= LINUX_VERSION_CODE) + mutex_init(&kbase_probe_mutex); +#endif + +#ifndef CONFIG_OF ret = kbase_platform_register(); if (ret) return ret; - +#endif ret = platform_driver_register(&kbase_platform_driver); - - if (ret) +#ifndef CONFIG_OF + if (ret) { kbase_platform_unregister(); + return ret; + } +#endif return ret; } @@ -5450,19 +5854,20 @@ static void __exit kbase_driver_exit(void) { platform_driver_unregister(&kbase_platform_driver); +#ifndef CONFIG_OF kbase_platform_unregister(); +#endif } module_init(kbase_driver_init); module_exit(kbase_driver_exit); - -#endif /* CONFIG_OF */ - +#endif MODULE_LICENSE("GPL"); MODULE_VERSION(MALI_RELEASE_NAME " (UK version " \ __stringify(BASE_UK_VERSION_MAJOR) "." \ __stringify(BASE_UK_VERSION_MINOR) ")"); MODULE_SOFTDEP("pre: memory_group_manager"); +MODULE_INFO(import_ns, "DMA_BUF"); #define CREATE_TRACE_POINTS /* Create the trace points (otherwise we just get code to call a tracepoint) */ @@ -5492,7 +5897,7 @@ trace_mali_page_fault_insert_pages(dev_id, event, value); } -void kbase_trace_mali_total_alloc_pages_change(u32 dev_id, long long int event) +void kbase_trace_mali_total_alloc_pages_change(u32 dev_id, long long event) { trace_mali_total_alloc_pages_change(dev_id, event); } -- Gitblit v1.6.2