All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH 3/6] API/cgroup: Add option for specific pid to tst_cgroup_opts
From: Luke Nowakowski-Krijger @ 2022-01-05 10:00 UTC (permalink / raw)
  To: ltp
In-Reply-To: <cover.1641376050.git.luke.nowakowskikrijger@canonical.com>

Add an option that would allow to create a test directory with a
specified pid, as opposed to the calling processes pid.

Signed-off-by: Luke Nowakowski-Krijger <luke.nowakowskikrijger@canonical.com>
---
 include/tst_cgroup.h | 3 +++
 lib/tst_cgroup.c     | 6 +++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/include/tst_cgroup.h b/include/tst_cgroup.h
index 632050e86..cfcc189ee 100644
--- a/include/tst_cgroup.h
+++ b/include/tst_cgroup.h
@@ -98,6 +98,9 @@ struct tst_cgroup_opts {
 	 * only indicates that we should mount V1 controllers if
 	 * nothing is present. By default we try to mount V2 first. */
 	int only_mount_v1:1;
+	/* Pass in a specific pid to create and identify the test
+	 * directory as opposed to the default pid of the calling process. */
+	int test_pid;
 };
 
 /* A Control Group in LTP's aggregated hierarchy */
diff --git a/lib/tst_cgroup.c b/lib/tst_cgroup.c
index b06ae6ab7..1cec3e722 100644
--- a/lib/tst_cgroup.c
+++ b/lib/tst_cgroup.c
@@ -713,7 +713,11 @@ mkdirs:
 
 	cgroup_dir_mk(&root->ltp_dir, cgroup_ltp_drain_dir, &root->drain_dir);
 
-	sprintf(cgroup_test_dir, "test-%d", getpid());
+	if (options->test_pid)
+		sprintf(cgroup_test_dir, "test-%d", options->test_pid);
+	else
+		sprintf(cgroup_test_dir, "test-%d", getpid());
+
 	cgroup_dir_mk(&root->ltp_dir, cgroup_test_dir, &root->test_dir);
 }
 
-- 
2.32.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related

* [LTP] [PATCH 1/6] API/cgroup: Modify tst_cgroup_print_config for easier parsing and consumption
From: Luke Nowakowski-Krijger @ 2022-01-05 10:00 UTC (permalink / raw)
  To: ltp
In-Reply-To: <cover.1641376050.git.luke.nowakowskikrijger@canonical.com>

Prepare tst_cgroup_print_config to be more easily parsed and consumed by
shell scripts and other programs.

Also add any detected root information as well as the relevant state
associated with the roots that would be needed by the test to properly
cleanup.

Signed-off-by: Luke Nowakowski-Krijger <luke.nowakowskikrijger@canonical.com>
---
 lib/tst_cgroup.c | 38 ++++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/lib/tst_cgroup.c b/lib/tst_cgroup.c
index c08ff2f20..166d0f97e 100644
--- a/lib/tst_cgroup.c
+++ b/lib/tst_cgroup.c
@@ -300,12 +300,27 @@ opendir:
 				  O_PATH | O_DIRECTORY);
 }
 
+#define CONFIG_LTPDIR_KEY "Created_Ltp_Dir"
+#define CONFIG_MOUNTROOT_KEY "Mounted_Root"
+#define CONFIG_DRAINDIR_KEY "Created_Drain_Dir"
+#define CONFIG_TESTID_KEY "Test_Id"
+#define CONFIG_CTRL_REQUIRED "Required"
+#define CONFIG_CTRL_HEADER "Detected Controllers:"
+#define CONFIG_ROOT_HEADER "Detected Roots:"
+
+/* Prints out the minimal internal state of the test to be consumed
+ * by tst_cgroup_load_config().
+ *
+ * The config keeps track of the minimal state needed for tst_cgroup_cleanup
+ * to cleanup after a test and does not keep track of the creation of
+ * test cgroups that might be created through tst_cgroup_group_mk().
+ */
 void tst_cgroup_print_config(void)
 {
 	struct cgroup_root *root;
 	const struct cgroup_ctrl *ctrl;
 
-	tst_res(TINFO, "Detected Controllers:");
+	printf("%s\n", CONFIG_CTRL_HEADER);
 
 	for_each_ctrl(ctrl) {
 		root = ctrl->ctrl_root;
@@ -313,11 +328,26 @@ void tst_cgroup_print_config(void)
 		if (!root)
 			continue;
 
-		tst_res(TINFO, "\t%.10s %s @ %s:%s",
+		printf("%s %s @ %s %s\n",
 			ctrl->ctrl_name,
-			root->no_cpuset_prefix ? "[noprefix]" : "",
 			root->ver == TST_CGROUP_V1 ? "V1" : "V2",
-			root->mnt_path);
+			root->mnt_path,
+			ctrl->we_require_it ? CONFIG_CTRL_REQUIRED : "");
+	}
+
+	printf("%s\n", CONFIG_ROOT_HEADER);
+
+	for_each_root(root) {
+		printf("%s %s=%s %s=%s %s=%s %s=%s\n",
+			root->mnt_path,
+			CONFIG_MOUNTROOT_KEY,
+			root->we_mounted_it ? "yes" : "no",
+			CONFIG_LTPDIR_KEY,
+			root->ltp_dir.we_created_it ? "yes" : "no",
+			CONFIG_DRAINDIR_KEY,
+			root->drain_dir.we_created_it ? "yes" : "no",
+			CONFIG_TESTID_KEY,
+			root->test_dir.dir_name ? root->test_dir.dir_name : "NULL");
 	}
 }
 
-- 
2.32.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related

* [LTP] [PATCH 2/6] API/cgroup: Add cgroup_find_root helper function
From: Luke Nowakowski-Krijger @ 2022-01-05 10:00 UTC (permalink / raw)
  To: ltp
In-Reply-To: <cover.1641376050.git.luke.nowakowskikrijger@canonical.com>

Add a helper function similar to cgroup_find_ctrl to make matching paths
to roots more convenient.

Signed-off-by: Luke Nowakowski-Krijger <luke.nowakowskikrijger@canonical.com>
---
 lib/tst_cgroup.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/lib/tst_cgroup.c b/lib/tst_cgroup.c
index 166d0f97e..b06ae6ab7 100644
--- a/lib/tst_cgroup.c
+++ b/lib/tst_cgroup.c
@@ -365,6 +365,19 @@ static struct cgroup_ctrl *cgroup_find_ctrl(const char *const ctrl_name)
 	return ctrl;
 }
 
+static struct cgroup_root *cgroup_find_root(const char *const mnt_path)
+{
+	struct cgroup_root *root = roots;
+
+	while (root->ver && strcmp(root->mnt_path, mnt_path))
+		root++;
+
+	if (!root->ver)
+		root = NULL;
+
+	return root;
+}
+
 /* Determine if a mounted cgroup hierarchy is unique and record it if so.
  *
  * For CGroups V2 this is very simple as there is only one
-- 
2.32.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related

* Re: [PATCH v20 3/7] soc: mediatek: SVS: introduce MTK SVS engine
From: AngeloGioacchino Del Regno @ 2022-01-05  9:58 UTC (permalink / raw)
  To: Roger Lu, Matthias Brugger, Enric Balletbo Serra, Kevin Hilman,
	Rob Herring, Nicolas Boichat, Stephen Boyd, Philipp Zabel
  Cc: Fan Chen, HenryC Chen, YT Lee, Xiaoqing Liu, Charles Yang,
	Angus Lin, Mark Rutland, Nishanth Menon, devicetree,
	linux-arm-kernel, linux-mediatek, linux-kernel, linux-pm,
	Project_Global_Chrome_Upstream_Group, Guenter Roeck
In-Reply-To: <20210721070904.15636-4-roger.lu@mediatek.com>

Il 21/07/21 09:09, Roger Lu ha scritto:
> The Smart Voltage Scaling(SVS) engine is a piece of hardware
> which calculates suitable SVS bank voltages to OPP voltage table.
> Then, DVFS driver could apply those SVS bank voltages to PMIC/Buck
> when receiving OPP_EVENT_ADJUST_VOLTAGE.
> 
> Signed-off-by: Roger Lu <roger.lu@mediatek.com>

Hello Roger,
thanks for the patch!

However, there are a few things to improve...

> ---
>   drivers/soc/mediatek/Kconfig   |   10 +
>   drivers/soc/mediatek/Makefile  |    1 +
>   drivers/soc/mediatek/mtk-svs.c | 1720 ++++++++++++++++++++++++++++++++
>   3 files changed, 1731 insertions(+)
>   create mode 100644 drivers/soc/mediatek/mtk-svs.c
> 
> diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
> index fdd8bc08569e..3c3eedea35f7 100644
> --- a/drivers/soc/mediatek/Kconfig
> +++ b/drivers/soc/mediatek/Kconfig
> @@ -73,4 +73,14 @@ config MTK_MMSYS
>   	  Say yes here to add support for the MediaTek Multimedia
>   	  Subsystem (MMSYS).
>   
> +config MTK_SVS
> +	tristate "MediaTek Smart Voltage Scaling(SVS)"
> +	depends on MTK_EFUSE && NVMEM
> +	help
> +	  The Smart Voltage Scaling(SVS) engine is a piece of hardware
> +	  which has several controllers(banks) for calculating suitable
> +	  voltage to different power domains(CPU/GPU/CCI) according to
> +	  chip process corner, temperatures and other factors. Then DVFS
> +	  driver could apply SVS bank voltage to PMIC/Buck.
> +
>   endmenu
> diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
> index 90270f8114ed..0e9e703c931a 100644
> --- a/drivers/soc/mediatek/Makefile
> +++ b/drivers/soc/mediatek/Makefile
> @@ -7,3 +7,4 @@ obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
>   obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
>   obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
>   obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
> +obj-$(CONFIG_MTK_SVS) += mtk-svs.o
> diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
> new file mode 100644
> index 000000000000..013667752ec2
> --- /dev/null
> +++ b/drivers/soc/mediatek/mtk-svs.c
> @@ -0,0 +1,1720 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_opp.h>
> +#include <linux/pm_qos.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/thermal.h>
> +
> +/* svs bank 1-line sw id */
> +#define SVSB_CPU_LITTLE			BIT(0)
> +#define SVSB_CPU_BIG			BIT(1)
> +#define SVSB_CCI			BIT(2)
> +#define SVSB_GPU			BIT(3)
> +
> +/* svs bank mode support */
> +#define SVSB_MODE_ALL_DISABLE		0
> +#define SVSB_MODE_INIT01		BIT(1)
> +#define SVSB_MODE_INIT02		BIT(2)
> +#define SVSB_MODE_MON			BIT(3)
> +
> +/* svs bank volt flags */
> +#define SVSB_INIT01_VOLT_IGNORE		BIT(1)
> +#define SVSB_INIT01_VOLT_INC_ONLY	BIT(2)
> +#define SVSB_INIT02_RM_DVTFIXED		BIT(8)
> +#define SVSB_MON_VOLT_IGNORE		BIT(16)
> +
> +/* svs bank common setting */
> +#define SVSB_DET_CLK_EN			BIT(31)
> +#define SVSB_TZONE_HIGH_TEMP_MAX	U32_MAX
> +#define SVSB_RUNCONFIG_DEFAULT		0x80000000
> +#define SVSB_DC_SIGNED_BIT		0x8000

SVSB_DC_SIGNED_BIT is.. clearly a bit, so this should be BIT(15)

