diff options
author | Sidath Senanayake <sidaths@google.com> | 2017-03-31 14:00:22 +0200 |
---|---|---|
committer | Sidath Senanayake <sidaths@google.com> | 2017-03-31 14:00:22 +0200 |
commit | 48f3554a4abf9ce182253fb5415a1a26b0790998 (patch) | |
tree | cfc431e095818263d3fba56114d031623f6d8bc8 /mali_kbase | |
parent | 44e8be9a3714ef2c7ce5a7b24d5428a9be72b17b (diff) | |
download | gpu-48f3554a4abf9ce182253fb5415a1a26b0790998.tar.gz |
Mali Bifrost DDK r5p0 KMD
Provenance:
927c9ef15 (collaborate/EAC/b_r5p0)
BX304L01B-BU-00000-r5p0-01rel0
BX304L06A-BU-00000-r5p0-01rel0
BX304X07X-BU-00000-r5p0-01rel0
Signed-off-by: Sidath Senanayake <sidaths@google.com>
Change-Id: I24848fc40f11d0e23206944a4bde9cf810aa1e70
Diffstat (limited to 'mali_kbase')
52 files changed, 1600 insertions, 762 deletions
diff --git a/mali_kbase/Kbuild b/mali_kbase/Kbuild index d9df906..3e78928 100644 --- a/mali_kbase/Kbuild +++ b/mali_kbase/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2012,2014 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2012-2016 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 @@ -15,7 +15,7 @@ # Driver version string which is returned to userspace via an ioctl -MALI_RELEASE_NAME ?= "r4p0-01rel0" +MALI_RELEASE_NAME ?= "r5p0-01rel0" # Paths required for build KBASE_PATH = $(src) @@ -163,47 +163,24 @@ ifeq ($(CONFIG_MALI_PLATFORM_FAKE),y) platform/vexpress_6xvirtex7_10mhz/mali_kbase_cpu_vexpress.c ccflags-y += -I$(src)/platform/vexpress_6xvirtex7_10mhz endif - - ifeq ($(CONFIG_MALI_PLATFORM_A7_KIPLING),y) - SRC += platform/a7_kipling/mali_kbase_config_a7_kipling.c \ - platform/a7_kipling/mali_kbase_cpu_a7_kipling.c - ccflags-y += -I$(src)/platform/a7_kipling - endif - - ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY),y) - # remove begin and end quotes from the Kconfig string type - platform_name := $(shell echo $(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME)) - MALI_PLATFORM_THIRDPARTY_DIR := platform/$(platform_name) - ccflags-y += -I$(src)/$(MALI_PLATFORM_THIRDPARTY_DIR) - ifeq ($(CONFIG_MALI_MIDGARD),m) - include $(src)/platform/$(platform_name)/Kbuild - else ifeq ($(CONFIG_MALI_MIDGARD),y) - obj-$(CONFIG_MALI_MIDGARD) += platform/ - endif - endif endif # CONFIG_MALI_PLATFORM_FAKE=y -ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY),y) -# remove begin and end quotes from the Kconfig string type -platform_name := $(shell echo $(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME)) -MALI_PLATFORM_THIRDPARTY_DIR := platform/$(platform_name) -ccflags-y += -I$(src)/$(MALI_PLATFORM_THIRDPARTY_DIR) -ifeq ($(CONFIG_MALI_MIDGARD),m) -include $(src)/platform/$(platform_name)/Kbuild -else ifeq ($(CONFIG_MALI_MIDGARD),y) -obj-$(CONFIG_MALI_MIDGARD) += platform/ -endif -endif - # Tell the Linux build system from which .o file to create the kernel module obj-$(CONFIG_MALI_MIDGARD) += mali_kbase.o # Tell the Linux build system to enable building of our .c files mali_kbase-y := $(SRC:.c=.o) +ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY),y) + # Kconfig passes in the name with quotes for in-tree builds - remove them. + platform_name := $(shell echo $(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME)) + MALI_PLATFORM_THIRDPARTY_DIR := platform/$(platform_name) + ccflags-y += -I$(src)/$(MALI_PLATFORM_THIRDPARTY_DIR) + include $(src)/$(MALI_PLATFORM_THIRDPARTY_DIR)/Kbuild +endif + ifeq ($(CONFIG_DEVFREQ_THERMAL),y) -include $(src)/ipa/Kbuild -mali_kbase-y += $(IPA:.c=.o) + include $(src)/ipa/Kbuild endif mali_kbase-$(CONFIG_MALI_DMA_FENCE) += mali_kbase_dma_fence.o diff --git a/mali_kbase/backend/gpu/Kbuild b/mali_kbase/backend/gpu/Kbuild index df4e796..5f700e9 100644 --- a/mali_kbase/backend/gpu/Kbuild +++ b/mali_kbase/backend/gpu/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2014 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2014,2017 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 @@ -46,7 +46,9 @@ BACKEND += \ endif ifeq ($(CONFIG_MALI_DEVFREQ),y) -BACKEND += backend/gpu/mali_kbase_devfreq.c +BACKEND += \ + backend/gpu/mali_kbase_devfreq.c \ + backend/gpu/mali_kbase_pm_ca_devfreq.c endif ifeq ($(CONFIG_MALI_NO_MALI),y) diff --git a/mali_kbase/backend/gpu/mali_kbase_devfreq.c b/mali_kbase/backend/gpu/mali_kbase_devfreq.c index 28b4f1d..574eb3e 100644 --- a/mali_kbase/backend/gpu/mali_kbase_devfreq.c +++ b/mali_kbase/backend/gpu/mali_kbase_devfreq.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2017 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 @@ -20,6 +20,7 @@ #include <mali_kbase_config_defaults.h> #include <backend/gpu/mali_kbase_pm_internal.h> +#include <linux/of.h> #include <linux/clk.h> #include <linux/devfreq.h> #ifdef CONFIG_DEVFREQ_THERMAL @@ -41,15 +42,47 @@ #define dev_pm_opp_find_freq_ceil opp_find_freq_ceil #endif /* Linux >= 3.13 */ +/** + * opp_translate - Translate nominal OPP frequency from devicetree into real + * frequency and core mask + * @kbdev: Device pointer + * @freq: Nominal frequency + * @core_mask: Pointer to u64 to store core mask to + * + * Return: Real target frequency + * + * This function will only perform translation if an operating-points-v2-mali + * table is present in devicetree. If one is not present then it will return an + * untranslated frequency and all cores enabled. + */ +static unsigned long opp_translate(struct kbase_device *kbdev, + unsigned long freq, u64 *core_mask) +{ + int i; + + for (i = 0; i < kbdev->num_opps; i++) { + if (kbdev->opp_table[i].opp_freq == freq) { + *core_mask = kbdev->opp_table[i].core_mask; + return kbdev->opp_table[i].real_freq; + } + } + + /* Failed to find OPP - return all cores enabled & nominal frequency */ + *core_mask = kbdev->gpu_props.props.raw_props.shader_present; + + return freq; +} static int kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags) { struct kbase_device *kbdev = dev_get_drvdata(dev); struct dev_pm_opp *opp; + unsigned long nominal_freq; unsigned long freq = 0; unsigned long voltage; int err; + u64 core_mask; freq = *target_freq; @@ -62,14 +95,17 @@ kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags) return PTR_ERR(opp); } + nominal_freq = freq; + /* * Only update if there is a change of frequency */ - if (kbdev->current_freq == freq) { - *target_freq = freq; + if (kbdev->current_nominal_freq == nominal_freq) { + *target_freq = nominal_freq; return 0; } + freq = opp_translate(kbdev, nominal_freq, &core_mask); #ifdef CONFIG_REGULATOR if (kbdev->regulator && kbdev->current_voltage != voltage && kbdev->current_freq < freq) { @@ -99,11 +135,17 @@ kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags) } #endif - *target_freq = freq; + if (kbdev->pm.backend.ca_current_policy->id == + KBASE_PM_CA_POLICY_ID_DEVFREQ) + kbase_devfreq_set_core_mask(kbdev, core_mask); + + *target_freq = nominal_freq; kbdev->current_voltage = voltage; + kbdev->current_nominal_freq = nominal_freq; kbdev->current_freq = freq; + kbdev->current_core_mask = core_mask; - KBASE_TLSTREAM_AUX_DEVFREQ_TARGET((u64)freq); + KBASE_TLSTREAM_AUX_DEVFREQ_TARGET((u64)nominal_freq); kbase_pm_reset_dvfs_utilisation(kbdev); @@ -115,7 +157,7 @@ kbase_devfreq_cur_freq(struct device *dev, unsigned long *freq) { struct kbase_device *kbdev = dev_get_drvdata(dev); - *freq = kbdev->current_freq; + *freq = kbdev->current_nominal_freq; return 0; } @@ -125,7 +167,7 @@ kbase_devfreq_status(struct device *dev, struct devfreq_dev_status *stat) { struct kbase_device *kbdev = dev_get_drvdata(dev); - stat->current_frequency = kbdev->current_freq; + stat->current_frequency = kbdev->current_nominal_freq; kbase_pm_get_dvfs_utilisation(kbdev, &stat->total_time, &stat->busy_time); @@ -189,15 +231,92 @@ static void kbase_devfreq_exit(struct device *dev) kbase_devfreq_term_freq_table(kbdev); } +static int kbase_devfreq_init_core_mask_table(struct kbase_device *kbdev) +{ + struct device_node *opp_node = of_parse_phandle(kbdev->dev->of_node, + "operating-points-v2", 0); + struct device_node *node; + int i = 0; + int count; + + if (!opp_node) + return 0; + if (!of_device_is_compatible(opp_node, "operating-points-v2-mali")) + return 0; + + count = dev_pm_opp_get_opp_count(kbdev->dev); + kbdev->opp_table = kmalloc_array(count, + sizeof(struct kbase_devfreq_opp), GFP_KERNEL); + if (!kbdev->opp_table) + return -ENOMEM; + + for_each_available_child_of_node(opp_node, node) { + u64 core_mask; + u64 opp_freq, real_freq; + const void *core_count_p; + + if (of_property_read_u64(node, "opp-hz", &opp_freq)) { + dev_warn(kbdev->dev, "OPP is missing required opp-hz property\n"); + continue; + } + if (of_property_read_u64(node, "opp-hz-real", &real_freq)) + real_freq = opp_freq; + if (of_property_read_u64(node, "opp-core-mask", &core_mask)) + core_mask = + kbdev->gpu_props.props.raw_props.shader_present; + core_count_p = of_get_property(node, "opp-core-count", NULL); + if (core_count_p) { + u64 remaining_core_mask = + kbdev->gpu_props.props.raw_props.shader_present; + int core_count = be32_to_cpup(core_count_p); + + core_mask = 0; + + for (; core_count > 0; core_count--) { + int core = ffs(remaining_core_mask); + + if (!core) { + dev_err(kbdev->dev, "OPP has more cores than GPU\n"); + return -ENODEV; + } + + core_mask |= (1ull << (core-1)); + remaining_core_mask &= ~(1ull << (core-1)); + } + } + + if (!core_mask) { + dev_err(kbdev->dev, "OPP has invalid core mask of 0\n"); + return -ENODEV; + } + + kbdev->opp_table[i].opp_freq = opp_freq; + kbdev->opp_table[i].real_freq = real_freq; + kbdev->opp_table[i].core_mask = core_mask; + + dev_info(kbdev->dev, "OPP %d : opp_freq=%llu real_freq=%llu core_mask=%llx\n", + i, opp_freq, real_freq, core_mask); + + i++; + } + + kbdev->num_opps = i; + + return 0; +} + int kbase_devfreq_init(struct kbase_device *kbdev) { struct devfreq_dev_profile *dp; int err; - if (!kbdev->clock) + if (!kbdev->clock) { + dev_err(kbdev->dev, "Clock not available for devfreq\n"); return -ENODEV; + } kbdev->current_freq = clk_get_rate(kbdev->clock); + kbdev->current_nominal_freq = kbdev->current_freq; dp = &kbdev->devfreq_profile; @@ -211,6 +330,10 @@ int kbase_devfreq_init(struct kbase_device *kbdev) if (kbase_devfreq_init_freq_table(kbdev, dp)) return -EFAULT; + err = kbase_devfreq_init_core_mask_table(kbdev); + if (err) + return err; + kbdev->devfreq = devfreq_add_device(kbdev->dev, dp, "simple_ondemand", NULL); if (IS_ERR(kbdev->devfreq)) { @@ -218,6 +341,10 @@ int kbase_devfreq_init(struct kbase_device *kbdev) return PTR_ERR(kbdev->devfreq); } + /* devfreq_add_device only copies a few of kbdev->dev's fields, so + * set drvdata explicitly so IPA models can access kbdev. */ + dev_set_drvdata(&kbdev->devfreq->dev, kbdev); + err = devfreq_register_opp_notifier(kbdev->dev, kbdev->devfreq); if (err) { dev_err(kbdev->dev, @@ -226,7 +353,7 @@ int kbase_devfreq_init(struct kbase_device *kbdev) } #ifdef CONFIG_DEVFREQ_THERMAL - err = kbase_ipa_model_init(kbdev); + err = kbase_ipa_init(kbdev); if (err) { dev_err(kbdev->dev, "IPA initialization failed\n"); goto cooling_failed; @@ -270,7 +397,7 @@ void kbase_devfreq_term(struct kbase_device *kbdev) if (kbdev->devfreq_cooling) devfreq_cooling_unregister(kbdev->devfreq_cooling); - kbase_ipa_model_term(kbdev); + kbase_ipa_term(kbdev); #endif devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq); @@ -280,4 +407,6 @@ void kbase_devfreq_term(struct kbase_device *kbdev) dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err); else kbdev->devfreq = NULL; + + kfree(kbdev->opp_table); } diff --git a/mali_kbase/backend/gpu/mali_kbase_jm_hw.c b/mali_kbase/backend/gpu/mali_kbase_jm_hw.c index 7856378..ef7497d 100644 --- a/mali_kbase/backend/gpu/mali_kbase_jm_hw.c +++ b/mali_kbase/backend/gpu/mali_kbase_jm_hw.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 @@ -129,8 +129,7 @@ void kbase_job_hw_submit(struct kbase_device *kbdev, /* Write an approximate start timestamp. * It's approximate because there might be a job in the HEAD register. - * In such cases, we'll try to make a better approximation in the IRQ - * handler (up to the KBASE_JS_IRQ_THROTTLE_TIME_US). */ + */ katom->start_timestamp = ktime_get(); /* GO ! */ @@ -184,9 +183,9 @@ void kbase_job_hw_submit(struct kbase_device *kbdev, * Update the start_timestamp of the job currently in the HEAD, based on the * fact that we got an IRQ for the previous set of completed jobs. * - * The estimate also takes into account the %KBASE_JS_IRQ_THROTTLE_TIME_US and - * the time the job was submitted, to work out the best estimate (which might - * still result in an over-estimate to the calculated time spent) + * The estimate also takes into account the time the job was submitted, to + * work out the best estimate (which might still result in an over-estimate to + * the calculated time spent) */ static void kbasep_job_slot_update_head_start_timestamp( struct kbase_device *kbdev, @@ -195,25 +194,20 @@ static void kbasep_job_slot_update_head_start_timestamp( { if (kbase_backend_nr_atoms_on_slot(kbdev, js) > 0) { struct kbase_jd_atom *katom; - ktime_t new_timestamp; ktime_t timestamp_diff; /* The atom in the HEAD */ katom = kbase_gpu_inspect(kbdev, js, 0); KBASE_DEBUG_ASSERT(katom != NULL); - /* Account for any IRQ Throttle time - makes an overestimate of - * the time spent by the job */ - new_timestamp = ktime_sub_ns(end_timestamp, - KBASE_JS_IRQ_THROTTLE_TIME_US * 1000); - timestamp_diff = ktime_sub(new_timestamp, - katom->start_timestamp); + timestamp_diff = ktime_sub(end_timestamp, + katom->start_timestamp); if (ktime_to_ns(timestamp_diff) >= 0) { /* Only update the timestamp if it's a better estimate * than what's currently stored. This is because our * estimate that accounts for the throttle time may be * too much of an overestimate */ - katom->start_timestamp = new_timestamp; + katom->start_timestamp = end_timestamp; } } } @@ -250,16 +244,6 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done) memset(&kbdev->slot_submit_count_irq[0], 0, sizeof(kbdev->slot_submit_count_irq)); - /* write irq throttle register, this will prevent irqs from occurring - * until the given number of gpu clock cycles have passed */ - { - int irq_throttle_cycles = - atomic_read(&kbdev->irq_throttle_cycles); - - kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_THROTTLE), - irq_throttle_cycles, NULL); - } - spin_lock_irqsave(&kbdev->hwaccess_lock, flags); while (done) { @@ -1139,10 +1123,9 @@ static void kbase_debug_dump_registers(struct kbase_device *kbdev) dev_err(kbdev->dev, " GPU_IRQ_RAWSTAT=0x%08x GPU_STATUS=0x%08x", kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), NULL), kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_STATUS), NULL)); - dev_err(kbdev->dev, " JOB_IRQ_RAWSTAT=0x%08x JOB_IRQ_JS_STATE=0x%08x JOB_IRQ_THROTTLE=0x%08x", + dev_err(kbdev->dev, " JOB_IRQ_RAWSTAT=0x%08x JOB_IRQ_JS_STATE=0x%08x", kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_RAWSTAT), NULL), - kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_JS_STATE), NULL), - kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_THROTTLE), NULL)); + kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_JS_STATE), NULL)); for (i = 0; i < 3; i++) { dev_err(kbdev->dev, " JS%d_STATUS=0x%08x JS%d_HEAD_LO=0x%08x", i, kbase_reg_read(kbdev, JOB_SLOT_REG(i, JS_STATUS), @@ -1163,6 +1146,9 @@ static void kbase_debug_dump_registers(struct kbase_device *kbdev) dev_err(kbdev->dev, " SHADER_CONFIG=0x%08x L2_MMU_CONFIG=0x%08x", kbase_reg_read(kbdev, GPU_CONTROL_REG(SHADER_CONFIG), NULL), kbase_reg_read(kbdev, GPU_CONTROL_REG(L2_MMU_CONFIG), NULL)); + dev_err(kbdev->dev, " TILER_CONFIG=0x%08x JM_CONFIG=0x%08x", + kbase_reg_read(kbdev, GPU_CONTROL_REG(TILER_CONFIG), NULL), + kbase_reg_read(kbdev, GPU_CONTROL_REG(JM_CONFIG), NULL)); } static void kbasep_reset_timeout_worker(struct work_struct *data) @@ -1264,15 +1250,16 @@ static void kbasep_reset_timeout_worker(struct work_struct *data) if (!silent) kbase_debug_dump_registers(kbdev); - /* Reset the GPU */ - kbase_pm_init_hw(kbdev, 0); - /* Complete any jobs that were still on the GPU */ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + kbdev->protected_mode = false; kbase_backend_reset(kbdev, &end_timestamp); kbase_pm_metrics_update(kbdev, NULL); spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + /* Reset the GPU */ + kbase_pm_init_hw(kbdev, 0); + mutex_unlock(&kbdev->pm.lock); mutex_lock(&js_devdata->runpool_mutex); @@ -1326,6 +1313,11 @@ static void kbasep_reset_timeout_worker(struct work_struct *data) kbase_js_sched_all(kbdev); } + /* Process any pending slot updates */ + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + kbase_backend_slot_update(kbdev); + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + kbase_pm_context_idle(kbdev); /* Release vinstr */ diff --git a/mali_kbase/backend/gpu/mali_kbase_jm_rb.c b/mali_kbase/backend/gpu/mali_kbase_jm_rb.c index d4ed3d4..418ae1f 100644 --- a/mali_kbase/backend/gpu/mali_kbase_jm_rb.c +++ b/mali_kbase/backend/gpu/mali_kbase_jm_rb.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2017 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 @@ -692,6 +692,7 @@ static void kbase_gpu_release_atom(struct kbase_device *kbdev, } katom->gpu_rb_state = KBASE_ATOM_GPU_RB_WAITING_BLOCKED; + katom->protected_state.exit = KBASE_ATOM_EXIT_PROTECTED_CHECK; } static void kbase_gpu_mark_atom_for_return(struct kbase_device *kbdev, @@ -1003,21 +1004,13 @@ static int kbase_jm_exit_protected_mode(struct kbase_device *kbdev, /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ case KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT: - if (kbase_reset_gpu_active(kbdev)) - return -EAGAIN; - - kbdev->protected_mode_transition = false; - kbdev->protected_mode = false; - KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_END(kbdev); - /* protected mode sanity checks */ - KBASE_DEBUG_ASSERT_MSG( - kbase_jd_katom_is_protected(katom[idx]) == kbase_gpu_in_protected_mode(kbdev), - "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", - kbase_jd_katom_is_protected(katom[idx]), kbase_gpu_in_protected_mode(kbdev)); - KBASE_DEBUG_ASSERT_MSG( - (kbase_jd_katom_is_protected(katom[idx]) && js == 0) || - !kbase_jd_katom_is_protected(katom[idx]), - "Protected atom on JS%d not supported", js); + /* A GPU reset is issued when exiting protected mode. Once the + * reset is done all atoms' state will also be reset. For this + * reason, if the atom is still in this state we can safely + * say that the reset has not completed i.e., we have not + * finished exiting protected mode yet. + */ + return -EAGAIN; } return 0; @@ -1297,6 +1290,18 @@ void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js, lockdep_assert_held(&kbdev->hwaccess_lock); + /* + * When a hard-stop is followed close after a soft-stop, the completion + * code may be set to STOPPED, even though the job is terminated + */ + if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_TMIX_8438)) { + if (completion_code == BASE_JD_EVENT_STOPPED && + (katom->atom_flags & + KBASE_KATOM_FLAG_BEEN_HARD_STOPPED)) { + completion_code = BASE_JD_EVENT_TERMINATED; + } + } + if ((kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_6787) || (katom->core_req & BASE_JD_REQ_SKIP_CACHE_END)) && completion_code != BASE_JD_EVENT_DONE && @@ -1492,6 +1497,9 @@ void kbase_backend_reset(struct kbase_device *kbdev, ktime_t *end_timestamp) lockdep_assert_held(&kbdev->hwaccess_lock); + /* Reset should always take the GPU out of protected mode */ + WARN_ON(kbase_gpu_in_protected_mode(kbdev)); + for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { int atom_idx = 0; int idx; @@ -1505,7 +1513,19 @@ void kbase_backend_reset(struct kbase_device *kbdev, ktime_t *end_timestamp) break; if (katom->protected_state.exit == KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT) + { KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_END(kbdev); + + /* protected mode sanity checks */ + KBASE_DEBUG_ASSERT_MSG( + kbase_jd_katom_is_protected(katom) == kbase_gpu_in_protected_mode(kbdev), + "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", + kbase_jd_katom_is_protected(katom), kbase_gpu_in_protected_mode(kbdev)); + KBASE_DEBUG_ASSERT_MSG( + (kbase_jd_katom_is_protected(katom) && js == 0) || + !kbase_jd_katom_is_protected(katom), + "Protected atom on JS%d not supported", js); + } if (katom->gpu_rb_state < KBASE_ATOM_GPU_RB_SUBMITTED) keep_in_jm_rb = true; @@ -1539,7 +1559,6 @@ void kbase_backend_reset(struct kbase_device *kbdev, ktime_t *end_timestamp) } kbdev->protected_mode_transition = false; - kbdev->protected_mode = false; } static inline void kbase_gpu_stop_atom(struct kbase_device *kbdev, diff --git a/mali_kbase/backend/gpu/mali_kbase_pm_ca.c b/mali_kbase/backend/gpu/mali_kbase_pm_ca.c index e8cd8cb..85890f1 100644 --- a/mali_kbase/backend/gpu/mali_kbase_pm_ca.c +++ b/mali_kbase/backend/gpu/mali_kbase_pm_ca.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2013-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2013-2017 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 @@ -25,6 +25,9 @@ static const struct kbase_pm_ca_policy *const policy_list[] = { &kbase_pm_ca_fixed_policy_ops, +#ifdef CONFIG_MALI_DEVFREQ + &kbase_pm_ca_devfreq_policy_ops, +#endif #if !MALI_CUSTOMER_RELEASE &kbase_pm_ca_random_policy_ops #endif diff --git a/mali_kbase/backend/gpu/mali_kbase_pm_ca_devfreq.c b/mali_kbase/backend/gpu/mali_kbase_pm_ca_devfreq.c new file mode 100644 index 0000000..66bf660 --- /dev/null +++ b/mali_kbase/backend/gpu/mali_kbase_pm_ca_devfreq.c @@ -0,0 +1,129 @@ +/* + * + * (C) COPYRIGHT 2017 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + +/* + * A core availability policy implementing core mask selection from devfreq OPPs + * + */ + +#include <mali_kbase.h> +#include <mali_kbase_pm.h> +#include <backend/gpu/mali_kbase_pm_internal.h> +#include <linux/version.h> + +void kbase_devfreq_set_core_mask(struct kbase_device *kbdev, u64 core_mask) +{ + struct kbasep_pm_ca_policy_devfreq *data = + &kbdev->pm.backend.ca_policy_data.devfreq; + unsigned long flags; + + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); + + data->cores_desired = core_mask; + + /* Disable any cores that are now unwanted */ + data->cores_enabled &= data->cores_desired; + + kbdev->pm.backend.ca_in_transition = true; + + /* If there are no cores to be powered off then power on desired cores + */ + if (!(data->cores_used & ~data->cores_desired)) { + data->cores_enabled = data->cores_desired; + kbdev->pm.backend.ca_in_transition = false; + } + + kbase_pm_update_cores_state_nolock(kbdev); + + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); + + dev_dbg(kbdev->dev, "Devfreq policy : new core mask=%llX %llX\n", + data->cores_desired, data->cores_enabled); +} + +static void devfreq_init(struct kbase_device *kbdev) +{ + struct kbasep_pm_ca_policy_devfreq *data = + &kbdev->pm.backend.ca_policy_data.devfreq; + + if (kbdev->current_core_mask) { + data->cores_enabled = kbdev->current_core_mask; + data->cores_desired = kbdev->current_core_mask; + } else { + data->cores_enabled = + kbdev->gpu_props.props.raw_props.shader_present; + data->cores_desired = + kbdev->gpu_props.props.raw_props.shader_present; + } + data->cores_used = 0; + kbdev->pm.backend.ca_in_transition = false; +} + +static void devfreq_term(struct kbase_device *kbdev) +{ +} + +static u64 devfreq_get_core_mask(struct kbase_device *kbdev) +{ + return kbdev->pm.backend.ca_policy_data.devfreq.cores_enabled; +} + +static void devfreq_update_core_status(struct kbase_device *kbdev, + u64 cores_ready, + u64 cores_transitioning) +{ + struct kbasep_pm_ca_policy_devfreq *data = + &kbdev->pm.backend.ca_policy_data.devfreq; + + lockdep_assert_held(&kbdev->hwaccess_lock); + + data->cores_used = cores_ready | cores_transitioning; + + /* If in desired state then clear transition flag */ + if (data->cores_enabled == data->cores_desired) + kbdev->pm.backend.ca_in_transition = false; + + /* If all undesired cores are now off then power on desired cores. + * The direct comparison against cores_enabled limits potential + * recursion to one level */ + if (!(data->cores_used & ~data->cores_desired) && + data->cores_enabled != data->cores_desired) { + data->cores_enabled = data->cores_desired; + + kbase_pm_update_cores_state_nolock(kbdev); + + kbdev->pm.backend.ca_in_transition = false; + } +} + +/* + * The struct kbase_pm_ca_policy structure for the devfreq core availability + * policy. + * + * This is the static structure that defines the devfreq core availability power + * policy's callback and name. + */ +const struct kbase_pm_ca_policy kbase_pm_ca_devfreq_policy_ops = { + "devfreq", /* name */ + devfreq_init, /* init */ + devfreq_term, /* term */ + devfreq_get_core_mask, /* get_core_mask */ + devfreq_update_core_status, /* update_core_status */ + 0u, /* flags */ + KBASE_PM_CA_POLICY_ID_DEVFREQ, /* id */ +}; + diff --git a/mali_kbase/backend/gpu/mali_kbase_pm_ca_devfreq.h b/mali_kbase/backend/gpu/mali_kbase_pm_ca_devfreq.h new file mode 100644 index 0000000..7ab3cd4 --- /dev/null +++ b/mali_kbase/backend/gpu/mali_kbase_pm_ca_devfreq.h @@ -0,0 +1,55 @@ +/* + * + * (C) COPYRIGHT 2017 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + +/* + * A core availability policy for use with devfreq, where core masks are + * associated with OPPs. + */ + +#ifndef MALI_KBASE_PM_CA_DEVFREQ_H +#define MALI_KBASE_PM_CA_DEVFREQ_H + +/** + * struct kbasep_pm_ca_policy_devfreq - Private structure for devfreq ca policy + * + * This contains data that is private to the devfreq core availability + * policy. + * + * @cores_desired: Cores that the policy wants to be available + * @cores_enabled: Cores that the policy is currently returning as available + * @cores_used: Cores currently powered or transitioning + */ +struct kbasep_pm_ca_policy_devfreq { + u64 cores_desired; + u64 cores_enabled; + u64 cores_used; +}; + +extern const struct kbase_pm_ca_policy kbase_pm_ca_devfreq_policy_ops; + +/** + * kbase_devfreq_set_core_mask - Set core mask for policy to use + * @kbdev: Device pointer + * @core_mask: New core mask + * + * The new core mask will have immediate effect if the GPU is powered, or will + * take effect when it is next powered on. + */ +void kbase_devfreq_set_core_mask(struct kbase_device *kbdev, u64 core_mask); + +#endif /* MALI_KBASE_PM_CA_DEVFREQ_H */ + diff --git a/mali_kbase/backend/gpu/mali_kbase_pm_defs.h b/mali_kbase/backend/gpu/mali_kbase_pm_defs.h index 632ef12..352744e 100644 --- a/mali_kbase/backend/gpu/mali_kbase_pm_defs.h +++ b/mali_kbase/backend/gpu/mali_kbase_pm_defs.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2017 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 @@ -23,6 +23,7 @@ #define _KBASE_PM_HWACCESS_DEFS_H_ #include "mali_kbase_pm_ca_fixed.h" +#include "mali_kbase_pm_ca_devfreq.h" #if !MALI_CUSTOMER_RELEASE #include "mali_kbase_pm_ca_random.h" #endif @@ -131,6 +132,7 @@ union kbase_pm_policy_data { union kbase_pm_ca_policy_data { struct kbasep_pm_ca_policy_fixed fixed; + struct kbasep_pm_ca_policy_devfreq devfreq; #if !MALI_CUSTOMER_RELEASE struct kbasep_pm_ca_policy_random random; #endif @@ -410,6 +412,7 @@ struct kbase_pm_policy { enum kbase_pm_ca_policy_id { KBASE_PM_CA_POLICY_ID_FIXED = 1, + KBASE_PM_CA_POLICY_ID_DEVFREQ, KBASE_PM_CA_POLICY_ID_RANDOM }; diff --git a/mali_kbase/backend/gpu/mali_kbase_pm_driver.c b/mali_kbase/backend/gpu/mali_kbase_pm_driver.c index 55763a8..ac63aa5 100644 --- a/mali_kbase/backend/gpu/mali_kbase_pm_driver.c +++ b/mali_kbase/backend/gpu/mali_kbase_pm_driver.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 @@ -1223,6 +1223,10 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev) kbdev->hw_quirks_sc |= SC_LS_ALLOW_ATTR_TYPES; } + if (!kbdev->hw_quirks_sc) + kbdev->hw_quirks_sc = kbase_reg_read(kbdev, + GPU_CONTROL_REG(SHADER_CONFIG), NULL); + kbdev->hw_quirks_tiler = kbase_reg_read(kbdev, GPU_CONTROL_REG(TILER_CONFIG), NULL); @@ -1251,7 +1255,7 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev) kbdev->hw_quirks_mmu |= L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY; } - kbdev->hw_quirks_jm = JM_CONFIG_UNUSED; + kbdev->hw_quirks_jm = 0; /* Only for T86x/T88x-based products after r2p0 */ if (prod_id >= 0x860 && prod_id <= 0x880 && major >= 2) { @@ -1273,7 +1277,7 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev) } /* Aggregate to one integer. */ - kbdev->hw_quirks_jm = (jm_values[0] ? + kbdev->hw_quirks_jm |= (jm_values[0] ? JM_TIMESTAMP_OVERRIDE : 0); kbdev->hw_quirks_jm |= (jm_values[1] ? JM_CLOCK_GATE_OVERRIDE : 0); @@ -1296,12 +1300,16 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev) */ if (coherency_features == COHERENCY_FEATURE_BIT(COHERENCY_ACE)) { - kbdev->hw_quirks_jm = + kbdev->hw_quirks_jm |= (COHERENCY_ACE_LITE | COHERENCY_ACE) << JM_FORCE_COHERENCY_FEATURES_SHIFT; } } + if (!kbdev->hw_quirks_jm) + kbdev->hw_quirks_jm = kbase_reg_read(kbdev, + GPU_CONTROL_REG(JM_CONFIG), NULL); + #ifdef CONFIG_MALI_CORESTACK #define MANUAL_POWER_CONTROL ((u32)(1 << 8)) kbdev->hw_quirks_jm |= MANUAL_POWER_CONTROL; @@ -1310,9 +1318,8 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev) static void kbase_pm_hw_issues_apply(struct kbase_device *kbdev) { - if (kbdev->hw_quirks_sc) - kbase_reg_write(kbdev, GPU_CONTROL_REG(SHADER_CONFIG), - kbdev->hw_quirks_sc, NULL); + kbase_reg_write(kbdev, GPU_CONTROL_REG(SHADER_CONFIG), + kbdev->hw_quirks_sc, NULL); kbase_reg_write(kbdev, GPU_CONTROL_REG(TILER_CONFIG), kbdev->hw_quirks_tiler, NULL); @@ -1320,10 +1327,8 @@ static void kbase_pm_hw_issues_apply(struct kbase_device *kbdev) kbase_reg_write(kbdev, GPU_CONTROL_REG(L2_MMU_CONFIG), kbdev->hw_quirks_mmu, NULL); - - if (kbdev->hw_quirks_jm != JM_CONFIG_UNUSED) - kbase_reg_write(kbdev, GPU_CONTROL_REG(JM_CONFIG), - kbdev->hw_quirks_jm, NULL); + kbase_reg_write(kbdev, GPU_CONTROL_REG(JM_CONFIG), + kbdev->hw_quirks_jm, NULL); } diff --git a/mali_kbase/ipa/Kbuild b/mali_kbase/ipa/Kbuild index 7551f9e..b3f8761 100644 --- a/mali_kbase/ipa/Kbuild +++ b/mali_kbase/ipa/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2016 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2016-2017 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 @@ -13,7 +13,8 @@ # +mali_kbase-y += \ + ipa/mali_kbase_ipa_simple.o \ + ipa/mali_kbase_ipa.o -IPA = \ - ipa/mali_kbase_ipa_generic.c \ - ipa/mali_kbase_ipa.c +mali_kbase-$(CONFIG_DEBUG_FS) += ipa/mali_kbase_ipa_debugfs.o diff --git a/mali_kbase/ipa/mali_kbase_ipa.c b/mali_kbase/ipa/mali_kbase_ipa.c index dd0f1d6..d289ea8 100644 --- a/mali_kbase/ipa/mali_kbase_ipa.c +++ b/mali_kbase/ipa/mali_kbase_ipa.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2016-2017 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 @@ -14,25 +14,57 @@ */ -#include <linux/sysfs.h> #include <linux/thermal.h> #include <linux/devfreq_cooling.h> #include <linux/of.h> #include "mali_kbase.h" +#include "mali_kbase_ipa.h" +#include "mali_kbase_ipa_debugfs.h" + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) +#include <linux/pm_opp.h> +#else +#include <linux/opp.h> +#define dev_pm_opp_find_freq_exact opp_find_freq_exact +#define dev_pm_opp_get_voltage opp_get_voltage +#define dev_pm_opp opp +#endif + +#define KBASE_IPA_FALLBACK_MODEL_NAME "mali-simple-power-model" + +int kbase_ipa_model_recalculate(struct kbase_ipa_model *model) +{ + int err = 0; + + lockdep_assert_held(&model->kbdev->ipa.lock); + + if (model->ops->recalculate) { + err = model->ops->recalculate(model); + if (err) { + dev_err(model->kbdev->dev, + "recalculation of power model %s returned error %d\n", + model->ops->name, err); + } + } + + return err; +} int kbase_ipa_model_ops_register(struct kbase_device *kbdev, struct kbase_ipa_model_ops *new_model_ops) { struct kbase_ipa_model *new_model; + lockdep_assert_held(&kbdev->ipa.lock); + new_model = kzalloc(sizeof(struct kbase_ipa_model), GFP_KERNEL); if (!new_model) return -ENOMEM; - INIT_LIST_HEAD(&new_model->link); + new_model->kbdev = kbdev; new_model->ops = new_model_ops; - list_add(&new_model->link, &kbdev->ipa_power_models); + list_add(&new_model->link, &kbdev->ipa.power_models); return 0; } @@ -41,8 +73,10 @@ static int kbase_ipa_internal_models_append_list(struct kbase_device *kbdev) { int err; - /* Always have the generic IPA */ - err = kbase_ipa_model_ops_register(kbdev, &kbase_generic_ipa_model_ops); + INIT_LIST_HEAD(&kbdev->ipa.power_models); + + /* Always have the simple IPA model */ + err = kbase_ipa_model_ops_register(kbdev, &kbase_simple_ipa_model_ops); if (err) return err; @@ -56,7 +90,9 @@ struct kbase_ipa_model *kbase_ipa_get_model(struct kbase_device *kbdev, /* Search registered power models first */ struct list_head *it; - list_for_each(it, &kbdev->ipa_power_models) { + lockdep_assert_held(&kbdev->ipa.lock); + + list_for_each(it, &kbdev->ipa.power_models) { struct kbase_ipa_model *model = list_entry(it, struct kbase_ipa_model, @@ -70,17 +106,13 @@ struct kbase_ipa_model *kbase_ipa_get_model(struct kbase_device *kbdev, void kbase_ipa_model_use_fallback_locked(struct kbase_device *kbdev) { - lockdep_assert_held(&kbdev->hwaccess_lock); - if (kbdev->ipa_current_model != kbdev->ipa_fallback_model) - kbdev->ipa_current_model = kbdev->ipa_fallback_model; + atomic_set(&kbdev->ipa_use_configured_model, false); } void kbase_ipa_model_use_configured_locked(struct kbase_device *kbdev) { - lockdep_assert_held(&kbdev->hwaccess_lock); - if (kbdev->ipa_current_model != kbdev->ipa_configured_model) - kbdev->ipa_current_model = kbdev->ipa_configured_model; + atomic_set(&kbdev->ipa_use_configured_model, true); } const char *kbase_ipa_model_name_from_id(u32 gpu_id) @@ -91,41 +123,218 @@ const char *kbase_ipa_model_name_from_id(u32 gpu_id) if (GPU_ID_IS_NEW_FORMAT(prod_id)) { switch (GPU_ID2_MODEL_MATCH_VALUE(prod_id)) { case GPU_ID2_PRODUCT_TMIX: - return "generic_ipa_model"; + return KBASE_IPA_FALLBACK_MODEL_NAME; default: - return "generic_ipa_model"; + return KBASE_IPA_FALLBACK_MODEL_NAME; } } - return "generic_ipa_model"; + return KBASE_IPA_FALLBACK_MODEL_NAME; +} + +static struct device_node *get_model_dt_node(struct kbase_ipa_model *model) +{ + struct device_node *model_dt_node; + char compat_string[64]; + + snprintf(compat_string, sizeof(compat_string), "arm,%s", + model->ops->name); + + model_dt_node = of_find_compatible_node(model->kbdev->dev->of_node, + NULL, compat_string); + if (!model_dt_node) { + dev_warn(model->kbdev->dev, + "Couldn't find power_model DT node matching \'%s\'\n", + compat_string); + } + + return model_dt_node; +} + +int kbase_ipa_model_add_param_u32_def(struct kbase_ipa_model *model, + const char *name, u32 *addr, + bool has_default, u32 default_value) +{ + int err; + struct device_node *model_dt_node = get_model_dt_node(model); + + err = of_property_read_u32(model_dt_node, name, addr); + + if (err && !has_default) { + dev_err(model->kbdev->dev, + "No DT entry or default found for %s.%s, err = %d\n", + model->ops->name, name, err); + goto exit; + } else if (err && has_default) { + *addr = default_value; + dev_dbg(model->kbdev->dev, "%s.%s = %u (default)\n", + model->ops->name, name, *addr); + err = 0; + } else /* !err */ { + dev_dbg(model->kbdev->dev, "%s.%s = %u (DT)\n", + model->ops->name, name, *addr); + } + + err = kbase_ipa_model_param_add(model, name, addr, sizeof(u32), + PARAM_TYPE_U32); +exit: + return err; +} + +int kbase_ipa_model_add_param_s32_array(struct kbase_ipa_model *model, + const char *name, s32 *addr, + size_t num_elems) +{ + int err, i; + struct device_node *model_dt_node = get_model_dt_node(model); + + err = of_property_read_u32_array(model_dt_node, name, addr, num_elems); + + if (err) { + dev_err(model->kbdev->dev, + "No DT entry found for %s.%s, err = %d\n", + model->ops->name, name, err); + goto exit; + } else { + for (i = 0; i < num_elems; ++i) + dev_dbg(model->kbdev->dev, "%s.%s[%u] = %d (DT)\n", + model->ops->name, name, i, *(addr + i)); + } + + /* Create a unique debugfs entry for each element */ + for (i = 0; i < num_elems; ++i) { + char elem_name[32]; + + snprintf(elem_name, sizeof(elem_name), "%s.%d", name, i); + err = kbase_ipa_model_param_add(model, elem_name, &addr[i], + sizeof(s32), PARAM_TYPE_S32); + if (err) + goto exit; + } +exit: + return err; +} + +int kbase_ipa_model_add_param_string(struct kbase_ipa_model *model, + const char *name, char *addr, + size_t len) +{ + int err; + struct device_node *model_dt_node = get_model_dt_node(model); + const char *string_prop_value; + + err = of_property_read_string(model_dt_node, name, + &string_prop_value); + if (err) { + dev_err(model->kbdev->dev, + "No DT entry found for %s.%s, err = %d\n", + model->ops->name, name, err); + goto exit; + } else { + strncpy(addr, string_prop_value, len); + dev_dbg(model->kbdev->dev, "%s.%s = \'%s\' (DT)\n", + model->ops->name, name, string_prop_value); + } + + err = kbase_ipa_model_param_add(model, name, addr, len, + PARAM_TYPE_STRING); +exit: + return err; } -int kbase_ipa_model_init(struct kbase_device *kbdev) +static void term_model(struct kbase_ipa_model *model) +{ + if (!model) + return; + + lockdep_assert_held(&model->kbdev->ipa.lock); + + if (model->ops->term) + model->ops->term(model); + + kbase_ipa_model_param_free_all(model); +} + +static struct kbase_ipa_model *init_model(struct kbase_device *kbdev, + const char *model_name) +{ + struct kbase_ipa_model *model; + int err; + + lockdep_assert_held(&kbdev->ipa.lock); + + model = kbase_ipa_get_model(kbdev, model_name); + if (!model) { + dev_err(kbdev->dev, "power model \'%s\' not found\n", + model_name); + return NULL; + } + + INIT_LIST_HEAD(&model->params); + + err = model->ops->init(model); + if (err) { + dev_err(kbdev->dev, + "init of power model \'%s\' returned error %d\n", + model_name, err); + term_model(model); + return NULL; + } + + err = kbase_ipa_model_recalculate(model); + if (err) { + term_model(model); + return NULL; + } + + return model; +} + +static void kbase_ipa_term_locked(struct kbase_device *kbdev) +{ + lockdep_assert_held(&kbdev->ipa.lock); + + /* Clean up the models */ + if (kbdev->ipa.configured_model != kbdev->ipa.fallback_model) + term_model(kbdev->ipa.configured_model); + term_model(kbdev->ipa.fallback_model); + + /* Clean up the list */ + if (!list_empty(&kbdev->ipa.power_models)) { + struct kbase_ipa_model *model_p, *model_n; + + list_for_each_entry_safe(model_p, model_n, &kbdev->ipa.power_models, link) { + list_del(&model_p->link); + kfree(model_p); + } + } +} + +int kbase_ipa_init(struct kbase_device *kbdev) { const char *model_name; struct kbase_ipa_model *default_model = NULL; - struct kbase_ipa_model *model = NULL; int err; + mutex_init(&kbdev->ipa.lock); + /* + * Lock during init to avoid warnings from lockdep_assert_held (there + * shouldn't be any concurrent access yet). + */ + mutex_lock(&kbdev->ipa.lock); + /* Add default ones to the list */ err = kbase_ipa_internal_models_append_list(kbdev); - default_model = kbase_ipa_get_model(kbdev, "generic_ipa_model"); - /* The generic_ipa_model 'MUST' always be present.*/ + /* The simple IPA model must *always* be present.*/ + default_model = init_model(kbdev, KBASE_IPA_FALLBACK_MODEL_NAME); if (!default_model) { err = -EINVAL; goto end; } - err = default_model->ops->init(default_model); - if (err) { - dev_err(kbdev->dev, - "failed to init default generic power model err %d\n", - err); - goto end; - } - kbdev->ipa_fallback_model = default_model; + kbdev->ipa.fallback_model = default_model; err = of_property_read_string(kbdev->dev->of_node, "ipa-model", &model_name); @@ -137,63 +346,43 @@ int kbase_ipa_model_init(struct kbase_device *kbdev) model_name = kbase_ipa_model_name_from_id(gpu_id); } - if (strcmp("generic_ipa_model", model_name) != 0) { - - model = kbase_ipa_get_model(kbdev, model_name); - kbdev->ipa_configured_model = model; - - if (model) { - kbdev->ipa_current_model = model; - err = model->ops->init(model); + if (strcmp(KBASE_IPA_FALLBACK_MODEL_NAME, model_name) != 0) { + kbdev->ipa.configured_model = init_model(kbdev, model_name); + if (!kbdev->ipa.configured_model) { + err = -EINVAL; goto end; } - dev_err(kbdev->dev, - "Failed to find IPA model matching: %s\n", - model_name); - err = -EINVAL; } else { - - kbdev->ipa_current_model = default_model; - kbdev->ipa_configured_model = default_model; - dev_dbg(kbdev->dev, "Using generic-ipa-model by default\n"); + kbdev->ipa.configured_model = default_model; err = 0; } + + kbase_ipa_model_use_configured_locked(kbdev); + end: if (err) - kbase_ipa_model_term(kbdev); - + kbase_ipa_term_locked(kbdev); + else + dev_info(kbdev->dev, + "Using configured power model %s, and fallback %s\n", + kbdev->ipa.fallback_model->ops->name, + kbdev->ipa.configured_model->ops->name); + + mutex_unlock(&kbdev->ipa.lock); return err; } -void kbase_ipa_model_term(struct kbase_device *kbdev) +void kbase_ipa_term(struct kbase_device *kbdev) { - /* Clean up the models */ - struct kbase_ipa_model *model = kbdev->ipa_configured_model; - - if (model) { - if (model->ops->term) - model->ops->term(model); - /* Always terminate the default model, - * unless it was the configured model */ - if (model != kbdev->ipa_fallback_model) - kbdev->ipa_fallback_model->ops->term(model); - } - /* Clean up the list */ - if (!list_empty(&kbdev->ipa_power_models)) { - struct kbase_ipa_model *model_p, *model_n; - - list_for_each_entry_safe(model_p, model_n, &kbdev->ipa_power_models, link) { - list_del(&model_p->link); - kfree(model_p); - } - } - + mutex_lock(&kbdev->ipa.lock); + kbase_ipa_term_locked(kbdev); + mutex_unlock(&kbdev->ipa.lock); } /** - * kbase_scale_power() - Scale a model-specific power coefficient to an OPP - * @c: Model coefficient, in pW/(Hz V^2). Should be in range - * 0 < c < 2^16 to prevent overflow. + * kbase_scale_dynamic_power() - Scale a dynamic power coefficient to an OPP + * @c: Dynamic model coefficient, in pW/(Hz V^2). Should be in range + * 0 < c < 2^26 to prevent overflow. * @freq: Frequency, in Hz. Range: 2^23 < freq < 2^30 (~8MHz to ~1GHz) * @voltage: Voltage, in mV. Range: 2^9 < voltage < 2^13 (~0.5V to ~8V) * @@ -204,9 +393,9 @@ void kbase_ipa_model_term(struct kbase_device *kbdev) * * Return: Power consumption, in mW. Range: 0 < p < 2^13 (0W to ~8W) */ -static inline unsigned long kbase_scale_power(const unsigned long c, - const unsigned long freq, - const unsigned long voltage) +static inline unsigned long kbase_scale_dynamic_power(const unsigned long c, + const unsigned long freq, + const unsigned long voltage) { /* Range: 2^8 < v2 < 2^16 m(V^2) */ const unsigned long v2 = (voltage * voltage) / 1000; @@ -220,38 +409,89 @@ static inline unsigned long kbase_scale_power(const unsigned long c, /* Range: 2^1 < v2f < 2^16 MHz V^2 */ const unsigned long v2f = v2f_big / 1000; - /* Range (working backwards from next line): 0 < v2fc < 2^23 uW */ - const unsigned long v2fc = c * v2f; + /* Range (working backwards from next line): 0 < v2fc < 2^23 uW. + * Must be < 2^42 to avoid overflowing the return value. */ + const u64 v2fc = (u64) c * (u64) v2f; /* Range: 0 < v2fc / 1000 < 2^13 mW */ return v2fc / 1000; } +/** + * kbase_scale_static_power() - Scale a static power coefficient to an OPP + * @c: Static model coefficient, in uW/V^3. Should be in range + * 0 < c < 2^32 to prevent overflow. + * @voltage: Voltage, in mV. Range: 2^9 < voltage < 2^13 (~0.5V to ~8V) + * + * Return: Power consumption, in mW. Range: 0 < p < 2^13 (0W to ~8W) + */ +unsigned long kbase_scale_static_power(const unsigned long c, + const unsigned long voltage) +{ + /* Range: 2^8 < v2 < 2^16 m(V^2) */ + const unsigned long v2 = (voltage * voltage) / 1000; + + /* Range: 2^17 < v3_big < 2^29 m(V^2) mV */ + const unsigned long v3_big = v2 * voltage; + + /* Range: 2^7 < v3 < 2^19 m(V^3) */ + const unsigned long v3 = v3_big / 1000; + + /* + * Range (working backwards from next line): 0 < v3c_big < 2^33 nW. + * The result should be < 2^52 to avoid overflowing the return value. + */ + const u64 v3c_big = (u64) c * (u64) v3; + + /* Range: 0 < v3c_big / 1000000 < 2^13 mW */ + return v3c_big / 1000000; +} + +static struct kbase_ipa_model *get_current_model(struct kbase_device *kbdev) +{ + lockdep_assert_held(&kbdev->ipa.lock); + + if (atomic_read(&kbdev->ipa_use_configured_model)) + return kbdev->ipa.configured_model; + else + return kbdev->ipa.fallback_model; +} + #ifdef CONFIG_MALI_PWRSOFT_765 static unsigned long kbase_get_static_power(struct devfreq *df, unsigned long voltage) #else static unsigned long kbase_get_static_power(unsigned long voltage) - #endif { struct kbase_ipa_model *model; + unsigned long power_coeff = 0, power = 0; #ifdef CONFIG_MALI_PWRSOFT_765 struct kbase_device *kbdev = dev_get_drvdata(&df->dev); #else struct kbase_device *kbdev = kbase_find_device(-1); #endif - /* We make sure that the model we access is the correct one */ - model = ACCESS_ONCE(kbdev->ipa_current_model); + mutex_lock(&kbdev->ipa.lock); + + model = get_current_model(kbdev); + + if (model) { + power_coeff = model->ops->get_static_power(model); + power = kbase_scale_static_power(power_coeff, voltage); + } else { + dev_err(kbdev->dev, "%s: No current IPA model set", __func__); + } + + kbdev->ipa.last_static_power_coeff = power_coeff; + + mutex_unlock(&kbdev->ipa.lock); #ifndef CONFIG_MALI_PWRSOFT_765 kbase_release_device(kbdev); #endif - if (model) - return model->ops->get_static_power(model, voltage); - return 0; + return power; } #ifdef CONFIG_MALI_PWRSOFT_765 @@ -264,43 +504,83 @@ static unsigned long kbase_get_dynamic_power(unsigned long freq, #endif { struct kbase_ipa_model *model; + unsigned long power_coeff = 0, power = 0; #ifdef CONFIG_MALI_PWRSOFT_765 struct kbase_device *kbdev = dev_get_drvdata(&df->dev); #else struct kbase_device *kbdev = kbase_find_device(-1); #endif - /* We make sure that the model we access is the correct one */ - model = ACCESS_ONCE(kbdev->ipa_current_model); + mutex_lock(&kbdev->ipa.lock); -#ifndef CONFIG_MALI_PWRSOFT_765 - kbase_release_device(kbdev); -#endif + model = get_current_model(kbdev); if (model) { - const unsigned long c = model->ops->get_dynamic_power(model); - - return kbase_scale_power(c, freq, voltage); + power_coeff = model->ops->get_dynamic_power(model); + power = kbase_scale_dynamic_power(power_coeff, freq, voltage); + } else { + dev_err(kbdev->dev, "%s: No current IPA model set", __func__); } - return 0; + kbdev->ipa.last_model_dyn_power_coeff = power_coeff; + + mutex_unlock(&kbdev->ipa.lock); + +#ifndef CONFIG_MALI_PWRSOFT_765 + kbase_release_device(kbdev); +#endif + + return power; } -#ifdef CONFIG_MALI_PWRSOFT_765 unsigned long kbase_power_to_state(struct devfreq *df, u32 target_power) { - struct kbase_ipa_model *model; struct kbase_device *kbdev = dev_get_drvdata(&df->dev); + struct device *dev = df->dev.parent; + unsigned long i, state = -1; + unsigned long dyn_coeff, static_coeff; - /* We make sure that the model we access is the correct one */ - model = ACCESS_ONCE(kbdev->ipa_current_model); + mutex_lock(&kbdev->ipa.lock); - if (model && model->ops->power_to_state) - return model->ops->power_to_state(model, target_power); + dyn_coeff = kbdev->ipa.last_model_dyn_power_coeff; + static_coeff = kbdev->ipa.last_static_power_coeff; - return 0; + mutex_unlock(&kbdev->ipa.lock); + + /* OPPs are sorted from highest frequency to lowest */ + for (i = 0; i < df->profile->max_state - 1; i++) { + struct dev_pm_opp *opp; + unsigned int freq; + unsigned long dyn_power, static_power, voltage; + + freq = df->profile->freq_table[i]; /* Hz */ + + rcu_read_lock(); + opp = dev_pm_opp_find_freq_exact(dev, freq, true); + /* Allow unavailable frequencies too in case we can enable a + * higher one. */ + if (PTR_ERR(opp) == -ERANGE) + opp = dev_pm_opp_find_freq_exact(dev, freq, false); + + if (IS_ERR(opp)) { + rcu_read_unlock(); + return PTR_ERR(opp); + } + + voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ + rcu_read_unlock(); + + dyn_power = kbase_scale_dynamic_power(dyn_coeff, freq, voltage); + static_power = kbase_scale_static_power(static_coeff, voltage); + + if (target_power >= dyn_power + static_power) + break; + } + state = i; + + return state; } -#endif +KBASE_EXPORT_TEST_API(kbase_power_to_state); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) struct devfreq_cooling_ops power_model_ops = { @@ -309,6 +589,9 @@ struct devfreq_cooling_power power_model_ops = { #endif .get_static_power = &kbase_get_static_power, .get_dynamic_power = &kbase_get_dynamic_power, +#ifdef CONFIG_MALI_PWRSOFT_765 + .power2state = &kbase_power_to_state, +#endif }; unsigned long kbase_ipa_dynamic_power(struct kbase_device *kbdev, @@ -323,5 +606,17 @@ unsigned long kbase_ipa_dynamic_power(struct kbase_device *kbdev, return kbase_get_dynamic_power(freq, voltage); #endif } - KBASE_EXPORT_TEST_API(kbase_ipa_dynamic_power); + +unsigned long kbase_ipa_static_power(struct kbase_device *kbdev, + unsigned long voltage) +{ +#ifdef CONFIG_MALI_PWRSOFT_765 + struct devfreq *df = kbdev->devfreq; + + return kbase_get_static_power(df, voltage); +#else + return kbase_get_static_power(voltage); +#endif +} +KBASE_EXPORT_TEST_API(kbase_ipa_static_power); diff --git a/mali_kbase/ipa/mali_kbase_ipa.h b/mali_kbase/ipa/mali_kbase_ipa.h index 67e0270..540d34a 100644 --- a/mali_kbase/ipa/mali_kbase_ipa.h +++ b/mali_kbase/ipa/mali_kbase_ipa.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2016-2017 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 @@ -23,53 +23,92 @@ struct kbase_ipa_model { struct kbase_device *kbdev; void *model_data; struct kbase_ipa_model_ops *ops; + struct list_head params; }; +int kbase_ipa_model_add_param_u32_def(struct kbase_ipa_model *model, + const char *name, u32 *addr, + bool has_default, u32 default_value); + +int kbase_ipa_model_add_param_s32_array(struct kbase_ipa_model *model, + const char *name, s32 *addr, + size_t num_elems); + +int kbase_ipa_model_add_param_string(struct kbase_ipa_model *model, + const char *name, char *addr, + size_t len); + +#define kbase_ipa_model_add_param_u32(MODEL, NAME, ADDR) \ + kbase_ipa_model_add_param_u32_def((MODEL), (NAME), (ADDR), \ + false, 0) + struct kbase_ipa_model_ops { char *name; - /* The init and term ops on the default model are always called. - * However, all the other models are only invoked if the model + /* The init, recalculate and term ops on the default model are always + * called. However, all the other models are only invoked if the model * is selected in the device tree. Otherwise they are never - * initialized. Additional resources can be acquired by models - * in init(), however they must be terminated in the term(). + * initialized. Additional resources can be acquired by models in + * init(), however they must be terminated in the term(). */ int (*init)(struct kbase_ipa_model *model); + /* Called immediately after init(), or when a parameter is changed, so + * that any coefficients derived from model parameters can be + * recalculated. */ + int (*recalculate)(struct kbase_ipa_model *model); void (*term)(struct kbase_ipa_model *model); /* get_dynamic_power() - return a coefficient with units pW/(Hz V^2), * which is scaled by the IPA framework according to the current OPP's * frequency and voltage. */ unsigned long (*get_dynamic_power)(struct kbase_ipa_model *model); - /* get_static_power() - return an estimate of the current static power - * consumption, in mW, based on the current OPP's voltage, in mV. */ - unsigned long (*get_static_power)(struct kbase_ipa_model *model, - unsigned long voltage); - unsigned long (*power_to_state)(struct kbase_ipa_model *model, - unsigned long power); + /* get_static_power() - return a coefficient with units uW/(V^3), + * which is scaled by the IPA framework according to the current OPP's + * voltage. */ + unsigned long (*get_static_power)(struct kbase_ipa_model *model); }; /* Models can be registered only in the platform's platform_init_func call */ int kbase_ipa_model_ops_register(struct kbase_device *kbdev, struct kbase_ipa_model_ops *new_model_ops); -int kbase_ipa_model_init(struct kbase_device *kbdev); -void kbase_ipa_model_term(struct kbase_device *kbdev); +int kbase_ipa_init(struct kbase_device *kbdev); +void kbase_ipa_term(struct kbase_device *kbdev); void kbase_ipa_model_use_fallback_locked(struct kbase_device *kbdev); void kbase_ipa_model_use_configured_locked(struct kbase_device *kbdev); +int kbase_ipa_model_recalculate(struct kbase_ipa_model *model); -extern struct kbase_ipa_model_ops kbase_generic_ipa_model_ops; +extern struct kbase_ipa_model_ops kbase_simple_ipa_model_ops; /** - * kbase_ipa_dynamic_power - calculate power - * @kbdev: kbase device - * @freq: frequency in Hz - * @voltage: voltage in mV + * kbase_ipa_dynamic_power() - Calculate dynamic power component + * @kbdev: Pointer to kbase device. + * @freq: Frequency, in Hz. + * @voltage: Voltage, in mV. * - * Return: returns power consumption + * Return: Dynamic power consumption, in mW. */ unsigned long kbase_ipa_dynamic_power(struct kbase_device *kbdev, - unsigned long freq, - unsigned long voltage); + unsigned long freq, + unsigned long voltage); + +/** + * kbase_ipa_static_power() - Calculate static power component + * @kbdev: Pointer to kbase device. + * @voltage: Voltage, in mV. + * + * Return: Static power consumption, in mW. + */ +unsigned long kbase_ipa_static_power(struct kbase_device *kbdev, + unsigned long voltage); +/** + * kbase_power_to_state() - Find the OPP which consumes target_power + * @df: Pointer to devfreq device. + * @target_power: Maximum power consumption, in mW. + * + * Return: The index of the most performant OPP whose power consumption is less + * than target_power. + */ +unsigned long kbase_power_to_state(struct devfreq *df, u32 target_power); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) extern struct devfreq_cooling_ops power_model_ops; diff --git a/mali_kbase/ipa/mali_kbase_ipa_debugfs.c b/mali_kbase/ipa/mali_kbase_ipa_debugfs.c new file mode 100644 index 0000000..78bdcef --- /dev/null +++ b/mali_kbase/ipa/mali_kbase_ipa_debugfs.c @@ -0,0 +1,237 @@ +/* + * + * (C) COPYRIGHT 2017 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + +#include <linux/debugfs.h> +#include <linux/list.h> +#include <linux/mutex.h> + +#include "mali_kbase.h" +#include "mali_kbase_ipa.h" +#include "mali_kbase_ipa_debugfs.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) +#define DEFINE_DEBUGFS_ATTRIBUTE DEFINE_SIMPLE_ATTRIBUTE +#endif + +struct kbase_ipa_model_param { + char *name; + union { + void *voidp; + u32 *u32p; + s32 *s32p; + char *str; + } addr; + size_t size; + enum kbase_ipa_model_param_type type; + struct kbase_ipa_model *model; + struct list_head link; +}; + +static int param_int_get(void *data, u64 *val) +{ + struct kbase_ipa_model_param *param = data; + + mutex_lock(¶m->model->kbdev->ipa.lock); + if (param->type == PARAM_TYPE_S32) + *(s64 *) val = *param->addr.s32p; + else + *val = *param->addr.u32p; + mutex_unlock(¶m->model->kbdev->ipa.lock); + + return 0; +} + +static int param_int_set(void *data, u64 val) +{ + struct kbase_ipa_model_param *param = data; + struct kbase_ipa_model *model = param->model; + s64 sval = (s64) val; + int err = 0; + + switch (param->type) { + case PARAM_TYPE_U32: + if (sval < 0 || val > U32_MAX) + return -ERANGE; + break; + case PARAM_TYPE_S32: + if (sval < S32_MIN || sval > S32_MAX) + return -ERANGE; + break; + default: + return -EINVAL; + } + + mutex_lock(¶m->model->kbdev->ipa.lock); + *param->addr.u32p = val; + err = kbase_ipa_model_recalculate(model); + mutex_unlock(¶m->model->kbdev->ipa.lock); + + return err; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, param_int_get, param_int_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_s32, param_int_get, param_int_set, "%lld\n"); + +static ssize_t param_string_get(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct kbase_ipa_model_param *param = file->private_data; + ssize_t ret; + size_t len; + + mutex_lock(¶m->model->kbdev->ipa.lock); + len = strnlen(param->addr.str, param->size - 1) + 1; + ret = simple_read_from_buffer(user_buf, count, ppos, + param->addr.str, len); + mutex_unlock(¶m->model->kbdev->ipa.lock); + + return ret; +} + +static ssize_t param_string_set(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct kbase_ipa_model_param *param = file->private_data; + struct kbase_ipa_model *model = param->model; + ssize_t ret = count; + size_t buf_size; + int err; + + mutex_lock(&model->kbdev->ipa.lock); + + if (count > param->size) { + ret = -EINVAL; + goto end; + } + + buf_size = min(param->size - 1, count); + if (copy_from_user(param->addr.str, user_buf, buf_size)) { + ret = -EFAULT; + goto end; + } + + param->addr.str[buf_size] = '\0'; + + err = kbase_ipa_model_recalculate(model); + if (err < 0) + ret = err; + +end: + mutex_unlock(&model->kbdev->ipa.lock); + + return ret; +} + +static const struct file_operations fops_string = { + .read = param_string_get, + .write = param_string_set, + .open = simple_open, + .llseek = default_llseek, +}; + +int kbase_ipa_model_param_add(struct kbase_ipa_model *model, const char *name, + void *addr, size_t size, + enum kbase_ipa_model_param_type type) +{ + struct kbase_ipa_model_param *param; + + param = kzalloc(sizeof(*param), GFP_KERNEL); + + if (!param) + return -ENOMEM; + + /* 'name' is stack-allocated for array elements, so copy it into + * heap-allocated storage */ + param->name = kstrdup(name, GFP_KERNEL); + param->addr.voidp = addr; + param->size = size; + param->type = type; + param->model = model; + + list_add(¶m->link, &model->params); + + return 0; +} + +void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model) +{ + struct kbase_ipa_model_param *param_p, *param_n; + + list_for_each_entry_safe(param_p, param_n, &model->params, link) { + list_del(¶m_p->link); + kfree(param_p->name); + kfree(param_p); + } +} + +static void kbase_ipa_model_debugfs_init(struct kbase_ipa_model *model) +{ + struct list_head *it; + struct dentry *dir; + + lockdep_assert_held(&model->kbdev->ipa.lock); + + dir = debugfs_create_dir(model->ops->name, + model->kbdev->mali_debugfs_directory); + + if (!dir) { + dev_err(model->kbdev->dev, + "Couldn't create mali debugfs %s directory", + model->ops->name); + return; + } + + list_for_each(it, &model->params) { + struct kbase_ipa_model_param *param = + list_entry(it, + struct kbase_ipa_model_param, + link); + const struct file_operations *fops = NULL; + + switch (param->type) { + case PARAM_TYPE_S32: + fops = &fops_s32; + break; + case PARAM_TYPE_U32: + fops = &fops_u32; + break; + case PARAM_TYPE_STRING: + fops = &fops_string; + break; + } + + if (unlikely(!fops)) { + dev_err(model->kbdev->dev, + "Type not set for %s parameter %s\n", + model->ops->name, param->name); + } else { + debugfs_create_file(param->name, S_IRUGO | S_IWUSR, + dir, param, fops); + } + } +} + +void kbase_ipa_debugfs_init(struct kbase_device *kbdev) +{ + mutex_lock(&kbdev->ipa.lock); + + if (kbdev->ipa.configured_model != kbdev->ipa.fallback_model) + kbase_ipa_model_debugfs_init(kbdev->ipa.configured_model); + kbase_ipa_model_debugfs_init(kbdev->ipa.fallback_model); + + mutex_unlock(&kbdev->ipa.lock); +} diff --git a/mali_kbase/ipa/mali_kbase_ipa_debugfs.h b/mali_kbase/ipa/mali_kbase_ipa_debugfs.h new file mode 100644 index 0000000..d7fc908 --- /dev/null +++ b/mali_kbase/ipa/mali_kbase_ipa_debugfs.h @@ -0,0 +1,50 @@ +/* + * + * (C) COPYRIGHT 2017 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + +#ifndef _KBASE_IPA_DEBUGFS_H_ +#define _KBASE_IPA_DEBUGFS_H_ + +enum kbase_ipa_model_param_type { + PARAM_TYPE_S32 = 1, + PARAM_TYPE_U32, + PARAM_TYPE_STRING, +}; + +#ifdef CONFIG_DEBUG_FS + +void kbase_ipa_debugfs_init(struct kbase_device *kbdev); +int kbase_ipa_model_param_add(struct kbase_ipa_model *model, const char *name, + void *addr, size_t size, + enum kbase_ipa_model_param_type type); +void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model); + +#else /* CONFIG_DEBUG_FS */ + +static inline int kbase_ipa_model_param_add(struct kbase_ipa_model *model, + const char *name, void *addr, + size_t size, + enum kbase_ipa_model_param_type type) +{ + return 0; +} + +static inline void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model) +{ } + +#endif /* CONFIG_DEBUG_FS */ + +#endif /* _KBASE_IPA_DEBUGFS_H_ */ diff --git a/mali_kbase/ipa/mali_kbase_ipa_generic.c b/mali_kbase/ipa/mali_kbase_ipa_generic.c deleted file mode 100644 index 18fb2b2..0000000 --- a/mali_kbase/ipa/mali_kbase_ipa_generic.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * - * (C) COPYRIGHT 2016 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 - * Foundation, and any use by you of this program is subject to the terms - * of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained - * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - - - -#include <linux/thermal.h> -#ifdef CONFIG_DEVFREQ_THERMAL -#include <linux/devfreq_cooling.h> -#endif -#include <linux/of.h> - -#include "mali_kbase.h" -#include "mali_kbase_defs.h" - -/* - * This model is primarily designed for the Juno platform. It may not be - * suitable for other platforms. The additional resources in this model - * should preferably be minimal, as this model is rarely used when a dynamic - * model is available. - */ - -/** - * struct kbase_ipa_model_generic_data - IPA context per device - * @dynamic_coefficient: dynamic coefficient of the model - * @static_coefficient: static coefficient of the model - * @ts: ts of the model - * @gpu_tz: thermal zone device - * @ipa_lock: protects the entire IPA context - */ - -struct kbase_ipa_model_generic_data { - u32 dynamic_coefficient; - u32 static_coefficient; - s32 ts[4]; - struct thermal_zone_device *gpu_tz; - struct mutex ipa_lock; -}; -#define FALLBACK_STATIC_TEMPERATURE 55000 - -static unsigned long model_static_power(struct kbase_ipa_model *model, - unsigned long voltage) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) - unsigned long temperature; -#else - int temperature; -#endif - unsigned long temp; - unsigned long temp_squared, temp_cubed, temp_scaling_factor; - const unsigned long voltage_cubed = (voltage * voltage * voltage) >> 10; - struct kbase_ipa_model_generic_data *model_data = - (struct kbase_ipa_model_generic_data *) model->model_data; - struct thermal_zone_device *gpu_tz = model_data->gpu_tz; - - if (gpu_tz) { - int ret; - - ret = gpu_tz->ops->get_temp(gpu_tz, &temperature); - if (ret) { - pr_warn_ratelimited("Error reading temperature for gpu thermal zone: %d\n", - ret); - temperature = FALLBACK_STATIC_TEMPERATURE; - } - } else { - temperature = FALLBACK_STATIC_TEMPERATURE; - } - - /* Calculate the temperature scaling factor. To be applied to the - * voltage scaled power. - */ - temp = temperature / 1000; - temp_squared = temp * temp; - temp_cubed = temp_squared * temp; - temp_scaling_factor = - (model_data->ts[3] * temp_cubed) - + (model_data->ts[2] * temp_squared) - + (model_data->ts[1] * temp) - + model_data->ts[0]; - - return (((model_data->static_coefficient * voltage_cubed) >> 20) - * temp_scaling_factor) - / 1000000; -} - -static unsigned long model_dynamic_power(struct kbase_ipa_model *model) -{ - struct kbase_ipa_model_generic_data *model_data = - (struct kbase_ipa_model_generic_data *) model->model_data; - - return model_data->dynamic_coefficient; -} - -static int kbase_generic_power_model_init(struct kbase_ipa_model *model) -{ - struct kbase_device *kbdev = model->kbdev; - struct device_node *power_model_node; - const char *tz_name; - u32 static_power, dynamic_power; - u32 voltage, voltage_squared, voltage_cubed, frequency; - struct kbase_ipa_model_generic_data *model_data; - int err; - - model_data = kzalloc(sizeof(struct kbase_ipa_model_generic_data), - GFP_KERNEL); - - if (!model_data) - return -ENOMEM; - - power_model_node = of_get_child_by_name(kbdev->dev->of_node, - "power_model"); - if (!power_model_node) { - dev_err(kbdev->dev, "could not find power_model node\n"); - err = -ENODEV; - goto error; - } - if (!of_device_is_compatible(power_model_node, - "arm,mali-simple-power-model")) { - dev_err(kbdev->dev, "power_model incompatible with simple power model\n"); - err = -ENODEV; - goto error; - } - - err = of_property_read_string(power_model_node, "thermal-zone", - &tz_name); - if (err) { - dev_err(kbdev->dev, "thermal zone in power_model not available\n"); - goto error; - } - - model_data->gpu_tz = thermal_zone_get_zone_by_name(tz_name); - if (IS_ERR(model_data->gpu_tz)) { - pr_warn_ratelimited("Error getting gpu thermal zone (%ld), not yet ready?\n", - PTR_ERR(model_data->gpu_tz)); - model_data->gpu_tz = NULL; - err = -EPROBE_DEFER; - goto error; - } - - err = of_property_read_u32(power_model_node, "static-power", - &static_power); - if (err) { - dev_err(kbdev->dev, "static-power in power_model not available\n"); - goto error; - } - - err = of_property_read_u32(power_model_node, "dynamic-power", - &dynamic_power); - if (err) { - dev_err(kbdev->dev, "dynamic-power in power_model not available\n"); - goto error; - } - - err = of_property_read_u32(power_model_node, "voltage", - &voltage); - if (err) { - dev_err(kbdev->dev, "voltage in power_model not available\n"); - goto error; - } - - err = of_property_read_u32(power_model_node, "frequency", - &frequency); - if (err) { - dev_err(kbdev->dev, "frequency in power_model not available\n"); - goto error; - } - voltage_squared = (voltage * voltage) / 1000; - voltage_cubed = voltage * voltage * voltage; - model_data->static_coefficient = - (static_power << 20) / (voltage_cubed >> 10); - model_data->dynamic_coefficient = - (((dynamic_power * 1000) / voltage_squared) * 1000) / frequency; - - err = of_property_read_u32_array(power_model_node, - "ts", - (u32 *)model_data->ts, - 4); - if (err) { - dev_err(kbdev->dev, "ts in power_model not available\n"); - goto error; - } - - model->model_data = (void *) model_data; - - return 0; -error: - kfree(model_data); - return err; -} - -static void kbase_generic_power_model_term(struct kbase_ipa_model *model) -{ - struct kbase_ipa_model_generic_data *model_data = - (struct kbase_ipa_model_generic_data *)model->model_data; - - kfree(model_data); -} - -struct kbase_ipa_model_ops kbase_generic_ipa_model_ops = { - .name = "generic_ipa_model", - .init = &kbase_generic_power_model_init, - .term = &kbase_generic_power_model_term, - .get_dynamic_power = &model_dynamic_power, - .get_static_power = &model_static_power, - .power_to_state = NULL -}; diff --git a/mali_kbase/ipa/mali_kbase_ipa_simple.c b/mali_kbase/ipa/mali_kbase_ipa_simple.c new file mode 100644 index 0000000..f8d46e1 --- /dev/null +++ b/mali_kbase/ipa/mali_kbase_ipa_simple.c @@ -0,0 +1,205 @@ +/* + * + * (C) COPYRIGHT 2016-2017 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 + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained + * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + + +#include <linux/thermal.h> +#ifdef CONFIG_DEVFREQ_THERMAL +#include <linux/devfreq_cooling.h> +#endif +#include <linux/of.h> + +#include "mali_kbase.h" +#include "mali_kbase_defs.h" + +/* + * This model is primarily designed for the Juno platform. It may not be + * suitable for other platforms. The additional resources in this model + * should preferably be minimal, as this model is rarely used when a dynamic + * model is available. + */ + +/** + * struct kbase_ipa_model_simple_data - IPA context per device + * @dynamic_coefficient: dynamic coefficient of the model + * @static_coefficient: static coefficient of the model + * @ts: Thermal scaling coefficients of the model + * @tz_name: Thermal zone name + * @gpu_tz: thermal zone device + */ + +struct kbase_ipa_model_simple_data { + u32 dynamic_coefficient; + u32 static_coefficient; + s32 ts[4]; + char tz_name[16]; + struct thermal_zone_device *gpu_tz; +}; +#define FALLBACK_STATIC_TEMPERATURE 55000 + +/** + * calculate_temp_scaling_factor() - Calculate temperature scaling coefficient + * @ts: Signed coefficients, in order t^0 to t^3, with units Deg^-N + * @t: Temperature, in mDeg C. Range: -2^17 < t < 2^17 + * + * Scale the temperature according to a cubic polynomial whose coefficients are + * provided in the device tree. The result is used to scale the static power + * coefficient, where 1000000 means no change. + * + * Return: Temperature scaling factor. Approx range 0 < ret < 10,000,000. + */ +static u32 calculate_temp_scaling_factor(s32 ts[4], s64 t) +{ + /* Range: -2^24 < t2 < 2^24 m(Deg^2) */ + const s64 t2 = (t * t) / 1000; + + /* Range: -2^31 < t3 < 2^31 m(Deg^3) */ + const s64 t3 = (t * t2) / 1000; + + /* + * Sum the parts. t^[1-3] are in m(Deg^N), but the coefficients are in + * Deg^-N, so we need to multiply the last coefficient by 1000. + * Range: -2^63 < res_big < 2^63 + */ + const s64 res_big = ts[3] * t3 /* +/- 2^62 */ + + ts[2] * t2 /* +/- 2^55 */ + + ts[1] * t /* +/- 2^48 */ + + ts[0] * 1000; /* +/- 2^41 */ + + /* Range: -2^60 < res_unclamped < 2^60 */ + s64 res_unclamped = res_big / 1000; + + /* Clamp to range of 0x to 10x the static power */ + return clamp(res_unclamped, (s64) 0, (s64) 10000000); +} + +static unsigned long model_static_power(struct kbase_ipa_model *model) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) + unsigned long temp; +#else + int temp; +#endif + u32 temp_scaling_factor; + struct kbase_ipa_model_simple_data *model_data = + (struct kbase_ipa_model_simple_data *) model->model_data; + struct thermal_zone_device *gpu_tz = model_data->gpu_tz; + + if (gpu_tz) { + int ret; + + ret = gpu_tz->ops->get_temp(gpu_tz, &temp); + if (ret) { + pr_warn_ratelimited("Error reading temperature for gpu thermal zone: %d\n", + ret); + temp = FALLBACK_STATIC_TEMPERATURE; + } + } else { + temp = FALLBACK_STATIC_TEMPERATURE; + } + + temp_scaling_factor = calculate_temp_scaling_factor(model_data->ts, + temp); + + return (model_data->static_coefficient * temp_scaling_factor) / 1000000; +} + +static unsigned long model_dynamic_power(struct kbase_ipa_model *model) +{ + struct kbase_ipa_model_simple_data *model_data = + (struct kbase_ipa_model_simple_data *) model->model_data; + + return model_data->dynamic_coefficient; +} + +static int add_params(struct kbase_ipa_model *model) +{ + int err = 0; + struct kbase_ipa_model_simple_data *model_data = + (struct kbase_ipa_model_simple_data *)model->model_data; + + err = kbase_ipa_model_add_param_u32(model, "static-coefficient", + &model_data->static_coefficient); + if (err) + goto end; + + err = kbase_ipa_model_add_param_u32(model, "dynamic-coefficient", + &model_data->dynamic_coefficient); + if (err) + goto end; + + err = kbase_ipa_model_add_param_s32_array(model, "ts", + model_data->ts, 4); + if (err) + goto end; + + err = kbase_ipa_model_add_param_string(model, "thermal-zone", + model_data->tz_name, + sizeof(model_data->tz_name)); + +end: + return err; +} + +static int kbase_simple_power_model_init(struct kbase_ipa_model *model) +{ + int err; + struct kbase_ipa_model_simple_data *model_data; + + model_data = kzalloc(sizeof(struct kbase_ipa_model_simple_data), + GFP_KERNEL); + if (!model_data) + return -ENOMEM; + + model->model_data = (void *) model_data; + + err = add_params(model); + + return err; +} + +static int kbase_simple_power_model_recalculate(struct kbase_ipa_model *model) +{ + struct kbase_ipa_model_simple_data *model_data = + (struct kbase_ipa_model_simple_data *)model->model_data; + + model_data->gpu_tz = thermal_zone_get_zone_by_name(model_data->tz_name); + if (IS_ERR(model_data->gpu_tz)) { + pr_warn_ratelimited("Error %ld getting thermal zone \'%s\', not yet ready?\n", + PTR_ERR(model_data->gpu_tz), + model_data->tz_name); + model_data->gpu_tz = NULL; + return -EPROBE_DEFER; + } + + return 0; +} + +static void kbase_simple_power_model_term(struct kbase_ipa_model *model) +{ + struct kbase_ipa_model_simple_data *model_data = + (struct kbase_ipa_model_simple_data *)model->model_data; + + kfree(model_data); +} + +struct kbase_ipa_model_ops kbase_simple_ipa_model_ops = { + .name = "mali-simple-power-model", + .init = &kbase_simple_power_model_init, + .recalculate = &kbase_simple_power_model_recalculate, + .term = &kbase_simple_power_model_term, + .get_dynamic_power = &model_dynamic_power, + .get_static_power = &model_static_power, +}; diff --git a/mali_kbase/mali_base_hwconfig_features.h b/mali_kbase/mali_base_hwconfig_features.h index 239582e..8ee19fc 100644 --- a/mali_kbase/mali_base_hwconfig_features.h +++ b/mali_kbase/mali_base_hwconfig_features.h @@ -246,4 +246,5 @@ static const enum base_hw_feature base_hw_features_tSIx[] = { BASE_HW_FEATURE_END }; + #endif /* _BASE_HWCONFIG_FEATURES_H_ */ diff --git a/mali_kbase/mali_base_hwconfig_issues.h b/mali_kbase/mali_base_hwconfig_issues.h index e1e43a1..53f3804 100644 --- a/mali_kbase/mali_base_hwconfig_issues.h +++ b/mali_kbase/mali_base_hwconfig_issues.h @@ -116,6 +116,8 @@ enum base_hw_issue { BASE_HW_ISSUE_TMIX_8463, BASE_HW_ISSUE_TMIX_8456, GPUCORE_1619, + BASE_HW_ISSUE_TSIX_1116, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -185,6 +187,7 @@ static const enum base_hw_issue base_hw_issues_t60x_r0p0_15dev0[] = { BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_3964, GPUCORE_1619, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -224,6 +227,7 @@ static const enum base_hw_issue base_hw_issues_t60x_r0p0_eac[] = { BASE_HW_ISSUE_11054, BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_3964, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -261,6 +265,7 @@ static const enum base_hw_issue base_hw_issues_t60x_r0p1[] = { BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_1963, BASE_HW_ISSUE_T76X_3964, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -294,6 +299,7 @@ static const enum base_hw_issue base_hw_issues_t62x_r0p1[] = { BASE_HW_ISSUE_11054, BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_1963, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -318,6 +324,7 @@ static const enum base_hw_issue base_hw_issues_t62x_r1p0[] = { BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_1963, BASE_HW_ISSUE_T76X_3964, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -339,6 +346,7 @@ static const enum base_hw_issue base_hw_issues_t62x_r1p1[] = { BASE_HW_ISSUE_11054, BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_1963, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -366,6 +374,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p0[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -393,6 +402,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p1[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -418,6 +428,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p1_50rel0[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -445,6 +456,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p2[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -470,6 +482,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p3[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -492,6 +505,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r1p0[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -511,6 +525,7 @@ static const enum base_hw_issue base_hw_issues_t72x_r0p0[] = { BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_1963, BASE_HW_ISSUE_T76X_3964, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -531,6 +546,7 @@ static const enum base_hw_issue base_hw_issues_t72x_r1p0[] = { BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_1963, BASE_HW_ISSUE_T76X_3964, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -551,6 +567,7 @@ static const enum base_hw_issue base_hw_issues_t72x_r1p1[] = { BASE_HW_ISSUE_T76X_1909, BASE_HW_ISSUE_T76X_1963, BASE_HW_ISSUE_T76X_3964, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -645,6 +662,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r0p1[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -665,6 +683,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r0p2[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -683,6 +702,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r1p0[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -701,6 +721,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r2p0[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -736,6 +757,7 @@ static const enum base_hw_issue base_hw_issues_t86x_r0p2[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -754,6 +776,7 @@ static const enum base_hw_issue base_hw_issues_t86x_r1p0[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -772,6 +795,7 @@ static const enum base_hw_issue base_hw_issues_t86x_r2p0[] = { BASE_HW_ISSUE_T76X_3966, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -806,6 +830,7 @@ static const enum base_hw_issue base_hw_issues_t83x_r0p1[] = { BASE_HW_ISSUE_T76X_3960, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -825,6 +850,7 @@ static const enum base_hw_issue base_hw_issues_t83x_r1p0[] = { BASE_HW_ISSUE_T76X_3960, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -840,6 +866,7 @@ static const enum base_hw_issue base_hw_issues_model_t83x[] = { BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, GPUCORE_1619, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -861,6 +888,7 @@ static const enum base_hw_issue base_hw_issues_t82x_r0p0[] = { BASE_HW_ISSUE_T76X_3964, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -881,6 +909,7 @@ static const enum base_hw_issue base_hw_issues_t82x_r0p1[] = { BASE_HW_ISSUE_T76X_3960, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -900,6 +929,7 @@ static const enum base_hw_issue base_hw_issues_t82x_r1p0[] = { BASE_HW_ISSUE_T76X_3960, BASE_HW_ISSUE_T76X_3979, BASE_HW_ISSUE_TMIX_7891, + BASE_HW_ISSUE_TMIX_8438, BASE_HW_ISSUE_END }; @@ -983,6 +1013,21 @@ static const enum base_hw_issue base_hw_issues_model_tHEx[] = { static const enum base_hw_issue base_hw_issues_tSIx_r0p0[] = { BASE_HW_ISSUE_9435, BASE_HW_ISSUE_TMIX_8133, + BASE_HW_ISSUE_TSIX_1116, + BASE_HW_ISSUE_END +}; + +static const enum base_hw_issue base_hw_issues_tSIx_r0p1[] = { + BASE_HW_ISSUE_9435, + BASE_HW_ISSUE_TMIX_8133, + BASE_HW_ISSUE_TSIX_1116, + BASE_HW_ISSUE_END +}; + +static const enum base_hw_issue base_hw_issues_tSIx_r1p0[] = { + BASE_HW_ISSUE_9435, + BASE_HW_ISSUE_TMIX_8133, + BASE_HW_ISSUE_TSIX_1116, BASE_HW_ISSUE_END }; @@ -990,7 +1035,10 @@ static const enum base_hw_issue base_hw_issues_model_tSIx[] = { BASE_HW_ISSUE_5736, BASE_HW_ISSUE_9435, BASE_HW_ISSUE_TMIX_8133, + BASE_HW_ISSUE_TSIX_1116, BASE_HW_ISSUE_END }; + + #endif /* _BASE_HWCONFIG_ISSUES_H_ */ diff --git a/mali_kbase/mali_base_kernel.h b/mali_kbase/mali_base_kernel.h index 0d2ac95..0c80e03 100644 --- a/mali_kbase/mali_base_kernel.h +++ b/mali_kbase/mali_base_kernel.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 diff --git a/mali_kbase/mali_kbase.h b/mali_kbase/mali_kbase.h index b5a771f..2289f80 100644 --- a/mali_kbase/mali_kbase.h +++ b/mali_kbase/mali_kbase.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 diff --git a/mali_kbase/mali_kbase_config_defaults.h b/mali_kbase/mali_kbase_config_defaults.h index f982aa5..f6eeac8 100644 --- a/mali_kbase/mali_kbase_config_defaults.h +++ b/mali_kbase/mali_kbase_config_defaults.h @@ -29,16 +29,6 @@ #include <mali_kbase_config_platform.h> /** - * Irq throttle. It is the minimum desired time in between two - * consecutive gpu interrupts (given in 'us'). The irq throttle - * gpu register will be configured after this, taking into - * account the configured max frequency. - * - * Attached value: number in micro seconds - */ -#define DEFAULT_IRQ_THROTTLE_TIME_US 20 - -/** * Boolean indicating whether the driver is configured to be secure at * a potential loss of performance. * diff --git a/mali_kbase/mali_kbase_core_linux.c b/mali_kbase/mali_kbase_core_linux.c index 4e95633..e335c0d 100644 --- a/mali_kbase/mali_kbase_core_linux.c +++ b/mali_kbase/mali_kbase_core_linux.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 @@ -23,6 +23,9 @@ #include <mali_kbase_mem_linux.h> #ifdef CONFIG_MALI_DEVFREQ #include <backend/gpu/mali_kbase_devfreq.h> +#ifdef CONFIG_DEVFREQ_THERMAL +#include <ipa/mali_kbase_ipa_debugfs.h> +#endif /* CONFIG_DEVFREQ_THERMAL */ #endif /* CONFIG_MALI_DEVFREQ */ #ifdef CONFIG_MALI_NO_MALI #include "mali_kbase_model_linux.h" @@ -250,9 +253,9 @@ enum { inited_vinstr = (1u << 8), inited_job_fault = (1u << 10), - inited_misc_register = (1u << 11), - inited_get_device = (1u << 12), - inited_sysfs_group = (1u << 13), + inited_sysfs_group = (1u << 11), + inited_misc_register = (1u << 12), + inited_get_device = (1u << 13), inited_dev_list = (1u << 14), inited_debugfs = (1u << 15), inited_gpu_device = (1u << 16), @@ -3324,7 +3327,8 @@ if (kbdev->clock != NULL) { static void power_control_term(struct kbase_device *kbdev) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || \ + defined(LSK_OPPV2_BACKPORT) dev_pm_opp_of_remove_table(kbdev->dev); #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) of_free_opp_table(kbdev->dev); @@ -3381,6 +3385,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_##type##_quirks, type##_quirks_get,\ MAKE_QUIRK_ACCESSORS(sc); MAKE_QUIRK_ACCESSORS(tiler); MAKE_QUIRK_ACCESSORS(mmu); +MAKE_QUIRK_ACCESSORS(jm); #endif /* KBASE_GPU_RESET_EN */ @@ -3464,6 +3469,8 @@ static int kbase_device_debugfs_init(struct kbase_device *kbdev) kbasep_gpu_memory_debugfs_init(kbdev); kbase_as_fault_debugfs_init(kbdev); #if KBASE_GPU_RESET_EN + /* fops_* variables created by invocations of macro + * MAKE_QUIRK_ACCESSORS() above. */ debugfs_create_file("quirks_sc", 0644, kbdev->mali_debugfs_directory, kbdev, &fops_sc_quirks); @@ -3473,6 +3480,9 @@ static int kbase_device_debugfs_init(struct kbase_device *kbdev) debugfs_create_file("quirks_mmu", 0644, kbdev->mali_debugfs_directory, kbdev, &fops_mmu_quirks); + debugfs_create_file("quirks_jm", 0644, + kbdev->mali_debugfs_directory, kbdev, + &fops_jm_quirks); #endif /* KBASE_GPU_RESET_EN */ #ifndef CONFIG_MALI_COH_USER @@ -3499,6 +3509,13 @@ static int kbase_device_debugfs_init(struct kbase_device *kbdev) kbasep_trace_timeline_debugfs_init(kbdev); #endif /* CONFIG_MALI_TRACE_TIMELINE */ +#ifdef CONFIG_MALI_DEVFREQ +#ifdef CONFIG_DEVFREQ_THERMAL + if (kbdev->inited_subsys & inited_devfreq) + kbase_ipa_debugfs_init(kbdev); +#endif /* CONFIG_DEVFREQ_THERMAL */ +#endif /* CONFIG_MALI_DEVFREQ */ + #ifdef CONFIG_DEBUG_FS debugfs_create_file("serialize_jobs", S_IRUGO | S_IWUSR, kbdev->mali_debugfs_directory, kbdev, @@ -3639,10 +3656,6 @@ static int kbase_platform_device_remove(struct platform_device *pdev) } #endif - if (kbdev->inited_subsys & inited_sysfs_group) { - sysfs_remove_group(&kbdev->dev->kobj, &kbase_attr_group); - kbdev->inited_subsys &= ~inited_sysfs_group; - } if (kbdev->inited_subsys & inited_dev_list) { dev_list = kbase_dev_list_get(); @@ -3656,6 +3669,11 @@ static int kbase_platform_device_remove(struct platform_device *pdev) kbdev->inited_subsys &= ~inited_misc_register; } + if (kbdev->inited_subsys & inited_sysfs_group) { + sysfs_remove_group(&kbdev->dev->kobj, &kbase_attr_group); + kbdev->inited_subsys &= ~inited_sysfs_group; + } + if (kbdev->inited_subsys & inited_get_device) { put_device(kbdev->dev); kbdev->inited_subsys &= ~inited_get_device; @@ -3788,7 +3806,7 @@ static int kbase_platform_device_probe(struct platform_device *pdev) dev_set_drvdata(kbdev->dev, kbdev); #ifdef CONFIG_DEVFREQ_THERMAL - INIT_LIST_HEAD(&kbdev->ipa_power_models); + INIT_LIST_HEAD(&kbdev->ipa.power_models); #endif #ifdef CONFIG_MALI_NO_MALI @@ -3851,8 +3869,6 @@ static int kbase_platform_device_probe(struct platform_device *pdev) core_props->gpu_freq_khz_min = GPU_FREQ_KHZ_MIN; core_props->gpu_freq_khz_max = GPU_FREQ_KHZ_MAX; - kbdev->gpu_props.irq_throttle_time_us = DEFAULT_IRQ_THROTTLE_TIME_US; - err = kbase_device_init(kbdev); if (err) { dev_err(kbdev->dev, "Device initialization failed (%d)\n", err); @@ -3919,12 +3935,10 @@ static int kbase_platform_device_probe(struct platform_device *pdev) #ifdef CONFIG_MALI_DEVFREQ err = kbase_devfreq_init(kbdev); - if (err) { - dev_err(kbdev->dev, "Devfreq initialization failed\n"); - kbase_platform_device_remove(pdev); - return err; - } - kbdev->inited_subsys |= inited_devfreq; + if (!err) + kbdev->inited_subsys |= inited_devfreq; + else + dev_err(kbdev->dev, "Continuing without devfreq\n"); #endif /* CONFIG_MALI_DEVFREQ */ kbdev->vinstr_ctx = kbase_vinstr_init(kbdev); @@ -3962,23 +3976,35 @@ static int kbase_platform_device_probe(struct platform_device *pdev) kbdev->mdev.parent = get_device(kbdev->dev); kbdev->inited_subsys |= inited_get_device; - err = misc_register(&kbdev->mdev); + /* This needs to happen before registering the device with misc_register(), + * otherwise it causes a race condition between registering the device and a + * uevent event being generated for userspace, causing udev rules to run + * which might expect certain sysfs attributes present. As a result of the + * race condition we avoid, some Mali sysfs entries may have appeared to + * udev to not exist. + + * For more information, see + * https://www.kernel.org/doc/Documentation/driver-model/device.txt, the + * paragraph that starts with "Word of warning", currently the second-last + * paragraph. + */ + err = sysfs_create_group(&kbdev->dev->kobj, &kbase_attr_group); if (err) { - dev_err(kbdev->dev, "Misc device registration failed for %s\n", - kbdev->devname); + dev_err(&pdev->dev, "SysFS group creation failed\n"); kbase_platform_device_remove(pdev); return err; } - kbdev->inited_subsys |= inited_misc_register; - + kbdev->inited_subsys |= inited_sysfs_group; - err = sysfs_create_group(&kbdev->dev->kobj, &kbase_attr_group); + err = misc_register(&kbdev->mdev); if (err) { - dev_err(&pdev->dev, "SysFS group creation failed\n"); + dev_err(kbdev->dev, "Misc device registration failed for %s\n", + kbdev->devname); kbase_platform_device_remove(pdev); return err; } - kbdev->inited_subsys |= inited_sysfs_group; + kbdev->inited_subsys |= inited_misc_register; + #ifdef CONFIG_MALI_FPGA_BUS_LOGGER err = bl_core_client_register(kbdev->devname, @@ -4021,9 +4047,10 @@ static int kbase_device_suspend(struct device *dev) if (!kbdev) return -ENODEV; -#if defined(CONFIG_PM_DEVFREQ) && \ +#if defined(CONFIG_MALI_DEVFREQ) && \ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) - devfreq_suspend_device(kbdev->devfreq); + if (kbdev->inited_subsys & inited_devfreq) + devfreq_suspend_device(kbdev->devfreq); #endif kbase_pm_suspend(kbdev); @@ -4048,9 +4075,10 @@ static int kbase_device_resume(struct device *dev) kbase_pm_resume(kbdev); -#if defined(CONFIG_PM_DEVFREQ) && \ +#if defined(CONFIG_MALI_DEVFREQ) && \ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) - devfreq_resume_device(kbdev->devfreq); + if (kbdev->inited_subsys & inited_devfreq) + devfreq_resume_device(kbdev->devfreq); #endif return 0; } @@ -4074,9 +4102,10 @@ static int kbase_device_runtime_suspend(struct device *dev) if (!kbdev) return -ENODEV; -#if defined(CONFIG_PM_DEVFREQ) && \ +#if defined(CONFIG_MALI_DEVFREQ) && \ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) - devfreq_suspend_device(kbdev->devfreq); + if (kbdev->inited_subsys & inited_devfreq) + devfreq_suspend_device(kbdev->devfreq); #endif if (kbdev->pm.backend.callback_power_runtime_off) { @@ -4111,9 +4140,10 @@ static int kbase_device_runtime_resume(struct device *dev) dev_dbg(dev, "runtime resume\n"); } -#if defined(CONFIG_PM_DEVFREQ) && \ +#if defined(CONFIG_MALI_DEVFREQ) && \ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) - devfreq_resume_device(kbdev->devfreq); + if (kbdev->inited_subsys & inited_devfreq) + devfreq_resume_device(kbdev->devfreq); #endif return ret; diff --git a/mali_kbase/mali_kbase_defs.h b/mali_kbase/mali_kbase_defs.h index 290d460..73f849c 100644 --- a/mali_kbase/mali_kbase_defs.h +++ b/mali_kbase/mali_kbase_defs.h @@ -945,6 +945,18 @@ struct kbase_mem_pool { struct kbase_mem_pool *next_pool; }; +/** + * struct kbase_devfreq_opp - Lookup table for converting between nominal OPP + * frequency, and real frequency and core mask + * @opp_freq: Nominal OPP frequency + * @real_freq: Real GPU frequency + * @core_mask: Shader core mask + */ +struct kbase_devfreq_opp { + u64 opp_freq; + u64 real_freq; + u64 core_mask; +}; #define DEVNAME_SIZE 16 @@ -1067,9 +1079,6 @@ struct kbase_device { struct kbase_vinstr_context *vinstr_ctx; - /*value to be written to the irq_throttle register each time an irq is served */ - atomic_t irq_throttle_cycles; - #if KBASE_TRACE_ENABLE spinlock_t trace_lock; u16 trace_first_out; @@ -1092,17 +1101,28 @@ struct kbase_device { struct devfreq_dev_profile devfreq_profile; struct devfreq *devfreq; unsigned long current_freq; + unsigned long current_nominal_freq; unsigned long current_voltage; + u64 current_core_mask; + struct kbase_devfreq_opp *opp_table; + int num_opps; #ifdef CONFIG_DEVFREQ_THERMAL #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) struct devfreq_cooling_device *devfreq_cooling; #else struct thermal_cooling_device *devfreq_cooling; #endif - struct list_head ipa_power_models; - struct kbase_ipa_model *ipa_current_model; - struct kbase_ipa_model *ipa_configured_model; - struct kbase_ipa_model *ipa_fallback_model; + /* Current IPA model - true for configured model, false for fallback */ + atomic_t ipa_use_configured_model; + struct { + /* Access to this struct must be with ipa.lock held */ + struct mutex lock; + unsigned long last_model_dyn_power_coeff; + unsigned long last_static_power_coeff; + struct list_head power_models; + struct kbase_ipa_model *configured_model; + struct kbase_ipa_model *fallback_model; + } ipa; #endif #endif diff --git a/mali_kbase/mali_kbase_device.c b/mali_kbase/mali_kbase_device.c index 7484eec..e53f876 100644 --- a/mali_kbase/mali_kbase_device.c +++ b/mali_kbase/mali_kbase_device.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 diff --git a/mali_kbase/mali_kbase_gator_api.c b/mali_kbase/mali_kbase_gator_api.c index 7c3c5f3..860e101 100644 --- a/mali_kbase/mali_kbase_gator_api.c +++ b/mali_kbase/mali_kbase_gator_api.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2017 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 diff --git a/mali_kbase/mali_kbase_gator_hwcnt_names.h b/mali_kbase/mali_kbase_gator_hwcnt_names.h index ce8e424..e4003f6 100644 --- a/mali_kbase/mali_kbase_gator_hwcnt_names.h +++ b/mali_kbase/mali_kbase_gator_hwcnt_names.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2017 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 @@ -2162,4 +2162,5 @@ static const char * const hardware_counters_mali_t88x[] = { #include "mali_kbase_gator_hwcnt_names_tsix.h" + #endif diff --git a/mali_kbase/mali_kbase_gator_hwcnt_names_tsix.h b/mali_kbase/mali_kbase_gator_hwcnt_names_tsix.h index 7ff7009..be09c45 100644 --- a/mali_kbase/mali_kbase_gator_hwcnt_names_tsix.h +++ b/mali_kbase/mali_kbase_gator_hwcnt_names_tsix.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2017 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 @@ -191,15 +191,15 @@ static const char * const hardware_counters_mali_tSIx[] = { "TSIx_ARITH_INSTR_DOUBLE", "TSIx_ARITH_INSTR_MSG", "TSIx_ARITH_INSTR_MSG_ONLY", - "TSIx_TEX_INSTR", - "TSIx_TEX_INSTR_MIPMAP", - "TSIx_TEX_INSTR_COMPRESSED", - "TSIx_TEX_INSTR_3D", - "TSIx_TEX_INSTR_TRILINEAR", - "TSIx_TEX_COORD_ISSUE", - "TSIx_TEX_COORD_STALL", - "TSIx_TEX_STARVE_CACHE", - "TSIx_TEX_STARVE_FILTER", + "TSIx_TEX_MSGI_NUM_QUADS", + "TSIx_TEX_DFCH_NUM_PASSES", + "TSIx_TEX_DFCH_NUM_PASSES_MISS", + "TSIx_TEX_DFCH_NUM_PASSES_MIP_MAP", + "TSIx_TEX_TIDX_NUM_SPLIT_MIP_MAP", + "TSIx_TEX_TFCH_NUM_LINES_FETCHED", + "TSIx_TEX_TFCH_NUM_LINES_FETCHED_BLOCK_COMPRESSED", + "TSIx_TEX_TFCH_NUM_OPERATIONS", + "TSIx_TEX_FILT_NUM_OPERATIONS", "TSIx_LS_MEM_READ_FULL", "TSIx_LS_MEM_READ_SHORT", "TSIx_LS_MEM_WRITE_FULL", diff --git a/mali_kbase/mali_kbase_gpu_id.h b/mali_kbase/mali_kbase_gpu_id.h index 5c2367f..60b4371 100644 --- a/mali_kbase/mali_kbase_gpu_id.h +++ b/mali_kbase/mali_kbase_gpu_id.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2015-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2015-2017 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 @@ -58,6 +58,9 @@ #define GPU_ID2_ARCH_MINOR (0xF << GPU_ID2_ARCH_MINOR_SHIFT) #define GPU_ID2_ARCH_MAJOR (0xF << GPU_ID2_ARCH_MAJOR_SHIFT) #define GPU_ID2_PRODUCT_MODEL (GPU_ID2_ARCH_MAJOR | GPU_ID2_PRODUCT_MAJOR) +#define GPU_ID2_VERSION (GPU_ID2_VERSION_MAJOR | \ + GPU_ID2_VERSION_MINOR | \ + GPU_ID2_VERSION_STATUS) /* Helper macro to create a partial GPU_ID (new format) that defines a product ignoring its version. */ @@ -95,9 +98,9 @@ (((product_id) << GPU_ID2_PRODUCT_MAJOR_SHIFT) & \ GPU_ID2_PRODUCT_MODEL) -#define GPU_ID2_PRODUCT_TMIX GPU_ID2_MODEL_MAKE(6, 0) -#define GPU_ID2_PRODUCT_THEX GPU_ID2_MODEL_MAKE(6, 1) -#define GPU_ID2_PRODUCT_TSIX GPU_ID2_MODEL_MAKE(7, 0) +#define GPU_ID2_PRODUCT_TMIX GPU_ID2_MODEL_MAKE(6u, 0) +#define GPU_ID2_PRODUCT_THEX GPU_ID2_MODEL_MAKE(6u, 1) +#define GPU_ID2_PRODUCT_TSIX GPU_ID2_MODEL_MAKE(7u, 0) /* Values for GPU_ID_VERSION_STATUS field for PRODUCT_ID GPU_ID_PI_T60X */ #define GPU_ID_S_15DEV0 0x1 diff --git a/mali_kbase/mali_kbase_gpuprops.c b/mali_kbase/mali_kbase_gpuprops.c index ceba27c..fc65223 100644 --- a/mali_kbase/mali_kbase_gpuprops.c +++ b/mali_kbase/mali_kbase_gpuprops.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2017 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 diff --git a/mali_kbase/mali_kbase_gpuprops.h b/mali_kbase/mali_kbase_gpuprops.h index f3c95cc..44b5e9e 100644 --- a/mali_kbase/mali_kbase_gpuprops.h +++ b/mali_kbase/mali_kbase_gpuprops.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2015, 2017 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 diff --git a/mali_kbase/mali_kbase_gpuprops_types.h b/mali_kbase/mali_kbase_gpuprops_types.h index 920cf77..b06e511 100644 --- a/mali_kbase/mali_kbase_gpuprops_types.h +++ b/mali_kbase/mali_kbase_gpuprops_types.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2017 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 @@ -82,11 +82,6 @@ struct kbase_gpu_props { struct kbase_gpu_mem_props mem; struct kbase_gpu_mmu_props mmu; - /** - * Implementation specific irq throttle value (us), should be adjusted during integration. - */ - int irq_throttle_time_us; - /* Properties shared with userspace */ base_gpu_props props; }; diff --git a/mali_kbase/mali_kbase_hw.c b/mali_kbase/mali_kbase_hw.c index 51a31fb..89fe0d8 100644 --- a/mali_kbase/mali_kbase_hw.c +++ b/mali_kbase/mali_kbase_hw.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2012-2017 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 @@ -109,16 +109,33 @@ int kbase_hw_set_issues_mask(struct kbase_device *kbdev) issues = base_hw_issues_tMIx_r0p0; break; default: - if ((gpu_id & GPU_ID2_PRODUCT_MODEL) == - GPU_ID2_PRODUCT_TMIX) { + switch (gpu_id & GPU_ID2_PRODUCT_MODEL) { + case GPU_ID2_PRODUCT_TMIX: issues = base_hw_issues_tMIx_r0p0; - } else if ((gpu_id & GPU_ID2_PRODUCT_MODEL) == - GPU_ID2_PRODUCT_THEX) { + break; + case GPU_ID2_PRODUCT_THEX: issues = base_hw_issues_tHEx_r0p0; - } else if ((gpu_id & GPU_ID2_PRODUCT_MODEL) == - GPU_ID2_PRODUCT_TSIX) { - issues = base_hw_issues_tSIx_r0p0; - } else { + break; + case GPU_ID2_PRODUCT_TSIX: + switch (gpu_id & (GPU_ID2_VERSION_MAJOR | + GPU_ID2_VERSION_MINOR)) { + case GPU_ID2_VERSION_MAKE(0, 0, 0): + issues = base_hw_issues_tSIx_r0p0; + break; + case GPU_ID2_VERSION_MAKE(0, 1, 0): + issues = base_hw_issues_tSIx_r0p1; + break; + case GPU_ID2_VERSION_MAKE(1, 0, 0): + issues = base_hw_issues_tSIx_r1p0; + break; + default: + dev_err(kbdev->dev, + "Unknown GPU ID %x", + gpu_id); + return -EINVAL; + } + break; + default: dev_err(kbdev->dev, "Unknown GPU ID %x", gpu_id); return -EINVAL; diff --git a/mali_kbase/mali_kbase_jd.c b/mali_kbase/mali_kbase_jd.c index 596b047..c2a5571 100644 --- a/mali_kbase/mali_kbase_jd.c +++ b/mali_kbase/mali_kbase_jd.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 diff --git a/mali_kbase/mali_kbase_js.c b/mali_kbase/mali_kbase_js.c index 3a675a1..d75dcba 100644 --- a/mali_kbase/mali_kbase_js.c +++ b/mali_kbase/mali_kbase_js.c @@ -577,15 +577,6 @@ int kbasep_js_devdata_init(struct kbase_device * const kbdev) dev_dbg(kbdev->dev, "Note: The JS tick timer (if coded) will still be run, but do nothing."); #endif - /* setup the number of irq throttle cycles base on given time */ - { - int time_us = kbdev->gpu_props.irq_throttle_time_us; - int cycles = kbasep_js_convert_us_to_gpu_ticks_max_freq(kbdev, - time_us); - - atomic_set(&kbdev->irq_throttle_cycles, cycles); - } - /* Clear the AS data, including setting NULL pointers */ memset(&jsdd->runpool_irq.per_as_data[0], 0, sizeof(jsdd->runpool_irq.per_as_data)); diff --git a/mali_kbase/mali_kbase_js.h b/mali_kbase/mali_kbase_js.h index 76172f7..d092fff 100644 --- a/mali_kbase/mali_kbase_js.h +++ b/mali_kbase/mali_kbase_js.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2011-2017 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 @@ -851,71 +851,6 @@ static inline struct kbase_context *kbasep_js_runpool_lookup_ctx_noretain(struct return found_kctx; } -/** - * This will provide a conversion from time (us) to ticks of the gpu clock - * based on the minimum available gpu frequency. - * This is usually good to compute best/worst case (where the use of current - * frequency is not valid due to DVFS). - * e.g.: when you need the number of cycles to guarantee you won't wait for - * longer than 'us' time (you might have a shorter wait). - */ -static inline u32 kbasep_js_convert_us_to_gpu_ticks_min_freq(struct kbase_device *kbdev, u32 us) -{ - u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_min; - - KBASE_DEBUG_ASSERT(0 != gpu_freq); - return us * (gpu_freq / 1000); -} - -/** - * This will provide a conversion from time (us) to ticks of the gpu clock - * based on the maximum available gpu frequency. - * This is usually good to compute best/worst case (where the use of current - * frequency is not valid due to DVFS). - * e.g.: When you need the number of cycles to guarantee you'll wait at least - * 'us' amount of time (but you might wait longer). - */ -static inline u32 kbasep_js_convert_us_to_gpu_ticks_max_freq(struct kbase_device *kbdev, u32 us) -{ - u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_max; - - KBASE_DEBUG_ASSERT(0 != gpu_freq); - return us * (u32) (gpu_freq / 1000); -} - -/** - * This will provide a conversion from ticks of the gpu clock to time (us) - * based on the minimum available gpu frequency. - * This is usually good to compute best/worst case (where the use of current - * frequency is not valid due to DVFS). - * e.g.: When you need to know the worst-case wait that 'ticks' cycles will - * take (you guarantee that you won't wait any longer than this, but it may - * be shorter). - */ -static inline u32 kbasep_js_convert_gpu_ticks_to_us_min_freq(struct kbase_device *kbdev, u32 ticks) -{ - u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_min; - - KBASE_DEBUG_ASSERT(0 != gpu_freq); - return ticks / gpu_freq * 1000; -} - -/** - * This will provide a conversion from ticks of the gpu clock to time (us) - * based on the maximum available gpu frequency. - * This is usually good to compute best/worst case (where the use of current - * frequency is not valid due to DVFS). - * e.g.: When you need to know the best-case wait for 'tick' cycles (you - * guarantee to be waiting for at least this long, but it may be longer). - */ -static inline u32 kbasep_js_convert_gpu_ticks_to_us_max_freq(struct kbase_device *kbdev, u32 ticks) -{ - u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_max; - - KBASE_DEBUG_ASSERT(0 != gpu_freq); - return ticks / gpu_freq * 1000; -} - /* * The following locking conditions are made on the caller: * - The caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex. diff --git a/mali_kbase/mali_kbase_js_defs.h b/mali_kbase/mali_kbase_js_defs.h index 119344c..6f5feba 100644 --- a/mali_kbase/mali_kbase_js_defs.h +++ b/mali_kbase/mali_kbase_js_defs.h @@ -67,16 +67,6 @@ typedef void (*kbasep_js_ctx_job_cb)(struct kbase_device *kbdev, struct kbase_jd #define KBASE_JS_MAX_JOB_SUBMIT_PER_SLOT_PER_IRQ 2 /** - * @brief the IRQ_THROTTLE time in microseconds - * - * This will be converted via the GPU's clock frequency into a cycle-count. - * - * @note we can make an estimate of the GPU's frequency by periodically - * sampling its CYCLE_COUNT register - */ -#define KBASE_JS_IRQ_THROTTLE_TIME_US 20 - -/** * @brief Context attributes * * Each context attribute can be thought of as a boolean value that caches some diff --git a/mali_kbase/mali_kbase_mem.h b/mali_kbase/mali_kbase_mem.h index fb4ca4d..eefb4a2 100644 --- a/mali_kbase/mali_kbase_mem.h +++ b/mali_kbase/mali_kbase_mem.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 diff --git a/mali_kbase/mali_kbase_mem_linux.c b/mali_kbase/mali_kbase_mem_linux.c index 503a5ec..0b3a7da 100644 --- a/mali_kbase/mali_kbase_mem_linux.c +++ b/mali_kbase/mali_kbase_mem_linux.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 diff --git a/mali_kbase/mali_kbase_mem_linux.h b/mali_kbase/mali_kbase_mem_linux.h index 2053a47..97e0bec 100644 --- a/mali_kbase/mali_kbase_mem_linux.h +++ b/mali_kbase/mali_kbase_mem_linux.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010, 2012-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010, 2012-2017 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 diff --git a/mali_kbase/mali_kbase_softjobs.c b/mali_kbase/mali_kbase_softjobs.c index 2997e6f..8a9a47d 100644 --- a/mali_kbase/mali_kbase_softjobs.c +++ b/mali_kbase/mali_kbase_softjobs.c @@ -423,13 +423,22 @@ static void kbase_fence_debug_wait_timeout(struct kbase_jd_atom *katom) { struct kbase_context *kctx = katom->kctx; struct device *dev = katom->kctx->kbdev->dev; - struct sync_fence *fence = katom->fence; + struct sync_fence *fence; int timeout_ms = atomic_read(&kctx->kbdev->js_data.soft_job_timeout_ms); - int status = kbase_fence_get_status(fence); + int status; unsigned long lflags; spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags); + fence = katom->fence; + if (!fence) { + /* Fence must have signaled just after timeout. */ + spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags); + return; + } + + status = kbase_fence_get_status(fence); + dev_warn(dev, "ctx %d_%d: Atom %d still waiting for fence [%p] after %dms\n", kctx->tgid, kctx->id, kbase_jd_atom_id(kctx, katom), diff --git a/mali_kbase/mali_kbase_tlstream.c b/mali_kbase/mali_kbase_tlstream.c index 408b9d9..aa7850a 100644 --- a/mali_kbase/mali_kbase_tlstream.c +++ b/mali_kbase/mali_kbase_tlstream.c @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2015-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2015-2017 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 diff --git a/mali_kbase/mali_kbase_tlstream.h b/mali_kbase/mali_kbase_tlstream.h index 7349ab2..69e188e 100644 --- a/mali_kbase/mali_kbase_tlstream.h +++ b/mali_kbase/mali_kbase_tlstream.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2015-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2015-2017 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 diff --git a/mali_kbase/mali_kbase_uku.h b/mali_kbase/mali_kbase_uku.h index baa9296..3f2cb15 100644 --- a/mali_kbase/mali_kbase_uku.h +++ b/mali_kbase/mali_kbase_uku.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2008-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2008-2017 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 diff --git a/mali_kbase/mali_midg_regmap.h b/mali_kbase/mali_midg_regmap.h index 2d8231d..7d7b7bc 100644 --- a/mali_kbase/mali_midg_regmap.h +++ b/mali_kbase/mali_midg_regmap.h @@ -1,6 +1,6 @@ /* * - * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2010-2017 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 @@ -605,7 +605,6 @@ #define JM_FORCE_COHERENCY_FEATURES_SHIFT (2) #define JM_IDVS_GROUP_SIZE_SHIFT (16) #define JM_MAX_IDVS_GROUP_SIZE (0x3F) -#define JM_CONFIG_UNUSED (1ul << 31) /* End JM_CONFIG register */ diff --git a/mali_kbase/platform/Kbuild b/mali_kbase/platform/Kbuild deleted file mode 100644 index 558657b..0000000 --- a/mali_kbase/platform/Kbuild +++ /dev/null @@ -1,21 +0,0 @@ -# -# (C) COPYRIGHT 2012 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 -# Foundation, and any use by you of this program is subject to the terms -# of such GNU licence. -# -# A copy of the licence is included with the program, and can also be obtained -# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -# Boston, MA 02110-1301, USA. -# -# - - - -ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY),y) -# remove begin and end quotes from the Kconfig string type - platform_name := $(shell echo $(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME)) - obj-y += $(platform_name)/ -endif diff --git a/mali_kbase/platform/devicetree/Kbuild b/mali_kbase/platform/devicetree/Kbuild index b5a49f3..e888a42 100644 --- a/mali_kbase/platform/devicetree/Kbuild +++ b/mali_kbase/platform/devicetree/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2012-2016 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 @@ -13,10 +13,6 @@ # -ifeq ($(CONFIG_MALI_MIDGARD),y) -obj-y += mali_kbase_runtime_pm.c -obj-y += mali_kbase_config_devicetree.c -else ifeq ($(CONFIG_MALI_MIDGARD),m) -SRC += platform/devicetree/mali_kbase_runtime_pm.c -SRC += platform/devicetree/mali_kbase_config_devicetree.c -endif +mali_kbase-y += \ + $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_devicetree.o \ + $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_runtime_pm.o diff --git a/mali_kbase/platform/juno_soc/Kbuild b/mali_kbase/platform/juno_soc/Kbuild index 0449442..5e1ce63 100644 --- a/mali_kbase/platform/juno_soc/Kbuild +++ b/mali_kbase/platform/juno_soc/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2013-2014, 2016 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2013-2016 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 @@ -13,10 +13,4 @@ # -obj-y += mali_kbase_config_juno_soc.o - -ifeq (($CONFIG_MALI_MIDGARD),y) -obj-m += juno_mali_opp.o -else ifeq ($(CONFIG_MALI_MIDGARD),m) -SRC += platform/juno_soc/mali_kbase_config_juno_soc.c -endif +mali_kbase-y += $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_juno_soc.o diff --git a/mali_kbase/platform/juno_soc/juno_mali_opp.c b/mali_kbase/platform/juno_soc/juno_mali_opp.c deleted file mode 100644 index ccfd8cc..0000000 --- a/mali_kbase/platform/juno_soc/juno_mali_opp.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * (C) COPYRIGHT 2014 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 - * Foundation, and any use by you of this program is subject to the terms - * of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained - * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - - - -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> -#include <linux/scpi_protocol.h> -#include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) -#include <linux/pm_opp.h> -#else /* Linux >= 3.13 */ -/* In 3.13 the OPP include header file, types, and functions were all - * renamed. Use the old filename for the include, and define the new names to - * the old, when an old kernel is detected. - */ -#include <linux/opp.h> -#define dev_pm_opp_add opp_add -#endif /* Linux >= 3.13 */ - - -static int init_juno_opps_from_scpi(struct device *dev) -{ - struct scpi_opp *sopp; - int i; - - /* Hard coded for Juno. 2 is GPU domain */ - sopp = scpi_dvfs_get_opps(2); - if (IS_ERR_OR_NULL(sopp)) - return PTR_ERR(sopp); - - for (i = 0; i < sopp->count; i++) { - struct scpi_opp_entry *e = &sopp->opp[i]; - - dev_info(dev, "Mali OPP from SCPI: %u Hz @ %u mV\n", - e->freq_hz, e->volt_mv); - - dev_pm_opp_add(dev, e->freq_hz, e->volt_mv * 1000); - } - - return 0; -} - -static int juno_setup_opps(void) -{ - struct device_node *np; - struct platform_device *pdev; - int err; - - np = of_find_node_by_name(NULL, "gpu"); - if (!np) { - pr_err("Failed to find DT entry for Mali\n"); - return -EFAULT; - } - - pdev = of_find_device_by_node(np); - if (!pdev) { - pr_err("Failed to find device for Mali\n"); - of_node_put(np); - return -EFAULT; - } - - err = init_juno_opps_from_scpi(&pdev->dev); - - of_node_put(np); - - return err; -} - -module_init(juno_setup_opps); -MODULE_LICENSE("GPL"); diff --git a/mali_kbase/platform/vexpress/Kbuild b/mali_kbase/platform/vexpress/Kbuild index 084a156..1caa293 100644 --- a/mali_kbase/platform/vexpress/Kbuild +++ b/mali_kbase/platform/vexpress/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2012-2013, 2016 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 @@ -13,6 +13,6 @@ # - -obj-y += mali_kbase_config_vexpress.o -obj-y += mali_kbase_cpu_vexpress.o +mali_kbase-y += \ + $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_vexpress.o \ + $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_cpu_vexpress.o diff --git a/mali_kbase/platform/vexpress_1xv7_a57/Kbuild b/mali_kbase/platform/vexpress_1xv7_a57/Kbuild index d9bfabc..7efe8fa 100644 --- a/mali_kbase/platform/vexpress_1xv7_a57/Kbuild +++ b/mali_kbase/platform/vexpress_1xv7_a57/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2013 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2013-2014, 2016 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 @@ -13,4 +13,4 @@ # -obj-y += mali_kbase_config_vexpress.o +mali_kbase-y += $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_vexpress.o diff --git a/mali_kbase/platform/vexpress_6xvirtex7_10mhz/Kbuild b/mali_kbase/platform/vexpress_6xvirtex7_10mhz/Kbuild index 0cb41ce..1caa293 100644 --- a/mali_kbase/platform/vexpress_6xvirtex7_10mhz/Kbuild +++ b/mali_kbase/platform/vexpress_6xvirtex7_10mhz/Kbuild @@ -1,5 +1,5 @@ # -# (C) COPYRIGHT 2012 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2012-2013, 2016 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 @@ -13,6 +13,6 @@ # - -obj-y += mali_kbase_config_vexpress.o -obj-y += mali_kbase_cpu_vexpress.o +mali_kbase-y += \ + $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_vexpress.o \ + $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_cpu_vexpress.o |