diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-10-22 01:19:19 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-10-22 01:19:20 -0600 |
| commit | 3bc48e6ff186a1cda9b62b16ef60c7ca0568ca68 (patch) | |
| tree | 34283bbaa7d08866e06b7d18d353e644f933be11 | |
| parent | 8872faa0ca8698d138361a1d09237e0ca81b4a62 (diff) | |
| parent | 876d57315fbf6751b6f2ddc10cbc67d49455bd60 (diff) | |
Promotion of kernel.lnx.4.4-161022.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1069108 Iffc380898eac33f6c30c3808eb38d7bb499f5769 driver: thermal: msm_lmh_dcvs: Match the hardware freque
1077693 I59d4472b49b67f481992867a34e6779a4589d035 fg-util: fix a possible buffer overflow
1079245 Iee80fd2bf4b549665a12791009f0cf5ecc7653b9 msm: gsi: add command stats
1080510 I2ddb8b3b96063be3c6a6cb6bc333998e007f9de7 sched/core_ctl: Move header file to global location
1072739 I1405a8561b1ecb2e3da87ed8b26fb087433a1c11 ARM: dts: msm: Change pinctrl settings for BLSP1 UART3 f
1069108 If042fdae3102390dca6d5b1e257b38504b14320f defconfig: Enable generic cpu cooling device for msmcoba
1069108 I23762895d04dd6f1da8bb496f2a4cf22c1b34216 driver: thermal: msm_lmh_dcvs: Register LMH DCVS cooling
1080510 Iad0a9fc45f1ce87433995e8e549bfca80e8b9cb2 core_ctl: Add refcounting to boost api
1069108 I47960b002bf1bce1cd588de2892de46793a95562 drivers: thermal: cpu_cooling: allow platform freq mitig
1079061 Ia90832f9280f69c367c5d9f404b0d27c656e5c28 input: misc: pat9125: add sysfs for suspend-resume test
Change-Id: Ib2dcbeb2d85e602236c2196f3f306ab405b26f9f
CRs-Fixed: 1079061, 1072739, 1069108, 1079245, 1080510, 1077693
| -rw-r--r-- | arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi | 6 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi | 88 | ||||
| -rw-r--r-- | arch/arm64/configs/msmcortex-perf_defconfig | 1 | ||||
| -rw-r--r-- | arch/arm64/configs/msmcortex_defconfig | 1 | ||||
| -rw-r--r-- | drivers/input/misc/ots_pat9125/pat9125_linux_driver.c | 29 | ||||
| -rw-r--r-- | drivers/platform/msm/gsi/gsi.c | 17 | ||||
| -rw-r--r-- | drivers/platform/msm/gsi/gsi.h | 11 | ||||
| -rw-r--r-- | drivers/power/qcom-charger/fg-util.c | 11 | ||||
| -rw-r--r-- | drivers/thermal/cpu_cooling.c | 56 | ||||
| -rw-r--r-- | drivers/thermal/msm_lmh_dcvs.c | 74 | ||||
| -rw-r--r-- | include/linux/cpu_cooling.h | 16 | ||||
| -rw-r--r-- | include/linux/sched/core_ctl.h (renamed from kernel/sched/core_ctl.h) | 7 | ||||
| -rw-r--r-- | include/trace/events/sched.h | 15 | ||||
| -rw-r--r-- | kernel/sched/core.c | 2 | ||||
| -rw-r--r-- | kernel/sched/core_ctl.c | 33 | ||||
| -rw-r--r-- | kernel/sched/hmp.c | 2 |
16 files changed, 333 insertions, 36 deletions
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi index 929a079c64c3..a660ea06795e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi @@ -736,8 +736,10 @@ clocks = <&clock_gcc clk_gcc_blsp1_uart3_apps_clk>, <&clock_gcc clk_gcc_blsp1_ahb_clk>; pinctrl-names = "sleep", "default"; - pinctrl-0 = <&blsp1_uart3_sleep>; - pinctrl-1 = <&blsp1_uart3_active>; + pinctrl-0 = <&blsp1_uart3_tx_sleep>, <&blsp1_uart3_rxcts_sleep>, + <&blsp1_uart3_rfr_sleep>; + pinctrl-1 = <&blsp1_uart3_tx_active>, + <&blsp1_uart3_rxcts_active>, <&blsp1_uart3_rfr_active>; qcom,msm-bus,name = "buart3"; qcom,msm-bus,num-cases = <2>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi index 3975bc5d16f5..e5fd988dccce 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi @@ -1223,29 +1223,83 @@ }; }; - blsp1_uart3_active: blsp1_uart3_active { - mux { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - function = "blsp_uart3_a"; + blsp1_uart3: blsp1_uart3 { + blsp1_uart3_tx_active: blsp1_uart3_tx_active { + mux { + pins = "gpio45"; + function = "blsp_uart3_a"; + }; + + config { + pins = "gpio45"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - drive-strength = <2>; - bias-disable; + blsp1_uart3_tx_sleep: blsp1_uart3_tx_sleep { + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + drive-strength = <2>; + bias-pull-up; + }; }; - }; - blsp1_uart3_sleep: blsp1_uart3_sleep { - mux { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - function = "gpio"; + blsp1_uart3_rxcts_active: blsp1_uart3_rxcts_active { + mux { + pins = "gpio46", "gpio47"; + function = "blsp_uart3_a"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - drive-strength = <2>; - bias-pull-up; + blsp1_uart3_rxcts_sleep: blsp1_uart3_rxcts_sleep { + mux { + pins = "gpio46", "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart3_rfr_active: blsp1_uart3_rfr_active { + mux { + pins = "gpio48"; + function = "blsp_uart3_a"; + }; + + config { + pins = "gpio48"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart3_rfr_sleep: blsp1_uart3_rfr_sleep { + mux { + pins = "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio48"; + drive-strength = <2>; + bias-no-pull; + }; }; }; diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 5d2f29b053c4..0bda100dfb5a 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -321,6 +321,7 @@ CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y CONFIG_QPNP_QNOVO=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_CPU_THERMAL=y CONFIG_LIMITS_MONITOR=y CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 741f2e5bc8f6..3568fe4ed29f 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -324,6 +324,7 @@ CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y CONFIG_QPNP_QNOVO=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_CPU_THERMAL=y CONFIG_LIMITS_MONITOR=y CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y diff --git a/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c b/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c index ca5a9ec2f7f9..fa5e4cca129d 100644 --- a/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c +++ b/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c @@ -31,6 +31,10 @@ struct pixart_pat9125_data { struct pinctrl_state *pinctrl_state_release; }; +/* Declaration of suspend and resume functions */ +static int pat9125_suspend(struct device *dev); +static int pat9125_resume(struct device *dev); + static int pat9125_i2c_write(struct i2c_client *client, u8 reg, u8 *data, int len) { @@ -146,6 +150,27 @@ static irqreturn_t pat9125_irq(int irq, void *dev_data) return IRQ_HANDLED; } +static ssize_t pat9125_suspend_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct pixart_pat9125_data *data = + (struct pixart_pat9125_data *) dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int mode; + + if (kstrtoint(buf, 10, &mode)) { + dev_err(dev, "failed to read input for sysfs\n"); + return -EINVAL; + } + + if (mode == 1) + pat9125_suspend(&client->dev); + else if (mode == 0) + pat9125_resume(&client->dev); + + return count; +} + static ssize_t pat9125_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -191,11 +216,15 @@ static ssize_t pat9125_test_show(struct device *dev, { return 0; } + +static DEVICE_ATTR(suspend, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, pat9125_suspend_store); static DEVICE_ATTR(test, S_IRUGO | S_IWUSR | S_IWGRP, pat9125_test_show, pat9125_test_store); static struct attribute *pat9125_attr_list[] = { &dev_attr_test.attr, + &dev_attr_suspend.attr, NULL, }; diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index bd2132d77360..df3901093006 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -108,6 +108,11 @@ static void gsi_handle_ch_ctrl(int ee) GSIDBG("ch %x\n", ch); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { + if (i >= gsi_ctx->max_ch || i >= GSI_CHAN_MAX) { + GSIERR("invalid channel %d\n", i); + break; + } + ctx = &gsi_ctx->chan[i]; val = gsi_readl(gsi_ctx->base + GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(i, ee)); @@ -116,6 +121,7 @@ static void gsi_handle_ch_ctrl(int ee) GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT; GSIDBG("ch %u state updated to %u\n", i, ctx->state); complete(&ctx->compl); + gsi_ctx->ch_dbg[i].cmd_completed++; } } @@ -135,6 +141,11 @@ static void gsi_handle_ev_ctrl(int ee) GSIDBG("ev %x\n", ch); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { + if (i >= gsi_ctx->max_ev || i >= GSI_EVT_RING_MAX) { + GSIERR("invalid event %d\n", i); + break; + } + ctx = &gsi_ctx->evtr[i]; val = gsi_readl(gsi_ctx->base + GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(i, ee)); @@ -1605,6 +1616,7 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, ctx->props = *props; mutex_lock(&gsi_ctx->mlock); + gsi_ctx->ch_dbg[props->ch_id].ch_allocate++; val = (((props->ch_id << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1775,6 +1787,7 @@ int gsi_start_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_start++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1832,6 +1845,7 @@ int gsi_stop_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_stop++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1900,6 +1914,7 @@ int gsi_stop_db_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_db_stop++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1964,6 +1979,7 @@ int gsi_reset_channel(unsigned long chan_hdl) reset: init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_reset++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -2030,6 +2046,7 @@ int gsi_dealloc_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_de_alloc++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index 0b94ed2d3a92..750ae2b329d3 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -125,12 +125,23 @@ struct gsi_ee_scratch { uint32_t word1; }; +struct ch_debug_stats { + unsigned long ch_allocate; + unsigned long ch_start; + unsigned long ch_stop; + unsigned long ch_reset; + unsigned long ch_de_alloc; + unsigned long ch_db_stop; + unsigned long cmd_completed; +}; + struct gsi_ctx { void __iomem *base; struct device *dev; struct gsi_per_props per; bool per_registered; struct gsi_chan_ctx chan[GSI_CHAN_MAX]; + struct ch_debug_stats ch_dbg[GSI_CHAN_MAX]; struct gsi_evt_ctx evtr[GSI_EVT_RING_MAX]; struct mutex mlock; spinlock_t slock; diff --git a/drivers/power/qcom-charger/fg-util.c b/drivers/power/qcom-charger/fg-util.c index bbdbe48896d7..0e3c7dbb5731 100644 --- a/drivers/power/qcom-charger/fg-util.c +++ b/drivers/power/qcom-charger/fg-util.c @@ -621,6 +621,17 @@ static ssize_t fg_sram_dfs_reg_write(struct file *file, const char __user *buf, /* Parse the data in the buffer. It should be a string of numbers */ while ((pos < count) && sscanf(kbuf + pos, "%i%n", &data, &bytes_read) == 1) { + /* + * We shouldn't be receiving a string of characters that + * exceeds a size of 5 to keep this functionally correct. + * Also, we should make sure that pos never gets overflowed + * beyond the limit. + */ + if (bytes_read > 5 || bytes_read > INT_MAX - pos) { + cnt = 0; + ret = -EINVAL; + break; + } pos += bytes_read; values[cnt++] = data & 0xff; } diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 6ceac4f2d4b2..560c5c72daeb 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -103,6 +103,7 @@ struct cpufreq_cooling_device { int dyn_power_table_entries; struct device *cpu_dev; get_static_t plat_get_static_power; + struct cpu_cooling_ops *plat_ops; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); @@ -504,8 +505,13 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; + unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); - *state = cpufreq_device->cpufreq_state; + if (cpufreq_device->plat_ops + && cpufreq_device->plat_ops->get_cur_state) + cpufreq_device->plat_ops->get_cur_state(cpu, state); + else + *state = cpufreq_device->cpufreq_state; return 0; } @@ -539,7 +545,17 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, cpufreq_device->cpufreq_state = state; cpufreq_device->clipped_freq = clip_freq; - cpufreq_update_policy(cpu); + /* Check if the device has a platform mitigation function that + * can handle the CPU freq mitigation, if not, notify cpufreq + * framework. + */ + if (cpufreq_device->plat_ops) { + if (cpufreq_device->plat_ops->ceil_limit) + cpufreq_device->plat_ops->ceil_limit(cpu, + clip_freq); + } else { + cpufreq_update_policy(cpu); + } return 0; } @@ -773,6 +789,9 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table, * @capacitance: dynamic power coefficient for these cpus * @plat_static_func: function to calculate the static power consumed by these * cpus (optional) + * @plat_mitig_func: function that does the mitigation by changing the + * frequencies (Optional). By default, cpufreq framweork will + * be notified of the new limits. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq @@ -785,7 +804,8 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table, static struct thermal_cooling_device * __cpufreq_cooling_register(struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance, - get_static_t plat_static_func) + get_static_t plat_static_func, + struct cpu_cooling_ops *plat_ops) { struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev; @@ -851,6 +871,8 @@ __cpufreq_cooling_register(struct device_node *np, } } + cpufreq_dev->plat_ops = plat_ops; + ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); if (ret) { cool_dev = ERR_PTR(ret); @@ -924,7 +946,7 @@ free_cdev: struct thermal_cooling_device * cpufreq_cooling_register(const struct cpumask *clip_cpus) { - return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL); + return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL, NULL); } EXPORT_SYMBOL_GPL(cpufreq_cooling_register); @@ -948,7 +970,7 @@ of_cpufreq_cooling_register(struct device_node *np, if (!np) return ERR_PTR(-EINVAL); - return __cpufreq_cooling_register(np, clip_cpus, 0, NULL); + return __cpufreq_cooling_register(np, clip_cpus, 0, NULL, NULL); } EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); @@ -978,11 +1000,31 @@ cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance, get_static_t plat_static_func) { return __cpufreq_cooling_register(NULL, clip_cpus, capacitance, - plat_static_func); + plat_static_func, NULL); } EXPORT_SYMBOL(cpufreq_power_cooling_register); /** + * cpufreq_platform_cooling_register() - create cpufreq cooling device with + * additional platform specific mitigation function. + * + * @clip_cpus: cpumask of cpus where the frequency constraints will happen + * @plat_ops: the platform mitigation functions that will be called insted of + * cpufreq, if provided. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +struct thermal_cooling_device * +cpufreq_platform_cooling_register(const struct cpumask *clip_cpus, + struct cpu_cooling_ops *plat_ops) +{ + return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL, + plat_ops); +} +EXPORT_SYMBOL(cpufreq_platform_cooling_register); + +/** * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions * @np: a valid struct device_node to the cooling device device tree node * @clip_cpus: cpumask of cpus where the frequency constraints will happen @@ -1015,7 +1057,7 @@ of_cpufreq_power_cooling_register(struct device_node *np, return ERR_PTR(-EINVAL); return __cpufreq_cooling_register(np, clip_cpus, capacitance, - plat_static_func); + plat_static_func, NULL); } EXPORT_SYMBOL(of_cpufreq_power_cooling_register); diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c index fbe76eaa3867..3758e39a1c02 100644 --- a/drivers/thermal/msm_lmh_dcvs.c +++ b/drivers/thermal/msm_lmh_dcvs.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/timer.h> #include <linux/pm_opp.h> +#include <linux/cpu_cooling.h> #include <asm/smp_plat.h> #include <asm/cacheflush.h> @@ -40,6 +41,7 @@ #define MSM_LIMITS_NODE_DCVS 0x44435653 #define MSM_LIMITS_SUB_FN_THERMAL 0x54484D4C +#define MSM_LIMITS_SUB_FN_GENERAL 0x47454E00 #define MSM_LIMITS_ALGO_MODE_ENABLE 0x454E424C @@ -49,6 +51,8 @@ #define MSM_LIMITS_CLUSTER_0 0x6370302D #define MSM_LIMITS_CLUSTER_1 0x6370312D +#define MSM_LIMITS_DOMAIN_MAX 0x444D4158 + #define MSM_LIMITS_HIGH_THRESHOLD_VAL 95000 #define MSM_LIMITS_ARM_THRESHOLD_VAL 65000 #define MSM_LIMITS_POLLING_DELAY_MS 10 @@ -77,8 +81,12 @@ struct msm_lmh_dcvs_hw { cpumask_t core_map; struct timer_list poll_timer; uint32_t max_freq; + uint32_t hw_freq_limit; + struct list_head list; }; +LIST_HEAD(lmh_dcvs_hw_list); + static void msm_lmh_dcvs_get_max_freq(uint32_t cpu, uint32_t *max_freq) { unsigned long freq_ceil = UINT_MAX; @@ -99,12 +107,29 @@ static void msm_lmh_dcvs_get_max_freq(uint32_t cpu, uint32_t *max_freq) static uint32_t msm_lmh_mitigation_notify(struct msm_lmh_dcvs_hw *hw) { uint32_t max_limit = 0, val = 0; + struct device *cpu_dev = NULL; + unsigned long freq_val; val = readl_relaxed(hw->osm_hw_reg); dcvsh_get_frequency(val, max_limit); + cpu_dev = get_cpu_device(cpumask_first(&hw->core_map)); + if (!cpu_dev) { + pr_err("Error in get CPU%d device\n", + cpumask_first(&hw->core_map)); + goto notify_exit; + } + + freq_val = max_limit; + rcu_read_lock(); + dev_pm_opp_find_freq_floor(cpu_dev, &freq_val); + rcu_read_unlock(); + max_limit = freq_val; + sched_update_cpu_freq_min_max(&hw->core_map, 0, max_limit); trace_lmh_dcvs_freq(cpumask_first(&hw->core_map), max_limit); +notify_exit: + hw->hw_freq_limit = max_limit; return max_limit; } @@ -250,6 +275,45 @@ static int trip_notify(enum thermal_trip_type type, int temp, void *data) return 0; } +static struct msm_lmh_dcvs_hw *get_dcvsh_hw_from_cpu(int cpu) +{ + struct msm_lmh_dcvs_hw *hw; + + list_for_each_entry(hw, &lmh_dcvs_hw_list, list) { + if (cpumask_test_cpu(cpu, &hw->core_map)) + return hw; + } + + return NULL; +} + +static int lmh_set_max_limit(int cpu, u32 freq) +{ + struct msm_lmh_dcvs_hw *hw = get_dcvsh_hw_from_cpu(cpu); + + if (!hw) + return -EINVAL; + + return msm_lmh_dcvs_write(hw->affinity, MSM_LIMITS_SUB_FN_GENERAL, + MSM_LIMITS_DOMAIN_MAX, freq); +} + +static int lmh_get_cur_limit(int cpu, unsigned long *freq) +{ + struct msm_lmh_dcvs_hw *hw = get_dcvsh_hw_from_cpu(cpu); + + if (!hw) + return -EINVAL; + *freq = hw->hw_freq_limit; + + return 0; +} + +static struct cpu_cooling_ops cd_ops = { + .get_cur_state = lmh_get_cur_limit, + .ceil_limit = lmh_set_max_limit, +}; + static int msm_lmh_dcvs_probe(struct platform_device *pdev) { int ret; @@ -257,6 +321,7 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) struct msm_lmh_dcvs_hw *hw; char sensor_name[] = "limits_sensor-00"; struct thermal_zone_device *tzdev; + struct thermal_cooling_device *cdev; struct device_node *dn = pdev->dev.of_node; struct device_node *cpu_node, *lmh_node; uint32_t id, max_freq, request_reg, clear_reg; @@ -331,6 +396,10 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) if (IS_ERR_OR_NULL(tzdev)) return PTR_ERR(tzdev); + /* Setup cooling devices to request mitigation states */ + cdev = cpufreq_platform_cooling_register(&hw->core_map, &cd_ops); + if (IS_ERR_OR_NULL(cdev)) + return PTR_ERR(cdev); /* * Driver defaults to for low and hi thresholds. * Since we make a check for hi > lo value, set the hi threshold @@ -356,7 +425,7 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) return ret; } - hw->max_freq = max_freq; + hw->hw_freq_limit = hw->max_freq = max_freq; switch (affinity) { case 0: @@ -399,6 +468,9 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) return ret; } + INIT_LIST_HEAD(&hw->list); + list_add(&hw->list, &lmh_dcvs_hw_list); + return ret; } diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index c156f5082758..e221494fb7a0 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -31,6 +31,11 @@ typedef int (*get_static_t)(cpumask_t *cpumask, int interval, unsigned long voltage, u32 *power); +struct cpu_cooling_ops { + int (*ceil_limit)(int, u32); + int (*get_cur_state)(int, unsigned long *); +}; + #ifdef CONFIG_CPU_THERMAL /** * cpufreq_cooling_register - function to create cpufreq cooling device. @@ -43,6 +48,10 @@ struct thermal_cooling_device * cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance, get_static_t plat_static_func); +struct thermal_cooling_device * +cpufreq_platform_cooling_register(const struct cpumask *clip_cpus, + struct cpu_cooling_ops *ops); + /** * of_cpufreq_cooling_register - create cpufreq cooling device based on DT. * @np: a valid struct device_node to the cooling device device tree node. @@ -112,6 +121,13 @@ of_cpufreq_power_cooling_register(struct device_node *np, return NULL; } +static inline struct thermal_cooling_device * +cpufreq_platform_cooling_register(const struct cpumask *clip_cpus, + struct cpu_cooling_ops *ops) +{ + return NULL; +} + static inline void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) { diff --git a/kernel/sched/core_ctl.h b/include/linux/sched/core_ctl.h index 3b0c12acb9c0..98d7cb3e899b 100644 --- a/kernel/sched/core_ctl.h +++ b/include/linux/sched/core_ctl.h @@ -16,9 +16,12 @@ #ifdef CONFIG_SCHED_CORE_CTL void core_ctl_check(u64 wallclock); -void core_ctl_set_boost(bool boost); +int core_ctl_set_boost(bool boost); #else static inline void core_ctl_check(u64 wallclock) {} -static inline void core_ctl_set_boost(bool boost) {} +static inline int core_ctl_set_boost(bool boost) +{ + return 0; +} #endif #endif diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index cd15ae7b8b0c..7778ff3947de 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -1323,6 +1323,21 @@ TRACE_EVENT(core_ctl_set_busy, __entry->is_busy) ); +TRACE_EVENT(core_ctl_set_boost, + + TP_PROTO(u32 refcount, s32 ret), + TP_ARGS(refcount, ret), + TP_STRUCT__entry( + __field(u32, refcount) + __field(s32, ret) + ), + TP_fast_assign( + __entry->refcount = refcount; + __entry->ret = ret; + ), + TP_printk("refcount=%u, ret=%d", __entry->refcount, __entry->ret) +); + /** * sched_isolate - called when cores are isolated/unisolated * diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 7e7e19ed53c6..53f7b50b7541 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -75,6 +75,7 @@ #include <linux/context_tracking.h> #include <linux/compiler.h> #include <linux/irq.h> +#include <linux/sched/core_ctl.h> #include <asm/switch_to.h> #include <asm/tlb.h> @@ -85,7 +86,6 @@ #endif #include "sched.h" -#include "core_ctl.h" #include "../workqueue_internal.h" #include "../smpboot.h" diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index d81886da7ca2..0db85a4fa9c8 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -45,7 +45,7 @@ struct cluster_data { bool nrrun_changed; struct task_struct *core_ctl_thread; unsigned int first_cpu; - bool boost; + unsigned int boost; struct kobject kobj; }; @@ -652,17 +652,40 @@ static bool do_check(u64 wallclock) return do_check; } -void core_ctl_set_boost(bool boost) +int core_ctl_set_boost(bool boost) { unsigned int index = 0; struct cluster_data *cluster; + unsigned long flags; + int ret = 0; + bool boost_state_changed = false; + spin_lock_irqsave(&state_lock, flags); for_each_cluster(cluster, index) { - if (cluster->is_big_cluster && cluster->boost != boost) { - cluster->boost = boost; - apply_need(cluster); + if (cluster->is_big_cluster) { + if (boost) { + boost_state_changed = !cluster->boost; + ++cluster->boost; + } else { + if (!cluster->boost) { + pr_err("Error turning off boost. Boost already turned off\n"); + ret = -EINVAL; + } else { + --cluster->boost; + boost_state_changed = !cluster->boost; + } + } + break; } } + spin_unlock_irqrestore(&state_lock, flags); + + if (boost_state_changed) + apply_need(cluster); + + trace_core_ctl_set_boost(cluster->boost, ret); + + return ret; } void core_ctl_check(u64 wallclock) diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 7039eb8f1e63..d220482f4dbc 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -18,9 +18,9 @@ #include <linux/list_sort.h> #include <linux/syscore_ops.h> #include <linux/of.h> +#include <linux/sched/core_ctl.h> #include "sched.h" -#include "core_ctl.h" #include <trace/events/sched.h> |