> +#define SVSB_INTEN_INIT0x		0x00005f01
> +#define SVSB_INTEN_MONVOPEN		0x00ff0000
> +#define SVSB_EN_OFF			0x0
> +#define SVSB_EN_MASK			0x7
> +#define SVSB_EN_INIT01			0x1
> +#define SVSB_EN_INIT02			0x5
> +#define SVSB_EN_MON			0x2
> +#define SVSB_INTSTS_MONVOP		0x00ff0000
> +#define SVSB_INTSTS_COMPLETE		0x1
> +#define SVSB_INTSTS_CLEAN		0x00ffffff
> +
> +static DEFINE_SPINLOCK(mtk_svs_lock);
> +
> +/*

Looks like the great intention is to have kernel-doc here, and it's already
in the right format, but the start of the comment block should be

/**

and not

/*

to be recognized as kerneldoc.
Please refer to https://www.kernel.org/doc/html/v5.15/doc-guide/kernel-doc.html

> + * enum svsb_phase - svs bank phase enumeration
> + * @SVSB_PHASE_INIT01: basic init for svs bank
> + * @SVSB_PHASE_INIT02: svs bank can provide voltages
> + * @SVSB_PHASE_MON: svs bank can provide voltages with thermal effect
> + * @SVSB_PHASE_ERROR: svs bank encounters unexpected condition

Please move @SVSB_PHASE_ERROR before @SVSB_PHASE_INIT01: the order

is important here, and has to be the same as the actual enumeration.

> + *
> + * Each svs bank has its own independent phase. We enable each svs bank by
> + * running their phase orderly. However, When svs bank encounters unexpected
> + * condition, it will fire an irq (PHASE_ERROR) to inform svs software.
> + *
> + * svs bank general phase-enabled order:
> + * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 -> SVSB_PHASE_MON
> + */
> +enum svsb_phase {
> +	SVSB_PHASE_ERROR = 0,
> +	SVSB_PHASE_INIT01,
> +	SVSB_PHASE_INIT02,
> +	SVSB_PHASE_MON,
> +};
> +
> +enum svs_reg_index {
> +	DESCHAR = 0,
> +	TEMPCHAR,
> +	DETCHAR,
> +	AGECHAR,
> +	DCCONFIG,
> +	AGECONFIG,
> +	FREQPCT30,
> +	FREQPCT74,
> +	LIMITVALS,
> +	VBOOT,
> +	DETWINDOW,
> +	CONFIG,
> +	TSCALCS,
> +	RUNCONFIG,
> +	SVSEN,
> +	INIT2VALS,
> +	DCVALUES,
> +	AGEVALUES,
> +	VOP30,
> +	VOP74,
> +	TEMP,
> +	INTSTS,
> +	INTSTSRAW,
> +	INTEN,
> +	CHKINT,
> +	CHKSHIFT,
> +	STATUS,
> +	VDESIGN30,
> +	VDESIGN74,
> +	DVT30,
> +	DVT74,
> +	AGECOUNT,
> +	SMSTATE0,
> +	SMSTATE1,
> +	CTL0,
> +	DESDETSEC,
> +	TEMPAGESEC,
> +	CTRLSPARE0,
> +	CTRLSPARE1,
> +	CTRLSPARE2,
> +	CTRLSPARE3,
> +	CORESEL,
> +	THERMINTST,
> +	INTST,
> +	THSTAGE0ST,
> +	THSTAGE1ST,
> +	THSTAGE2ST,
> +	THAHBST0,
> +	THAHBST1,
> +	SPARE0,
> +	SPARE1,
> +	SPARE2,
> +	SPARE3,
> +	THSLPEVEB,
> +};
> +
> +static const u32 svs_regs_v2[] = {
> +	[DESCHAR]		= 0xc00,
> +	[TEMPCHAR]		= 0xc04,
> +	[DETCHAR]		= 0xc08,
> +	[AGECHAR]		= 0xc0c,
> +	[DCCONFIG]		= 0xc10,
> +	[AGECONFIG]		= 0xc14,
> +	[FREQPCT30]		= 0xc18,
> +	[FREQPCT74]		= 0xc1c,
> +	[LIMITVALS]		= 0xc20,
> +	[VBOOT]			= 0xc24,
> +	[DETWINDOW]		= 0xc28,
> +	[CONFIG]		= 0xc2c,
> +	[TSCALCS]		= 0xc30,
> +	[RUNCONFIG]		= 0xc34,
> +	[SVSEN]			= 0xc38,
> +	[INIT2VALS]		= 0xc3c,
> +	[DCVALUES]		= 0xc40,
> +	[AGEVALUES]		= 0xc44,
> +	[VOP30]			= 0xc48,
> +	[VOP74]			= 0xc4c,
> +	[TEMP]			= 0xc50,
> +	[INTSTS]		= 0xc54,
> +	[INTSTSRAW]		= 0xc58,
> +	[INTEN]			= 0xc5c,
> +	[CHKINT]		= 0xc60,
> +	[CHKSHIFT]		= 0xc64,
> +	[STATUS]		= 0xc68,
> +	[VDESIGN30]		= 0xc6c,
> +	[VDESIGN74]		= 0xc70,
> +	[DVT30]			= 0xc74,
> +	[DVT74]			= 0xc78,
> +	[AGECOUNT]		= 0xc7c,
> +	[SMSTATE0]		= 0xc80,
> +	[SMSTATE1]		= 0xc84,
> +	[CTL0]			= 0xc88,
> +	[DESDETSEC]		= 0xce0,
> +	[TEMPAGESEC]		= 0xce4,
> +	[CTRLSPARE0]		= 0xcf0,
> +	[CTRLSPARE1]		= 0xcf4,
> +	[CTRLSPARE2]		= 0xcf8,
> +	[CTRLSPARE3]		= 0xcfc,
> +	[CORESEL]		= 0xf00,
> +	[THERMINTST]		= 0xf04,
> +	[INTST]			= 0xf08,
> +	[THSTAGE0ST]		= 0xf0c,
> +	[THSTAGE1ST]		= 0xf10,
> +	[THSTAGE2ST]		= 0xf14,
> +	[THAHBST0]		= 0xf18,
> +	[THAHBST1]		= 0xf1c,
> +	[SPARE0]		= 0xf20,
> +	[SPARE1]		= 0xf24,
> +	[SPARE2]		= 0xf28,
> +	[SPARE3]		= 0xf2c,
> +	[THSLPEVEB]		= 0xf30,
> +};
> +
> +/*
> + * struct thermal_parameter - This is for storing thermal efuse data.
> + * We calculate thermal efuse data to produce "mts" and "bts" for
> + * svs bank mon mode.
> + */
> +struct thermal_parameter {
> +	int adc_ge_t;
> +	int adc_oe_t;
> +	int ge;
> +	int oe;
> +	int gain;
> +	int o_vtsabb;
> +	int o_vtsmcu1;
> +	int o_vtsmcu2;
> +	int o_vtsmcu3;
> +	int o_vtsmcu4;
> +	int o_vtsmcu5;
> +	int degc_cali;
> +	int adc_cali_en_t;
> +	int o_slope;
> +	int o_slope_sign;
> +	int ts_id;
> +};
> +
> +/*

... same here, /** for kerneldoc

> + * struct svs_platform - svs platform data
> + * @dev: svs platform device
> + * @base: svs platform register address base
> + * @main_clk: main clock for svs bank
> + * @pbank: phandle of svs bank and needs to be protected by spin_lock
> + * @banks: phandle of the banks that support
> + * @efuse_parsing: phandle of efuse parsing function
> + * @irqflags: irq settings flags
> + * @rst: svs reset control
> + * @regs: phandle to the registers map

@name should be here

> + * @efuse_num: the total number of svs platform efuse
> + * @tefuse_num: the total number of thermal efuse
> + * @bank_num: the total number of banks
> + * @efuse_check: the svs efuse check index
> + * @efuse: svs platform efuse data received from NVMEM framework
> + * @tefuse: thermal efuse data received from NVMEM framework
> + * @name: svs platform name
> + */
> +struct svs_platform {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct clk *main_clk;
> +	struct svs_bank *pbank;
> +	struct svs_bank *banks;
> +	bool (*efuse_parsing)(struct svs_platform *svsp);
> +	unsigned long irqflags;
> +	struct reset_control *rst;
> +	const u32 *regs;
> +	char *name;
> +	size_t efuse_num;
> +	size_t tefuse_num;
> +	u32 bank_num;
> +	u32 efuse_check;
> +	u32 *efuse;
> +	u32 *tefuse;
> +};
> +
> +/*

... and here

> + * struct svs_bank - svs bank representation
> + * @dev: svs bank device
> + * @opp_dev: device for opp table/buck control
> + * @pd_dev: power domain device for SoC mtcmos control
> + * @init_completion: the timeout completion for bank init
> + * @buck: phandle of the regulator
> + * @lock: mutex lock to protect voltage update process
> + * @phase: bank current phase
> + * @name: bank name
> + * @tzone_name: thermal zone name
> + * @buck_name: regulator name
> + * @suspended: suspend flag of this bank
> + * @pd_req: bank's power-domain on request
> + * @enable_pm_runtime_ever: bank enables pm-runtime flag
> + * @set_freqs_pct: phandle of set frequencies percent function
> + * @get_vops: phandle of get bank voltages function
> + * @volt_offset: bank voltage offset controlled by svs software
> + * @mode_support: bank mode support.
> + * @opp_freqs: signed-off frequencies from default opp table
> + * @opp_volts: signed-off voltages from default opp table
> + * @freqs_pct: percent of "opp_freqs / freq_base" for bank init
> + * @volts: bank voltages
> + * @freq_base: reference frequency for bank init
> + * @vboot: voltage request for bank init01 stage only
> + * @volt_step: bank voltage step
> + * @volt_base: bank voltage base
> + * @volt_flags: bank voltage flags
> + * @vmax: bank voltage maximum
> + * @vmin: bank voltage minimum

I love when developers take the effort to document with kerneldoc, so, great job
about that.... however, you forgot to document a few variables... can you please
add the required documentation for them?

> + * @temp: bank temperature
> + * @temp_upper_bound: bank temperature upper bound
> + * @temp_lower_bound: bank temperature lower bound
> + * @tzone_high_temp: thermal zone high temperature threshold
> + * @tzone_high_temp_offset: thermal zone high temperature offset
> + * @tzone_low_temp: thermal zone low temperature threshold
> + * @tzone_low_temp_offset: thermal zone low temperature offset
> + * @core_sel: bank selection
> + * @opp_count: bank opp count
> + * @int_st: bank interrupt identification
> + * @sw_id: bank software identification
> + * @ctl0: bank thermal sensor selection
> + * @cpu_id: cpu core id for SVS CPU only
> + *
> + * Other structure members which are not listed above are svs platform
> + * efuse data for bank init
> + */
> +struct svs_bank {
> +	struct device *dev;
> +	struct device *opp_dev;
> +	struct device *pd_dev;
> +	struct completion init_completion;
> +	struct regulator *buck;
> +	struct mutex lock;	/* lock to protect voltage update process */
> +	enum svsb_phase phase;
> +	char *name;
> +	char *tzone_name;
> +	char *buck_name;
> +	bool suspended;
> +	bool pd_req;
> +	bool enable_pm_runtime_ever;
> +	void (*set_freqs_pct)(struct svs_platform *svsp);
> +	void (*get_vops)(struct svs_platform *svsp);
> +	s32 volt_offset;
> +	u32 mode_support;
> +	u32 opp_freqs[16];

At the beginning of the file....
#define MAX_OPP_ENTRIES 16

...so you can do...
	u32 opp_freqs[MAX_OPP_ENTRIES];
	u32 opp_volts[MAX_OPP_ENTRIES];
...and the same for the other two.

> +	u32 opp_volts[16];
> +	u32 freqs_pct[16];
> +	u32 volts[16];
> +	u32 freq_base;
> +	u32 vboot;
> +	u32 volt_step;
> +	u32 volt_base;
> +	u32 volt_flags;
> +	u32 vmax;
> +	u32 vmin;

Document these entries, please.

vvvvvvvvv From here.... vvvvvvvvv

> +	u32 bts;
> +	u32 mts;
> +	u32 bdes;
> +	u32 mdes;
> +	u32 mtdes;
> +	u32 dcbdet;
> +	u32 dcmdet;
> +	u32 dthi;
> +	u32 dtlo;
> +	u32 det_window;
> +	u32 det_max;
> +	u32 age_config;
> +	u32 age_voffset_in;
> +	u32 agem;
> +	u32 dc_config;
> +	u32 dc_voffset_in;
> +	u32 dvt_fixed;
> +	u32 vco;
> +	u32 chk_shift;

^^^^^^^^^ ....to there ^^^^^^^^^

> +	u32 temp;
> +	u32 temp_upper_bound;
> +	u32 temp_lower_bound;
> +	u32 tzone_high_temp;
> +	u32 tzone_high_temp_offset;
> +	u32 tzone_low_temp;
> +	u32 tzone_low_temp_offset;
> +	u32 core_sel;
> +	u32 opp_count;
> +	u32 int_st;
> +	u32 sw_id;
> +	u32 ctl0;
> +	u32 cpu_id;
> +};
> +
> +static u32 percent(u32 numerator, u32 denominator)
> +{
> +	/* If not divide 1000, "numerator * 100" will have data overflow. */
> +	numerator /= 1000;
> +	denominator /= 1000;
> +
> +	return DIV_ROUND_UP(numerator * 100, denominator);
> +}
> +
> +static u32 svs_readl(struct svs_platform *svsp, enum svs_reg_index rg_i)
> +{
> +	return readl(svsp->base + svsp->regs[rg_i]);
> +}
> +
> +static void svs_writel(struct svs_platform *svsp, u32 val,
> +		       enum svs_reg_index rg_i)
> +{
> +	writel(val, svsp->base + svsp->regs[rg_i]);
> +}
> +
> +static void svs_switch_bank(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svs_writel(svsp, svsb->core_sel, CORESEL);
> +}
> +
> +static u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step,
> +				     u32 svsb_volt_base)
> +{
> +	return (svsb_volt * svsb_volt_step) + svsb_volt_base;
> +}
> +
> +static int svs_get_bank_zone_temperature(const char *tzone_name,
> +					 int *tzone_temp)
> +{
> +	struct thermal_zone_device *tzd;
> +
> +	tzd = thermal_zone_get_zone_by_name(tzone_name);
> +	if (IS_ERR(tzd))
> +		return PTR_ERR(tzd);
> +
> +	return thermal_zone_get_temp(tzd, tzone_temp);
> +}
> +
> +static int svs_adjust_pm_opp_volts(struct svs_bank *svsb, bool force_update)
> +{
> +	int tzone_temp = 0, ret = -EPERM;
> +	u32 i, svsb_volt, opp_volt, temp_offset = 0;
> +
> +	mutex_lock(&svsb->lock);
> +
> +	/*
> +	 * If svs bank is suspended, it means signed-off voltages are applied.
> +	 * Don't need to update opp voltage anymore.
> +	 */
> +	if (svsb->suspended && !force_update) {
> +		dev_notice(svsb->dev, "bank is suspended\n");
> +		ret = -EPERM;
> +		goto unlock_mutex;
> +	}
> +
> +	/* Get thermal effect */
> +	if (svsb->phase == SVSB_PHASE_MON) {
> +		if (svsb->temp > svsb->temp_upper_bound &&
> +		    svsb->temp < svsb->temp_lower_bound) {
> +			dev_warn(svsb->dev, "svsb temp = 0x%x?\n", svsb->temp);
> +			ret = -EINVAL;
> +			goto unlock_mutex;
> +		}
> +
> +		ret = svs_get_bank_zone_temperature(svsb->tzone_name,
> +						    &tzone_temp);
> +		if (ret) {
> +			dev_err(svsb->dev, "no %s? (%d), run default volts\n",
> +				svsb->tzone_name, ret);
> +			svsb->phase = SVSB_PHASE_ERROR;
> +		}
> +
> +		if (tzone_temp >= svsb->tzone_high_temp)
> +			temp_offset += svsb->tzone_high_temp_offset;
> +		else if (tzone_temp <= svsb->tzone_low_temp)
> +			temp_offset += svsb->tzone_low_temp_offset;
> +	}
> +
> +	/* vmin <= svsb_volt (opp_volt) <= signed-off (default) voltage */
> +	for (i = 0; i < svsb->opp_count; i++) {



What about using switch here?



         switch (svsb->phase) {

         case SVSB_PHASE_MON:

             ......

             break;

         case .......:

             .........

             break;

         default:

             dev_err(......);

             ret = -EINVAL;

             goto unlock_mutex;

         }

> +		if (svsb->phase == SVSB_PHASE_MON) {
> +			svsb_volt = max(svsb->volts[i] + svsb->volt_offset +
> +					temp_offset, svsb->vmin);
> +			opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
> +							     svsb->volt_step,
> +							     svsb->volt_base);
> +		} else if (svsb->phase == SVSB_PHASE_INIT02) {
> +			svsb_volt = max(svsb->volts[i] + svsb->volt_offset,
> +					svsb->vmin);
> +			opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
> +							     svsb->volt_step,
> +							     svsb->volt_base);
> +		} else if (svsb->phase == SVSB_PHASE_ERROR) {
> +			opp_volt = svsb->opp_volts[i];
> +		} else {
> +			dev_err(svsb->dev, "unknown phase: %u?\n", svsb->phase);
> +			ret = -EINVAL;
> +			goto unlock_mutex;
> +		}
> +
> +		opp_volt = min(opp_volt, svsb->opp_volts[i]);
> +		ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
> +						svsb->opp_freqs[i],
> +						opp_volt, opp_volt,
> +						svsb->opp_volts[i]);
> +		if (ret) {
> +			dev_err(svsb->dev, "set voltage fail: %d\n", ret);
> +			goto unlock_mutex;
> +		}
> +	}
> +
> +unlock_mutex:
> +	mutex_unlock(&svsb->lock);
> +
> +	return ret;
> +}
> +
> +static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
> +{
> +	u32 vx;
> +
> +	if (v0 == v1 || f0 == f1)
> +		return v0;
> +
> +	/* *100 to have decimal fraction factor */
> +	vx = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
> +
> +	return DIV_ROUND_UP(vx, 100);
> +}
> +
> +static void svs_get_vops_v2(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +	u32 temp, i;
> +
> +	if (svsb->phase == SVSB_PHASE_MON &&
> +	    svsb->volt_flags & SVSB_MON_VOLT_IGNORE)
> +		return;
> +
> +	temp = svs_readl(svsp, VOP74);
> +	svsb->volts[14] = (temp >> 24) & GENMASK(7, 0);
> +	svsb->volts[12] = (temp >> 16) & GENMASK(7, 0);
> +	svsb->volts[10] = (temp >> 8)  & GENMASK(7, 0);
> +	svsb->volts[8] = (temp & GENMASK(7, 0));
> +
> +	temp = svs_readl(svsp, VOP30);
> +	svsb->volts[6] = (temp >> 24) & GENMASK(7, 0);
> +	svsb->volts[4] = (temp >> 16) & GENMASK(7, 0);
> +	svsb->volts[2] = (temp >> 8)  & GENMASK(7, 0);
> +	svsb->volts[0] = (temp & GENMASK(7, 0));
> +
> +	for (i = 0; i <= 12; i += 2)
> +		svsb->volts[i + 1] =
> +			interpolate(svsb->freqs_pct[i],
> +				    svsb->freqs_pct[i + 2],
> +				    svsb->volts[i],
> +				    svsb->volts[i + 2],
> +				    svsb->freqs_pct[i + 1]);
> +
> +	svsb->volts[15] =
> +		interpolate(svsb->freqs_pct[12],
> +			    svsb->freqs_pct[14],
> +			    svsb->volts[12],
> +			    svsb->volts[14],
> +			    svsb->freqs_pct[15]);
> +
> +	if (svsb->volt_flags & SVSB_INIT02_RM_DVTFIXED)
> +		for (i = 0; i < svsb->opp_count; i++)
> +			svsb->volts[i] -= svsb->dvt_fixed;
> +}
> +
> +static void svs_set_freqs_pct_v2(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svs_writel(svsp,
> +		   (svsb->freqs_pct[14] << 24) |
> +		   (svsb->freqs_pct[12] << 16) |
> +		   (svsb->freqs_pct[10] << 8) |
> +		   svsb->freqs_pct[8],
> +		   FREQPCT74);
> +
> +	svs_writel(svsp,
> +		   (svsb->freqs_pct[6] << 24) |
> +		   (svsb->freqs_pct[4] << 16) |
> +		   (svsb->freqs_pct[2] << 8) |
> +		   svsb->freqs_pct[0],
> +		   FREQPCT30);
> +}
> +
> +static void svs_set_bank_phase(struct svs_platform *svsp,
> +			       enum svsb_phase target_phase)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +	u32 des_char, temp_char, det_char, limit_vals;
> +	u32 init2vals, ts_calcs, val, filter, i;
> +
> +	svs_switch_bank(svsp);
> +
> +	des_char = (svsb->bdes << 8) | svsb->mdes;
> +	svs_writel(svsp, des_char, DESCHAR);
> +
> +	temp_char = (svsb->vco << 16) | (svsb->mtdes << 8) | svsb->dvt_fixed;
> +	svs_writel(svsp, temp_char, TEMPCHAR);
> +
> +	det_char = (svsb->dcbdet << 8) | svsb->dcmdet;
> +	svs_writel(svsp, det_char, DETCHAR);
> +
> +	svs_writel(svsp, svsb->dc_config, DCCONFIG);
> +	svs_writel(svsp, svsb->age_config, AGECONFIG);
> +
> +	if (!svsb->agem) {
> +		svs_writel(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG);
> +	} else {
> +		val = 0x0;

val = 0;

> +
> +		for (i = 0; i < 24; i += 2) {
> +			filter = 0x3 << i;
> +
> +			if (!(svsb->age_config & filter))
> +				val |= (0x1 << i);

val |= BIT(i);

> +			else
> +				val |= (svsb->age_config & filter);
> +		}
> +		svs_writel(svsp, val, RUNCONFIG);
> +	}
> +
> +	svsb->set_freqs_pct(svsp);
> +
> +	limit_vals = (svsb->vmax << 24) | (svsb->vmin << 16) |
> +		     (svsb->dthi << 8) | svsb->dtlo;
> +	svs_writel(svsp, limit_vals, LIMITVALS);
> +	svs_writel(svsp, svsb->vboot, VBOOT);
> +	svs_writel(svsp, svsb->det_window, DETWINDOW);
> +	svs_writel(svsp, svsb->det_max, CONFIG);
> +
> +	if (svsb->chk_shift)
> +		svs_writel(svsp, svsb->chk_shift, CHKSHIFT);
> +
> +	if (svsb->ctl0)
> +		svs_writel(svsp, svsb->ctl0, CTL0);
> +
> +	svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +
> +	switch (target_phase) {
> +	case SVSB_PHASE_INIT01:
> +		svs_writel(svsp, SVSB_INTEN_INIT0x, INTEN);
> +		svs_writel(svsp, SVSB_EN_INIT01, SVSEN);
> +		break;
> +	case SVSB_PHASE_INIT02:
> +		svs_writel(svsp, SVSB_INTEN_INIT0x, INTEN);
> +		init2vals = (svsb->age_voffset_in << 16) | svsb->dc_voffset_in;
> +		svs_writel(svsp, init2vals, INIT2VALS);
> +		svs_writel(svsp, SVSB_EN_INIT02, SVSEN);
> +		break;
> +	case SVSB_PHASE_MON:
> +		ts_calcs = (svsb->bts << 12) | svsb->mts;
> +		svs_writel(svsp, ts_calcs, TSCALCS);
> +		svs_writel(svsp, SVSB_INTEN_MONVOPEN, INTEN);
> +		svs_writel(svsp, SVSB_EN_MON, SVSEN);
> +		break;
> +	default:
> +		WARN_ON(1);



I agree about printing a big warning in kmsg here, but you can do that in a

slightly more descriptive way:



         WARN(1, "Requested unknown target phase %u", target_phase);

> +		break;
> +	}
> +}
> +
> +static inline void svs_init01_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n",
> +		 __func__, svs_readl(svsp, VDESIGN74),
> +		 svs_readl(svsp, VDESIGN30), svs_readl(svsp, DCVALUES));
> +
> +	svsb->phase = SVSB_PHASE_INIT01;
> +	svsb->dc_voffset_in = ~(svs_readl(svsp, DCVALUES) & GENMASK(15, 0)) + 1;
> +	if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE ||
> +	    (svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT &&
> +	     svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY))
> +		svsb->dc_voffset_in = 0;
> +
> +	svsb->age_voffset_in = svs_readl(svsp, AGEVALUES) & GENMASK(15, 0);
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
> +
> +	/* svs init01 clock gating */
> +	svsb->core_sel &= ~SVSB_DET_CLK_EN;
> +}
> +
> +static inline void svs_init02_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n",
> +		 __func__, svs_readl(svsp, VOP74), svs_readl(svsp, VOP30),
> +		 svs_readl(svsp, DCVALUES));
> +
> +	svsb->phase = SVSB_PHASE_INIT02;
> +	svsb->get_vops(svsp);
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
> +}
> +
> +static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svsb->phase = SVSB_PHASE_MON;
> +	svsb->temp = svs_readl(svsp, TEMP) & GENMASK(7, 0);
> +	svsb->get_vops(svsp);
> +
> +	svs_writel(svsp, SVSB_INTSTS_MONVOP, INTSTS);
> +}
> +
> +static inline void svs_error_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n",
> +		__func__, svs_readl(svsp, CORESEL));
> +	dev_err(svsb->dev, "SVSEN = 0x%08x, INTSTS = 0x%08x\n",
> +		svs_readl(svsp, SVSEN), svs_readl(svsp, INTSTS));
> +	dev_err(svsb->dev, "SMSTATE0 = 0x%08x, SMSTATE1 = 0x%08x\n",
> +		svs_readl(svsp, SMSTATE0), svs_readl(svsp, SMSTATE1));
> +	dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl(svsp, TEMP));
> +
> +	svsb->mode_support = SVSB_MODE_ALL_DISABLE;
> +	svsb->phase = SVSB_PHASE_ERROR;
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +}
> +
> +static irqreturn_t svs_isr(int irq, void *data)
> +{
> +	struct svs_platform *svsp = data;
> +	struct svs_bank *svsb = NULL;
> +	unsigned long flags;
> +	u32 idx, int_sts, svs_en;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		WARN_ON(!svsb);
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +
> +		/* Find out which svs bank fires interrupt */
> +		if (svsb->int_st & svs_readl(svsp, INTST)) {
> +			spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +			continue;
> +		}
> +
> +		if (!svsb->suspended) {
> +			svs_switch_bank(svsp);
> +			int_sts = svs_readl(svsp, INTSTS);
> +			svs_en = svs_readl(svsp, SVSEN) & SVSB_EN_MASK;
> +
> +			if (int_sts == SVSB_INTSTS_COMPLETE &&
> +			    svs_en == SVSB_EN_INIT01)
> +				svs_init01_isr_handler(svsp);
> +			else if (int_sts == SVSB_INTSTS_COMPLETE &&
> +				 svs_en == SVSB_EN_INIT02)
> +				svs_init02_isr_handler(svsp);
> +			else if (int_sts & SVSB_INTSTS_MONVOP)
> +				svs_mon_mode_isr_handler(svsp);
> +			else
> +				svs_error_isr_handler(svsp);
> +		}
> +
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +		break;
> +	}
> +
> +	if (svsb->phase != SVSB_PHASE_INIT01)
> +		svs_adjust_pm_opp_volts(svsb, false);
> +
> +	if (svsb->phase == SVSB_PHASE_INIT01 ||
> +	    svsb->phase == SVSB_PHASE_INIT02)
> +		complete(&svsb->init_completion);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void svs_mon_mode(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	unsigned long flags;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_MON))
> +			continue;
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_MON);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +	}
> +}
> +
> +static int svs_init02(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	unsigned long flags, time_left;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT02))
> +			continue;
> +
> +		reinit_completion(&svsb->init_completion);
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_INIT02);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		time_left =
> +			wait_for_completion_timeout(&svsb->init_completion,
> +						    msecs_to_jiffies(5000));
> +		if (!time_left) {
> +			dev_err(svsb->dev, "init02 completion timeout\n");
> +			return -EBUSY;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int svs_init01(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	struct pm_qos_request *qos_request;
> +	unsigned long flags, time_left;
> +	bool search_done;
> +	int ret = 0;
> +	u32 opp_freqs, opp_vboot, buck_volt, idx, i;
> +
> +	qos_request = kzalloc(sizeof(*qos_request), GFP_KERNEL);
> +	if (!qos_request)
> +		return -ENOMEM;
> +
> +	/* Let CPUs leave idle-off state for initializing svs_init01. */
> +	cpu_latency_qos_add_request(qos_request, 0);
> +
> +	/*
> +	 * Sometimes two svs banks use the same buck.
> +	 * Therefore, we set each svs bank to vboot voltage first.
> +	 */
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		search_done = false;
> +
> +		if (svsb->pd_req) {
> +			ret = regulator_enable(svsb->buck);
> +			if (ret) {
> +				dev_err(svsb->dev, "%s enable fail: %d\n",
> +					svsb->buck_name, ret);
> +				goto init01_finish;
> +			}
> +
> +			if (!pm_runtime_enabled(svsb->pd_dev)) {
> +				pm_runtime_enable(svsb->pd_dev);
> +				svsb->enable_pm_runtime_ever = true;
> +			}
> +
> +			ret = pm_runtime_get_sync(svsb->pd_dev);
> +			if (ret < 0) {
> +				dev_err(svsb->dev, "mtcmos on fail: %d\n", ret);
> +				goto init01_finish;
> +			}
> +		}
> +
> +		if (regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST))
> +			dev_notice(svsb->dev, "set fast mode fail\n");
> +
> +		/*
> +		 * Find the fastest freq that can be run at vboot and
> +		 * fix to that freq until svs_init01 is done.
> +		 */
> +		opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
> +						      svsb->volt_step,
> +						      svsb->volt_base);
> +
> +		for (i = 0; i < svsb->opp_count; i++) {
> +			opp_freqs = svsb->opp_freqs[i];
> +			if (!search_done && svsb->opp_volts[i] <= opp_vboot) {
> +				ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
> +								opp_freqs,
> +								opp_vboot,
> +								opp_vboot,
> +								opp_vboot);
> +				if (ret) {
> +					dev_err(svsb->dev,
> +						"set voltage fail: %d\n", ret);
> +					goto init01_finish;
> +				}
> +
> +				search_done = true;
> +			} else {
> +				dev_pm_opp_disable(svsb->opp_dev,
> +						   svsb->opp_freqs[i]);
> +			}
> +		}
> +	}
> +
> +	/* svs bank init01 begins */
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
> +						      svsb->volt_step,
> +						      svsb->volt_base);
> +
> +		buck_volt = regulator_get_voltage(svsb->buck);
> +		if (buck_volt != opp_vboot) {
> +			dev_err(svsb->dev,
> +				"buck voltage: %u, expected vboot: %u\n",
> +				buck_volt, opp_vboot);
> +			ret = -EPERM;
> +			goto init01_finish;
> +		}
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_INIT01);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		time_left =
> +			wait_for_completion_timeout(&svsb->init_completion,
> +						    msecs_to_jiffies(5000));
> +		if (!time_left) {
> +			dev_err(svsb->dev, "init01 completion timeout\n");
> +			ret = -EBUSY;
> +			goto init01_finish;
> +		}
> +	}
> +
> +init01_finish:
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		for (i = 0; i < svsb->opp_count; i++)
> +			dev_pm_opp_enable(svsb->opp_dev, svsb->opp_freqs[i]);
> +
> +		if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL))
> +			dev_notice(svsb->dev, "fail to set normal mode\n");
> +
> +		if (svsb->pd_req) {
> +			if (pm_runtime_put_sync(svsb->pd_dev))
> +				dev_err(svsb->dev, "mtcmos off fail\n");
> +
> +			if (svsb->enable_pm_runtime_ever) {
> +				pm_runtime_disable(svsb->pd_dev);
> +				svsb->enable_pm_runtime_ever = false;
> +			}
> +
> +			if (regulator_disable(svsb->buck))
> +				dev_err(svsb->dev, "%s disable fail: %d\n",
> +					svsb->buck_name, ret);
> +		}
> +	}
> +
> +	cpu_latency_qos_remove_request(qos_request);
> +	kfree(qos_request);
> +
> +	return ret;
> +}
> +
> +static int svs_start(struct svs_platform *svsp)
> +{
> +	int ret;
> +
> +	ret = svs_init01(svsp);
> +	if (ret)
> +		return ret;
> +
> +	ret = svs_init02(svsp);
> +	if (ret)
> +		return ret;
> +
> +	svs_mon_mode(svsp);
> +
> +	return 0;
> +}
> +
> +static struct device *svs_get_subsys_device(struct svs_platform *svsp,
> +					    const char *node_name)
> +{
> +	struct platform_device *pdev;
> +	struct device_node *np;
> +
> +	np = of_find_node_by_name(NULL, node_name);
> +	if (!np) {
> +		dev_err(svsp->dev, "cannot find %s node\n", node_name);
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	pdev = of_find_device_by_node(np);
> +	if (!pdev) {
> +		of_node_put(np);
> +		dev_err(svsp->dev, "cannot find pdev by %s\n", node_name);
> +		return ERR_PTR(-ENXIO);
> +	}
> +
> +	of_node_put(np);
> +
> +	return &pdev->dev;
> +}
> +
> +static struct device *svs_add_device_link(struct svs_platform *svsp,
> +					  const char *node_name)
> +{
> +	struct device *dev;
> +	struct device_link *sup_link;
> +
> +	if (!node_name) {
> +		dev_err(svsp->dev, "node name cannot be null\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	dev = svs_get_subsys_device(svsp, node_name);
> +	if (IS_ERR(dev))
> +		return dev;
> +
> +	sup_link = device_link_add(svsp->dev, dev,
> +				   DL_FLAG_AUTOREMOVE_CONSUMER);
> +	if (!sup_link) {
> +		dev_err(svsp->dev, "sup_link is NULL\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	return dev;
> +}
> +
> +static int svs_resource_setup(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	struct dev_pm_opp *opp;
> +	unsigned long freq;
> +	int count, ret;
> +	u32 idx, i;
> +
> +	dev_set_drvdata(svsp->dev, svsp);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			svsb->name = "SVSB_CPU_LITTLE";
> +			break;
> +		case SVSB_CPU_BIG:
> +			svsb->name = "SVSB_CPU_BIG";
> +			break;
> +		case SVSB_CCI:
> +			svsb->name = "SVSB_CCI";
> +			break;
> +		case SVSB_GPU:
> +			svsb->name = "SVSB_GPU";
> +			break;
> +		default:
> +			WARN_ON(1);
> +			return -EINVAL;
> +		}
> +
> +		svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev),
> +					 GFP_KERNEL);
> +		if (!svsb->dev)
> +			return -ENOMEM;
> +
> +		ret = dev_set_name(svsb->dev, "%s", svsb->name);
> +		if (ret)
> +			return ret;
> +
> +		dev_set_drvdata(svsb->dev, svsp);
> +
> +		ret = dev_pm_opp_of_add_table(svsb->opp_dev);
> +		if (ret) {
> +			dev_err(svsb->dev, "add opp table fail: %d\n", ret);
> +			return ret;
> +		}
> +
> +		mutex_init(&svsb->lock);
> +		init_completion(&svsb->init_completion);
> +
> +		svsb->buck = devm_regulator_get_optional(svsb->opp_dev,
> +							 svsb->buck_name);
> +		if (IS_ERR(svsb->buck)) {
> +			dev_err(svsb->dev, "cannot get \"%s-supply\"\n",
> +				svsb->buck_name);
> +			return PTR_ERR(svsb->buck);
> +		}
> +
> +		count = dev_pm_opp_get_opp_count(svsb->opp_dev);
> +		if (svsb->opp_count != count) {
> +			dev_err(svsb->dev,
> +				"opp_count not \"%u\" but get \"%d\"?\n",
> +				svsb->opp_count, count);
> +			return count;
> +		}
> +
> +		for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
> +			opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq);
> +			if (IS_ERR(opp)) {
> +				dev_err(svsb->dev, "cannot find freq = %ld\n",
> +					PTR_ERR(opp));
> +				return PTR_ERR(opp);
> +			}
> +
> +			svsb->opp_freqs[i] = freq;
> +			svsb->opp_volts[i] = dev_pm_opp_get_voltage(opp);
> +			svsb->freqs_pct[i] = percent(svsb->opp_freqs[i],
> +						     svsb->freq_base);
> +			dev_pm_opp_put(opp);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
> +{
> +	struct thermal_parameter tp;
> +	struct svs_bank *svsb;
> +	bool mon_mode_support = true;
> +	int format[6], x_roomt[6], tb_roomt = 0;
> +	struct nvmem_cell *cell;
> +	u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
> +
> +	for (i = 0; i < svsp->efuse_num; i++)
> +		if (svsp->efuse[i])
> +			dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
> +				 i, svsp->efuse[i]);
> +
> +	/* Svs efuse parsing */
> +	ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (ft_pgm <= 1)
> +			svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE;
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			svsb->bdes = svsp->efuse[16] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 10;
> +			else
> +				svsb->volt_offset += 2;
> +			break;
> +		case SVSB_CPU_BIG:
> +			svsb->bdes = svsp->efuse[18] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = svsp->efuse[17] & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 15;
> +			else
> +				svsb->volt_offset += 12;
> +			break;
> +		case SVSB_CCI:
> +			svsb->bdes = svsp->efuse[4] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = (svsp->efuse[5] >> 16) & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 10;
> +			else
> +				svsb->volt_offset += 2;
> +			break;
> +		case SVSB_GPU:
> +			svsb->bdes = svsp->efuse[6] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = svsp->efuse[5] & GENMASK(7, 0);
> +
> +			if (ft_pgm >= 2) {
> +				svsb->freq_base = 800000000; /* 800MHz */
> +				svsb->dvt_fixed = 2;
> +			}
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	/* Get thermal efuse by nvmem */
> +	cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
> +	if (IS_ERR_OR_NULL(cell)) {
> +		dev_err(svsp->dev, "no thermal cell, no mon mode\n");
> +		for (idx = 0; idx < svsp->bank_num; idx++) {
> +			svsb = &svsp->banks[idx];
> +			svsb->mode_support &= ~SVSB_MODE_MON;
> +		}
> +
> +		return true;
> +	}
> +
> +	svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_num);



nvmem_cell_read may return an error pointer: you have to check that.



     if (IS_ERR(svsp->tefuse))

         .........



Failing to perform this check will produce unpredictable behavior

during the parsing stage.


> +	svsp->tefuse_num /= sizeof(u32);
> +	nvmem_cell_put(cell);
> +
> +	/* Thermal efuse parsing */
> +	tp.adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0);
> +	tp.adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0);
> +
> +	tp.o_vtsmcu1 = (svsp->tefuse[0] >> 17) & GENMASK(8, 0);
> +	tp.o_vtsmcu2 = (svsp->tefuse[0] >> 8) & GENMASK(8, 0);
> +	tp.o_vtsmcu3 = svsp->tefuse[1] & GENMASK(8, 0);
> +	tp.o_vtsmcu4 = (svsp->tefuse[2] >> 23) & GENMASK(8, 0);
> +	tp.o_vtsmcu5 = (svsp->tefuse[2] >> 5) & GENMASK(8, 0);
> +	tp.o_vtsabb = (svsp->tefuse[2] >> 14) & GENMASK(8, 0);
> +
> +	tp.degc_cali = (svsp->tefuse[0] >> 1) & GENMASK(5, 0);
> +	tp.adc_cali_en_t = svsp->tefuse[0] & BIT(0);
> +	tp.o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0);
> +
> +	tp.ts_id = (svsp->tefuse[1] >> 9) & BIT(0);
> +	tp.o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
> +
> +	if (tp.adc_cali_en_t == 1) {
> +		if (!tp.ts_id)
> +			tp.o_slope = 0;
> +
> +		if (tp.adc_ge_t < 265 || tp.adc_ge_t > 758 ||
> +		    tp.adc_oe_t < 265 || tp.adc_oe_t > 758 ||
> +		    tp.o_vtsmcu1 < -8 || tp.o_vtsmcu1 > 484 ||
> +		    tp.o_vtsmcu2 < -8 || tp.o_vtsmcu2 > 484 ||
> +		    tp.o_vtsmcu3 < -8 || tp.o_vtsmcu3 > 484 ||
> +		    tp.o_vtsmcu4 < -8 || tp.o_vtsmcu4 > 484 ||
> +		    tp.o_vtsmcu5 < -8 || tp.o_vtsmcu5 > 484 ||
> +		    tp.o_vtsabb < -8 || tp.o_vtsabb > 484 ||
> +		    tp.degc_cali < 1 || tp.degc_cali > 63) {
> +			dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
> +			mon_mode_support = false;
> +		}
> +	} else {
> +		dev_err(svsp->dev, "no thermal efuse, no mon mode\n");
> +		mon_mode_support = false;
> +	}
> +
> +	if (!mon_mode_support) {
> +		for (idx = 0; idx < svsp->bank_num; idx++) {
> +			svsb = &svsp->banks[idx];
> +			svsb->mode_support &= ~SVSB_MODE_MON;
> +		}
> +
> +		return true;
> +	}
> +
> +	tp.ge = ((tp.adc_ge_t - 512) * 10000) / 4096;
> +	tp.oe = (tp.adc_oe_t - 512);
> +	tp.gain = (10000 + tp.ge);
> +
> +	format[0] = (tp.o_vtsmcu1 + 3350 - tp.oe);
> +	format[1] = (tp.o_vtsmcu2 + 3350 - tp.oe);
> +	format[2] = (tp.o_vtsmcu3 + 3350 - tp.oe);
> +	format[3] = (tp.o_vtsmcu4 + 3350 - tp.oe);
> +	format[4] = (tp.o_vtsmcu5 + 3350 - tp.oe);
> +	format[5] = (tp.o_vtsabb + 3350 - tp.oe);
> +
> +	for (i = 0; i < 6; i++)
> +		x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / tp.gain;
> +
> +	temp0 = (10000 * 100000 / tp.gain) * 15 / 18;
> +
> +	if (!tp.o_slope_sign)
> +		mts = (temp0 * 10) / (1534 + tp.o_slope * 10);
> +	else
> +		mts = (temp0 * 10) / (1534 - tp.o_slope * 10);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		svsb->mts = mts;
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			tb_roomt = x_roomt[3];
> +			break;
> +		case SVSB_CPU_BIG:
> +			tb_roomt = x_roomt[4];
> +			break;
> +		case SVSB_CCI:
> +			tb_roomt = x_roomt[3];
> +			break;
> +		case SVSB_GPU:
> +			tb_roomt = x_roomt[1];
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		temp0 = (tp.degc_cali * 10 / 2);
> +		temp1 = ((10000 * 100000 / 4096 / tp.gain) *
> +			 tp.oe + tb_roomt * 10) * 15 / 18;
> +
> +		if (!tp.o_slope_sign)
> +			temp2 = temp1 * 100 / (1534 + tp.o_slope * 10);
> +		else
> +			temp2 = temp1 * 100 / (1534 - tp.o_slope * 10);
> +
> +		svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
> +	}
> +
> +	return true;
> +}
> +
> +static bool svs_is_supported(struct svs_platform *svsp)
> +{
> +	struct nvmem_cell *cell;
> +
> +	/* Get svs efuse by nvmem */
> +	cell = nvmem_cell_get(svsp->dev, "svs-calibration-data");
> +	if (IS_ERR_OR_NULL(cell)) {
> +		dev_err(svsp->dev,
> +			"no \"svs-calibration-data\" from dts? disable svs\n");
> +		return false;
> +	}
> +
> +	svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_num);
> +	svsp->efuse_num /= sizeof(u32);
> +	nvmem_cell_put(cell);
> +
> +	if (!svsp->efuse[svsp->efuse_check]) {
> +		dev_err(svsp->dev, "svs_efuse[%u] = 0x%x?\n",
> +			svsp->efuse_check, svsp->efuse[svsp->efuse_check]);
> +		return false;
> +	}
> +
> +	return svsp->efuse_parsing(svsp);
> +}
> +
> +static int svs_suspend(struct device *dev)
> +{
> +	struct svs_platform *svsp = dev_get_drvdata(dev);
> +	struct svs_bank *svsb;
> +	unsigned long flags;
> +	int ret;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		/* Wait if svs_isr() is still in process. */
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_switch_bank(svsp);
> +		svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +		svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		svsb->suspended = true;
> +		if (svsb->phase != SVSB_PHASE_INIT01) {
> +			svsb->phase = SVSB_PHASE_ERROR;
> +			svs_adjust_pm_opp_volts(svsb, true);
> +		}
> +	}
> +
> +	ret = reset_control_assert(svsp->rst);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot assert reset %d\n", ret);
> +		return ret;
> +	}
> +
> +	clk_disable_unprepare(svsp->main_clk);
> +
> +	return 0;
> +}
> +
> +static int svs_resume(struct device *dev)
> +{
> +	struct svs_platform *svsp = dev_get_drvdata(dev);
> +	struct svs_bank *svsb;
> +	int ret;
> +	u32 idx;
> +
> +	ret = clk_prepare_enable(svsp->main_clk);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot enable main_clk, disable svs\n");
> +		return ret;
> +	}
> +
> +	ret = reset_control_deassert(svsp->rst);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot deassert reset %d\n", ret);
> +		return ret;
> +	}
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		svsb->suspended = false;
> +	}
> +
> +	ret = svs_init02(svsp);
> +	if (ret)
> +		return ret;
> +
> +	svs_mon_mode(svsp);
> +
> +	return 0;
> +}
> +
> +static struct svs_bank svs_mt8183_banks[] = {
> +	{
> +		.sw_id			= SVSB_CPU_LITTLE,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.cpu_id			= 0,
> +		.tzone_name		= "tzts4",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1989000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x64,
> +		.vmin			= 0x18,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0000,
> +		.int_st			= BIT(0),
> +		.ctl0			= 0x00010001,
> +	},
> +	{
> +		.sw_id			= SVSB_CPU_BIG,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.cpu_id			= 4,
> +		.tzone_name		= "tzts5",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1989000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x58,
> +		.vmin			= 0x10,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0001,
> +		.int_st			= BIT(1),
> +		.ctl0			= 0x00000001,
> +	},
> +	{
> +		.sw_id			= SVSB_CCI,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.tzone_name		= "tzts4",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1196000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x64,
> +		.vmin			= 0x18,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0002,
> +		.int_st			= BIT(2),
> +		.ctl0			= 0x00100003,
> +	},
> +	{
> +		.sw_id			= SVSB_GPU,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.tzone_name		= "tzts2",
> +		.buck_name		= "mali",
> +		.pd_req			= true,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
> +					  SVSB_MODE_MON,
> +		.opp_count		= 16,
> +		.freq_base		= 900000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x40,
> +		.vmin			= 0x14,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x3,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 3,
> +		.core_sel		= 0x8fff0003,
> +		.int_st			= BIT(3),
> +		.ctl0			= 0x00050001,
> +	},
> +};
> +
> +static int svs_get_svs_mt8183_platform_data(struct svs_platform *svsp)
> +{
> +	struct device *dev;
> +	struct svs_bank *svsb;
> +	u32 idx;
> +
> +	svsp->name = "mt8183-svs";
> +	svsp->banks = svs_mt8183_banks;
> +	svsp->efuse_parsing = svs_mt8183_efuse_parsing;
> +	svsp->regs = svs_regs_v2;
> +	svsp->irqflags = IRQF_TRIGGER_LOW;
> +	svsp->rst = NULL;
> +	svsp->bank_num = ARRAY_SIZE(svs_mt8183_banks);
> +	svsp->efuse_check = 2;
> +
> +	dev = svs_add_device_link(svsp, "thermal");
> +	if (IS_ERR(dev))
> +		return PTR_ERR(dev);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +		case SVSB_CPU_BIG:
> +			svsb->opp_dev = get_cpu_device(svsb->cpu_id);
> +			break;
> +		case SVSB_CCI:
> +			svsb->opp_dev = svs_add_device_link(svsp, "cci");
> +			break;
> +		case SVSB_GPU:
> +			svsb->opp_dev = svs_add_device_link(svsp, "mali");
> +			svsb->pd_dev = svs_add_device_link(svsp,
> +							   "mali_gpu_core2");
> +			if (IS_ERR(svsb->pd_dev))
> +				return PTR_ERR(svsb->pd_dev);
> +			break;
> +		default:
> +			WARN_ON(1);
> +			return -EINVAL;
> +		}
> +
> +		if (IS_ERR(svsb->opp_dev))
> +			return PTR_ERR(svsb->opp_dev);
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mtk_svs_of_match[] = {
> +	{
> +		.compatible = "mediatek,mt8183-svs",
> +		.data = &svs_get_svs_mt8183_platform_data,
> +	}, {
> +		/* Sentinel */
> +	},
> +};
> +
> +static int svs_probe(struct platform_device *pdev)
> +{
> +	int (*svs_get_svs_platform_data)(struct svs_platform *svsp);
> +	struct svs_platform *svsp;
> +	unsigned int svsp_irq;
> +	int ret;
> +
> +	svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL);
> +	if (!svsp)
> +		return -ENOMEM;
> +
> +	svs_get_svs_platform_data = of_device_get_match_data(&pdev->dev);
> +	if (!svs_get_svs_platform_data) {
> +		dev_err(svsp->dev, "no svs platform data? why?\n");
> +		return -EPERM;
> +	}
> +
> +	svsp->dev = &pdev->dev;
> +	ret = svs_get_svs_platform_data(svsp);
> +	if (ret) {
> +		dev_err_probe(svsp->dev, ret, "fail to get svsp data\n");
> +		return ret;
> +	}
> +
> +	if (!svs_is_supported(svsp)) {
> +		dev_notice(svsp->dev, "svs is not supported\n");
> +		return -EPERM;
> +	}
> +
> +	ret = svs_resource_setup(svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "svs resource setup fail: %d\n", ret);
> +		return ret;
> +	}
> +
> +	svsp_irq = irq_of_parse_and_map(svsp->dev->of_node, 0);
> +	ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
> +					svsp->irqflags | IRQF_ONESHOT,
> +					svsp->name, svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "register irq(%d) failed: %d\n",
> +			svsp_irq, ret);
> +		return ret;
> +	}
> +
> +	svsp->main_clk = devm_clk_get(svsp->dev, "main");
> +	if (IS_ERR(svsp->main_clk)) {
> +		dev_err(svsp->dev, "failed to get clock: %ld\n",
> +			PTR_ERR(svsp->main_clk));
> +		return PTR_ERR(svsp->main_clk);
> +	}
> +
> +	ret = clk_prepare_enable(svsp->main_clk);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot enable main clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	svsp->base = of_iomap(svsp->dev->of_node, 0);
> +	if (IS_ERR_OR_NULL(svsp->base)) {
> +		dev_err(svsp->dev, "cannot find svs register base\n");
> +		ret = -EINVAL;
> +		goto svs_probe_clk_disable;
> +	}
> +
> +	ret = svs_start(svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "svs start fail: %d\n", ret);
> +		goto svs_probe_iounmap;
> +	}
> +
> +	return 0;
> +
> +svs_probe_iounmap:
> +	iounmap(svsp->base);
> +
> +svs_probe_clk_disable:
> +	clk_disable_unprepare(svsp->main_clk);
> +
> +	return ret;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(svs_pm_ops, svs_suspend, svs_resume);
> +
> +static struct platform_driver svs_driver = {
> +	.probe	= svs_probe,
> +	.driver	= {
> +		.name		= "mtk-svs",
> +		.pm		= &svs_pm_ops,
> +		.of_match_table	= of_match_ptr(mtk_svs_of_match),
> +	},
> +};
> +
> +module_platform_driver(svs_driver);
> +
> +MODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>");
> +MODULE_DESCRIPTION("MediaTek SVS driver");
> +MODULE_LICENSE("GPL v2");
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] platform: finally disallow IRQ0 in platform_get_irq() and its ilk
From: Andy Shevchenko @ 2022-01-05  9:59 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Marc Zyngier, Sergey Shtylyov, Greg Kroah-Hartman,
	Rafael J. Wysocki, Linux Kernel Mailing List, Thomas Gleixner
In-Reply-To: <CAMuHMdUdU82Kes87zq-15buRTLv44k8XQJmmw3QoBq_rZmvGKw@mail.gmail.com>

On Tue, Jan 4, 2022 at 3:14 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Marc,
>
> On Tue, Jan 4, 2022 at 11:48 AM Marc Zyngier <maz@kernel.org> wrote:
> > On Tue, 04 Jan 2022 09:47:21 +0000,
> > Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > > On Tue, Jan 4, 2022 at 10:26 AM Marc Zyngier <maz@kernel.org> wrote:
> > > > [Adding Geert]
> > > >
> > > > On Sat, 06 Nov 2021 20:26:47 +0000,
> > > > Sergey Shtylyov <s.shtylyov@omp.ru> wrote:
> > > > > The commit a85a6c86c25b ("driver core: platform: Clarify that IRQ 0 is
> > > > > invalid") only calls WARN() when IRQ0 is about to be returned, however
> > > > > using IRQ0 is considered invalid (according to Linus) outside the arch/
> > > > > code where it's used by the i8253 drivers. Many driver subsystems treat
> > > > > 0 specially (e.g. as an indication of the polling mode by libata), so
> > > > > the users of platform_get_irq[_byname]() in them would have to filter
> > > > > out IRQ0 explicitly and this (quite obviously) doesn't scale...
> > > > > Let's finally get this straight and return -EINVAL instead of IRQ0!
> > > > >
> > > > > Fixes: a85a6c86c25b ("driver core: platform: Clarify that IRQ 0 is invalid")
> > > > > Signed-off-by: Sergey Shtylyov <s.shtylyov@omp.ru>
> > >
> > > > > --- driver-core.orig/drivers/base/platform.c
> > > > > +++ driver-core/drivers/base/platform.c
> > > > > @@ -231,7 +231,8 @@ int platform_get_irq_optional(struct pla
> > > > >  out_not_found:
> > > > >       ret = -ENXIO;
> > > > >  out:
> > > > > -     WARN(ret == 0, "0 is an invalid IRQ number\n");
> > > > > +     if (WARN(!ret, "0 is an invalid IRQ number\n"))
> > > > > +             return -EINVAL;
> > > > >       return ret;
> > > > >  }
> > > > >  EXPORT_SYMBOL_GPL(platform_get_irq_optional);
> > > > > @@ -445,7 +446,8 @@ static int __platform_get_irq_byname(str
> > > > >
> > > > >       r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
> > > > >       if (r) {
> > > > > -             WARN(r->start == 0, "0 is an invalid IRQ number\n");
> > > > > +             if (WARN(!r->start, "0 is an invalid IRQ number\n"))
> > > > > +                     return -EINVAL;
> > > > >               return r->start;
> > > > >       }
> > > >
> > > > Geert recently mentioned that a few architectures (such as sh?) still
> > > > use IRQ0 as something valid in limited cases.
> > >
> > > https://lore.kernel.org/all/CAMuHMdUg3=q7gyaVHP0XcYUOo3PQUUv8Hc8wp5faVQ+bTBpg4A@mail.gmail.com
> > >
> > > TL;DR: Probably only smsc911x Ethernet on the AP-SH4A-3A and
> > > AP-SH4AD-0A boards, which should trigger the warning since v5.8.
> > >
> > > > From my PoV, this patch is fine, but please be prepared to fix things
> > > > in a couple of years when someone decides to boot a recent kernel on
> > > > their pet dinosaur. With that in mind:
> > > >
> > > > Acked-by: Marc Zyngier <maz@kernel.org>
> > >
> > > TBH, I don't see much point in this patch, as the WARN() has been
> > > there since a while, and the end goal is to return zero instead of
> > > -ENXIO for no interrupt, right?
> >
> > I think the end-goal is to never return 0. Either we return a valid
> > interrupt number, or we return an error. It should be the
> > responsibility of the caller to decide what they want to do in the
> > error case.
>
> This is platform_get_irq_optional(). All other *_optional() APIs
> return 0 (or NULL[1]) in case the optional resource is not available.

+1 to Geert's p.o.v. here. The platform_get_irq() and (non-optional)
Co should never return 0, while _optional variants as Geert explained.

> [1] Most (all?) return pointers, NULL, or a negative error code.



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* [PATCH mptcp-next v5] selftests: mptcp: add mp_fail testcases
From: Geliang Tang @ 2022-01-05  9:59 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang, Davide Caratti, Matthieu Baerts

Added the test cases for MP_FAIL, use 'tc' command to trigger the
checksum failure.

Suggested-by: Davide Caratti <dcaratti@redhat.com>
Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Geliang Tang <geliang.tang@suse.com>
---
 v5:
 - add validate_checksum as Mat suggested.
 - drop make_file in reset_with_fail() as Matt suggested, reuse
   the test_link_fail argument to make larger files.
 - drop mp_fail_del_dev(), add a new function get_nr_fail().
 - this patch deponds on another patch (v2, the new version dosen't work)
 to send MP_FAIL + MP_RST together:
 https://patchwork.kernel.org/project/mptcp/patch/5a8c6024481d6106c662c3e892ae5e499b4a7f76.1638156809.git.geliang.tang@suse.com/

 v4:
 - enable checksum in reset_with_fail()
---
 tools/testing/selftests/net/mptcp/config      |   5 +
 .../testing/selftests/net/mptcp/mptcp_join.sh | 111 ++++++++++++++++--
 2 files changed, 107 insertions(+), 9 deletions(-)

diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config
index d36b7da5082a..26955abe49f0 100644
--- a/tools/testing/selftests/net/mptcp/config
+++ b/tools/testing/selftests/net/mptcp/config
@@ -19,3 +19,8 @@ CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NET_ACT_CSUM=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_SCH_INGRESS=m
diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
index e48ce23d2386..535baa3c01e7 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
@@ -16,6 +16,7 @@ mptcp_connect=""
 capture=0
 checksum=0
 do_all_tests=1
+nr_fail=0
 
 TEST_COUNT=0
 
@@ -58,6 +59,8 @@ init()
 		fi
 	done
 
+	validate_checksum=$checksum
+
 	#  ns1              ns2
 	# ns1eth1    ns2eth1
 	# ns1eth2    ns2eth2
@@ -161,6 +164,45 @@ reset_with_allow_join_id0()
 	ip netns exec $ns2 sysctl -q net.mptcp.allow_join_initial_addr_port=$ns2_enable
 }
 
+# Modify TCP payload without corrupting the TCP packet
+#
+# This rule inverts a 32-bit word at byte offset 148 for all TCP ACK
+# packets carrying enough data.
+# Once it is done, the TCP Checksum field is updated so the packet
+# is still considered as valid at the TCP level.
+# But because the MPTCP checksum, covering the TCP options and data,
+# has not been updated, we will detect the modification and emit an
+# MP_FAIL: what we want to validate here.
+#
+# Please note that this rule will produce this pr_info() message for
+# each TCP ACK packets not carrying enough data:
+#
+#     tc action pedit offset 162 out of bounds
+#
+# But this should be limited to a very few numbers of packets as we
+# restrict this rule to outgoing TCP traffic with only the ACK flag
+# + except the 3rd ACK, only packets carrying data should be seen in
+# this direction.
+reset_with_fail()
+{
+	reset
+
+	ip netns exec $ns1 sysctl -q net.mptcp.checksum_enabled=1
+	ip netns exec $ns2 sysctl -q net.mptcp.checksum_enabled=1
+
+	validate_checksum=1
+	nr_fail=0
+	i="$1"
+
+	tc -n $ns2 qdisc add dev ns2eth$i clsact
+	tc -n $ns2 filter add dev ns2eth$i egress \
+		protocol ip prio 1000 \
+		flower ip_proto tcp tcp_flags 0x10/0xff \
+		action pedit munge offset 148 u32 invert \
+		pipe csum tcp \
+		index 100
+}
+
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
 	echo "SKIP: Could not run test without ip tool"
@@ -179,6 +221,12 @@ if [ $? -ne 0 ];then
 	exit $ksft_skip
 fi
 
+jq -V > /dev/null 2>&1
+if [ $? -ne 0 ];then
+	echo "SKIP: Could not run all tests without jq tool"
+	exit $ksft_skip
+fi
+
 print_file_err()
 {
 	ls -l "$1" 1>&2
@@ -233,6 +281,21 @@ link_failure()
 	done
 }
 
+get_nr_fail()
+{
+	i="$1"
+
+	local action=$(tc -n $ns2 -j -s action show action pedit index 100)
+	local packets=$(echo $action | jq '.[1].actions[0].stats.packets')
+	local overlimits=$(echo $action | jq '.[1].actions[0].stats.overlimits')
+
+	let pkt=$packets-$overlimits
+	if [ $pkt -gt 0 ]; then
+		nr_fail=1
+	fi
+	tc -n $ns2 qdisc del dev ns2eth$i clsact
+}
+
 # $1: IP address
 is_v6()
 {
@@ -589,6 +652,8 @@ dump_stats()
 chk_csum_nr()
 {
 	local msg=${1:-""}
+	local csum_ns1=${2:-0}
+	local csum_ns2=${3:-0}
 	local count
 	local dump_stats
 
@@ -600,8 +665,8 @@ chk_csum_nr()
 	printf " %-36s %s" "$msg" "sum"
 	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtDataCsumErr | awk '{print $2}'`
 	[ -z "$count" ] && count=0
-	if [ "$count" != 0 ]; then
-		echo "[fail] got $count data checksum error[s] expected 0"
+	if [ "$count" != $csum_ns1 ]; then
+		echo "[fail] got $count data checksum error[s] expected $csum_ns1"
 		ret=1
 		dump_stats=1
 	else
@@ -610,8 +675,8 @@ chk_csum_nr()
 	echo -n " - csum  "
 	count=`ip netns exec $ns2 nstat -as | grep MPTcpExtDataCsumErr | awk '{print $2}'`
 	[ -z "$count" ] && count=0
-	if [ "$count" != 0 ]; then
-		echo "[fail] got $count data checksum error[s] expected 0"
+	if [ "$count" != $csum_ns2 ]; then
+		echo "[fail] got $count data checksum error[s] expected $csum_ns2"
 		ret=1
 		dump_stats=1
 	else
@@ -690,6 +755,8 @@ chk_join_nr()
 	local syn_nr=$2
 	local syn_ack_nr=$3
 	local ack_nr=$4
+	local fail_nr=${5:-0}
+	local infi_nr=${6:-0}
 	local count
 	local dump_stats
 
@@ -726,10 +793,10 @@ chk_join_nr()
 		echo "[ ok ]"
 	fi
 	[ "${dump_stats}" = 1 ] && dump_stats
-	if [ $checksum -eq 1 ]; then
-		chk_csum_nr
-		chk_fail_nr 0 0
-		chk_infi_nr 0 0
+	if [ $validate_checksum -eq 1 ]; then
+		chk_csum_nr "" $fail_nr
+		chk_fail_nr $fail_nr $fail_nr
+		chk_infi_nr $infi_nr $infi_nr
 	fi
 }
 
@@ -1985,6 +2052,27 @@ userspace_tests()
 	chk_rm_nr 0 0
 }
 
+fail_tests()
+{
+	# multiple subflows
+	reset_with_fail 2
+	ip netns exec $ns1 ./pm_nl_ctl limits 0 2
+	ip netns exec $ns2 ./pm_nl_ctl limits 0 2
+	ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 dev ns2eth3 flags subflow
+	ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 dev ns2eth2 flags subflow
+	run_tests $ns1 $ns2 10.0.1.1 2
+	get_nr_fail 2
+	chk_join_nr "$nr_fail MP_FAIL, multiple subflows" 2 2 2 $nr_fail
+
+	# single subflow
+	reset_with_fail 1
+	ip netns exec $ns1 ./pm_nl_ctl limits 0 2
+	ip netns exec $ns2 ./pm_nl_ctl limits 0 2
+	run_tests $ns1 $ns2 10.0.1.1 2
+	get_nr_fail 1
+	chk_join_nr "$nr_fail MP_FAIL, single subflow" 0 0 0 $nr_fail $nr_fail
+}
+
 all_tests()
 {
 	subflows_tests
@@ -2003,6 +2091,7 @@ all_tests()
 	deny_join_id0_tests
 	fullmesh_tests
 	userspace_tests
+	fail_tests
 }
 
 usage()
@@ -2024,6 +2113,7 @@ usage()
 	echo "  -d deny_join_id0_tests"
 	echo "  -m fullmesh_tests"
 	echo "  -u userspace_tests"
+	echo "  -F fail_tests"
 	echo "  -c capture pcap files"
 	echo "  -C enable data checksum"
 	echo "  -h help"
@@ -2059,7 +2149,7 @@ if [ $do_all_tests -eq 1 ]; then
 	exit $ret
 fi
 
-while getopts 'fesltra64bpkdmuchCS' opt; do
+while getopts 'fesltra64bpkdmuchCSF' opt; do
 	case $opt in
 		f)
 			subflows_tests
@@ -2109,6 +2199,9 @@ while getopts 'fesltra64bpkdmuchCS' opt; do
 		u)
 			userspace_tests
 			;;
+		F)
+			fail_tests
+			;;
 		c)
 			;;
 		C)
-- 
2.31.1


^ permalink raw reply related

* Re: [PATCH net-next 07/15] net: dsa: remove cross-chip support for MRP
From: Horatiu Vultur @ 2022-01-05 10:01 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, David S. Miller, Jakub Kicinski, Andrew Lunn,
	Vivien Didelot, Florian Fainelli
In-Reply-To: <20220104171413.2293847-8-vladimir.oltean@nxp.com>

The 01/04/2022 19:14, Vladimir Oltean wrote:
> 
> The cross-chip notifiers for MRP are bypass operations, meaning that
> even though all switches in a tree are notified, only the switch
> specified in the info structure is targeted.
> 
> We can eliminate the unnecessary complexity by deleting the cross-chip
> notifier logic and calling the ds->ops straight from port.c.

It looks like structs dsa_notifier_mrp_info and
dsa_notifier_mrp_ring_role_info are not used anywhere anymore. So they
should also be deleted.

> 
> Cc: Horatiu Vultur <horatiu.vultur@microchip.com>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
>  net/dsa/dsa_priv.h |  4 ---
>  net/dsa/port.c     | 44 +++++++++++++++----------------
>  net/dsa/switch.c   | 64 ----------------------------------------------
>  3 files changed, 20 insertions(+), 92 deletions(-)
> 
> diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
> index b5ae21f172a8..54c23479b9ba 100644
> --- a/net/dsa/dsa_priv.h
> +++ b/net/dsa/dsa_priv.h
> @@ -40,10 +40,6 @@ enum {
>         DSA_NOTIFIER_TAG_PROTO,
>         DSA_NOTIFIER_TAG_PROTO_CONNECT,
>         DSA_NOTIFIER_TAG_PROTO_DISCONNECT,
> -       DSA_NOTIFIER_MRP_ADD,
> -       DSA_NOTIFIER_MRP_DEL,
> -       DSA_NOTIFIER_MRP_ADD_RING_ROLE,
> -       DSA_NOTIFIER_MRP_DEL_RING_ROLE,
>         DSA_NOTIFIER_TAG_8021Q_VLAN_ADD,
>         DSA_NOTIFIER_TAG_8021Q_VLAN_DEL,
>  };
> diff --git a/net/dsa/port.c b/net/dsa/port.c
> index 05677e016982..5c72f890c6a2 100644
> --- a/net/dsa/port.c
> +++ b/net/dsa/port.c
> @@ -907,49 +907,45 @@ int dsa_port_vlan_del(struct dsa_port *dp,
>  int dsa_port_mrp_add(const struct dsa_port *dp,
>                      const struct switchdev_obj_mrp *mrp)
>  {
> -       struct dsa_notifier_mrp_info info = {
> -               .sw_index = dp->ds->index,
> -               .port = dp->index,
> -               .mrp = mrp,
> -       };
> +       struct dsa_switch *ds = dp->ds;
> +
> +       if (!ds->ops->port_mrp_add)
> +               return -EOPNOTSUPP;
> 
> -       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_ADD, &info);
> +       return ds->ops->port_mrp_add(ds, dp->index, mrp);
>  }
> 
>  int dsa_port_mrp_del(const struct dsa_port *dp,
>                      const struct switchdev_obj_mrp *mrp)
>  {
> -       struct dsa_notifier_mrp_info info = {
> -               .sw_index = dp->ds->index,
> -               .port = dp->index,
> -               .mrp = mrp,
> -       };
> +       struct dsa_switch *ds = dp->ds;
> +
> +       if (!ds->ops->port_mrp_del)
> +               return -EOPNOTSUPP;
> 
> -       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_DEL, &info);
> +       return ds->ops->port_mrp_del(ds, dp->index, mrp);
>  }
> 
>  int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
>                                const struct switchdev_obj_ring_role_mrp *mrp)
>  {
> -       struct dsa_notifier_mrp_ring_role_info info = {
> -               .sw_index = dp->ds->index,
> -               .port = dp->index,
> -               .mrp = mrp,
> -       };
> +       struct dsa_switch *ds = dp->ds;
> +
> +       if (!ds->ops->port_mrp_add)
> +               return -EOPNOTSUPP;
> 
> -       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_ADD_RING_ROLE, &info);
> +       return ds->ops->port_mrp_add_ring_role(ds, dp->index, mrp);
>  }
> 
>  int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
>                                const struct switchdev_obj_ring_role_mrp *mrp)
>  {
> -       struct dsa_notifier_mrp_ring_role_info info = {
> -               .sw_index = dp->ds->index,
> -               .port = dp->index,
> -               .mrp = mrp,
> -       };
> +       struct dsa_switch *ds = dp->ds;
> +
> +       if (!ds->ops->port_mrp_del)
> +               return -EOPNOTSUPP;
> 
> -       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_DEL_RING_ROLE, &info);
> +       return ds->ops->port_mrp_del_ring_role(ds, dp->index, mrp);
>  }
> 
>  void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
> diff --git a/net/dsa/switch.c b/net/dsa/switch.c
> index 393f2d8a860a..a164ec02b4e9 100644
> --- a/net/dsa/switch.c
> +++ b/net/dsa/switch.c
> @@ -701,58 +701,6 @@ dsa_switch_disconnect_tag_proto(struct dsa_switch *ds,
>         return 0;
>  }
> 
> -static int dsa_switch_mrp_add(struct dsa_switch *ds,
> -                             struct dsa_notifier_mrp_info *info)
> -{
> -       if (!ds->ops->port_mrp_add)
> -               return -EOPNOTSUPP;
> -
> -       if (ds->index == info->sw_index)
> -               return ds->ops->port_mrp_add(ds, info->port, info->mrp);
> -
> -       return 0;
> -}
> -
> -static int dsa_switch_mrp_del(struct dsa_switch *ds,
> -                             struct dsa_notifier_mrp_info *info)
> -{
> -       if (!ds->ops->port_mrp_del)
> -               return -EOPNOTSUPP;
> -
> -       if (ds->index == info->sw_index)
> -               return ds->ops->port_mrp_del(ds, info->port, info->mrp);
> -
> -       return 0;
> -}
> -
> -static int
> -dsa_switch_mrp_add_ring_role(struct dsa_switch *ds,
> -                            struct dsa_notifier_mrp_ring_role_info *info)
> -{
> -       if (!ds->ops->port_mrp_add)
> -               return -EOPNOTSUPP;
> -
> -       if (ds->index == info->sw_index)
> -               return ds->ops->port_mrp_add_ring_role(ds, info->port,
> -                                                      info->mrp);
> -
> -       return 0;
> -}
> -
> -static int
> -dsa_switch_mrp_del_ring_role(struct dsa_switch *ds,
> -                            struct dsa_notifier_mrp_ring_role_info *info)
> -{
> -       if (!ds->ops->port_mrp_del)
> -               return -EOPNOTSUPP;
> -
> -       if (ds->index == info->sw_index)
> -               return ds->ops->port_mrp_del_ring_role(ds, info->port,
> -                                                      info->mrp);
> -
> -       return 0;
> -}
> -
>  static int dsa_switch_event(struct notifier_block *nb,
>                             unsigned long event, void *info)
>  {
> @@ -826,18 +774,6 @@ static int dsa_switch_event(struct notifier_block *nb,
>         case DSA_NOTIFIER_TAG_PROTO_DISCONNECT:
>                 err = dsa_switch_disconnect_tag_proto(ds, info);
>                 break;
> -       case DSA_NOTIFIER_MRP_ADD:
> -               err = dsa_switch_mrp_add(ds, info);
> -               break;
> -       case DSA_NOTIFIER_MRP_DEL:
> -               err = dsa_switch_mrp_del(ds, info);
> -               break;
> -       case DSA_NOTIFIER_MRP_ADD_RING_ROLE:
> -               err = dsa_switch_mrp_add_ring_role(ds, info);
> -               break;
> -       case DSA_NOTIFIER_MRP_DEL_RING_ROLE:
> -               err = dsa_switch_mrp_del_ring_role(ds, info);
> -               break;
>         case DSA_NOTIFIER_TAG_8021Q_VLAN_ADD:
>                 err = dsa_switch_tag_8021q_vlan_add(ds, info);
>                 break;
> --
> 2.25.1
> 

-- 
/Horatiu

^ permalink raw reply

* Re: [PATCH v6 07/10] hda: cs35l41: Add support for CS35L41 in HDA systems
From: Charles Keepax @ 2022-01-05  9:58 UTC (permalink / raw)
  To: Lucas Tanure
  Cc: Rafael J . Wysocki, Len Brown, Hans de Goede, Mark Gross,
	Liam Girdwood, Jaroslav Kysela, Mark Brown, Takashi Iwai,
	alsa-devel, linux-acpi, patches, platform-driver-x86,
	linux-kernel
In-Reply-To: <20211217115708.882525-8-tanureal@opensource.cirrus.com>

On Fri, Dec 17, 2021 at 11:57:05AM +0000, Lucas Tanure wrote:
> Add support for CS35L41 using a new separated driver
> that can be used in all upcoming designs
> 
> Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com>
> ---
> +	mtl_revid = reg_revid & CS35L41_MTLREVID_MASK;
> +
> +	chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
> +	if (regid != chipid) {
> +		dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", regid, chipid);
> +		ret = -ENODEV;
> +		goto err;
> +	}
> +
> +	ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid);
> +	if (ret)
> +		goto err;
> +
> +	ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
> +	if (ret) {
> +		dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
> +		goto err;
> +	}
> +
> +	ret = cs35l41_hda_apply_properties(cs35l41, acpi_hw_cfg);
> +	if (ret)
> +		goto err;
> +	kfree(acpi_hw_cfg);
> +
> +	if (cs35l41->reg_seq->probe) {
> +		ret = regmap_register_patch(cs35l41->regmap, cs35l41->reg_seq->probe,
> +					    cs35l41->reg_seq->num_probe);
> +		if (ret) {
> +			dev_err(cs35l41->dev, "Fail to apply probe reg patch: %d\n", ret);
> +			goto err;
> +		}
> +	}

Probably shouldn't use regmap_register_patch here,
cs35l41_register_errata_patch has already registered a patch to
the regmap, and this will then overwrite that patch. Probably
better to do this stuff as a multi-write.

Thanks,
Charles

^ permalink raw reply

* Re: [PATCH v6 07/10] hda: cs35l41: Add support for CS35L41 in HDA systems
From: Charles Keepax @ 2022-01-05  9:58 UTC (permalink / raw)
  To: Lucas Tanure
  Cc: alsa-devel, linux-acpi, Rafael J . Wysocki, patches, Takashi Iwai,
	Liam Girdwood, Mark Gross, Hans de Goede, Mark Brown,
	platform-driver-x86, linux-kernel, Len Brown
In-Reply-To: <20211217115708.882525-8-tanureal@opensource.cirrus.com>

On Fri, Dec 17, 2021 at 11:57:05AM +0000, Lucas Tanure wrote:
> Add support for CS35L41 using a new separated driver
> that can be used in all upcoming designs
> 
> Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com>
> ---
> +	mtl_revid = reg_revid & CS35L41_MTLREVID_MASK;
> +
> +	chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
> +	if (regid != chipid) {
> +		dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", regid, chipid);
> +		ret = -ENODEV;
> +		goto err;
> +	}
> +
> +	ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid);
> +	if (ret)
> +		goto err;
> +
> +	ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
> +	if (ret) {
> +		dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
> +		goto err;
> +	}
> +
> +	ret = cs35l41_hda_apply_properties(cs35l41, acpi_hw_cfg);
> +	if (ret)
> +		goto err;
> +	kfree(acpi_hw_cfg);
> +
> +	if (cs35l41->reg_seq->probe) {
> +		ret = regmap_register_patch(cs35l41->regmap, cs35l41->reg_seq->probe,
> +					    cs35l41->reg_seq->num_probe);
> +		if (ret) {
> +			dev_err(cs35l41->dev, "Fail to apply probe reg patch: %d\n", ret);
> +			goto err;
> +		}
> +	}

Probably shouldn't use regmap_register_patch here,
cs35l41_register_errata_patch has already registered a patch to
the regmap, and this will then overwrite that patch. Probably
better to do this stuff as a multi-write.

Thanks,
Charles

^ permalink raw reply

* Re: [PATCH v20 3/7] soc: mediatek: SVS: introduce MTK SVS engine
From: AngeloGioacchino Del Regno @ 2022-01-05  9:58 UTC (permalink / raw)
  To: Roger Lu, Matthias Brugger, Enric Balletbo Serra, Kevin Hilman,
	Rob Herring, Nicolas Boichat, Stephen Boyd, Philipp Zabel
  Cc: Fan Chen, HenryC Chen, YT Lee, Xiaoqing Liu, Charles Yang,
	Angus Lin, Mark Rutland, Nishanth Menon, devicetree,
	linux-arm-kernel, linux-mediatek, linux-kernel, linux-pm,
	Project_Global_Chrome_Upstream_Group, Guenter Roeck
In-Reply-To: <20210721070904.15636-4-roger.lu@mediatek.com>

Il 21/07/21 09:09, Roger Lu ha scritto:
> The Smart Voltage Scaling(SVS) engine is a piece of hardware
> which calculates suitable SVS bank voltages to OPP voltage table.
> Then, DVFS driver could apply those SVS bank voltages to PMIC/Buck
> when receiving OPP_EVENT_ADJUST_VOLTAGE.
> 
> Signed-off-by: Roger Lu <roger.lu@mediatek.com>

Hello Roger,
thanks for the patch!

However, there are a few things to improve...

> ---
>   drivers/soc/mediatek/Kconfig   |   10 +
>   drivers/soc/mediatek/Makefile  |    1 +
>   drivers/soc/mediatek/mtk-svs.c | 1720 ++++++++++++++++++++++++++++++++
>   3 files changed, 1731 insertions(+)
>   create mode 100644 drivers/soc/mediatek/mtk-svs.c
> 
> diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
> index fdd8bc08569e..3c3eedea35f7 100644
> --- a/drivers/soc/mediatek/Kconfig
> +++ b/drivers/soc/mediatek/Kconfig
> @@ -73,4 +73,14 @@ config MTK_MMSYS
>   	  Say yes here to add support for the MediaTek Multimedia
>   	  Subsystem (MMSYS).
>   
> +config MTK_SVS
> +	tristate "MediaTek Smart Voltage Scaling(SVS)"
> +	depends on MTK_EFUSE && NVMEM
> +	help
> +	  The Smart Voltage Scaling(SVS) engine is a piece of hardware
> +	  which has several controllers(banks) for calculating suitable
> +	  voltage to different power domains(CPU/GPU/CCI) according to
> +	  chip process corner, temperatures and other factors. Then DVFS
> +	  driver could apply SVS bank voltage to PMIC/Buck.
> +
>   endmenu
> diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
> index 90270f8114ed..0e9e703c931a 100644
> --- a/drivers/soc/mediatek/Makefile
> +++ b/drivers/soc/mediatek/Makefile
> @@ -7,3 +7,4 @@ obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
>   obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
>   obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
>   obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
> +obj-$(CONFIG_MTK_SVS) += mtk-svs.o
> diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
> new file mode 100644
> index 000000000000..013667752ec2
> --- /dev/null
> +++ b/drivers/soc/mediatek/mtk-svs.c
> @@ -0,0 +1,1720 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_opp.h>
> +#include <linux/pm_qos.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/thermal.h>
> +
> +/* svs bank 1-line sw id */
> +#define SVSB_CPU_LITTLE			BIT(0)
> +#define SVSB_CPU_BIG			BIT(1)
> +#define SVSB_CCI			BIT(2)
> +#define SVSB_GPU			BIT(3)
> +
> +/* svs bank mode support */
> +#define SVSB_MODE_ALL_DISABLE		0
> +#define SVSB_MODE_INIT01		BIT(1)
> +#define SVSB_MODE_INIT02		BIT(2)
> +#define SVSB_MODE_MON			BIT(3)
> +
> +/* svs bank volt flags */
> +#define SVSB_INIT01_VOLT_IGNORE		BIT(1)
> +#define SVSB_INIT01_VOLT_INC_ONLY	BIT(2)
> +#define SVSB_INIT02_RM_DVTFIXED		BIT(8)
> +#define SVSB_MON_VOLT_IGNORE		BIT(16)
> +
> +/* svs bank common setting */
> +#define SVSB_DET_CLK_EN			BIT(31)
> +#define SVSB_TZONE_HIGH_TEMP_MAX	U32_MAX
> +#define SVSB_RUNCONFIG_DEFAULT		0x80000000
> +#define SVSB_DC_SIGNED_BIT		0x8000

SVSB_DC_SIGNED_BIT is.. clearly a bit, so this should be BIT(15)

> +#define SVSB_INTEN_INIT0x		0x00005f01
> +#define SVSB_INTEN_MONVOPEN		0x00ff0000
> +#define SVSB_EN_OFF			0x0
> +#define SVSB_EN_MASK			0x7
> +#define SVSB_EN_INIT01			0x1
> +#define SVSB_EN_INIT02			0x5
> +#define SVSB_EN_MON			0x2
> +#define SVSB_INTSTS_MONVOP		0x00ff0000
> +#define SVSB_INTSTS_COMPLETE		0x1
> +#define SVSB_INTSTS_CLEAN		0x00ffffff
> +
> +static DEFINE_SPINLOCK(mtk_svs_lock);
> +
> +/*

Looks like the great intention is to have kernel-doc here, and it's already
in the right format, but the start of the comment block should be

/**

and not

/*

to be recognized as kerneldoc.
Please refer to https://www.kernel.org/doc/html/v5.15/doc-guide/kernel-doc.html

> + * enum svsb_phase - svs bank phase enumeration
> + * @SVSB_PHASE_INIT01: basic init for svs bank
> + * @SVSB_PHASE_INIT02: svs bank can provide voltages
> + * @SVSB_PHASE_MON: svs bank can provide voltages with thermal effect
> + * @SVSB_PHASE_ERROR: svs bank encounters unexpected condition

Please move @SVSB_PHASE_ERROR before @SVSB_PHASE_INIT01: the order

is important here, and has to be the same as the actual enumeration.

> + *
> + * Each svs bank has its own independent phase. We enable each svs bank by
> + * running their phase orderly. However, When svs bank encounters unexpected
> + * condition, it will fire an irq (PHASE_ERROR) to inform svs software.
> + *
> + * svs bank general phase-enabled order:
> + * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 -> SVSB_PHASE_MON
> + */
> +enum svsb_phase {
> +	SVSB_PHASE_ERROR = 0,
> +	SVSB_PHASE_INIT01,
> +	SVSB_PHASE_INIT02,
> +	SVSB_PHASE_MON,
> +};
> +
> +enum svs_reg_index {
> +	DESCHAR = 0,
> +	TEMPCHAR,
> +	DETCHAR,
> +	AGECHAR,
> +	DCCONFIG,
> +	AGECONFIG,
> +	FREQPCT30,
> +	FREQPCT74,
> +	LIMITVALS,
> +	VBOOT,
> +	DETWINDOW,
> +	CONFIG,
> +	TSCALCS,
> +	RUNCONFIG,
> +	SVSEN,
> +	INIT2VALS,
> +	DCVALUES,
> +	AGEVALUES,
> +	VOP30,
> +	VOP74,
> +	TEMP,
> +	INTSTS,
> +	INTSTSRAW,
> +	INTEN,
> +	CHKINT,
> +	CHKSHIFT,
> +	STATUS,
> +	VDESIGN30,
> +	VDESIGN74,
> +	DVT30,
> +	DVT74,
> +	AGECOUNT,
> +	SMSTATE0,
> +	SMSTATE1,
> +	CTL0,
> +	DESDETSEC,
> +	TEMPAGESEC,
> +	CTRLSPARE0,
> +	CTRLSPARE1,
> +	CTRLSPARE2,
> +	CTRLSPARE3,
> +	CORESEL,
> +	THERMINTST,
> +	INTST,
> +	THSTAGE0ST,
> +	THSTAGE1ST,
> +	THSTAGE2ST,
> +	THAHBST0,
> +	THAHBST1,
> +	SPARE0,
> +	SPARE1,
> +	SPARE2,
> +	SPARE3,
> +	THSLPEVEB,
> +};
> +
> +static const u32 svs_regs_v2[] = {
> +	[DESCHAR]		= 0xc00,
> +	[TEMPCHAR]		= 0xc04,
> +	[DETCHAR]		= 0xc08,
> +	[AGECHAR]		= 0xc0c,
> +	[DCCONFIG]		= 0xc10,
> +	[AGECONFIG]		= 0xc14,
> +	[FREQPCT30]		= 0xc18,
> +	[FREQPCT74]		= 0xc1c,
> +	[LIMITVALS]		= 0xc20,
> +	[VBOOT]			= 0xc24,
> +	[DETWINDOW]		= 0xc28,
> +	[CONFIG]		= 0xc2c,
> +	[TSCALCS]		= 0xc30,
> +	[RUNCONFIG]		= 0xc34,
> +	[SVSEN]			= 0xc38,
> +	[INIT2VALS]		= 0xc3c,
> +	[DCVALUES]		= 0xc40,
> +	[AGEVALUES]		= 0xc44,
> +	[VOP30]			= 0xc48,
> +	[VOP74]			= 0xc4c,
> +	[TEMP]			= 0xc50,
> +	[INTSTS]		= 0xc54,
> +	[INTSTSRAW]		= 0xc58,
> +	[INTEN]			= 0xc5c,
> +	[CHKINT]		= 0xc60,
> +	[CHKSHIFT]		= 0xc64,
> +	[STATUS]		= 0xc68,
> +	[VDESIGN30]		= 0xc6c,
> +	[VDESIGN74]		= 0xc70,
> +	[DVT30]			= 0xc74,
> +	[DVT74]			= 0xc78,
> +	[AGECOUNT]		= 0xc7c,
> +	[SMSTATE0]		= 0xc80,
> +	[SMSTATE1]		= 0xc84,
> +	[CTL0]			= 0xc88,
> +	[DESDETSEC]		= 0xce0,
> +	[TEMPAGESEC]		= 0xce4,
> +	[CTRLSPARE0]		= 0xcf0,
> +	[CTRLSPARE1]		= 0xcf4,
> +	[CTRLSPARE2]		= 0xcf8,
> +	[CTRLSPARE3]		= 0xcfc,
> +	[CORESEL]		= 0xf00,
> +	[THERMINTST]		= 0xf04,
> +	[INTST]			= 0xf08,
> +	[THSTAGE0ST]		= 0xf0c,
> +	[THSTAGE1ST]		= 0xf10,
> +	[THSTAGE2ST]		= 0xf14,
> +	[THAHBST0]		= 0xf18,
> +	[THAHBST1]		= 0xf1c,
> +	[SPARE0]		= 0xf20,
> +	[SPARE1]		= 0xf24,
> +	[SPARE2]		= 0xf28,
> +	[SPARE3]		= 0xf2c,
> +	[THSLPEVEB]		= 0xf30,
> +};
> +
> +/*
> + * struct thermal_parameter - This is for storing thermal efuse data.
> + * We calculate thermal efuse data to produce "mts" and "bts" for
> + * svs bank mon mode.
> + */
> +struct thermal_parameter {
> +	int adc_ge_t;
> +	int adc_oe_t;
> +	int ge;
> +	int oe;
> +	int gain;
> +	int o_vtsabb;
> +	int o_vtsmcu1;
> +	int o_vtsmcu2;
> +	int o_vtsmcu3;
> +	int o_vtsmcu4;
> +	int o_vtsmcu5;
> +	int degc_cali;
> +	int adc_cali_en_t;
> +	int o_slope;
> +	int o_slope_sign;
> +	int ts_id;
> +};
> +
> +/*

... same here, /** for kerneldoc

> + * struct svs_platform - svs platform data
> + * @dev: svs platform device
> + * @base: svs platform register address base
> + * @main_clk: main clock for svs bank
> + * @pbank: phandle of svs bank and needs to be protected by spin_lock
> + * @banks: phandle of the banks that support
> + * @efuse_parsing: phandle of efuse parsing function
> + * @irqflags: irq settings flags
> + * @rst: svs reset control
> + * @regs: phandle to the registers map

@name should be here

> + * @efuse_num: the total number of svs platform efuse
> + * @tefuse_num: the total number of thermal efuse
> + * @bank_num: the total number of banks
> + * @efuse_check: the svs efuse check index
> + * @efuse: svs platform efuse data received from NVMEM framework
> + * @tefuse: thermal efuse data received from NVMEM framework
> + * @name: svs platform name
> + */
> +struct svs_platform {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct clk *main_clk;
> +	struct svs_bank *pbank;
> +	struct svs_bank *banks;
> +	bool (*efuse_parsing)(struct svs_platform *svsp);
> +	unsigned long irqflags;
> +	struct reset_control *rst;
> +	const u32 *regs;
> +	char *name;
> +	size_t efuse_num;
> +	size_t tefuse_num;
> +	u32 bank_num;
> +	u32 efuse_check;
> +	u32 *efuse;
> +	u32 *tefuse;
> +};
> +
> +/*

... and here

> + * struct svs_bank - svs bank representation
> + * @dev: svs bank device
> + * @opp_dev: device for opp table/buck control
> + * @pd_dev: power domain device for SoC mtcmos control
> + * @init_completion: the timeout completion for bank init
> + * @buck: phandle of the regulator
> + * @lock: mutex lock to protect voltage update process
> + * @phase: bank current phase
> + * @name: bank name
> + * @tzone_name: thermal zone name
> + * @buck_name: regulator name
> + * @suspended: suspend flag of this bank
> + * @pd_req: bank's power-domain on request
> + * @enable_pm_runtime_ever: bank enables pm-runtime flag
> + * @set_freqs_pct: phandle of set frequencies percent function
> + * @get_vops: phandle of get bank voltages function
> + * @volt_offset: bank voltage offset controlled by svs software
> + * @mode_support: bank mode support.
> + * @opp_freqs: signed-off frequencies from default opp table
> + * @opp_volts: signed-off voltages from default opp table
> + * @freqs_pct: percent of "opp_freqs / freq_base" for bank init
> + * @volts: bank voltages
> + * @freq_base: reference frequency for bank init
> + * @vboot: voltage request for bank init01 stage only
> + * @volt_step: bank voltage step
> + * @volt_base: bank voltage base
> + * @volt_flags: bank voltage flags
> + * @vmax: bank voltage maximum
> + * @vmin: bank voltage minimum

I love when developers take the effort to document with kerneldoc, so, great job
about that.... however, you forgot to document a few variables... can you please
add the required documentation for them?

> + * @temp: bank temperature
> + * @temp_upper_bound: bank temperature upper bound
> + * @temp_lower_bound: bank temperature lower bound
> + * @tzone_high_temp: thermal zone high temperature threshold
> + * @tzone_high_temp_offset: thermal zone high temperature offset
> + * @tzone_low_temp: thermal zone low temperature threshold
> + * @tzone_low_temp_offset: thermal zone low temperature offset
> + * @core_sel: bank selection
> + * @opp_count: bank opp count
> + * @int_st: bank interrupt identification
> + * @sw_id: bank software identification
> + * @ctl0: bank thermal sensor selection
> + * @cpu_id: cpu core id for SVS CPU only
> + *
> + * Other structure members which are not listed above are svs platform
> + * efuse data for bank init
> + */
> +struct svs_bank {
> +	struct device *dev;
> +	struct device *opp_dev;
> +	struct device *pd_dev;
> +	struct completion init_completion;
> +	struct regulator *buck;
> +	struct mutex lock;	/* lock to protect voltage update process */
> +	enum svsb_phase phase;
> +	char *name;
> +	char *tzone_name;
> +	char *buck_name;
> +	bool suspended;
> +	bool pd_req;
> +	bool enable_pm_runtime_ever;
> +	void (*set_freqs_pct)(struct svs_platform *svsp);
> +	void (*get_vops)(struct svs_platform *svsp);
> +	s32 volt_offset;
> +	u32 mode_support;
> +	u32 opp_freqs[16];

At the beginning of the file....
#define MAX_OPP_ENTRIES 16

...so you can do...
	u32 opp_freqs[MAX_OPP_ENTRIES];
	u32 opp_volts[MAX_OPP_ENTRIES];
...and the same for the other two.

> +	u32 opp_volts[16];
> +	u32 freqs_pct[16];
> +	u32 volts[16];
> +	u32 freq_base;
> +	u32 vboot;
> +	u32 volt_step;
> +	u32 volt_base;
> +	u32 volt_flags;
> +	u32 vmax;
> +	u32 vmin;

Document these entries, please.

vvvvvvvvv From here.... vvvvvvvvv

> +	u32 bts;
> +	u32 mts;
> +	u32 bdes;
> +	u32 mdes;
> +	u32 mtdes;
> +	u32 dcbdet;
> +	u32 dcmdet;
> +	u32 dthi;
> +	u32 dtlo;
> +	u32 det_window;
> +	u32 det_max;
> +	u32 age_config;
> +	u32 age_voffset_in;
> +	u32 agem;
> +	u32 dc_config;
> +	u32 dc_voffset_in;
> +	u32 dvt_fixed;
> +	u32 vco;
> +	u32 chk_shift;

^^^^^^^^^ ....to there ^^^^^^^^^

> +	u32 temp;
> +	u32 temp_upper_bound;
> +	u32 temp_lower_bound;
> +	u32 tzone_high_temp;
> +	u32 tzone_high_temp_offset;
> +	u32 tzone_low_temp;
> +	u32 tzone_low_temp_offset;
> +	u32 core_sel;
> +	u32 opp_count;
> +	u32 int_st;
> +	u32 sw_id;
> +	u32 ctl0;
> +	u32 cpu_id;
> +};
> +
> +static u32 percent(u32 numerator, u32 denominator)
> +{
> +	/* If not divide 1000, "numerator * 100" will have data overflow. */
> +	numerator /= 1000;
> +	denominator /= 1000;
> +
> +	return DIV_ROUND_UP(numerator * 100, denominator);
> +}
> +
> +static u32 svs_readl(struct svs_platform *svsp, enum svs_reg_index rg_i)
> +{
> +	return readl(svsp->base + svsp->regs[rg_i]);
> +}
> +
> +static void svs_writel(struct svs_platform *svsp, u32 val,
> +		       enum svs_reg_index rg_i)
> +{
> +	writel(val, svsp->base + svsp->regs[rg_i]);
> +}
> +
> +static void svs_switch_bank(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svs_writel(svsp, svsb->core_sel, CORESEL);
> +}
> +
> +static u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step,
> +				     u32 svsb_volt_base)
> +{
> +	return (svsb_volt * svsb_volt_step) + svsb_volt_base;
> +}
> +
> +static int svs_get_bank_zone_temperature(const char *tzone_name,
> +					 int *tzone_temp)
> +{
> +	struct thermal_zone_device *tzd;
> +
> +	tzd = thermal_zone_get_zone_by_name(tzone_name);
> +	if (IS_ERR(tzd))
> +		return PTR_ERR(tzd);
> +
> +	return thermal_zone_get_temp(tzd, tzone_temp);
> +}
> +
> +static int svs_adjust_pm_opp_volts(struct svs_bank *svsb, bool force_update)
> +{
> +	int tzone_temp = 0, ret = -EPERM;
> +	u32 i, svsb_volt, opp_volt, temp_offset = 0;
> +
> +	mutex_lock(&svsb->lock);
> +
> +	/*
> +	 * If svs bank is suspended, it means signed-off voltages are applied.
> +	 * Don't need to update opp voltage anymore.
> +	 */
> +	if (svsb->suspended && !force_update) {
> +		dev_notice(svsb->dev, "bank is suspended\n");
> +		ret = -EPERM;
> +		goto unlock_mutex;
> +	}
> +
> +	/* Get thermal effect */
> +	if (svsb->phase == SVSB_PHASE_MON) {
> +		if (svsb->temp > svsb->temp_upper_bound &&
> +		    svsb->temp < svsb->temp_lower_bound) {
> +			dev_warn(svsb->dev, "svsb temp = 0x%x?\n", svsb->temp);
> +			ret = -EINVAL;
> +			goto unlock_mutex;
> +		}
> +
> +		ret = svs_get_bank_zone_temperature(svsb->tzone_name,
> +						    &tzone_temp);
> +		if (ret) {
> +			dev_err(svsb->dev, "no %s? (%d), run default volts\n",
> +				svsb->tzone_name, ret);
> +			svsb->phase = SVSB_PHASE_ERROR;
> +		}
> +
> +		if (tzone_temp >= svsb->tzone_high_temp)
> +			temp_offset += svsb->tzone_high_temp_offset;
> +		else if (tzone_temp <= svsb->tzone_low_temp)
> +			temp_offset += svsb->tzone_low_temp_offset;
> +	}
> +
> +	/* vmin <= svsb_volt (opp_volt) <= signed-off (default) voltage */
> +	for (i = 0; i < svsb->opp_count; i++) {



What about using switch here?



         switch (svsb->phase) {

         case SVSB_PHASE_MON:

             ......

             break;

         case .......:

             .........

             break;

         default:

             dev_err(......);

             ret = -EINVAL;

             goto unlock_mutex;

         }

> +		if (svsb->phase == SVSB_PHASE_MON) {
> +			svsb_volt = max(svsb->volts[i] + svsb->volt_offset +
> +					temp_offset, svsb->vmin);
> +			opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
> +							     svsb->volt_step,
> +							     svsb->volt_base);
> +		} else if (svsb->phase == SVSB_PHASE_INIT02) {
> +			svsb_volt = max(svsb->volts[i] + svsb->volt_offset,
> +					svsb->vmin);
> +			opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
> +							     svsb->volt_step,
> +							     svsb->volt_base);
> +		} else if (svsb->phase == SVSB_PHASE_ERROR) {
> +			opp_volt = svsb->opp_volts[i];
> +		} else {
> +			dev_err(svsb->dev, "unknown phase: %u?\n", svsb->phase);
> +			ret = -EINVAL;
> +			goto unlock_mutex;
> +		}
> +
> +		opp_volt = min(opp_volt, svsb->opp_volts[i]);
> +		ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
> +						svsb->opp_freqs[i],
> +						opp_volt, opp_volt,
> +						svsb->opp_volts[i]);
> +		if (ret) {
> +			dev_err(svsb->dev, "set voltage fail: %d\n", ret);
> +			goto unlock_mutex;
> +		}
> +	}
> +
> +unlock_mutex:
> +	mutex_unlock(&svsb->lock);
> +
> +	return ret;
> +}
> +
> +static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
> +{
> +	u32 vx;
> +
> +	if (v0 == v1 || f0 == f1)
> +		return v0;
> +
> +	/* *100 to have decimal fraction factor */
> +	vx = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
> +
> +	return DIV_ROUND_UP(vx, 100);
> +}
> +
> +static void svs_get_vops_v2(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +	u32 temp, i;
> +
> +	if (svsb->phase == SVSB_PHASE_MON &&
> +	    svsb->volt_flags & SVSB_MON_VOLT_IGNORE)
> +		return;
> +
> +	temp = svs_readl(svsp, VOP74);
> +	svsb->volts[14] = (temp >> 24) & GENMASK(7, 0);
> +	svsb->volts[12] = (temp >> 16) & GENMASK(7, 0);
> +	svsb->volts[10] = (temp >> 8)  & GENMASK(7, 0);
> +	svsb->volts[8] = (temp & GENMASK(7, 0));
> +
> +	temp = svs_readl(svsp, VOP30);
> +	svsb->volts[6] = (temp >> 24) & GENMASK(7, 0);
> +	svsb->volts[4] = (temp >> 16) & GENMASK(7, 0);
> +	svsb->volts[2] = (temp >> 8)  & GENMASK(7, 0);
> +	svsb->volts[0] = (temp & GENMASK(7, 0));
> +
> +	for (i = 0; i <= 12; i += 2)
> +		svsb->volts[i + 1] =
> +			interpolate(svsb->freqs_pct[i],
> +				    svsb->freqs_pct[i + 2],
> +				    svsb->volts[i],
> +				    svsb->volts[i + 2],
> +				    svsb->freqs_pct[i + 1]);
> +
> +	svsb->volts[15] =
> +		interpolate(svsb->freqs_pct[12],
> +			    svsb->freqs_pct[14],
> +			    svsb->volts[12],
> +			    svsb->volts[14],
> +			    svsb->freqs_pct[15]);
> +
> +	if (svsb->volt_flags & SVSB_INIT02_RM_DVTFIXED)
> +		for (i = 0; i < svsb->opp_count; i++)
> +			svsb->volts[i] -= svsb->dvt_fixed;
> +}
> +
> +static void svs_set_freqs_pct_v2(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svs_writel(svsp,
> +		   (svsb->freqs_pct[14] << 24) |
> +		   (svsb->freqs_pct[12] << 16) |
> +		   (svsb->freqs_pct[10] << 8) |
> +		   svsb->freqs_pct[8],
> +		   FREQPCT74);
> +
> +	svs_writel(svsp,
> +		   (svsb->freqs_pct[6] << 24) |
> +		   (svsb->freqs_pct[4] << 16) |
> +		   (svsb->freqs_pct[2] << 8) |
> +		   svsb->freqs_pct[0],
> +		   FREQPCT30);
> +}
> +
> +static void svs_set_bank_phase(struct svs_platform *svsp,
> +			       enum svsb_phase target_phase)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +	u32 des_char, temp_char, det_char, limit_vals;
> +	u32 init2vals, ts_calcs, val, filter, i;
> +
> +	svs_switch_bank(svsp);
> +
> +	des_char = (svsb->bdes << 8) | svsb->mdes;
> +	svs_writel(svsp, des_char, DESCHAR);
> +
> +	temp_char = (svsb->vco << 16) | (svsb->mtdes << 8) | svsb->dvt_fixed;
> +	svs_writel(svsp, temp_char, TEMPCHAR);
> +
> +	det_char = (svsb->dcbdet << 8) | svsb->dcmdet;
> +	svs_writel(svsp, det_char, DETCHAR);
> +
> +	svs_writel(svsp, svsb->dc_config, DCCONFIG);
> +	svs_writel(svsp, svsb->age_config, AGECONFIG);
> +
> +	if (!svsb->agem) {
> +		svs_writel(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG);
> +	} else {
> +		val = 0x0;

val = 0;

> +
> +		for (i = 0; i < 24; i += 2) {
> +			filter = 0x3 << i;
> +
> +			if (!(svsb->age_config & filter))
> +				val |= (0x1 << i);

val |= BIT(i);

> +			else
> +				val |= (svsb->age_config & filter);
> +		}
> +		svs_writel(svsp, val, RUNCONFIG);
> +	}
> +
> +	svsb->set_freqs_pct(svsp);
> +
> +	limit_vals = (svsb->vmax << 24) | (svsb->vmin << 16) |
> +		     (svsb->dthi << 8) | svsb->dtlo;
> +	svs_writel(svsp, limit_vals, LIMITVALS);
> +	svs_writel(svsp, svsb->vboot, VBOOT);
> +	svs_writel(svsp, svsb->det_window, DETWINDOW);
> +	svs_writel(svsp, svsb->det_max, CONFIG);
> +
> +	if (svsb->chk_shift)
> +		svs_writel(svsp, svsb->chk_shift, CHKSHIFT);
> +
> +	if (svsb->ctl0)
> +		svs_writel(svsp, svsb->ctl0, CTL0);
> +
> +	svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +
> +	switch (target_phase) {
> +	case SVSB_PHASE_INIT01:
> +		svs_writel(svsp, SVSB_INTEN_INIT0x, INTEN);
> +		svs_writel(svsp, SVSB_EN_INIT01, SVSEN);
> +		break;
> +	case SVSB_PHASE_INIT02:
> +		svs_writel(svsp, SVSB_INTEN_INIT0x, INTEN);
> +		init2vals = (svsb->age_voffset_in << 16) | svsb->dc_voffset_in;
> +		svs_writel(svsp, init2vals, INIT2VALS);
> +		svs_writel(svsp, SVSB_EN_INIT02, SVSEN);
> +		break;
> +	case SVSB_PHASE_MON:
> +		ts_calcs = (svsb->bts << 12) | svsb->mts;
> +		svs_writel(svsp, ts_calcs, TSCALCS);
> +		svs_writel(svsp, SVSB_INTEN_MONVOPEN, INTEN);
> +		svs_writel(svsp, SVSB_EN_MON, SVSEN);
> +		break;
> +	default:
> +		WARN_ON(1);



I agree about printing a big warning in kmsg here, but you can do that in a

slightly more descriptive way:



         WARN(1, "Requested unknown target phase %u", target_phase);

> +		break;
> +	}
> +}
> +
> +static inline void svs_init01_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n",
> +		 __func__, svs_readl(svsp, VDESIGN74),
> +		 svs_readl(svsp, VDESIGN30), svs_readl(svsp, DCVALUES));
> +
> +	svsb->phase = SVSB_PHASE_INIT01;
> +	svsb->dc_voffset_in = ~(svs_readl(svsp, DCVALUES) & GENMASK(15, 0)) + 1;
> +	if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE ||
> +	    (svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT &&
> +	     svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY))
> +		svsb->dc_voffset_in = 0;
> +
> +	svsb->age_voffset_in = svs_readl(svsp, AGEVALUES) & GENMASK(15, 0);
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
> +
> +	/* svs init01 clock gating */
> +	svsb->core_sel &= ~SVSB_DET_CLK_EN;
> +}
> +
> +static inline void svs_init02_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n",
> +		 __func__, svs_readl(svsp, VOP74), svs_readl(svsp, VOP30),
> +		 svs_readl(svsp, DCVALUES));
> +
> +	svsb->phase = SVSB_PHASE_INIT02;
> +	svsb->get_vops(svsp);
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
> +}
> +
> +static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svsb->phase = SVSB_PHASE_MON;
> +	svsb->temp = svs_readl(svsp, TEMP) & GENMASK(7, 0);
> +	svsb->get_vops(svsp);
> +
> +	svs_writel(svsp, SVSB_INTSTS_MONVOP, INTSTS);
> +}
> +
> +static inline void svs_error_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n",
> +		__func__, svs_readl(svsp, CORESEL));
> +	dev_err(svsb->dev, "SVSEN = 0x%08x, INTSTS = 0x%08x\n",
> +		svs_readl(svsp, SVSEN), svs_readl(svsp, INTSTS));
> +	dev_err(svsb->dev, "SMSTATE0 = 0x%08x, SMSTATE1 = 0x%08x\n",
> +		svs_readl(svsp, SMSTATE0), svs_readl(svsp, SMSTATE1));
> +	dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl(svsp, TEMP));
> +
> +	svsb->mode_support = SVSB_MODE_ALL_DISABLE;
> +	svsb->phase = SVSB_PHASE_ERROR;
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +}
> +
> +static irqreturn_t svs_isr(int irq, void *data)
> +{
> +	struct svs_platform *svsp = data;
> +	struct svs_bank *svsb = NULL;
> +	unsigned long flags;
> +	u32 idx, int_sts, svs_en;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		WARN_ON(!svsb);
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +
> +		/* Find out which svs bank fires interrupt */
> +		if (svsb->int_st & svs_readl(svsp, INTST)) {
> +			spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +			continue;
> +		}
> +
> +		if (!svsb->suspended) {
> +			svs_switch_bank(svsp);
> +			int_sts = svs_readl(svsp, INTSTS);
> +			svs_en = svs_readl(svsp, SVSEN) & SVSB_EN_MASK;
> +
> +			if (int_sts == SVSB_INTSTS_COMPLETE &&
> +			    svs_en == SVSB_EN_INIT01)
> +				svs_init01_isr_handler(svsp);
> +			else if (int_sts == SVSB_INTSTS_COMPLETE &&
> +				 svs_en == SVSB_EN_INIT02)
> +				svs_init02_isr_handler(svsp);
> +			else if (int_sts & SVSB_INTSTS_MONVOP)
> +				svs_mon_mode_isr_handler(svsp);
> +			else
> +				svs_error_isr_handler(svsp);
> +		}
> +
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +		break;
> +	}
> +
> +	if (svsb->phase != SVSB_PHASE_INIT01)
> +		svs_adjust_pm_opp_volts(svsb, false);
> +
> +	if (svsb->phase == SVSB_PHASE_INIT01 ||
> +	    svsb->phase == SVSB_PHASE_INIT02)
> +		complete(&svsb->init_completion);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void svs_mon_mode(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	unsigned long flags;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_MON))
> +			continue;
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_MON);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +	}
> +}
> +
> +static int svs_init02(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	unsigned long flags, time_left;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT02))
> +			continue;
> +
> +		reinit_completion(&svsb->init_completion);
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_INIT02);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		time_left =
> +			wait_for_completion_timeout(&svsb->init_completion,
> +						    msecs_to_jiffies(5000));
> +		if (!time_left) {
> +			dev_err(svsb->dev, "init02 completion timeout\n");
> +			return -EBUSY;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int svs_init01(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	struct pm_qos_request *qos_request;
> +	unsigned long flags, time_left;
> +	bool search_done;
> +	int ret = 0;
> +	u32 opp_freqs, opp_vboot, buck_volt, idx, i;
> +
> +	qos_request = kzalloc(sizeof(*qos_request), GFP_KERNEL);
> +	if (!qos_request)
> +		return -ENOMEM;
> +
> +	/* Let CPUs leave idle-off state for initializing svs_init01. */
> +	cpu_latency_qos_add_request(qos_request, 0);
> +
> +	/*
> +	 * Sometimes two svs banks use the same buck.
> +	 * Therefore, we set each svs bank to vboot voltage first.
> +	 */
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		search_done = false;
> +
> +		if (svsb->pd_req) {
> +			ret = regulator_enable(svsb->buck);
> +			if (ret) {
> +				dev_err(svsb->dev, "%s enable fail: %d\n",
> +					svsb->buck_name, ret);
> +				goto init01_finish;
> +			}
> +
> +			if (!pm_runtime_enabled(svsb->pd_dev)) {
> +				pm_runtime_enable(svsb->pd_dev);
> +				svsb->enable_pm_runtime_ever = true;
> +			}
> +
> +			ret = pm_runtime_get_sync(svsb->pd_dev);
> +			if (ret < 0) {
> +				dev_err(svsb->dev, "mtcmos on fail: %d\n", ret);
> +				goto init01_finish;
> +			}
> +		}
> +
> +		if (regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST))
> +			dev_notice(svsb->dev, "set fast mode fail\n");
> +
> +		/*
> +		 * Find the fastest freq that can be run at vboot and
> +		 * fix to that freq until svs_init01 is done.
> +		 */
> +		opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
> +						      svsb->volt_step,
> +						      svsb->volt_base);
> +
> +		for (i = 0; i < svsb->opp_count; i++) {
> +			opp_freqs = svsb->opp_freqs[i];
> +			if (!search_done && svsb->opp_volts[i] <= opp_vboot) {
> +				ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
> +								opp_freqs,
> +								opp_vboot,
> +								opp_vboot,
> +								opp_vboot);
> +				if (ret) {
> +					dev_err(svsb->dev,
> +						"set voltage fail: %d\n", ret);
> +					goto init01_finish;
> +				}
> +
> +				search_done = true;
> +			} else {
> +				dev_pm_opp_disable(svsb->opp_dev,
> +						   svsb->opp_freqs[i]);
> +			}
> +		}
> +	}
> +
> +	/* svs bank init01 begins */
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
> +						      svsb->volt_step,
> +						      svsb->volt_base);
> +
> +		buck_volt = regulator_get_voltage(svsb->buck);
> +		if (buck_volt != opp_vboot) {
> +			dev_err(svsb->dev,
> +				"buck voltage: %u, expected vboot: %u\n",
> +				buck_volt, opp_vboot);
> +			ret = -EPERM;
> +			goto init01_finish;
> +		}
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_INIT01);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		time_left =
> +			wait_for_completion_timeout(&svsb->init_completion,
> +						    msecs_to_jiffies(5000));
> +		if (!time_left) {
> +			dev_err(svsb->dev, "init01 completion timeout\n");
> +			ret = -EBUSY;
> +			goto init01_finish;
> +		}
> +	}
> +
> +init01_finish:
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		for (i = 0; i < svsb->opp_count; i++)
> +			dev_pm_opp_enable(svsb->opp_dev, svsb->opp_freqs[i]);
> +
> +		if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL))
> +			dev_notice(svsb->dev, "fail to set normal mode\n");
> +
> +		if (svsb->pd_req) {
> +			if (pm_runtime_put_sync(svsb->pd_dev))
> +				dev_err(svsb->dev, "mtcmos off fail\n");
> +
> +			if (svsb->enable_pm_runtime_ever) {
> +				pm_runtime_disable(svsb->pd_dev);
> +				svsb->enable_pm_runtime_ever = false;
> +			}
> +
> +			if (regulator_disable(svsb->buck))
> +				dev_err(svsb->dev, "%s disable fail: %d\n",
> +					svsb->buck_name, ret);
> +		}
> +	}
> +
> +	cpu_latency_qos_remove_request(qos_request);
> +	kfree(qos_request);
> +
> +	return ret;
> +}
> +
> +static int svs_start(struct svs_platform *svsp)
> +{
> +	int ret;
> +
> +	ret = svs_init01(svsp);
> +	if (ret)
> +		return ret;
> +
> +	ret = svs_init02(svsp);
> +	if (ret)
> +		return ret;
> +
> +	svs_mon_mode(svsp);
> +
> +	return 0;
> +}
> +
> +static struct device *svs_get_subsys_device(struct svs_platform *svsp,
> +					    const char *node_name)
> +{
> +	struct platform_device *pdev;
> +	struct device_node *np;
> +
> +	np = of_find_node_by_name(NULL, node_name);
> +	if (!np) {
> +		dev_err(svsp->dev, "cannot find %s node\n", node_name);
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	pdev = of_find_device_by_node(np);
> +	if (!pdev) {
> +		of_node_put(np);
> +		dev_err(svsp->dev, "cannot find pdev by %s\n", node_name);
> +		return ERR_PTR(-ENXIO);
> +	}
> +
> +	of_node_put(np);
> +
> +	return &pdev->dev;
> +}
> +
> +static struct device *svs_add_device_link(struct svs_platform *svsp,
> +					  const char *node_name)
> +{
> +	struct device *dev;
> +	struct device_link *sup_link;
> +
> +	if (!node_name) {
> +		dev_err(svsp->dev, "node name cannot be null\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	dev = svs_get_subsys_device(svsp, node_name);
> +	if (IS_ERR(dev))
> +		return dev;
> +
> +	sup_link = device_link_add(svsp->dev, dev,
> +				   DL_FLAG_AUTOREMOVE_CONSUMER);
> +	if (!sup_link) {
> +		dev_err(svsp->dev, "sup_link is NULL\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	return dev;
> +}
> +
> +static int svs_resource_setup(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	struct dev_pm_opp *opp;
> +	unsigned long freq;
> +	int count, ret;
> +	u32 idx, i;
> +
> +	dev_set_drvdata(svsp->dev, svsp);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			svsb->name = "SVSB_CPU_LITTLE";
> +			break;
> +		case SVSB_CPU_BIG:
> +			svsb->name = "SVSB_CPU_BIG";
> +			break;
> +		case SVSB_CCI:
> +			svsb->name = "SVSB_CCI";
> +			break;
> +		case SVSB_GPU:
> +			svsb->name = "SVSB_GPU";
> +			break;
> +		default:
> +			WARN_ON(1);
> +			return -EINVAL;
> +		}
> +
> +		svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev),
> +					 GFP_KERNEL);
> +		if (!svsb->dev)
> +			return -ENOMEM;
> +
> +		ret = dev_set_name(svsb->dev, "%s", svsb->name);
> +		if (ret)
> +			return ret;
> +
> +		dev_set_drvdata(svsb->dev, svsp);
> +
> +		ret = dev_pm_opp_of_add_table(svsb->opp_dev);
> +		if (ret) {
> +			dev_err(svsb->dev, "add opp table fail: %d\n", ret);
> +			return ret;
> +		}
> +
> +		mutex_init(&svsb->lock);
> +		init_completion(&svsb->init_completion);
> +
> +		svsb->buck = devm_regulator_get_optional(svsb->opp_dev,
> +							 svsb->buck_name);
> +		if (IS_ERR(svsb->buck)) {
> +			dev_err(svsb->dev, "cannot get \"%s-supply\"\n",
> +				svsb->buck_name);
> +			return PTR_ERR(svsb->buck);
> +		}
> +
> +		count = dev_pm_opp_get_opp_count(svsb->opp_dev);
> +		if (svsb->opp_count != count) {
> +			dev_err(svsb->dev,
> +				"opp_count not \"%u\" but get \"%d\"?\n",
> +				svsb->opp_count, count);
> +			return count;
> +		}
> +
> +		for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
> +			opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq);
> +			if (IS_ERR(opp)) {
> +				dev_err(svsb->dev, "cannot find freq = %ld\n",
> +					PTR_ERR(opp));
> +				return PTR_ERR(opp);
> +			}
> +
> +			svsb->opp_freqs[i] = freq;
> +			svsb->opp_volts[i] = dev_pm_opp_get_voltage(opp);
> +			svsb->freqs_pct[i] = percent(svsb->opp_freqs[i],
> +						     svsb->freq_base);
> +			dev_pm_opp_put(opp);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
> +{
> +	struct thermal_parameter tp;
> +	struct svs_bank *svsb;
> +	bool mon_mode_support = true;
> +	int format[6], x_roomt[6], tb_roomt = 0;
> +	struct nvmem_cell *cell;
> +	u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
> +
> +	for (i = 0; i < svsp->efuse_num; i++)
> +		if (svsp->efuse[i])
> +			dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
> +				 i, svsp->efuse[i]);
> +
> +	/* Svs efuse parsing */
> +	ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (ft_pgm <= 1)
> +			svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE;
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			svsb->bdes = svsp->efuse[16] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 10;
> +			else
> +				svsb->volt_offset += 2;
> +			break;
> +		case SVSB_CPU_BIG:
> +			svsb->bdes = svsp->efuse[18] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = svsp->efuse[17] & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 15;
> +			else
> +				svsb->volt_offset += 12;
> +			break;
> +		case SVSB_CCI:
> +			svsb->bdes = svsp->efuse[4] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = (svsp->efuse[5] >> 16) & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 10;
> +			else
> +				svsb->volt_offset += 2;
> +			break;
> +		case SVSB_GPU:
> +			svsb->bdes = svsp->efuse[6] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = svsp->efuse[5] & GENMASK(7, 0);
> +
> +			if (ft_pgm >= 2) {
> +				svsb->freq_base = 800000000; /* 800MHz */
> +				svsb->dvt_fixed = 2;
> +			}
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	/* Get thermal efuse by nvmem */
> +	cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
> +	if (IS_ERR_OR_NULL(cell)) {
> +		dev_err(svsp->dev, "no thermal cell, no mon mode\n");
> +		for (idx = 0; idx < svsp->bank_num; idx++) {
> +			svsb = &svsp->banks[idx];
> +			svsb->mode_support &= ~SVSB_MODE_MON;
> +		}
> +
> +		return true;
> +	}
> +
> +	svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_num);



nvmem_cell_read may return an error pointer: you have to check that.



     if (IS_ERR(svsp->tefuse))

         .........



Failing to perform this check will produce unpredictable behavior

during the parsing stage.


> +	svsp->tefuse_num /= sizeof(u32);
> +	nvmem_cell_put(cell);
> +
> +	/* Thermal efuse parsing */
> +	tp.adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0);
> +	tp.adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0);
> +
> +	tp.o_vtsmcu1 = (svsp->tefuse[0] >> 17) & GENMASK(8, 0);
> +	tp.o_vtsmcu2 = (svsp->tefuse[0] >> 8) & GENMASK(8, 0);
> +	tp.o_vtsmcu3 = svsp->tefuse[1] & GENMASK(8, 0);
> +	tp.o_vtsmcu4 = (svsp->tefuse[2] >> 23) & GENMASK(8, 0);
> +	tp.o_vtsmcu5 = (svsp->tefuse[2] >> 5) & GENMASK(8, 0);
> +	tp.o_vtsabb = (svsp->tefuse[2] >> 14) & GENMASK(8, 0);
> +
> +	tp.degc_cali = (svsp->tefuse[0] >> 1) & GENMASK(5, 0);
> +	tp.adc_cali_en_t = svsp->tefuse[0] & BIT(0);
> +	tp.o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0);
> +
> +	tp.ts_id = (svsp->tefuse[1] >> 9) & BIT(0);
> +	tp.o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
> +
> +	if (tp.adc_cali_en_t == 1) {
> +		if (!tp.ts_id)
> +			tp.o_slope = 0;
> +
> +		if (tp.adc_ge_t < 265 || tp.adc_ge_t > 758 ||
> +		    tp.adc_oe_t < 265 || tp.adc_oe_t > 758 ||
> +		    tp.o_vtsmcu1 < -8 || tp.o_vtsmcu1 > 484 ||
> +		    tp.o_vtsmcu2 < -8 || tp.o_vtsmcu2 > 484 ||
> +		    tp.o_vtsmcu3 < -8 || tp.o_vtsmcu3 > 484 ||
> +		    tp.o_vtsmcu4 < -8 || tp.o_vtsmcu4 > 484 ||
> +		    tp.o_vtsmcu5 < -8 || tp.o_vtsmcu5 > 484 ||
> +		    tp.o_vtsabb < -8 || tp.o_vtsabb > 484 ||
> +		    tp.degc_cali < 1 || tp.degc_cali > 63) {
> +			dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
> +			mon_mode_support = false;
> +		}
> +	} else {
> +		dev_err(svsp->dev, "no thermal efuse, no mon mode\n");
> +		mon_mode_support = false;
> +	}
> +
> +	if (!mon_mode_support) {
> +		for (idx = 0; idx < svsp->bank_num; idx++) {
> +			svsb = &svsp->banks[idx];
> +			svsb->mode_support &= ~SVSB_MODE_MON;
> +		}
> +
> +		return true;
> +	}
> +
> +	tp.ge = ((tp.adc_ge_t - 512) * 10000) / 4096;
> +	tp.oe = (tp.adc_oe_t - 512);
> +	tp.gain = (10000 + tp.ge);
> +
> +	format[0] = (tp.o_vtsmcu1 + 3350 - tp.oe);
> +	format[1] = (tp.o_vtsmcu2 + 3350 - tp.oe);
> +	format[2] = (tp.o_vtsmcu3 + 3350 - tp.oe);
> +	format[3] = (tp.o_vtsmcu4 + 3350 - tp.oe);
> +	format[4] = (tp.o_vtsmcu5 + 3350 - tp.oe);
> +	format[5] = (tp.o_vtsabb + 3350 - tp.oe);
> +
> +	for (i = 0; i < 6; i++)
> +		x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / tp.gain;
> +
> +	temp0 = (10000 * 100000 / tp.gain) * 15 / 18;
> +
> +	if (!tp.o_slope_sign)
> +		mts = (temp0 * 10) / (1534 + tp.o_slope * 10);
> +	else
> +		mts = (temp0 * 10) / (1534 - tp.o_slope * 10);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		svsb->mts = mts;
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			tb_roomt = x_roomt[3];
> +			break;
> +		case SVSB_CPU_BIG:
> +			tb_roomt = x_roomt[4];
> +			break;
> +		case SVSB_CCI:
> +			tb_roomt = x_roomt[3];
> +			break;
> +		case SVSB_GPU:
> +			tb_roomt = x_roomt[1];
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		temp0 = (tp.degc_cali * 10 / 2);
> +		temp1 = ((10000 * 100000 / 4096 / tp.gain) *
> +			 tp.oe + tb_roomt * 10) * 15 / 18;
> +
> +		if (!tp.o_slope_sign)
> +			temp2 = temp1 * 100 / (1534 + tp.o_slope * 10);
> +		else
> +			temp2 = temp1 * 100 / (1534 - tp.o_slope * 10);
> +
> +		svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
> +	}
> +
> +	return true;
> +}
> +
> +static bool svs_is_supported(struct svs_platform *svsp)
> +{
> +	struct nvmem_cell *cell;
> +
> +	/* Get svs efuse by nvmem */
> +	cell = nvmem_cell_get(svsp->dev, "svs-calibration-data");
> +	if (IS_ERR_OR_NULL(cell)) {
> +		dev_err(svsp->dev,
> +			"no \"svs-calibration-data\" from dts? disable svs\n");
> +		return false;
> +	}
> +
> +	svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_num);
> +	svsp->efuse_num /= sizeof(u32);
> +	nvmem_cell_put(cell);
> +
> +	if (!svsp->efuse[svsp->efuse_check]) {
> +		dev_err(svsp->dev, "svs_efuse[%u] = 0x%x?\n",
> +			svsp->efuse_check, svsp->efuse[svsp->efuse_check]);
> +		return false;
> +	}
> +
> +	return svsp->efuse_parsing(svsp);
> +}
> +
> +static int svs_suspend(struct device *dev)
> +{
> +	struct svs_platform *svsp = dev_get_drvdata(dev);
> +	struct svs_bank *svsb;
> +	unsigned long flags;
> +	int ret;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		/* Wait if svs_isr() is still in process. */
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_switch_bank(svsp);
> +		svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +		svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		svsb->suspended = true;
> +		if (svsb->phase != SVSB_PHASE_INIT01) {
> +			svsb->phase = SVSB_PHASE_ERROR;
> +			svs_adjust_pm_opp_volts(svsb, true);
> +		}
> +	}
> +
> +	ret = reset_control_assert(svsp->rst);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot assert reset %d\n", ret);
> +		return ret;
> +	}
> +
> +	clk_disable_unprepare(svsp->main_clk);
> +
> +	return 0;
> +}
> +
> +static int svs_resume(struct device *dev)
> +{
> +	struct svs_platform *svsp = dev_get_drvdata(dev);
> +	struct svs_bank *svsb;
> +	int ret;
> +	u32 idx;
> +
> +	ret = clk_prepare_enable(svsp->main_clk);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot enable main_clk, disable svs\n");
> +		return ret;
> +	}
> +
> +	ret = reset_control_deassert(svsp->rst);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot deassert reset %d\n", ret);
> +		return ret;
> +	}
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		svsb->suspended = false;
> +	}
> +
> +	ret = svs_init02(svsp);
> +	if (ret)
> +		return ret;
> +
> +	svs_mon_mode(svsp);
> +
> +	return 0;
> +}
> +
> +static struct svs_bank svs_mt8183_banks[] = {
> +	{
> +		.sw_id			= SVSB_CPU_LITTLE,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.cpu_id			= 0,
> +		.tzone_name		= "tzts4",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1989000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x64,
> +		.vmin			= 0x18,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0000,
> +		.int_st			= BIT(0),
> +		.ctl0			= 0x00010001,
> +	},
> +	{
> +		.sw_id			= SVSB_CPU_BIG,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.cpu_id			= 4,
> +		.tzone_name		= "tzts5",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1989000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x58,
> +		.vmin			= 0x10,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0001,
> +		.int_st			= BIT(1),
> +		.ctl0			= 0x00000001,
> +	},
> +	{
> +		.sw_id			= SVSB_CCI,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.tzone_name		= "tzts4",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1196000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x64,
> +		.vmin			= 0x18,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0002,
> +		.int_st			= BIT(2),
> +		.ctl0			= 0x00100003,
> +	},
> +	{
> +		.sw_id			= SVSB_GPU,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.tzone_name		= "tzts2",
> +		.buck_name		= "mali",
> +		.pd_req			= true,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
> +					  SVSB_MODE_MON,
> +		.opp_count		= 16,
> +		.freq_base		= 900000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x40,
> +		.vmin			= 0x14,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x3,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 3,
> +		.core_sel		= 0x8fff0003,
> +		.int_st			= BIT(3),
> +		.ctl0			= 0x00050001,
> +	},
> +};
> +
> +static int svs_get_svs_mt8183_platform_data(struct svs_platform *svsp)
> +{
> +	struct device *dev;
> +	struct svs_bank *svsb;
> +	u32 idx;
> +
> +	svsp->name = "mt8183-svs";
> +	svsp->banks = svs_mt8183_banks;
> +	svsp->efuse_parsing = svs_mt8183_efuse_parsing;
> +	svsp->regs = svs_regs_v2;
> +	svsp->irqflags = IRQF_TRIGGER_LOW;
> +	svsp->rst = NULL;
> +	svsp->bank_num = ARRAY_SIZE(svs_mt8183_banks);
> +	svsp->efuse_check = 2;
> +
> +	dev = svs_add_device_link(svsp, "thermal");
> +	if (IS_ERR(dev))
> +		return PTR_ERR(dev);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +		case SVSB_CPU_BIG:
> +			svsb->opp_dev = get_cpu_device(svsb->cpu_id);
> +			break;
> +		case SVSB_CCI:
> +			svsb->opp_dev = svs_add_device_link(svsp, "cci");
> +			break;
> +		case SVSB_GPU:
> +			svsb->opp_dev = svs_add_device_link(svsp, "mali");
> +			svsb->pd_dev = svs_add_device_link(svsp,
> +							   "mali_gpu_core2");
> +			if (IS_ERR(svsb->pd_dev))
> +				return PTR_ERR(svsb->pd_dev);
> +			break;
> +		default:
> +			WARN_ON(1);
> +			return -EINVAL;
> +		}
> +
> +		if (IS_ERR(svsb->opp_dev))
> +			return PTR_ERR(svsb->opp_dev);
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mtk_svs_of_match[] = {
> +	{
> +		.compatible = "mediatek,mt8183-svs",
> +		.data = &svs_get_svs_mt8183_platform_data,
> +	}, {
> +		/* Sentinel */
> +	},
> +};
> +
> +static int svs_probe(struct platform_device *pdev)
> +{
> +	int (*svs_get_svs_platform_data)(struct svs_platform *svsp);
> +	struct svs_platform *svsp;
> +	unsigned int svsp_irq;
> +	int ret;
> +
> +	svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL);
> +	if (!svsp)
> +		return -ENOMEM;
> +
> +	svs_get_svs_platform_data = of_device_get_match_data(&pdev->dev);
> +	if (!svs_get_svs_platform_data) {
> +		dev_err(svsp->dev, "no svs platform data? why?\n");
> +		return -EPERM;
> +	}
> +
> +	svsp->dev = &pdev->dev;
> +	ret = svs_get_svs_platform_data(svsp);
> +	if (ret) {
> +		dev_err_probe(svsp->dev, ret, "fail to get svsp data\n");
> +		return ret;
> +	}
> +
> +	if (!svs_is_supported(svsp)) {
> +		dev_notice(svsp->dev, "svs is not supported\n");
> +		return -EPERM;
> +	}
> +
> +	ret = svs_resource_setup(svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "svs resource setup fail: %d\n", ret);
> +		return ret;
> +	}
> +
> +	svsp_irq = irq_of_parse_and_map(svsp->dev->of_node, 0);
> +	ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
> +					svsp->irqflags | IRQF_ONESHOT,
> +					svsp->name, svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "register irq(%d) failed: %d\n",
> +			svsp_irq, ret);
> +		return ret;
> +	}
> +
> +	svsp->main_clk = devm_clk_get(svsp->dev, "main");
> +	if (IS_ERR(svsp->main_clk)) {
> +		dev_err(svsp->dev, "failed to get clock: %ld\n",
> +			PTR_ERR(svsp->main_clk));
> +		return PTR_ERR(svsp->main_clk);
> +	}
> +
> +	ret = clk_prepare_enable(svsp->main_clk);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot enable main clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	svsp->base = of_iomap(svsp->dev->of_node, 0);
> +	if (IS_ERR_OR_NULL(svsp->base)) {
> +		dev_err(svsp->dev, "cannot find svs register base\n");
> +		ret = -EINVAL;
> +		goto svs_probe_clk_disable;
> +	}
> +
> +	ret = svs_start(svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "svs start fail: %d\n", ret);
> +		goto svs_probe_iounmap;
> +	}
> +
> +	return 0;
> +
> +svs_probe_iounmap:
> +	iounmap(svsp->base);
> +
> +svs_probe_clk_disable:
> +	clk_disable_unprepare(svsp->main_clk);
> +
> +	return ret;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(svs_pm_ops, svs_suspend, svs_resume);
> +
> +static struct platform_driver svs_driver = {
> +	.probe	= svs_probe,
> +	.driver	= {
> +		.name		= "mtk-svs",
> +		.pm		= &svs_pm_ops,
> +		.of_match_table	= of_match_ptr(mtk_svs_of_match),
> +	},
> +};
> +
> +module_platform_driver(svs_driver);
> +
> +MODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>");
> +MODULE_DESCRIPTION("MediaTek SVS driver");
> +MODULE_LICENSE("GPL v2");
> 


_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply

* Re: [PATCH v8 8/8] ls-tree.c: introduce "--format" option
From: Teng Long @ 2022-01-05  9:58 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: avarab, congdanhqx, git, Junio C Hamano, peff, tenglong.tl
In-Reply-To: <nycvar.QRO.7.76.6.2201041533540.7076@tvgsbejvaqbjf.bet>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> This, along with two other similar instances, triggers the
> `static-analysis` job in the CI failure of `seen`. The suggested diff is:

The second and third I will optimize in the next patch.

The first one. Actually I am a little puzzled from this :

> -               strbuf_addf(line, "%7s", "-");
> +               strbuf_addstr(line, "-");

> But I think that the first hunk indicates a deeper issue, as `%7s`
> probably meant to pad the dash to seven dashes (which that format won't
> accomplish, but `strbuf_addchars()` would)?

"strbuf_addf(line, "%7s", "-");" here is used to align the columns
with a width of
seven chars, not repeat one DASH to seven.

A little weird about the fix recommendation of  "strbuf_addstr(line, "-");" ,
because it will only add a single DASH here.

It's the identical result which compares to the "master"[1]  I think with the
current codes and I tested the "strbuf_addf()" simply and it seems to work
fine.

[1] https://github.com/git/git/blob/master/builtin/ls-tree.c#L106

Thanks.

Johannes Schindelin <Johannes.Schindelin@gmx.de> 于2022年1月4日周二 22:38写道:
>
> Hi Teng,
>
> On Sat, 1 Jan 2022, Teng Long wrote:
>
> > diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
> > index 009ffeb15d..6e3e5a4d06 100644
> > --- a/builtin/ls-tree.c
> > +++ b/builtin/ls-tree.c
> > @@ -56,23 +56,75 @@ enum {
> >
> >  static int cmdmode = MODE_UNSPECIFIED;
> >
> > -static int parse_shown_fields(void)
> > +static const char *format;
> > +static const char *default_format = "%(mode) %(type) %(object)%x09%(file)";
> > +static const char *long_format = "%(mode) %(type) %(object) %(size:padded)%x09%(file)";
> > +static const char *name_only_format = "%(file)";
> > +static const char *object_only_format = "%(object)";
> > +
> > +static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
> > +                           const enum object_type type, unsigned int padded)
> >  {
> > -     if (cmdmode == MODE_NAME_ONLY) {
> > -             shown_bits = SHOW_FILE_NAME;
> > -             return 0;
> > +     if (type == OBJ_BLOB) {
> > +             unsigned long size;
> > +             if (oid_object_info(the_repository, oid, &size) < 0)
> > +                     die(_("could not get object info about '%s'"),
> > +                         oid_to_hex(oid));
> > +             if (padded)
> > +                     strbuf_addf(line, "%7" PRIuMAX, (uintmax_t)size);
> > +             else
> > +                     strbuf_addf(line, "%" PRIuMAX, (uintmax_t)size);
> > +     } else if (padded) {
> > +             strbuf_addf(line, "%7s", "-");
>
> This, along with two other similar instances, triggers the
> `static-analysis` job in the CI failure of `seen`. The suggested diff is:
>
>
> -- snip --
> diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
> index 6e3e5a4d0634..8301d1a15f9a 100644
> --- a/builtin/ls-tree.c
> +++ b/builtin/ls-tree.c
> @@ -75,7 +75,7 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
>                 else
>                         strbuf_addf(line, "%" PRIuMAX, (uintmax_t)size);
>         } else if (padded) {
> -               strbuf_addf(line, "%7s", "-");
> +               strbuf_addstr(line, "-");
>         } else {
>                 strbuf_addstr(line, "-");
>         }
> @@ -110,7 +110,7 @@ static size_t expand_show_tree(struct strbuf *line, const char *start,
>         } else if (skip_prefix(start, "(size)", &p)) {
>                 expand_objectsize(line, data->oid, data->type, 0);
>         } else if (skip_prefix(start, "(object)", &p)) {
> -               strbuf_addstr(line, find_unique_abbrev(data->oid, abbrev));
> +               strbuf_add_unique_abbrev(line, data->oid, abbrev);
>         } else if (skip_prefix(start, "(file)", &p)) {
>                 const char *name = data->base->buf;
>                 const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
> @@ -119,7 +119,7 @@ static size_t expand_show_tree(struct strbuf *line, const char *start,
>                 strbuf_addstr(data->base, data->pathname);
>                 name = relative_path(data->base->buf, prefix, &sb);
>                 quote_c_style(name, &quoted, NULL, 0);
> -               strbuf_addstr(line, quoted.buf);
> +               strbuf_addbuf(line, &quoted);
>         } else {
>                 errlen = (unsigned long)len;
>                 die(_("bad ls-tree format: %%%.*s"), errlen, start);
> -- snap --
>
> But I think that the first hunk indicates a deeper issue, as `%7s`
> probably meant to pad the dash to seven dashes (which that format won't
> accomplish, but `strbuf_addchars()` would)?
>
> Ciao,
> Dscho
>
> > +     } else {
> > +             strbuf_addstr(line, "-");
> >       }
> > -     if (cmdmode == MODE_OBJECT_ONLY) {
> > -             shown_bits = SHOW_OBJECT_NAME;
> > -             return 0;
> > +}
> > +
> > +static size_t expand_show_tree(struct strbuf *line, const char *start,
> > +                            void *context)
> > +{
> > +     struct shown_data *data = context;
> > +     const char *end;
> > +     const char *p;
> > +     unsigned int errlen;
> > +     size_t len;
> > +     len = strbuf_expand_literal_cb(line, start, NULL);
> > +     if (len)
> > +             return len;
> > +
> > +     if (*start != '(')
> > +             die(_("bad ls-tree format: as '%s'"), start);
> > +
> > +     end = strchr(start + 1, ')');
> > +     if (!end)
> > +             die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
> > +
> > +     len = end - start + 1;
> > +     if (skip_prefix(start, "(mode)", &p)) {
> > +             strbuf_addf(line, "%06o", data->mode);
> > +     } else if (skip_prefix(start, "(type)", &p)) {
> > +             strbuf_addstr(line, type_name(data->type));
> > +     } else if (skip_prefix(start, "(size:padded)", &p)) {
> > +             expand_objectsize(line, data->oid, data->type, 1);
> > +     } else if (skip_prefix(start, "(size)", &p)) {
> > +             expand_objectsize(line, data->oid, data->type, 0);
> > +     } else if (skip_prefix(start, "(object)", &p)) {
> > +             strbuf_addstr(line, find_unique_abbrev(data->oid, abbrev));
> > +     } else if (skip_prefix(start, "(file)", &p)) {
> > +             const char *name = data->base->buf;
> > +             const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
> > +             struct strbuf quoted = STRBUF_INIT;
> > +             struct strbuf sb = STRBUF_INIT;
> > +             strbuf_addstr(data->base, data->pathname);
> > +             name = relative_path(data->base->buf, prefix, &sb);
> > +             quote_c_style(name, &quoted, NULL, 0);
> > +             strbuf_addstr(line, quoted.buf);
> > +     } else {
> > +             errlen = (unsigned long)len;
> > +             die(_("bad ls-tree format: %%%.*s"), errlen, start);
> >       }
> > -     if (!ls_options || (ls_options & LS_RECURSIVE)
> > -         || (ls_options & LS_SHOW_TREES)
> > -         || (ls_options & LS_TREE_ONLY))
> > -             shown_bits = SHOW_DEFAULT;
> > -     if (cmdmode == MODE_LONG)
> > -             shown_bits = SHOW_DEFAULT | SHOW_SIZE;
> > -     return 1;
> > +     return len;
> >  }
> >
> >  static int show_recursive(const char *base, size_t baselen,
> > @@ -106,6 +158,75 @@ static int show_recursive(const char *base, size_t baselen,
> >       return 0;
> >  }
> >
> > +static int show_tree_init(enum object_type *type, struct strbuf *base,
> > +                       const char *pathname, unsigned mode, int *retval)
> > +{
> > +     if (S_ISGITLINK(mode)) {
> > +             *type = OBJ_COMMIT;
> > +     } else if (S_ISDIR(mode)) {
> > +             if (show_recursive(base->buf, base->len, pathname)) {
> > +                     *retval = READ_TREE_RECURSIVE;
> > +                     if (!(ls_options & LS_SHOW_TREES))
> > +                             return 1;
> > +             }
> > +             *type = OBJ_TREE;
> > +     }
> > +     else if (ls_options & LS_TREE_ONLY)
> > +             return 1;
> > +     return 0;
> > +}
> > +
> > +static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
> > +                      const char *pathname, unsigned mode, void *context)
> > +{
> > +     size_t baselen;
> > +     int retval = 0;
> > +     struct strbuf line = STRBUF_INIT;
> > +     struct shown_data data = {
> > +             .mode = mode,
> > +             .type = OBJ_BLOB,
> > +             .oid = oid,
> > +             .pathname = pathname,
> > +             .base = base,
> > +     };
> > +
> > +     if (show_tree_init(&data.type, base, pathname, mode, &retval))
> > +             return retval;
> > +
> > +     baselen = base->len;
> > +     strbuf_expand(&line, format, expand_show_tree, &data);
> > +     strbuf_addch(&line, line_termination);
> > +     fwrite(line.buf, line.len, 1, stdout);
> > +     strbuf_setlen(base, baselen);
> > +     return retval;
> > +}
> > +
> > +static int parse_shown_fields(void)
> > +{
> > +     if (cmdmode == MODE_NAME_ONLY ||
> > +         (format && !strcmp(format, name_only_format))) {
> > +             shown_bits = SHOW_FILE_NAME;
> > +             return 1;
> > +     }
> > +
> > +     if (cmdmode == MODE_OBJECT_ONLY ||
> > +         (format && !strcmp(format, object_only_format))) {
> > +             shown_bits = SHOW_OBJECT_NAME;
> > +             return 1;
> > +     }
> > +
> > +     if (!ls_options || (ls_options & LS_RECURSIVE)
> > +         || (ls_options & LS_SHOW_TREES)
> > +         || (ls_options & LS_TREE_ONLY)
> > +             || (format && !strcmp(format, default_format)))
> > +             shown_bits = SHOW_DEFAULT;
> > +
> > +     if (cmdmode == MODE_LONG ||
> > +             (format && !strcmp(format, long_format)))
> > +             shown_bits = SHOW_DEFAULT | SHOW_SIZE;
> > +     return 1;
> > +}
> > +
> >  static int show_default(struct shown_data *data)
> >  {
> >       size_t baselen = data->base->len;
> > @@ -137,24 +258,6 @@ static int show_default(struct shown_data *data)
> >       return 1;
> >  }
> >
> > -static int show_tree_init(enum object_type *type, struct strbuf *base,
> > -                       const char *pathname, unsigned mode, int *retval)
> > -{
> > -     if (S_ISGITLINK(mode)) {
> > -             *type = OBJ_COMMIT;
> > -     } else if (S_ISDIR(mode)) {
> > -             if (show_recursive(base->buf, base->len, pathname)) {
> > -                     *retval = READ_TREE_RECURSIVE;
> > -                     if (!(ls_options & LS_SHOW_TREES))
> > -                             return 1;
> > -             }
> > -             *type = OBJ_TREE;
> > -     }
> > -     else if (ls_options & LS_TREE_ONLY)
> > -             return 1;
> > -     return 0;
> > -}
> > -
> >  static int show_tree(const struct object_id *oid, struct strbuf *base,
> >               const char *pathname, unsigned mode, void *context)
> >  {
> > @@ -196,6 +299,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
> >       struct object_id oid;
> >       struct tree *tree;
> >       int i, full_tree = 0;
> > +     read_tree_fn_t fn = show_tree;
> >       const struct option ls_tree_options[] = {
> >               OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
> >                       LS_TREE_ONLY),
> > @@ -218,6 +322,9 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
> >               OPT_BOOL(0, "full-tree", &full_tree,
> >                        N_("list entire tree; not just current directory "
> >                           "(implies --full-name)")),
> > +             OPT_STRING_F(0, "format", &format, N_("format"),
> > +                          N_("format to use for the output"),
> > +                          PARSE_OPT_NONEG),
> >               OPT__ABBREV(&abbrev),
> >               OPT_END()
> >       };
> > @@ -238,6 +345,10 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
> >           ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
> >               ls_options |= LS_SHOW_TREES;
> >
> > +     if (format && cmdmode)
> > +             usage_msg_opt(
> > +                     _("--format can't be combined with other format-altering options"),
> > +                     ls_tree_usage, ls_tree_options);
> >       if (argc < 1)
> >               usage_with_options(ls_tree_usage, ls_tree_options);
> >       if (get_oid(argv[0], &oid))
> > @@ -261,6 +372,18 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
> >       tree = parse_tree_indirect(&oid);
> >       if (!tree)
> >               die("not a tree object");
> > -     return !!read_tree(the_repository, tree,
> > -                        &pathspec, show_tree, NULL);
> > +
> > +     /*
> > +      * The generic show_tree_fmt() is slower than show_tree(), so
> > +      * take the fast path if possible.
> > +      */
> > +     if (format && (!strcmp(format, default_format) ||
> > +                                !strcmp(format, long_format) ||
> > +                                !strcmp(format, name_only_format) ||
> > +                                !strcmp(format, object_only_format)))
> > +             fn = show_tree;
> > +     else if (format)
> > +             fn = show_tree_fmt;
> > +
> > +     return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
> >  }
> > diff --git a/t/t3105-ls-tree-format.sh b/t/t3105-ls-tree-format.sh
> > new file mode 100755
> > index 0000000000..92b4d240e8
> > --- /dev/null
> > +++ b/t/t3105-ls-tree-format.sh
> > @@ -0,0 +1,55 @@
> > +#!/bin/sh
> > +
> > +test_description='ls-tree --format'
> > +
> > +TEST_PASSES_SANITIZE_LEAK=true
> > +. ./test-lib.sh
> > +
> > +test_expect_success 'ls-tree --format usage' '
> > +     test_expect_code 129 git ls-tree --format=fmt -l &&
> > +     test_expect_code 129 git ls-tree --format=fmt --name-only &&
> > +     test_expect_code 129 git ls-tree --format=fmt --name-status &&
> > +     test_expect_code 129 git ls-tree --format=fmt --object-only
> > +'
> > +
> > +test_expect_success 'setup' '
> > +     mkdir dir &&
> > +     test_commit dir/sub-file &&
> > +     test_commit top-file
> > +'
> > +
> > +test_ls_tree_format () {
> > +     format=$1 &&
> > +     opts=$2 &&
> > +     shift 2 &&
> > +     git ls-tree $opts -r HEAD >expect.raw &&
> > +     sed "s/^/> /" >expect <expect.raw &&
> > +     git ls-tree --format="> $format" -r HEAD >actual &&
> > +     test_cmp expect actual
> > +}
> > +
> > +test_expect_success 'ls-tree --format=<default-like>' '
> > +     test_ls_tree_format \
> > +             "%(mode) %(type) %(object)%x09%(file)" \
> > +             ""
> > +'
> > +
> > +test_expect_success 'ls-tree --format=<long-like>' '
> > +     test_ls_tree_format \
> > +             "%(mode) %(type) %(object) %(size:padded)%x09%(file)" \
> > +             "--long"
> > +'
> > +
> > +test_expect_success 'ls-tree --format=<name-only-like>' '
> > +     test_ls_tree_format \
> > +             "%(file)" \
> > +             "--name-only"
> > +'
> > +
> > +test_expect_success 'ls-tree --format=<object-only-like>' '
> > +     test_ls_tree_format \
> > +             "%(object)" \
> > +             "--object-only"
> > +'
> > +
> > +test_done
> > --
> > 2.33.0.rc1.1802.gbb1c3936fb.dirty
> >
> >
> >

^ permalink raw reply

* Re: [PATCH v20 3/7] soc: mediatek: SVS: introduce MTK SVS engine
From: AngeloGioacchino Del Regno @ 2022-01-05  9:58 UTC (permalink / raw)
  To: Roger Lu, Matthias Brugger, Enric Balletbo Serra, Kevin Hilman,
	Rob Herring, Nicolas Boichat, Stephen Boyd, Philipp Zabel
  Cc: Fan Chen, HenryC Chen, YT Lee, Xiaoqing Liu, Charles Yang,
	Angus Lin, Mark Rutland, Nishanth Menon, devicetree,
	linux-arm-kernel, linux-mediatek, linux-kernel, linux-pm,
	Project_Global_Chrome_Upstream_Group, Guenter Roeck
In-Reply-To: <20210721070904.15636-4-roger.lu@mediatek.com>

Il 21/07/21 09:09, Roger Lu ha scritto:
> The Smart Voltage Scaling(SVS) engine is a piece of hardware
> which calculates suitable SVS bank voltages to OPP voltage table.
> Then, DVFS driver could apply those SVS bank voltages to PMIC/Buck
> when receiving OPP_EVENT_ADJUST_VOLTAGE.
> 
> Signed-off-by: Roger Lu <roger.lu@mediatek.com>

Hello Roger,
thanks for the patch!

However, there are a few things to improve...

> ---
>   drivers/soc/mediatek/Kconfig   |   10 +
>   drivers/soc/mediatek/Makefile  |    1 +
>   drivers/soc/mediatek/mtk-svs.c | 1720 ++++++++++++++++++++++++++++++++
>   3 files changed, 1731 insertions(+)
>   create mode 100644 drivers/soc/mediatek/mtk-svs.c
> 
> diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
> index fdd8bc08569e..3c3eedea35f7 100644
> --- a/drivers/soc/mediatek/Kconfig
> +++ b/drivers/soc/mediatek/Kconfig
> @@ -73,4 +73,14 @@ config MTK_MMSYS
>   	  Say yes here to add support for the MediaTek Multimedia
>   	  Subsystem (MMSYS).
>   
> +config MTK_SVS
> +	tristate "MediaTek Smart Voltage Scaling(SVS)"
> +	depends on MTK_EFUSE && NVMEM
> +	help
> +	  The Smart Voltage Scaling(SVS) engine is a piece of hardware
> +	  which has several controllers(banks) for calculating suitable
> +	  voltage to different power domains(CPU/GPU/CCI) according to
> +	  chip process corner, temperatures and other factors. Then DVFS
> +	  driver could apply SVS bank voltage to PMIC/Buck.
> +
>   endmenu
> diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
> index 90270f8114ed..0e9e703c931a 100644
> --- a/drivers/soc/mediatek/Makefile
> +++ b/drivers/soc/mediatek/Makefile
> @@ -7,3 +7,4 @@ obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
>   obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
>   obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
>   obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
> +obj-$(CONFIG_MTK_SVS) += mtk-svs.o
> diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
> new file mode 100644
> index 000000000000..013667752ec2
> --- /dev/null
> +++ b/drivers/soc/mediatek/mtk-svs.c
> @@ -0,0 +1,1720 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_opp.h>
> +#include <linux/pm_qos.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/thermal.h>
> +
> +/* svs bank 1-line sw id */
> +#define SVSB_CPU_LITTLE			BIT(0)
> +#define SVSB_CPU_BIG			BIT(1)
> +#define SVSB_CCI			BIT(2)
> +#define SVSB_GPU			BIT(3)
> +
> +/* svs bank mode support */
> +#define SVSB_MODE_ALL_DISABLE		0
> +#define SVSB_MODE_INIT01		BIT(1)
> +#define SVSB_MODE_INIT02		BIT(2)
> +#define SVSB_MODE_MON			BIT(3)
> +
> +/* svs bank volt flags */
> +#define SVSB_INIT01_VOLT_IGNORE		BIT(1)
> +#define SVSB_INIT01_VOLT_INC_ONLY	BIT(2)
> +#define SVSB_INIT02_RM_DVTFIXED		BIT(8)
> +#define SVSB_MON_VOLT_IGNORE		BIT(16)
> +
> +/* svs bank common setting */
> +#define SVSB_DET_CLK_EN			BIT(31)
> +#define SVSB_TZONE_HIGH_TEMP_MAX	U32_MAX
> +#define SVSB_RUNCONFIG_DEFAULT		0x80000000
> +#define SVSB_DC_SIGNED_BIT		0x8000

SVSB_DC_SIGNED_BIT is.. clearly a bit, so this should be BIT(15)

> +#define SVSB_INTEN_INIT0x		0x00005f01
> +#define SVSB_INTEN_MONVOPEN		0x00ff0000
> +#define SVSB_EN_OFF			0x0
> +#define SVSB_EN_MASK			0x7
> +#define SVSB_EN_INIT01			0x1
> +#define SVSB_EN_INIT02			0x5
> +#define SVSB_EN_MON			0x2
> +#define SVSB_INTSTS_MONVOP		0x00ff0000
> +#define SVSB_INTSTS_COMPLETE		0x1
> +#define SVSB_INTSTS_CLEAN		0x00ffffff
> +
> +static DEFINE_SPINLOCK(mtk_svs_lock);
> +
> +/*

Looks like the great intention is to have kernel-doc here, and it's already
in the right format, but the start of the comment block should be

/**

and not

/*

to be recognized as kerneldoc.
Please refer to https://www.kernel.org/doc/html/v5.15/doc-guide/kernel-doc.html

> + * enum svsb_phase - svs bank phase enumeration
> + * @SVSB_PHASE_INIT01: basic init for svs bank
> + * @SVSB_PHASE_INIT02: svs bank can provide voltages
> + * @SVSB_PHASE_MON: svs bank can provide voltages with thermal effect
> + * @SVSB_PHASE_ERROR: svs bank encounters unexpected condition

Please move @SVSB_PHASE_ERROR before @SVSB_PHASE_INIT01: the order

is important here, and has to be the same as the actual enumeration.

> + *
> + * Each svs bank has its own independent phase. We enable each svs bank by
> + * running their phase orderly. However, When svs bank encounters unexpected
> + * condition, it will fire an irq (PHASE_ERROR) to inform svs software.
> + *
> + * svs bank general phase-enabled order:
> + * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 -> SVSB_PHASE_MON
> + */
> +enum svsb_phase {
> +	SVSB_PHASE_ERROR = 0,
> +	SVSB_PHASE_INIT01,
> +	SVSB_PHASE_INIT02,
> +	SVSB_PHASE_MON,
> +};
> +
> +enum svs_reg_index {
> +	DESCHAR = 0,
> +	TEMPCHAR,
> +	DETCHAR,
> +	AGECHAR,
> +	DCCONFIG,
> +	AGECONFIG,
> +	FREQPCT30,
> +	FREQPCT74,
> +	LIMITVALS,
> +	VBOOT,
> +	DETWINDOW,
> +	CONFIG,
> +	TSCALCS,
> +	RUNCONFIG,
> +	SVSEN,
> +	INIT2VALS,
> +	DCVALUES,
> +	AGEVALUES,
> +	VOP30,
> +	VOP74,
> +	TEMP,
> +	INTSTS,
> +	INTSTSRAW,
> +	INTEN,
> +	CHKINT,
> +	CHKSHIFT,
> +	STATUS,
> +	VDESIGN30,
> +	VDESIGN74,
> +	DVT30,
> +	DVT74,
> +	AGECOUNT,
> +	SMSTATE0,
> +	SMSTATE1,
> +	CTL0,
> +	DESDETSEC,
> +	TEMPAGESEC,
> +	CTRLSPARE0,
> +	CTRLSPARE1,
> +	CTRLSPARE2,
> +	CTRLSPARE3,
> +	CORESEL,
> +	THERMINTST,
> +	INTST,
> +	THSTAGE0ST,
> +	THSTAGE1ST,
> +	THSTAGE2ST,
> +	THAHBST0,
> +	THAHBST1,
> +	SPARE0,
> +	SPARE1,
> +	SPARE2,
> +	SPARE3,
> +	THSLPEVEB,
> +};
> +
> +static const u32 svs_regs_v2[] = {
> +	[DESCHAR]		= 0xc00,
> +	[TEMPCHAR]		= 0xc04,
> +	[DETCHAR]		= 0xc08,
> +	[AGECHAR]		= 0xc0c,
> +	[DCCONFIG]		= 0xc10,
> +	[AGECONFIG]		= 0xc14,
> +	[FREQPCT30]		= 0xc18,
> +	[FREQPCT74]		= 0xc1c,
> +	[LIMITVALS]		= 0xc20,
> +	[VBOOT]			= 0xc24,
> +	[DETWINDOW]		= 0xc28,
> +	[CONFIG]		= 0xc2c,
> +	[TSCALCS]		= 0xc30,
> +	[RUNCONFIG]		= 0xc34,
> +	[SVSEN]			= 0xc38,
> +	[INIT2VALS]		= 0xc3c,
> +	[DCVALUES]		= 0xc40,
> +	[AGEVALUES]		= 0xc44,
> +	[VOP30]			= 0xc48,
> +	[VOP74]			= 0xc4c,
> +	[TEMP]			= 0xc50,
> +	[INTSTS]		= 0xc54,
> +	[INTSTSRAW]		= 0xc58,
> +	[INTEN]			= 0xc5c,
> +	[CHKINT]		= 0xc60,
> +	[CHKSHIFT]		= 0xc64,
> +	[STATUS]		= 0xc68,
> +	[VDESIGN30]		= 0xc6c,
> +	[VDESIGN74]		= 0xc70,
> +	[DVT30]			= 0xc74,
> +	[DVT74]			= 0xc78,
> +	[AGECOUNT]		= 0xc7c,
> +	[SMSTATE0]		= 0xc80,
> +	[SMSTATE1]		= 0xc84,
> +	[CTL0]			= 0xc88,
> +	[DESDETSEC]		= 0xce0,
> +	[TEMPAGESEC]		= 0xce4,
> +	[CTRLSPARE0]		= 0xcf0,
> +	[CTRLSPARE1]		= 0xcf4,
> +	[CTRLSPARE2]		= 0xcf8,
> +	[CTRLSPARE3]		= 0xcfc,
> +	[CORESEL]		= 0xf00,
> +	[THERMINTST]		= 0xf04,
> +	[INTST]			= 0xf08,
> +	[THSTAGE0ST]		= 0xf0c,
> +	[THSTAGE1ST]		= 0xf10,
> +	[THSTAGE2ST]		= 0xf14,
> +	[THAHBST0]		= 0xf18,
> +	[THAHBST1]		= 0xf1c,
> +	[SPARE0]		= 0xf20,
> +	[SPARE1]		= 0xf24,
> +	[SPARE2]		= 0xf28,
> +	[SPARE3]		= 0xf2c,
> +	[THSLPEVEB]		= 0xf30,
> +};
> +
> +/*
> + * struct thermal_parameter - This is for storing thermal efuse data.
> + * We calculate thermal efuse data to produce "mts" and "bts" for
> + * svs bank mon mode.
> + */
> +struct thermal_parameter {
> +	int adc_ge_t;
> +	int adc_oe_t;
> +	int ge;
> +	int oe;
> +	int gain;
> +	int o_vtsabb;
> +	int o_vtsmcu1;
> +	int o_vtsmcu2;
> +	int o_vtsmcu3;
> +	int o_vtsmcu4;
> +	int o_vtsmcu5;
> +	int degc_cali;
> +	int adc_cali_en_t;
> +	int o_slope;
> +	int o_slope_sign;
> +	int ts_id;
> +};
> +
> +/*

... same here, /** for kerneldoc

> + * struct svs_platform - svs platform data
> + * @dev: svs platform device
> + * @base: svs platform register address base
> + * @main_clk: main clock for svs bank
> + * @pbank: phandle of svs bank and needs to be protected by spin_lock
> + * @banks: phandle of the banks that support
> + * @efuse_parsing: phandle of efuse parsing function
> + * @irqflags: irq settings flags
> + * @rst: svs reset control
> + * @regs: phandle to the registers map

@name should be here

> + * @efuse_num: the total number of svs platform efuse
> + * @tefuse_num: the total number of thermal efuse
> + * @bank_num: the total number of banks
> + * @efuse_check: the svs efuse check index
> + * @efuse: svs platform efuse data received from NVMEM framework
> + * @tefuse: thermal efuse data received from NVMEM framework
> + * @name: svs platform name
> + */
> +struct svs_platform {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct clk *main_clk;
> +	struct svs_bank *pbank;
> +	struct svs_bank *banks;
> +	bool (*efuse_parsing)(struct svs_platform *svsp);
> +	unsigned long irqflags;
> +	struct reset_control *rst;
> +	const u32 *regs;
> +	char *name;
> +	size_t efuse_num;
> +	size_t tefuse_num;
> +	u32 bank_num;
> +	u32 efuse_check;
> +	u32 *efuse;
> +	u32 *tefuse;
> +};
> +
> +/*

... and here

> + * struct svs_bank - svs bank representation
> + * @dev: svs bank device
> + * @opp_dev: device for opp table/buck control
> + * @pd_dev: power domain device for SoC mtcmos control
> + * @init_completion: the timeout completion for bank init
> + * @buck: phandle of the regulator
> + * @lock: mutex lock to protect voltage update process
> + * @phase: bank current phase
> + * @name: bank name
> + * @tzone_name: thermal zone name
> + * @buck_name: regulator name
> + * @suspended: suspend flag of this bank
> + * @pd_req: bank's power-domain on request
> + * @enable_pm_runtime_ever: bank enables pm-runtime flag
> + * @set_freqs_pct: phandle of set frequencies percent function
> + * @get_vops: phandle of get bank voltages function
> + * @volt_offset: bank voltage offset controlled by svs software
> + * @mode_support: bank mode support.
> + * @opp_freqs: signed-off frequencies from default opp table
> + * @opp_volts: signed-off voltages from default opp table
> + * @freqs_pct: percent of "opp_freqs / freq_base" for bank init
> + * @volts: bank voltages
> + * @freq_base: reference frequency for bank init
> + * @vboot: voltage request for bank init01 stage only
> + * @volt_step: bank voltage step
> + * @volt_base: bank voltage base
> + * @volt_flags: bank voltage flags
> + * @vmax: bank voltage maximum
> + * @vmin: bank voltage minimum

I love when developers take the effort to document with kerneldoc, so, great job
about that.... however, you forgot to document a few variables... can you please
add the required documentation for them?

> + * @temp: bank temperature
> + * @temp_upper_bound: bank temperature upper bound
> + * @temp_lower_bound: bank temperature lower bound
> + * @tzone_high_temp: thermal zone high temperature threshold
> + * @tzone_high_temp_offset: thermal zone high temperature offset
> + * @tzone_low_temp: thermal zone low temperature threshold
> + * @tzone_low_temp_offset: thermal zone low temperature offset
> + * @core_sel: bank selection
> + * @opp_count: bank opp count
> + * @int_st: bank interrupt identification
> + * @sw_id: bank software identification
> + * @ctl0: bank thermal sensor selection
> + * @cpu_id: cpu core id for SVS CPU only
> + *
> + * Other structure members which are not listed above are svs platform
> + * efuse data for bank init
> + */
> +struct svs_bank {
> +	struct device *dev;
> +	struct device *opp_dev;
> +	struct device *pd_dev;
> +	struct completion init_completion;
> +	struct regulator *buck;
> +	struct mutex lock;	/* lock to protect voltage update process */
> +	enum svsb_phase phase;
> +	char *name;
> +	char *tzone_name;
> +	char *buck_name;
> +	bool suspended;
> +	bool pd_req;
> +	bool enable_pm_runtime_ever;
> +	void (*set_freqs_pct)(struct svs_platform *svsp);
> +	void (*get_vops)(struct svs_platform *svsp);
> +	s32 volt_offset;
> +	u32 mode_support;
> +	u32 opp_freqs[16];

At the beginning of the file....
#define MAX_OPP_ENTRIES 16

...so you can do...
	u32 opp_freqs[MAX_OPP_ENTRIES];
	u32 opp_volts[MAX_OPP_ENTRIES];
...and the same for the other two.

> +	u32 opp_volts[16];
> +	u32 freqs_pct[16];
> +	u32 volts[16];
> +	u32 freq_base;
> +	u32 vboot;
> +	u32 volt_step;
> +	u32 volt_base;
> +	u32 volt_flags;
> +	u32 vmax;
> +	u32 vmin;

Document these entries, please.

vvvvvvvvv From here.... vvvvvvvvv

> +	u32 bts;
> +	u32 mts;
> +	u32 bdes;
> +	u32 mdes;
> +	u32 mtdes;
> +	u32 dcbdet;
> +	u32 dcmdet;
> +	u32 dthi;
> +	u32 dtlo;
> +	u32 det_window;
> +	u32 det_max;
> +	u32 age_config;
> +	u32 age_voffset_in;
> +	u32 agem;
> +	u32 dc_config;
> +	u32 dc_voffset_in;
> +	u32 dvt_fixed;
> +	u32 vco;
> +	u32 chk_shift;

^^^^^^^^^ ....to there ^^^^^^^^^

> +	u32 temp;
> +	u32 temp_upper_bound;
> +	u32 temp_lower_bound;
> +	u32 tzone_high_temp;
> +	u32 tzone_high_temp_offset;
> +	u32 tzone_low_temp;
> +	u32 tzone_low_temp_offset;
> +	u32 core_sel;
> +	u32 opp_count;
> +	u32 int_st;
> +	u32 sw_id;
> +	u32 ctl0;
> +	u32 cpu_id;
> +};
> +
> +static u32 percent(u32 numerator, u32 denominator)
> +{
> +	/* If not divide 1000, "numerator * 100" will have data overflow. */
> +	numerator /= 1000;
> +	denominator /= 1000;
> +
> +	return DIV_ROUND_UP(numerator * 100, denominator);
> +}
> +
> +static u32 svs_readl(struct svs_platform *svsp, enum svs_reg_index rg_i)
> +{
> +	return readl(svsp->base + svsp->regs[rg_i]);
> +}
> +
> +static void svs_writel(struct svs_platform *svsp, u32 val,
> +		       enum svs_reg_index rg_i)
> +{
> +	writel(val, svsp->base + svsp->regs[rg_i]);
> +}
> +
> +static void svs_switch_bank(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svs_writel(svsp, svsb->core_sel, CORESEL);
> +}
> +
> +static u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step,
> +				     u32 svsb_volt_base)
> +{
> +	return (svsb_volt * svsb_volt_step) + svsb_volt_base;
> +}
> +
> +static int svs_get_bank_zone_temperature(const char *tzone_name,
> +					 int *tzone_temp)
> +{
> +	struct thermal_zone_device *tzd;
> +
> +	tzd = thermal_zone_get_zone_by_name(tzone_name);
> +	if (IS_ERR(tzd))
> +		return PTR_ERR(tzd);
> +
> +	return thermal_zone_get_temp(tzd, tzone_temp);
> +}
> +
> +static int svs_adjust_pm_opp_volts(struct svs_bank *svsb, bool force_update)
> +{
> +	int tzone_temp = 0, ret = -EPERM;
> +	u32 i, svsb_volt, opp_volt, temp_offset = 0;
> +
> +	mutex_lock(&svsb->lock);
> +
> +	/*
> +	 * If svs bank is suspended, it means signed-off voltages are applied.
> +	 * Don't need to update opp voltage anymore.
> +	 */
> +	if (svsb->suspended && !force_update) {
> +		dev_notice(svsb->dev, "bank is suspended\n");
> +		ret = -EPERM;
> +		goto unlock_mutex;
> +	}
> +
> +	/* Get thermal effect */
> +	if (svsb->phase == SVSB_PHASE_MON) {
> +		if (svsb->temp > svsb->temp_upper_bound &&
> +		    svsb->temp < svsb->temp_lower_bound) {
> +			dev_warn(svsb->dev, "svsb temp = 0x%x?\n", svsb->temp);
> +			ret = -EINVAL;
> +			goto unlock_mutex;
> +		}
> +
> +		ret = svs_get_bank_zone_temperature(svsb->tzone_name,
> +						    &tzone_temp);
> +		if (ret) {
> +			dev_err(svsb->dev, "no %s? (%d), run default volts\n",
> +				svsb->tzone_name, ret);
> +			svsb->phase = SVSB_PHASE_ERROR;
> +		}
> +
> +		if (tzone_temp >= svsb->tzone_high_temp)
> +			temp_offset += svsb->tzone_high_temp_offset;
> +		else if (tzone_temp <= svsb->tzone_low_temp)
> +			temp_offset += svsb->tzone_low_temp_offset;
> +	}
> +
> +	/* vmin <= svsb_volt (opp_volt) <= signed-off (default) voltage */
> +	for (i = 0; i < svsb->opp_count; i++) {



What about using switch here?



         switch (svsb->phase) {

         case SVSB_PHASE_MON:

             ......

             break;

         case .......:

             .........

             break;

         default:

             dev_err(......);

             ret = -EINVAL;

             goto unlock_mutex;

         }

> +		if (svsb->phase == SVSB_PHASE_MON) {
> +			svsb_volt = max(svsb->volts[i] + svsb->volt_offset +
> +					temp_offset, svsb->vmin);
> +			opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
> +							     svsb->volt_step,
> +							     svsb->volt_base);
> +		} else if (svsb->phase == SVSB_PHASE_INIT02) {
> +			svsb_volt = max(svsb->volts[i] + svsb->volt_offset,
> +					svsb->vmin);
> +			opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
> +							     svsb->volt_step,
> +							     svsb->volt_base);
> +		} else if (svsb->phase == SVSB_PHASE_ERROR) {
> +			opp_volt = svsb->opp_volts[i];
> +		} else {
> +			dev_err(svsb->dev, "unknown phase: %u?\n", svsb->phase);
> +			ret = -EINVAL;
> +			goto unlock_mutex;
> +		}
> +
> +		opp_volt = min(opp_volt, svsb->opp_volts[i]);
> +		ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
> +						svsb->opp_freqs[i],
> +						opp_volt, opp_volt,
> +						svsb->opp_volts[i]);
> +		if (ret) {
> +			dev_err(svsb->dev, "set voltage fail: %d\n", ret);
> +			goto unlock_mutex;
> +		}
> +	}
> +
> +unlock_mutex:
> +	mutex_unlock(&svsb->lock);
> +
> +	return ret;
> +}
> +
> +static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
> +{
> +	u32 vx;
> +
> +	if (v0 == v1 || f0 == f1)
> +		return v0;
> +
> +	/* *100 to have decimal fraction factor */
> +	vx = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
> +
> +	return DIV_ROUND_UP(vx, 100);
> +}
> +
> +static void svs_get_vops_v2(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +	u32 temp, i;
> +
> +	if (svsb->phase == SVSB_PHASE_MON &&
> +	    svsb->volt_flags & SVSB_MON_VOLT_IGNORE)
> +		return;
> +
> +	temp = svs_readl(svsp, VOP74);
> +	svsb->volts[14] = (temp >> 24) & GENMASK(7, 0);
> +	svsb->volts[12] = (temp >> 16) & GENMASK(7, 0);
> +	svsb->volts[10] = (temp >> 8)  & GENMASK(7, 0);
> +	svsb->volts[8] = (temp & GENMASK(7, 0));
> +
> +	temp = svs_readl(svsp, VOP30);
> +	svsb->volts[6] = (temp >> 24) & GENMASK(7, 0);
> +	svsb->volts[4] = (temp >> 16) & GENMASK(7, 0);
> +	svsb->volts[2] = (temp >> 8)  & GENMASK(7, 0);
> +	svsb->volts[0] = (temp & GENMASK(7, 0));
> +
> +	for (i = 0; i <= 12; i += 2)
> +		svsb->volts[i + 1] =
> +			interpolate(svsb->freqs_pct[i],
> +				    svsb->freqs_pct[i + 2],
> +				    svsb->volts[i],
> +				    svsb->volts[i + 2],
> +				    svsb->freqs_pct[i + 1]);
> +
> +	svsb->volts[15] =
> +		interpolate(svsb->freqs_pct[12],
> +			    svsb->freqs_pct[14],
> +			    svsb->volts[12],
> +			    svsb->volts[14],
> +			    svsb->freqs_pct[15]);
> +
> +	if (svsb->volt_flags & SVSB_INIT02_RM_DVTFIXED)
> +		for (i = 0; i < svsb->opp_count; i++)
> +			svsb->volts[i] -= svsb->dvt_fixed;
> +}
> +
> +static void svs_set_freqs_pct_v2(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svs_writel(svsp,
> +		   (svsb->freqs_pct[14] << 24) |
> +		   (svsb->freqs_pct[12] << 16) |
> +		   (svsb->freqs_pct[10] << 8) |
> +		   svsb->freqs_pct[8],
> +		   FREQPCT74);
> +
> +	svs_writel(svsp,
> +		   (svsb->freqs_pct[6] << 24) |
> +		   (svsb->freqs_pct[4] << 16) |
> +		   (svsb->freqs_pct[2] << 8) |
> +		   svsb->freqs_pct[0],
> +		   FREQPCT30);
> +}
> +
> +static void svs_set_bank_phase(struct svs_platform *svsp,
> +			       enum svsb_phase target_phase)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +	u32 des_char, temp_char, det_char, limit_vals;
> +	u32 init2vals, ts_calcs, val, filter, i;
> +
> +	svs_switch_bank(svsp);
> +
> +	des_char = (svsb->bdes << 8) | svsb->mdes;
> +	svs_writel(svsp, des_char, DESCHAR);
> +
> +	temp_char = (svsb->vco << 16) | (svsb->mtdes << 8) | svsb->dvt_fixed;
> +	svs_writel(svsp, temp_char, TEMPCHAR);
> +
> +	det_char = (svsb->dcbdet << 8) | svsb->dcmdet;
> +	svs_writel(svsp, det_char, DETCHAR);
> +
> +	svs_writel(svsp, svsb->dc_config, DCCONFIG);
> +	svs_writel(svsp, svsb->age_config, AGECONFIG);
> +
> +	if (!svsb->agem) {
> +		svs_writel(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG);
> +	} else {
> +		val = 0x0;

val = 0;

> +
> +		for (i = 0; i < 24; i += 2) {
> +			filter = 0x3 << i;
> +
> +			if (!(svsb->age_config & filter))
> +				val |= (0x1 << i);

val |= BIT(i);

> +			else
> +				val |= (svsb->age_config & filter);
> +		}
> +		svs_writel(svsp, val, RUNCONFIG);
> +	}
> +
> +	svsb->set_freqs_pct(svsp);
> +
> +	limit_vals = (svsb->vmax << 24) | (svsb->vmin << 16) |
> +		     (svsb->dthi << 8) | svsb->dtlo;
> +	svs_writel(svsp, limit_vals, LIMITVALS);
> +	svs_writel(svsp, svsb->vboot, VBOOT);
> +	svs_writel(svsp, svsb->det_window, DETWINDOW);
> +	svs_writel(svsp, svsb->det_max, CONFIG);
> +
> +	if (svsb->chk_shift)
> +		svs_writel(svsp, svsb->chk_shift, CHKSHIFT);
> +
> +	if (svsb->ctl0)
> +		svs_writel(svsp, svsb->ctl0, CTL0);
> +
> +	svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +
> +	switch (target_phase) {
> +	case SVSB_PHASE_INIT01:
> +		svs_writel(svsp, SVSB_INTEN_INIT0x, INTEN);
> +		svs_writel(svsp, SVSB_EN_INIT01, SVSEN);
> +		break;
> +	case SVSB_PHASE_INIT02:
> +		svs_writel(svsp, SVSB_INTEN_INIT0x, INTEN);
> +		init2vals = (svsb->age_voffset_in << 16) | svsb->dc_voffset_in;
> +		svs_writel(svsp, init2vals, INIT2VALS);
> +		svs_writel(svsp, SVSB_EN_INIT02, SVSEN);
> +		break;
> +	case SVSB_PHASE_MON:
> +		ts_calcs = (svsb->bts << 12) | svsb->mts;
> +		svs_writel(svsp, ts_calcs, TSCALCS);
> +		svs_writel(svsp, SVSB_INTEN_MONVOPEN, INTEN);
> +		svs_writel(svsp, SVSB_EN_MON, SVSEN);
> +		break;
> +	default:
> +		WARN_ON(1);



I agree about printing a big warning in kmsg here, but you can do that in a

slightly more descriptive way:



         WARN(1, "Requested unknown target phase %u", target_phase);

> +		break;
> +	}
> +}
> +
> +static inline void svs_init01_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n",
> +		 __func__, svs_readl(svsp, VDESIGN74),
> +		 svs_readl(svsp, VDESIGN30), svs_readl(svsp, DCVALUES));
> +
> +	svsb->phase = SVSB_PHASE_INIT01;
> +	svsb->dc_voffset_in = ~(svs_readl(svsp, DCVALUES) & GENMASK(15, 0)) + 1;
> +	if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE ||
> +	    (svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT &&
> +	     svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY))
> +		svsb->dc_voffset_in = 0;
> +
> +	svsb->age_voffset_in = svs_readl(svsp, AGEVALUES) & GENMASK(15, 0);
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
> +
> +	/* svs init01 clock gating */
> +	svsb->core_sel &= ~SVSB_DET_CLK_EN;
> +}
> +
> +static inline void svs_init02_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n",
> +		 __func__, svs_readl(svsp, VOP74), svs_readl(svsp, VOP30),
> +		 svs_readl(svsp, DCVALUES));
> +
> +	svsb->phase = SVSB_PHASE_INIT02;
> +	svsb->get_vops(svsp);
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
> +}
> +
> +static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	svsb->phase = SVSB_PHASE_MON;
> +	svsb->temp = svs_readl(svsp, TEMP) & GENMASK(7, 0);
> +	svsb->get_vops(svsp);
> +
> +	svs_writel(svsp, SVSB_INTSTS_MONVOP, INTSTS);
> +}
> +
> +static inline void svs_error_isr_handler(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb = svsp->pbank;
> +
> +	dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n",
> +		__func__, svs_readl(svsp, CORESEL));
> +	dev_err(svsb->dev, "SVSEN = 0x%08x, INTSTS = 0x%08x\n",
> +		svs_readl(svsp, SVSEN), svs_readl(svsp, INTSTS));
> +	dev_err(svsb->dev, "SMSTATE0 = 0x%08x, SMSTATE1 = 0x%08x\n",
> +		svs_readl(svsp, SMSTATE0), svs_readl(svsp, SMSTATE1));
> +	dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl(svsp, TEMP));
> +
> +	svsb->mode_support = SVSB_MODE_ALL_DISABLE;
> +	svsb->phase = SVSB_PHASE_ERROR;
> +
> +	svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +	svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +}
> +
> +static irqreturn_t svs_isr(int irq, void *data)
> +{
> +	struct svs_platform *svsp = data;
> +	struct svs_bank *svsb = NULL;
> +	unsigned long flags;
> +	u32 idx, int_sts, svs_en;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		WARN_ON(!svsb);
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +
> +		/* Find out which svs bank fires interrupt */
> +		if (svsb->int_st & svs_readl(svsp, INTST)) {
> +			spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +			continue;
> +		}
> +
> +		if (!svsb->suspended) {
> +			svs_switch_bank(svsp);
> +			int_sts = svs_readl(svsp, INTSTS);
> +			svs_en = svs_readl(svsp, SVSEN) & SVSB_EN_MASK;
> +
> +			if (int_sts == SVSB_INTSTS_COMPLETE &&
> +			    svs_en == SVSB_EN_INIT01)
> +				svs_init01_isr_handler(svsp);
> +			else if (int_sts == SVSB_INTSTS_COMPLETE &&
> +				 svs_en == SVSB_EN_INIT02)
> +				svs_init02_isr_handler(svsp);
> +			else if (int_sts & SVSB_INTSTS_MONVOP)
> +				svs_mon_mode_isr_handler(svsp);
> +			else
> +				svs_error_isr_handler(svsp);
> +		}
> +
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +		break;
> +	}
> +
> +	if (svsb->phase != SVSB_PHASE_INIT01)
> +		svs_adjust_pm_opp_volts(svsb, false);
> +
> +	if (svsb->phase == SVSB_PHASE_INIT01 ||
> +	    svsb->phase == SVSB_PHASE_INIT02)
> +		complete(&svsb->init_completion);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void svs_mon_mode(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	unsigned long flags;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_MON))
> +			continue;
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_MON);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +	}
> +}
> +
> +static int svs_init02(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	unsigned long flags, time_left;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT02))
> +			continue;
> +
> +		reinit_completion(&svsb->init_completion);
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_INIT02);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		time_left =
> +			wait_for_completion_timeout(&svsb->init_completion,
> +						    msecs_to_jiffies(5000));
> +		if (!time_left) {
> +			dev_err(svsb->dev, "init02 completion timeout\n");
> +			return -EBUSY;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int svs_init01(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	struct pm_qos_request *qos_request;
> +	unsigned long flags, time_left;
> +	bool search_done;
> +	int ret = 0;
> +	u32 opp_freqs, opp_vboot, buck_volt, idx, i;
> +
> +	qos_request = kzalloc(sizeof(*qos_request), GFP_KERNEL);
> +	if (!qos_request)
> +		return -ENOMEM;
> +
> +	/* Let CPUs leave idle-off state for initializing svs_init01. */
> +	cpu_latency_qos_add_request(qos_request, 0);
> +
> +	/*
> +	 * Sometimes two svs banks use the same buck.
> +	 * Therefore, we set each svs bank to vboot voltage first.
> +	 */
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		search_done = false;
> +
> +		if (svsb->pd_req) {
> +			ret = regulator_enable(svsb->buck);
> +			if (ret) {
> +				dev_err(svsb->dev, "%s enable fail: %d\n",
> +					svsb->buck_name, ret);
> +				goto init01_finish;
> +			}
> +
> +			if (!pm_runtime_enabled(svsb->pd_dev)) {
> +				pm_runtime_enable(svsb->pd_dev);
> +				svsb->enable_pm_runtime_ever = true;
> +			}
> +
> +			ret = pm_runtime_get_sync(svsb->pd_dev);
> +			if (ret < 0) {
> +				dev_err(svsb->dev, "mtcmos on fail: %d\n", ret);
> +				goto init01_finish;
> +			}
> +		}
> +
> +		if (regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST))
> +			dev_notice(svsb->dev, "set fast mode fail\n");
> +
> +		/*
> +		 * Find the fastest freq that can be run at vboot and
> +		 * fix to that freq until svs_init01 is done.
> +		 */
> +		opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
> +						      svsb->volt_step,
> +						      svsb->volt_base);
> +
> +		for (i = 0; i < svsb->opp_count; i++) {
> +			opp_freqs = svsb->opp_freqs[i];
> +			if (!search_done && svsb->opp_volts[i] <= opp_vboot) {
> +				ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
> +								opp_freqs,
> +								opp_vboot,
> +								opp_vboot,
> +								opp_vboot);
> +				if (ret) {
> +					dev_err(svsb->dev,
> +						"set voltage fail: %d\n", ret);
> +					goto init01_finish;
> +				}
> +
> +				search_done = true;
> +			} else {
> +				dev_pm_opp_disable(svsb->opp_dev,
> +						   svsb->opp_freqs[i]);
> +			}
> +		}
> +	}
> +
> +	/* svs bank init01 begins */
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
> +						      svsb->volt_step,
> +						      svsb->volt_base);
> +
> +		buck_volt = regulator_get_voltage(svsb->buck);
> +		if (buck_volt != opp_vboot) {
> +			dev_err(svsb->dev,
> +				"buck voltage: %u, expected vboot: %u\n",
> +				buck_volt, opp_vboot);
> +			ret = -EPERM;
> +			goto init01_finish;
> +		}
> +
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_set_bank_phase(svsp, SVSB_PHASE_INIT01);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		time_left =
> +			wait_for_completion_timeout(&svsb->init_completion,
> +						    msecs_to_jiffies(5000));
> +		if (!time_left) {
> +			dev_err(svsb->dev, "init01 completion timeout\n");
> +			ret = -EBUSY;
> +			goto init01_finish;
> +		}
> +	}
> +
> +init01_finish:
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (!(svsb->mode_support & SVSB_MODE_INIT01))
> +			continue;
> +
> +		for (i = 0; i < svsb->opp_count; i++)
> +			dev_pm_opp_enable(svsb->opp_dev, svsb->opp_freqs[i]);
> +
> +		if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL))
> +			dev_notice(svsb->dev, "fail to set normal mode\n");
> +
> +		if (svsb->pd_req) {
> +			if (pm_runtime_put_sync(svsb->pd_dev))
> +				dev_err(svsb->dev, "mtcmos off fail\n");
> +
> +			if (svsb->enable_pm_runtime_ever) {
> +				pm_runtime_disable(svsb->pd_dev);
> +				svsb->enable_pm_runtime_ever = false;
> +			}
> +
> +			if (regulator_disable(svsb->buck))
> +				dev_err(svsb->dev, "%s disable fail: %d\n",
> +					svsb->buck_name, ret);
> +		}
> +	}
> +
> +	cpu_latency_qos_remove_request(qos_request);
> +	kfree(qos_request);
> +
> +	return ret;
> +}
> +
> +static int svs_start(struct svs_platform *svsp)
> +{
> +	int ret;
> +
> +	ret = svs_init01(svsp);
> +	if (ret)
> +		return ret;
> +
> +	ret = svs_init02(svsp);
> +	if (ret)
> +		return ret;
> +
> +	svs_mon_mode(svsp);
> +
> +	return 0;
> +}
> +
> +static struct device *svs_get_subsys_device(struct svs_platform *svsp,
> +					    const char *node_name)
> +{
> +	struct platform_device *pdev;
> +	struct device_node *np;
> +
> +	np = of_find_node_by_name(NULL, node_name);
> +	if (!np) {
> +		dev_err(svsp->dev, "cannot find %s node\n", node_name);
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	pdev = of_find_device_by_node(np);
> +	if (!pdev) {
> +		of_node_put(np);
> +		dev_err(svsp->dev, "cannot find pdev by %s\n", node_name);
> +		return ERR_PTR(-ENXIO);
> +	}
> +
> +	of_node_put(np);
> +
> +	return &pdev->dev;
> +}
> +
> +static struct device *svs_add_device_link(struct svs_platform *svsp,
> +					  const char *node_name)
> +{
> +	struct device *dev;
> +	struct device_link *sup_link;
> +
> +	if (!node_name) {
> +		dev_err(svsp->dev, "node name cannot be null\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	dev = svs_get_subsys_device(svsp, node_name);
> +	if (IS_ERR(dev))
> +		return dev;
> +
> +	sup_link = device_link_add(svsp->dev, dev,
> +				   DL_FLAG_AUTOREMOVE_CONSUMER);
> +	if (!sup_link) {
> +		dev_err(svsp->dev, "sup_link is NULL\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	return dev;
> +}
> +
> +static int svs_resource_setup(struct svs_platform *svsp)
> +{
> +	struct svs_bank *svsb;
> +	struct dev_pm_opp *opp;
> +	unsigned long freq;
> +	int count, ret;
> +	u32 idx, i;
> +
> +	dev_set_drvdata(svsp->dev, svsp);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			svsb->name = "SVSB_CPU_LITTLE";
> +			break;
> +		case SVSB_CPU_BIG:
> +			svsb->name = "SVSB_CPU_BIG";
> +			break;
> +		case SVSB_CCI:
> +			svsb->name = "SVSB_CCI";
> +			break;
> +		case SVSB_GPU:
> +			svsb->name = "SVSB_GPU";
> +			break;
> +		default:
> +			WARN_ON(1);
> +			return -EINVAL;
> +		}
> +
> +		svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev),
> +					 GFP_KERNEL);
> +		if (!svsb->dev)
> +			return -ENOMEM;
> +
> +		ret = dev_set_name(svsb->dev, "%s", svsb->name);
> +		if (ret)
> +			return ret;
> +
> +		dev_set_drvdata(svsb->dev, svsp);
> +
> +		ret = dev_pm_opp_of_add_table(svsb->opp_dev);
> +		if (ret) {
> +			dev_err(svsb->dev, "add opp table fail: %d\n", ret);
> +			return ret;
> +		}
> +
> +		mutex_init(&svsb->lock);
> +		init_completion(&svsb->init_completion);
> +
> +		svsb->buck = devm_regulator_get_optional(svsb->opp_dev,
> +							 svsb->buck_name);
> +		if (IS_ERR(svsb->buck)) {
> +			dev_err(svsb->dev, "cannot get \"%s-supply\"\n",
> +				svsb->buck_name);
> +			return PTR_ERR(svsb->buck);
> +		}
> +
> +		count = dev_pm_opp_get_opp_count(svsb->opp_dev);
> +		if (svsb->opp_count != count) {
> +			dev_err(svsb->dev,
> +				"opp_count not \"%u\" but get \"%d\"?\n",
> +				svsb->opp_count, count);
> +			return count;
> +		}
> +
> +		for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
> +			opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq);
> +			if (IS_ERR(opp)) {
> +				dev_err(svsb->dev, "cannot find freq = %ld\n",
> +					PTR_ERR(opp));
> +				return PTR_ERR(opp);
> +			}
> +
> +			svsb->opp_freqs[i] = freq;
> +			svsb->opp_volts[i] = dev_pm_opp_get_voltage(opp);
> +			svsb->freqs_pct[i] = percent(svsb->opp_freqs[i],
> +						     svsb->freq_base);
> +			dev_pm_opp_put(opp);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
> +{
> +	struct thermal_parameter tp;
> +	struct svs_bank *svsb;
> +	bool mon_mode_support = true;
> +	int format[6], x_roomt[6], tb_roomt = 0;
> +	struct nvmem_cell *cell;
> +	u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
> +
> +	for (i = 0; i < svsp->efuse_num; i++)
> +		if (svsp->efuse[i])
> +			dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
> +				 i, svsp->efuse[i]);
> +
> +	/* Svs efuse parsing */
> +	ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		if (ft_pgm <= 1)
> +			svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE;
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			svsb->bdes = svsp->efuse[16] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 10;
> +			else
> +				svsb->volt_offset += 2;
> +			break;
> +		case SVSB_CPU_BIG:
> +			svsb->bdes = svsp->efuse[18] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = svsp->efuse[17] & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 15;
> +			else
> +				svsb->volt_offset += 12;
> +			break;
> +		case SVSB_CCI:
> +			svsb->bdes = svsp->efuse[4] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = (svsp->efuse[5] >> 16) & GENMASK(7, 0);
> +
> +			if (ft_pgm <= 3)
> +				svsb->volt_offset += 10;
> +			else
> +				svsb->volt_offset += 2;
> +			break;
> +		case SVSB_GPU:
> +			svsb->bdes = svsp->efuse[6] & GENMASK(7, 0);
> +			svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0);
> +			svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0);
> +			svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0);
> +			svsb->mtdes  = svsp->efuse[5] & GENMASK(7, 0);
> +
> +			if (ft_pgm >= 2) {
> +				svsb->freq_base = 800000000; /* 800MHz */
> +				svsb->dvt_fixed = 2;
> +			}
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	/* Get thermal efuse by nvmem */
> +	cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
> +	if (IS_ERR_OR_NULL(cell)) {
> +		dev_err(svsp->dev, "no thermal cell, no mon mode\n");
> +		for (idx = 0; idx < svsp->bank_num; idx++) {
> +			svsb = &svsp->banks[idx];
> +			svsb->mode_support &= ~SVSB_MODE_MON;
> +		}
> +
> +		return true;
> +	}
> +
> +	svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_num);



nvmem_cell_read may return an error pointer: you have to check that.



     if (IS_ERR(svsp->tefuse))

         .........



Failing to perform this check will produce unpredictable behavior

during the parsing stage.


> +	svsp->tefuse_num /= sizeof(u32);
> +	nvmem_cell_put(cell);
> +
> +	/* Thermal efuse parsing */
> +	tp.adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0);
> +	tp.adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0);
> +
> +	tp.o_vtsmcu1 = (svsp->tefuse[0] >> 17) & GENMASK(8, 0);
> +	tp.o_vtsmcu2 = (svsp->tefuse[0] >> 8) & GENMASK(8, 0);
> +	tp.o_vtsmcu3 = svsp->tefuse[1] & GENMASK(8, 0);
> +	tp.o_vtsmcu4 = (svsp->tefuse[2] >> 23) & GENMASK(8, 0);
> +	tp.o_vtsmcu5 = (svsp->tefuse[2] >> 5) & GENMASK(8, 0);
> +	tp.o_vtsabb = (svsp->tefuse[2] >> 14) & GENMASK(8, 0);
> +
> +	tp.degc_cali = (svsp->tefuse[0] >> 1) & GENMASK(5, 0);
> +	tp.adc_cali_en_t = svsp->tefuse[0] & BIT(0);
> +	tp.o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0);
> +
> +	tp.ts_id = (svsp->tefuse[1] >> 9) & BIT(0);
> +	tp.o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
> +
> +	if (tp.adc_cali_en_t == 1) {
> +		if (!tp.ts_id)
> +			tp.o_slope = 0;
> +
> +		if (tp.adc_ge_t < 265 || tp.adc_ge_t > 758 ||
> +		    tp.adc_oe_t < 265 || tp.adc_oe_t > 758 ||
> +		    tp.o_vtsmcu1 < -8 || tp.o_vtsmcu1 > 484 ||
> +		    tp.o_vtsmcu2 < -8 || tp.o_vtsmcu2 > 484 ||
> +		    tp.o_vtsmcu3 < -8 || tp.o_vtsmcu3 > 484 ||
> +		    tp.o_vtsmcu4 < -8 || tp.o_vtsmcu4 > 484 ||
> +		    tp.o_vtsmcu5 < -8 || tp.o_vtsmcu5 > 484 ||
> +		    tp.o_vtsabb < -8 || tp.o_vtsabb > 484 ||
> +		    tp.degc_cali < 1 || tp.degc_cali > 63) {
> +			dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
> +			mon_mode_support = false;
> +		}
> +	} else {
> +		dev_err(svsp->dev, "no thermal efuse, no mon mode\n");
> +		mon_mode_support = false;
> +	}
> +
> +	if (!mon_mode_support) {
> +		for (idx = 0; idx < svsp->bank_num; idx++) {
> +			svsb = &svsp->banks[idx];
> +			svsb->mode_support &= ~SVSB_MODE_MON;
> +		}
> +
> +		return true;
> +	}
> +
> +	tp.ge = ((tp.adc_ge_t - 512) * 10000) / 4096;
> +	tp.oe = (tp.adc_oe_t - 512);
> +	tp.gain = (10000 + tp.ge);
> +
> +	format[0] = (tp.o_vtsmcu1 + 3350 - tp.oe);
> +	format[1] = (tp.o_vtsmcu2 + 3350 - tp.oe);
> +	format[2] = (tp.o_vtsmcu3 + 3350 - tp.oe);
> +	format[3] = (tp.o_vtsmcu4 + 3350 - tp.oe);
> +	format[4] = (tp.o_vtsmcu5 + 3350 - tp.oe);
> +	format[5] = (tp.o_vtsabb + 3350 - tp.oe);
> +
> +	for (i = 0; i < 6; i++)
> +		x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / tp.gain;
> +
> +	temp0 = (10000 * 100000 / tp.gain) * 15 / 18;
> +
> +	if (!tp.o_slope_sign)
> +		mts = (temp0 * 10) / (1534 + tp.o_slope * 10);
> +	else
> +		mts = (temp0 * 10) / (1534 - tp.o_slope * 10);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		svsb->mts = mts;
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +			tb_roomt = x_roomt[3];
> +			break;
> +		case SVSB_CPU_BIG:
> +			tb_roomt = x_roomt[4];
> +			break;
> +		case SVSB_CCI:
> +			tb_roomt = x_roomt[3];
> +			break;
> +		case SVSB_GPU:
> +			tb_roomt = x_roomt[1];
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		temp0 = (tp.degc_cali * 10 / 2);
> +		temp1 = ((10000 * 100000 / 4096 / tp.gain) *
> +			 tp.oe + tb_roomt * 10) * 15 / 18;
> +
> +		if (!tp.o_slope_sign)
> +			temp2 = temp1 * 100 / (1534 + tp.o_slope * 10);
> +		else
> +			temp2 = temp1 * 100 / (1534 - tp.o_slope * 10);
> +
> +		svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
> +	}
> +
> +	return true;
> +}
> +
> +static bool svs_is_supported(struct svs_platform *svsp)
> +{
> +	struct nvmem_cell *cell;
> +
> +	/* Get svs efuse by nvmem */
> +	cell = nvmem_cell_get(svsp->dev, "svs-calibration-data");
> +	if (IS_ERR_OR_NULL(cell)) {
> +		dev_err(svsp->dev,
> +			"no \"svs-calibration-data\" from dts? disable svs\n");
> +		return false;
> +	}
> +
> +	svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_num);
> +	svsp->efuse_num /= sizeof(u32);
> +	nvmem_cell_put(cell);
> +
> +	if (!svsp->efuse[svsp->efuse_check]) {
> +		dev_err(svsp->dev, "svs_efuse[%u] = 0x%x?\n",
> +			svsp->efuse_check, svsp->efuse[svsp->efuse_check]);
> +		return false;
> +	}
> +
> +	return svsp->efuse_parsing(svsp);
> +}
> +
> +static int svs_suspend(struct device *dev)
> +{
> +	struct svs_platform *svsp = dev_get_drvdata(dev);
> +	struct svs_bank *svsb;
> +	unsigned long flags;
> +	int ret;
> +	u32 idx;
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		/* Wait if svs_isr() is still in process. */
> +		spin_lock_irqsave(&mtk_svs_lock, flags);
> +		svsp->pbank = svsb;
> +		svs_switch_bank(svsp);
> +		svs_writel(svsp, SVSB_EN_OFF, SVSEN);
> +		svs_writel(svsp, SVSB_INTSTS_CLEAN, INTSTS);
> +		spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +
> +		svsb->suspended = true;
> +		if (svsb->phase != SVSB_PHASE_INIT01) {
> +			svsb->phase = SVSB_PHASE_ERROR;
> +			svs_adjust_pm_opp_volts(svsb, true);
> +		}
> +	}
> +
> +	ret = reset_control_assert(svsp->rst);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot assert reset %d\n", ret);
> +		return ret;
> +	}
> +
> +	clk_disable_unprepare(svsp->main_clk);
> +
> +	return 0;
> +}
> +
> +static int svs_resume(struct device *dev)
> +{
> +	struct svs_platform *svsp = dev_get_drvdata(dev);
> +	struct svs_bank *svsb;
> +	int ret;
> +	u32 idx;
> +
> +	ret = clk_prepare_enable(svsp->main_clk);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot enable main_clk, disable svs\n");
> +		return ret;
> +	}
> +
> +	ret = reset_control_deassert(svsp->rst);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot deassert reset %d\n", ret);
> +		return ret;
> +	}
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +		svsb->suspended = false;
> +	}
> +
> +	ret = svs_init02(svsp);
> +	if (ret)
> +		return ret;
> +
> +	svs_mon_mode(svsp);
> +
> +	return 0;
> +}
> +
> +static struct svs_bank svs_mt8183_banks[] = {
> +	{
> +		.sw_id			= SVSB_CPU_LITTLE,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.cpu_id			= 0,
> +		.tzone_name		= "tzts4",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1989000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x64,
> +		.vmin			= 0x18,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0000,
> +		.int_st			= BIT(0),
> +		.ctl0			= 0x00010001,
> +	},
> +	{
> +		.sw_id			= SVSB_CPU_BIG,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.cpu_id			= 4,
> +		.tzone_name		= "tzts5",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1989000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x58,
> +		.vmin			= 0x10,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0001,
> +		.int_st			= BIT(1),
> +		.ctl0			= 0x00000001,
> +	},
> +	{
> +		.sw_id			= SVSB_CCI,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.tzone_name		= "tzts4",
> +		.buck_name		= "proc",
> +		.pd_req			= false,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> +		.opp_count		= 16,
> +		.freq_base		= 1196000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x64,
> +		.vmin			= 0x18,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x7,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 0,
> +		.core_sel		= 0x8fff0002,
> +		.int_st			= BIT(2),
> +		.ctl0			= 0x00100003,
> +	},
> +	{
> +		.sw_id			= SVSB_GPU,
> +		.set_freqs_pct		= svs_set_freqs_pct_v2,
> +		.get_vops		= svs_get_vops_v2,
> +		.tzone_name		= "tzts2",
> +		.buck_name		= "mali",
> +		.pd_req			= true,
> +		.volt_flags		= SVSB_INIT01_VOLT_INC_ONLY,
> +		.mode_support		= SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
> +					  SVSB_MODE_MON,
> +		.opp_count		= 16,
> +		.freq_base		= 900000000,
> +		.vboot			= 0x30,
> +		.volt_step		= 6250,
> +		.volt_base		= 500000,
> +		.volt_offset		= 0,
> +		.vmax			= 0x40,
> +		.vmin			= 0x14,
> +		.dthi			= 0x1,
> +		.dtlo			= 0xfe,
> +		.det_window		= 0xa28,
> +		.det_max		= 0xffff,
> +		.age_config		= 0x555555,
> +		.agem			= 0,
> +		.dc_config		= 0x555555,
> +		.dvt_fixed		= 0x3,
> +		.vco			= 0x10,
> +		.chk_shift		= 0x77,
> +		.temp_upper_bound	= 0x64,
> +		.temp_lower_bound	= 0xb2,
> +		.tzone_high_temp	= SVSB_TZONE_HIGH_TEMP_MAX,
> +		.tzone_low_temp		= 25000,
> +		.tzone_low_temp_offset	= 3,
> +		.core_sel		= 0x8fff0003,
> +		.int_st			= BIT(3),
> +		.ctl0			= 0x00050001,
> +	},
> +};
> +
> +static int svs_get_svs_mt8183_platform_data(struct svs_platform *svsp)
> +{
> +	struct device *dev;
> +	struct svs_bank *svsb;
> +	u32 idx;
> +
> +	svsp->name = "mt8183-svs";
> +	svsp->banks = svs_mt8183_banks;
> +	svsp->efuse_parsing = svs_mt8183_efuse_parsing;
> +	svsp->regs = svs_regs_v2;
> +	svsp->irqflags = IRQF_TRIGGER_LOW;
> +	svsp->rst = NULL;
> +	svsp->bank_num = ARRAY_SIZE(svs_mt8183_banks);
> +	svsp->efuse_check = 2;
> +
> +	dev = svs_add_device_link(svsp, "thermal");
> +	if (IS_ERR(dev))
> +		return PTR_ERR(dev);
> +
> +	for (idx = 0; idx < svsp->bank_num; idx++) {
> +		svsb = &svsp->banks[idx];
> +
> +		switch (svsb->sw_id) {
> +		case SVSB_CPU_LITTLE:
> +		case SVSB_CPU_BIG:
> +			svsb->opp_dev = get_cpu_device(svsb->cpu_id);
> +			break;
> +		case SVSB_CCI:
> +			svsb->opp_dev = svs_add_device_link(svsp, "cci");
> +			break;
> +		case SVSB_GPU:
> +			svsb->opp_dev = svs_add_device_link(svsp, "mali");
> +			svsb->pd_dev = svs_add_device_link(svsp,
> +							   "mali_gpu_core2");
> +			if (IS_ERR(svsb->pd_dev))
> +				return PTR_ERR(svsb->pd_dev);
> +			break;
> +		default:
> +			WARN_ON(1);
> +			return -EINVAL;
> +		}
> +
> +		if (IS_ERR(svsb->opp_dev))
> +			return PTR_ERR(svsb->opp_dev);
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mtk_svs_of_match[] = {
> +	{
> +		.compatible = "mediatek,mt8183-svs",
> +		.data = &svs_get_svs_mt8183_platform_data,
> +	}, {
> +		/* Sentinel */
> +	},
> +};
> +
> +static int svs_probe(struct platform_device *pdev)
> +{
> +	int (*svs_get_svs_platform_data)(struct svs_platform *svsp);
> +	struct svs_platform *svsp;
> +	unsigned int svsp_irq;
> +	int ret;
> +
> +	svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL);
> +	if (!svsp)
> +		return -ENOMEM;
> +
> +	svs_get_svs_platform_data = of_device_get_match_data(&pdev->dev);
> +	if (!svs_get_svs_platform_data) {
> +		dev_err(svsp->dev, "no svs platform data? why?\n");
> +		return -EPERM;
> +	}
> +
> +	svsp->dev = &pdev->dev;
> +	ret = svs_get_svs_platform_data(svsp);
> +	if (ret) {
> +		dev_err_probe(svsp->dev, ret, "fail to get svsp data\n");
> +		return ret;
> +	}
> +
> +	if (!svs_is_supported(svsp)) {
> +		dev_notice(svsp->dev, "svs is not supported\n");
> +		return -EPERM;
> +	}
> +
> +	ret = svs_resource_setup(svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "svs resource setup fail: %d\n", ret);
> +		return ret;
> +	}
> +
> +	svsp_irq = irq_of_parse_and_map(svsp->dev->of_node, 0);
> +	ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
> +					svsp->irqflags | IRQF_ONESHOT,
> +					svsp->name, svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "register irq(%d) failed: %d\n",
> +			svsp_irq, ret);
> +		return ret;
> +	}
> +
> +	svsp->main_clk = devm_clk_get(svsp->dev, "main");
> +	if (IS_ERR(svsp->main_clk)) {
> +		dev_err(svsp->dev, "failed to get clock: %ld\n",
> +			PTR_ERR(svsp->main_clk));
> +		return PTR_ERR(svsp->main_clk);
> +	}
> +
> +	ret = clk_prepare_enable(svsp->main_clk);
> +	if (ret) {
> +		dev_err(svsp->dev, "cannot enable main clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	svsp->base = of_iomap(svsp->dev->of_node, 0);
> +	if (IS_ERR_OR_NULL(svsp->base)) {
> +		dev_err(svsp->dev, "cannot find svs register base\n");
> +		ret = -EINVAL;
> +		goto svs_probe_clk_disable;
> +	}
> +
> +	ret = svs_start(svsp);
> +	if (ret) {
> +		dev_err(svsp->dev, "svs start fail: %d\n", ret);
> +		goto svs_probe_iounmap;
> +	}
> +
> +	return 0;
> +
> +svs_probe_iounmap:
> +	iounmap(svsp->base);
> +
> +svs_probe_clk_disable:
> +	clk_disable_unprepare(svsp->main_clk);
> +
> +	return ret;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(svs_pm_ops, svs_suspend, svs_resume);
> +
> +static struct platform_driver svs_driver = {
> +	.probe	= svs_probe,
> +	.driver	= {
> +		.name		= "mtk-svs",
> +		.pm		= &svs_pm_ops,
> +		.of_match_table	= of_match_ptr(mtk_svs_of_match),
> +	},
> +};
> +
> +module_platform_driver(svs_driver);
> +
> +MODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>");
> +MODULE_DESCRIPTION("MediaTek SVS driver");
> +MODULE_LICENSE("GPL v2");
> 


^ permalink raw reply

* [PATCHv2] Documentation: kgdb: Replace deprecated remotebaud
From: Christian Löhle @ 2022-01-05  9:58 UTC (permalink / raw)
  To: jason.wessel@windriver.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, daniel.thompson@linaro.org
  Cc: dianders@chromium.org, corbet@lwn.net
In-Reply-To: <13287b7914344c7995de27224cd2fa73@hyperstone.com>

Using set remotebaud to set the baud rate was deprecated in
gdb-7.7 and completely removed from the command parser in gdb-7.8
(released in 2014). Adopt set serial baud instead.

Signed-off-by: Christian Loehle <cloehle@hyperstone.com>
---
 Documentation/dev-tools/kgdb.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/dev-tools/kgdb.rst b/Documentation/dev-tools/kgdb.rst
index 43456244651a..7c90e111b364 100644
--- a/Documentation/dev-tools/kgdb.rst
+++ b/Documentation/dev-tools/kgdb.rst
@@ -557,7 +557,7 @@ Connecting with gdb to a serial port
    Example (using a directly connected port)::
 
            % gdb ./vmlinux
-           (gdb) set remotebaud 115200
+           (gdb) set serial baud 115200
            (gdb) target remote /dev/ttyS0
 
 
-- 
2.34.1
Hyperstone GmbH | Reichenaustr. 39a  | 78467 Konstanz
Managing Director: Dr. Jan Peter Berns.
Commercial register of local courts: Freiburg HRB381782


^ permalink raw reply related

* Re: [PATCH rdma-next] RDMA/rxe: Delete deprecated module parameters interface
From: Zhu Yanjun @ 2022-01-05  9:58 UTC (permalink / raw)
  To: Leon Romanovsky; +Cc: Jason Gunthorpe, Leon Romanovsky, LKML, RDMA mailing list
In-Reply-To: <c8376d7517aebe7cc851f0baaeef7b13707cf767.1641372460.git.leonro@nvidia.com>

On Wed, Jan 5, 2022 at 4:50 PM Leon Romanovsky <leon@kernel.org> wrote:
>
> From: Leon Romanovsky <leonro@nvidia.com>
>
> Starting from the commit 66920e1b2586 ("rdma_rxe: Use netlink messages
> to add/delete links") from the 2019, the RXE modules parameters are marked
> as deprecated in favour of rdmatool. So remove the kernel code too.
>
> Signed-off-by: Leon Romanovsky <leonro@nvidia.com>

Reviewed-by: Zhu Yanjun <zyjzyj2000@gmail.com>

Zhu Yanjun

> ---
>  drivers/infiniband/sw/rxe/Makefile    |   1 -
>  drivers/infiniband/sw/rxe/rxe.c       |   4 -
>  drivers/infiniband/sw/rxe/rxe.h       |   2 -
>  drivers/infiniband/sw/rxe/rxe_sysfs.c | 119 --------------------------
>  4 files changed, 126 deletions(-)
>  delete mode 100644 drivers/infiniband/sw/rxe/rxe_sysfs.c
>
> diff --git a/drivers/infiniband/sw/rxe/Makefile b/drivers/infiniband/sw/rxe/Makefile
> index 1e24673e9318..5395a581f4bb 100644
> --- a/drivers/infiniband/sw/rxe/Makefile
> +++ b/drivers/infiniband/sw/rxe/Makefile
> @@ -22,5 +22,4 @@ rdma_rxe-y := \
>         rxe_mcast.o \
>         rxe_task.o \
>         rxe_net.o \
> -       rxe_sysfs.o \
>         rxe_hw_counters.o
> diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c
> index 8e0f9c489cab..fab291245366 100644
> --- a/drivers/infiniband/sw/rxe/rxe.c
> +++ b/drivers/infiniband/sw/rxe/rxe.c
> @@ -13,8 +13,6 @@ MODULE_AUTHOR("Bob Pearson, Frank Zago, John Groves, Kamal Heib");
>  MODULE_DESCRIPTION("Soft RDMA transport");
>  MODULE_LICENSE("Dual BSD/GPL");
>
> -bool rxe_initialized;
> -
>  /* free resources for a rxe device all objects created for this device must
>   * have been destroyed
>   */
> @@ -290,7 +288,6 @@ static int __init rxe_module_init(void)
>                 return err;
>
>         rdma_link_register(&rxe_link_ops);
> -       rxe_initialized = true;
>         pr_info("loaded\n");
>         return 0;
>  }
> @@ -301,7 +298,6 @@ static void __exit rxe_module_exit(void)
>         ib_unregister_driver(RDMA_DRIVER_RXE);
>         rxe_net_exit();
>
> -       rxe_initialized = false;
>         pr_info("unloaded\n");
>  }
>
> diff --git a/drivers/infiniband/sw/rxe/rxe.h b/drivers/infiniband/sw/rxe/rxe.h
> index 1bb3fb618bf5..fb9066e6f5f0 100644
> --- a/drivers/infiniband/sw/rxe/rxe.h
> +++ b/drivers/infiniband/sw/rxe/rxe.h
> @@ -39,8 +39,6 @@
>
>  #define RXE_ROCE_V2_SPORT              (0xc000)
>
> -extern bool rxe_initialized;
> -
>  void rxe_set_mtu(struct rxe_dev *rxe, unsigned int dev_mtu);
>
>  int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name);
> diff --git a/drivers/infiniband/sw/rxe/rxe_sysfs.c b/drivers/infiniband/sw/rxe/rxe_sysfs.c
> deleted file mode 100644
> index 666202ddff48..000000000000
> --- a/drivers/infiniband/sw/rxe/rxe_sysfs.c
> +++ /dev/null
> @@ -1,119 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
> -/*
> - * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
> - * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
> - */
> -
> -#include "rxe.h"
> -#include "rxe_net.h"
> -
> -/* Copy argument and remove trailing CR. Return the new length. */
> -static int sanitize_arg(const char *val, char *intf, int intf_len)
> -{
> -       int len;
> -
> -       if (!val)
> -               return 0;
> -
> -       /* Remove newline. */
> -       for (len = 0; len < intf_len - 1 && val[len] && val[len] != '\n'; len++)
> -               intf[len] = val[len];
> -       intf[len] = 0;
> -
> -       if (len == 0 || (val[len] != 0 && val[len] != '\n'))
> -               return 0;
> -
> -       return len;
> -}
> -
> -static int rxe_param_set_add(const char *val, const struct kernel_param *kp)
> -{
> -       int len;
> -       int err = 0;
> -       char intf[32];
> -       struct net_device *ndev;
> -       struct rxe_dev *exists;
> -
> -       if (!rxe_initialized) {
> -               pr_err("Module parameters are not supported, use rdma link add or rxe_cfg\n");
> -               return -EAGAIN;
> -       }
> -
> -       len = sanitize_arg(val, intf, sizeof(intf));
> -       if (!len) {
> -               pr_err("add: invalid interface name\n");
> -               return -EINVAL;
> -       }
> -
> -       ndev = dev_get_by_name(&init_net, intf);
> -       if (!ndev) {
> -               pr_err("interface %s not found\n", intf);
> -               return -EINVAL;
> -       }
> -
> -       if (is_vlan_dev(ndev)) {
> -               pr_err("rxe creation allowed on top of a real device only\n");
> -               err = -EPERM;
> -               goto err;
> -       }
> -
> -       exists = rxe_get_dev_from_net(ndev);
> -       if (exists) {
> -               ib_device_put(&exists->ib_dev);
> -               pr_err("already configured on %s\n", intf);
> -               err = -EINVAL;
> -               goto err;
> -       }
> -
> -       err = rxe_net_add("rxe%d", ndev);
> -       if (err) {
> -               pr_err("failed to add %s\n", intf);
> -               goto err;
> -       }
> -
> -err:
> -       dev_put(ndev);
> -       return err;
> -}
> -
> -static int rxe_param_set_remove(const char *val, const struct kernel_param *kp)
> -{
> -       int len;
> -       char intf[32];
> -       struct ib_device *ib_dev;
> -
> -       len = sanitize_arg(val, intf, sizeof(intf));
> -       if (!len) {
> -               pr_err("add: invalid interface name\n");
> -               return -EINVAL;
> -       }
> -
> -       if (strncmp("all", intf, len) == 0) {
> -               pr_info("rxe_sys: remove all");
> -               ib_unregister_driver(RDMA_DRIVER_RXE);
> -               return 0;
> -       }
> -
> -       ib_dev = ib_device_get_by_name(intf, RDMA_DRIVER_RXE);
> -       if (!ib_dev) {
> -               pr_err("not configured on %s\n", intf);
> -               return -EINVAL;
> -       }
> -
> -       ib_unregister_device_and_put(ib_dev);
> -
> -       return 0;
> -}
> -
> -static const struct kernel_param_ops rxe_add_ops = {
> -       .set = rxe_param_set_add,
> -};
> -
> -static const struct kernel_param_ops rxe_remove_ops = {
> -       .set = rxe_param_set_remove,
> -};
> -
> -module_param_cb(add, &rxe_add_ops, NULL, 0200);
> -MODULE_PARM_DESC(add, "DEPRECATED.  Create RXE device over network interface");
> -module_param_cb(remove, &rxe_remove_ops, NULL, 0200);
> -MODULE_PARM_DESC(remove, "DEPRECATED.  Remove RXE device over network interface");
> --
> 2.33.1
>

^ permalink raw reply

* Re: [PATCH v2 0/3] dmaengine: Use platform_get_irq*() variants to fetch IRQ's
From: Andy Shevchenko @ 2022-01-05  9:56 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Matthias Brugger, Rob Herring, Prabhakar, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support
In-Reply-To: <20220104163519.21929-1-prabhakar.mahadev-lad.rj@bp.renesas.com>

On Tue, Jan 4, 2022 at 6:35 PM Lad Prabhakar
<prabhakar.mahadev-lad.rj@bp.renesas.com> wrote:
>
> Hi All,
>
> This patch series aims to drop using platform_get_resource() for IRQ types
> in preparation for removal of static setup of IRQ resource from DT core
> code.
>
> Dropping usage of platform_get_resource() was agreed based on
> the discussion [0].


All three looks good to me, FWIW,
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

> [0] https://patchwork.kernel.org/project/linux-renesas-soc/
> patch/20211209001056.29774-1-prabhakar.mahadev-lad.rj@bp.renesas.com/
>
> Cheers,
> Prabhakar
>
> Lad Prabhakar (3):
>   dmaengine: nbpfaxi: Use platform_get_irq_optional() to get the
>     interrupt
>   dmaengine: mediatek: mtk-hsdma: Use platform_get_irq() to get the
>     interrupt
>   dmaengine: mediatek-cqdma: Use platform_get_irq() to get the interrupt
>
>  drivers/dma/mediatek/mtk-cqdma.c | 12 ++++--------
>  drivers/dma/mediatek/mtk-hsdma.c | 11 ++++-------
>  drivers/dma/nbpfaxi.c            | 14 ++++++--------
>  3 files changed, 14 insertions(+), 23 deletions(-)
>
> --
> 2.17.1
>


-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] staging: rtl8723bs: Fix styling issues
From: Dan Carpenter @ 2022-01-05  9:57 UTC (permalink / raw)
  To: Ismayil Mirzali
  Cc: gregkh, Larry.Finger, linux-kernel, linux-staging, simon.fodin
In-Reply-To: <20211218203647.24486-1-ismayilmirzeli@gmail.com>

On Sat, Dec 18, 2021 at 10:36:47PM +0200, Ismayil Mirzali wrote:
> Removed extra whitespaces and brackets for oneline if statements

s/oneline/one line/.

Do this in two separate patches.

> 
> Signed-off-by: Ismayil Mirzali <ismayilmirzeli@gmail.com>
> ---
>  .../staging/rtl8723bs/hal/rtl8723bs_xmit.c    | 20 ++++++++-----------
>  1 file changed, 8 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
> index 7fe3df863fe1..7807b2a6cdc5 100644
> --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
> +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
> @@ -32,7 +32,7 @@ static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num)
>  	pHalData->SdioTxOQTFreeSpace -= agg_num;
>  
>  	/* if (n > 1) */
> -	/* 	++priv->pshare->nr_out_of_txoqt_space; */
> +	/*	++priv->pshare->nr_out_of_txoqt_space; */

Just delete dead code.

>  
>  	return true;
>  }
> @@ -147,13 +147,12 @@ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
>  		return _SUCCESS;
>  
>  	ret = rtw_register_tx_alive(padapter);
> -	if (ret != _SUCCESS) {
> +	if (ret != _SUCCESS)
>  		return _SUCCESS;
> -	}
>  
>  	do {
>  		queue_empty = rtl8723_dequeue_writeport(padapter);
> -/* 	dump secondary adapter xmitbuf */
> +		/*	dump secondary adapter xmitbuf */
>  	} while (!queue_empty);
>  
>  	rtw_unregister_tx_alive(padapter);
> @@ -311,7 +310,7 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
>  					pxmitframe->pg_num = (txlen + 127) / 128;
>  					pxmitbuf->pg_num += (txlen + 127) / 128;
>  				    /* if (k != 1) */
> -					/* 	((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */
> +					/*	((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */

Delete.

>  					pxmitbuf->ptail += _RND(txlen, 8); /*  round to 8 bytes alignment */
>  					pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
>  				}
> @@ -385,9 +384,8 @@ static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
>  	spin_lock_bh(&pxmitpriv->lock);
>  	ret = rtw_txframes_pending(padapter);
>  	spin_unlock_bh(&pxmitpriv->lock);
> -	if (ret == 0) {
> +	if (ret == 0)
>  		return _SUCCESS;
> -	}
>  
>  	/*  dequeue frame and write to hardware */
>  
> @@ -405,9 +403,8 @@ static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
>  	spin_lock_bh(&pxmitpriv->lock);
>  	ret = rtw_txframes_pending(padapter);
>  	spin_unlock_bh(&pxmitpriv->lock);
> -	if (ret == 1) {
> +	if (ret == 1)
>  		goto next;
> -	}
>  
>  	return _SUCCESS;
>  }
> @@ -428,10 +425,9 @@ int rtl8723bs_xmit_thread(void *context)
>  
>  	do {
>  		ret = rtl8723bs_xmit_handler(padapter);
> -		if (signal_pending(current)) {
> +		if (signal_pending(current))
>  			flush_signals(current);
> -		}
> -	} while (_SUCCESS == ret);
> +	} while (ret == _SUCCESS);

This change was not described in the commit message.

regards,
dan carpenter


^ permalink raw reply

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for series starting with [v2,1/2] drm/i915: split out intel_vtd.[ch] from i915_drv.h
From: Patchwork @ 2022-01-05  9:57 UTC (permalink / raw)
  To: Jani Nikula; +Cc: intel-gfx
In-Reply-To: <20220105094155.933291-1-jani.nikula@intel.com>

== Series Details ==

Series: series starting with [v2,1/2] drm/i915: split out intel_vtd.[ch] from i915_drv.h
URL   : https://patchwork.freedesktop.org/series/98498/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.



^ permalink raw reply

* [PATCH 0/2] spapr: Fix support of POWER5+ processors
From: Cédric Le Goater @ 2022-01-05  9:51 UTC (permalink / raw)
  To: qemu-ppc, qemu-devel
  Cc: Alexey Kardashevskiy, Cédric Le Goater, Greg Kurz,
	David Gibson

Hello,

Grab the images under : 

  https://github.com/legoater/qemu-ppc-boot/tree/main/buildroot/qemu_ppc64_pseries_p5p-2021.11-730-g4f325ce788-20220104

and run with :

  qemu-system-ppc64 -M pseries -cpu POWER5+ -m 1G -smp 2 -kernel ./vmlinux -append "root=/dev/sda" -drive file=./rootfs.ext2,if=scsi,index=0,format=raw  -device spapr-vlan,netdev=net0 -netdev user,id=net0 -serial mon:stdio -nographic -nodefaults

CPU 970, 970MP are also well supported. 

Virtio devices and USB should be avoided because SLOF would use a
'stdbrx' instruction (cpu_to_le64 helper) which is invalid under
POWER5+ and 970 CPUs. SLOF needs to be compiled with -mcpu=power5 to
fix this issue.

Thanks,

C. 

Cédric Le Goater (2):
  target/ppc: Add popcntb instruction to POWER5+ processors
  spapr: Fix support of POWER5+ processors

 hw/ppc/spapr.c        | 10 ++++++----
 target/ppc/cpu_init.c |  1 +
 2 files changed, 7 insertions(+), 4 deletions(-)

-- 
2.31.1



^ permalink raw reply

* linux-next: Signed-off-by missing for commits in the libata tree
From: Stephen Rothwell @ 2022-01-05  9:57 UTC (permalink / raw)
  To: Damien Le Moal; +Cc: Linux Kernel Mailing List, Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 230 bytes --]

Hi all,

Commits

  b3a1ea642b5f ("ata: sata_dwc_460ex: drop DEBUG_NCQ")
  8fb32f1d555c ("ata: libata: tracepoints for bus-master DMA")

are missing a Signed-off-by from their committers.

-- 
Cheers,
Stephen Rothwell

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH v2 0/3] dmaengine: Use platform_get_irq*() variants to fetch IRQ's
From: Andy Shevchenko @ 2022-01-05  9:56 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Matthias Brugger, Rob Herring, Prabhakar, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support
In-Reply-To: <20220104163519.21929-1-prabhakar.mahadev-lad.rj@bp.renesas.com>

On Tue, Jan 4, 2022 at 6:35 PM Lad Prabhakar
<prabhakar.mahadev-lad.rj@bp.renesas.com> wrote:
>
> Hi All,
>
> This patch series aims to drop using platform_get_resource() for IRQ types
> in preparation for removal of static setup of IRQ resource from DT core
> code.
>
> Dropping usage of platform_get_resource() was agreed based on
> the discussion [0].


All three looks good to me, FWIW,
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

> [0] https://patchwork.kernel.org/project/linux-renesas-soc/
> patch/20211209001056.29774-1-prabhakar.mahadev-lad.rj@bp.renesas.com/
>
> Cheers,
> Prabhakar
>
> Lad Prabhakar (3):
>   dmaengine: nbpfaxi: Use platform_get_irq_optional() to get the
>     interrupt
>   dmaengine: mediatek: mtk-hsdma: Use platform_get_irq() to get the
>     interrupt
>   dmaengine: mediatek-cqdma: Use platform_get_irq() to get the interrupt
>
>  drivers/dma/mediatek/mtk-cqdma.c | 12 ++++--------
>  drivers/dma/mediatek/mtk-hsdma.c | 11 ++++-------
>  drivers/dma/nbpfaxi.c            | 14 ++++++--------
>  3 files changed, 14 insertions(+), 23 deletions(-)
>
> --
> 2.17.1
>


-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

^ permalink raw reply

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [v2,1/2] drm/i915: split out intel_vtd.[ch] from i915_drv.h
From: Patchwork @ 2022-01-05  9:56 UTC (permalink / raw)
  To: Jani Nikula; +Cc: intel-gfx
In-Reply-To: <20220105094155.933291-1-jani.nikula@intel.com>

== Series Details ==

Series: series starting with [v2,1/2] drm/i915: split out intel_vtd.[ch] from i915_drv.h
URL   : https://patchwork.freedesktop.org/series/98498/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
4c826c63dab3 drm/i915: split out intel_vtd.[ch] from i915_drv.h
-:314: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#314: 
new file mode 100644

total: 0 errors, 1 warnings, 0 checks, 272 lines checked
312bce2a81ff drm/i915/vtd: rename functions to have the usual prefix



^ permalink raw reply

* Re: [RFC v2 4/8] drm/amdgpu: Serialize non TDR gpu recovery with TDRs
From: Lazar, Lijo @ 2022-01-05  9:54 UTC (permalink / raw)
  To: Andrey Grodzovsky, dri-devel, amd-gfx
  Cc: daniel, horace.chen, christian.koenig, Monk.Liu
In-Reply-To: <20211222220506.789133-5-andrey.grodzovsky@amd.com>



On 12/23/2021 3:35 AM, Andrey Grodzovsky wrote:
> Use reset domain wq also for non TDR gpu recovery trigers
> such as sysfs and RAS. We must serialize all possible
> GPU recoveries to gurantee no concurrency there.
> For TDR call the original recovery function directly since
> it's already executed from within the wq. For others just
> use a wrapper to qeueue work and wait on it to finish.
> 
> v2: Rename to amdgpu_recover_work_struct
> 
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu.h        |  2 ++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 33 +++++++++++++++++++++-
>   drivers/gpu/drm/amd/amdgpu/amdgpu_job.c    |  2 +-
>   3 files changed, 35 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index b5ff76aae7e0..8e96b9a14452 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -1296,6 +1296,8 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev);
>   bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
>   int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
>   			      struct amdgpu_job* job);
> +int amdgpu_device_gpu_recover_imp(struct amdgpu_device *adev,
> +			      struct amdgpu_job *job);
>   void amdgpu_device_pci_config_reset(struct amdgpu_device *adev);
>   int amdgpu_device_pci_reset(struct amdgpu_device *adev);
>   bool amdgpu_device_need_post(struct amdgpu_device *adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 7c063fd37389..258ec3c0b2af 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -4979,7 +4979,7 @@ static void amdgpu_device_recheck_guilty_jobs(
>    * Returns 0 for success or an error on failure.
>    */
>   
> -int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
> +int amdgpu_device_gpu_recover_imp(struct amdgpu_device *adev,
>   			      struct amdgpu_job *job)
>   {
>   	struct list_head device_list, *device_list_handle =  NULL;
> @@ -5237,6 +5237,37 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
>   	return r;
>   }
>   
> +struct amdgpu_recover_work_struct {
> +	struct work_struct base;
> +	struct amdgpu_device *adev;
> +	struct amdgpu_job *job;
> +	int ret;
> +};
> +
> +static void amdgpu_device_queue_gpu_recover_work(struct work_struct *work)
> +{
> +	struct amdgpu_recover_work_struct *recover_work = container_of(work, struct amdgpu_recover_work_struct, base);
> +
> +	recover_work->ret = amdgpu_device_gpu_recover_imp(recover_work->adev, recover_work->job);
> +}
> +/*
> + * Serialize gpu recover into reset domain single threaded wq
> + */
> +int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
> +				    struct amdgpu_job *job)
> +{
> +	struct amdgpu_recover_work_struct work = {.adev = adev, .job = job};
> +
> +	INIT_WORK(&work.base, amdgpu_device_queue_gpu_recover_work);
> +
> +	if (!queue_work(adev->reset_domain.wq, &work.base))
> +		return -EAGAIN;
> +

The decision to schedule a reset is made at this point. Subsequent 
accesses to hardware may not be reliable. So should the flag in_reset be 
set here itself rather than waiting for the work to start execution?

Also, what about having the reset_active or in_reset flag in the 
reset_domain itself?

Thanks,
Lijo

> +	flush_work(&work.base);
> +
> +	return work.ret;
> +}
> +
>   /**
>    * amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot
>    *
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> index bfc47bea23db..38c9fd7b7ad4 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> @@ -63,7 +63,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
>   		  ti.process_name, ti.tgid, ti.task_name, ti.pid);
>   
>   	if (amdgpu_device_should_recover_gpu(ring->adev)) {
> -		amdgpu_device_gpu_recover(ring->adev, job);
> +		amdgpu_device_gpu_recover_imp(ring->adev, job);
>   	} else {
>   		drm_sched_suspend_timeout(&ring->sched);
>   		if (amdgpu_sriov_vf(adev))
> 

^ permalink raw reply

* Re: [RFC v2 4/8] drm/amdgpu: Serialize non TDR gpu recovery with TDRs
From: Lazar, Lijo @ 2022-01-05  9:54 UTC (permalink / raw)
  To: Andrey Grodzovsky, dri-devel, amd-gfx
  Cc: horace.chen, christian.koenig, Monk.Liu
In-Reply-To: <20211222220506.789133-5-andrey.grodzovsky@amd.com>



On 12/23/2021 3:35 AM, Andrey Grodzovsky wrote:
> Use reset domain wq also for non TDR gpu recovery trigers
> such as sysfs and RAS. We must serialize all possible
> GPU recoveries to gurantee no concurrency there.
> For TDR call the original recovery function directly since
> it's already executed from within the wq. For others just
> use a wrapper to qeueue work and wait on it to finish.
> 
> v2: Rename to amdgpu_recover_work_struct
> 
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu.h        |  2 ++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 33 +++++++++++++++++++++-
>   drivers/gpu/drm/amd/amdgpu/amdgpu_job.c    |  2 +-
>   3 files changed, 35 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index b5ff76aae7e0..8e96b9a14452 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -1296,6 +1296,8 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev);
>   bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
>   int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
>   			      struct amdgpu_job* job);
> +int amdgpu_device_gpu_recover_imp(struct amdgpu_device *adev,
> +			      struct amdgpu_job *job);
>   void amdgpu_device_pci_config_reset(struct amdgpu_device *adev);
>   int amdgpu_device_pci_reset(struct amdgpu_device *adev);
>   bool amdgpu_device_need_post(struct amdgpu_device *adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 7c063fd37389..258ec3c0b2af 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -4979,7 +4979,7 @@ static void amdgpu_device_recheck_guilty_jobs(
>    * Returns 0 for success or an error on failure.
>    */
>   
> -int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
> +int amdgpu_device_gpu_recover_imp(struct amdgpu_device *adev,
>   			      struct amdgpu_job *job)
>   {
>   	struct list_head device_list, *device_list_handle =  NULL;
> @@ -5237,6 +5237,37 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
>   	return r;
>   }
>   
> +struct amdgpu_recover_work_struct {
> +	struct work_struct base;
> +	struct amdgpu_device *adev;
> +	struct amdgpu_job *job;
> +	int ret;
> +};
> +
> +static void amdgpu_device_queue_gpu_recover_work(struct work_struct *work)
> +{
> +	struct amdgpu_recover_work_struct *recover_work = container_of(work, struct amdgpu_recover_work_struct, base);
> +
> +	recover_work->ret = amdgpu_device_gpu_recover_imp(recover_work->adev, recover_work->job);
> +}
> +/*
> + * Serialize gpu recover into reset domain single threaded wq
> + */
> +int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
> +				    struct amdgpu_job *job)
> +{
> +	struct amdgpu_recover_work_struct work = {.adev = adev, .job = job};
> +
> +	INIT_WORK(&work.base, amdgpu_device_queue_gpu_recover_work);
> +
> +	if (!queue_work(adev->reset_domain.wq, &work.base))
> +		return -EAGAIN;
> +

The decision to schedule a reset is made at this point. Subsequent 
accesses to hardware may not be reliable. So should the flag in_reset be 
set here itself rather than waiting for the work to start execution?

Also, what about having the reset_active or in_reset flag in the 
reset_domain itself?

Thanks,
Lijo

> +	flush_work(&work.base);
> +
> +	return work.ret;
> +}
> +
>   /**
>    * amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot
>    *
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> index bfc47bea23db..38c9fd7b7ad4 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> @@ -63,7 +63,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
>   		  ti.process_name, ti.tgid, ti.task_name, ti.pid);
>   
>   	if (amdgpu_device_should_recover_gpu(ring->adev)) {
> -		amdgpu_device_gpu_recover(ring->adev, job);
> +		amdgpu_device_gpu_recover_imp(ring->adev, job);
>   	} else {
>   		drm_sched_suspend_timeout(&ring->sched);
>   		if (amdgpu_sriov_vf(adev))
> 

^ permalink raw reply

* [PATCH] MAINTAINERS: Add entry for QEMU Guest Agent Windows components
From: Kostiantyn Kostiuk @ 2022-01-05  9:50 UTC (permalink / raw)
  To: qemu-devel, Michael Roth, Marc-André Lureau,
	Philippe Mathieu-Daudé, Paolo Bonzini, Daniel P . Berrange

Signed-off-by: Kostiantyn Kostiuk <kkostiuk@redhat.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f871d759fd..1f255ec874 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2729,6 +2729,14 @@ F: scripts/qemu-guest-agent/
 F: tests/unit/test-qga.c
 T: git https://github.com/mdroth/qemu.git qga

+QEMU Guest Agent Win32
+M: Konstantin Kostiuk <kkostiuk@redhat.com>
+S: Maintained
+F: qga/*win32*
+F: qga/vss-win32/
+F: qga/installer/
+T: git https://github.com/kostyanf14/qemu.git qga-win32
+
 QOM
 M: Paolo Bonzini <pbonzini@redhat.com>
 R: Daniel P. Berrange <berrange@redhat.com>
--
2.25.1



^ permalink raw reply related

* [PATCH 1/2] target/ppc: Add popcntb instruction to POWER5+ processors
From: Cédric Le Goater @ 2022-01-05  9:51 UTC (permalink / raw)
  To: qemu-ppc, qemu-devel
  Cc: Alexey Kardashevskiy, Cédric Le Goater, Greg Kurz,
	David Gibson
In-Reply-To: <20220105095142.3990430-1-clg@kaod.org>

popcntb instruction was added in ISA v2.02. Add support for POWER5+
processors since they implement ISA v2.03.

PPC970 CPUs implement v2.01 and do not support popcntb.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 target/ppc/cpu_init.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index cc93bff3fac4..f15a52259c90 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6957,6 +6957,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
                        PPC_MEM_SYNC | PPC_MEM_EIEIO |
                        PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
                        PPC_64B |
+                       PPC_POPCNTB |
                        PPC_SEGMENT_64B | PPC_SLBI;
     pcc->insns_flags2 = PPC2_FP_CVT_S64;
     pcc->msr_mask = (1ull << MSR_SF) |
-- 
2.31.1



^ permalink raw reply related


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.